Only use accumulated hash in Witness object

This commit is contained in:
Manfred Karrer 2017-10-21 14:07:48 -05:00
parent a33923cc1e
commit e56fc44956
No known key found for this signature in database
GPG key ID: 401250966A6B2C46
43 changed files with 666 additions and 713 deletions

View file

@ -248,7 +248,7 @@ public class CurrencyUtil {
if (isCryptoCurrency(currencyCode) && cryptoCurrencyOptional.isPresent()) { if (isCryptoCurrency(currencyCode) && cryptoCurrencyOptional.isPresent()) {
return Optional.of(cryptoCurrencyOptional.get()); return Optional.of(cryptoCurrencyOptional.get());
} else { } else {
return Optional.empty(); return Optional.<TradeCurrency>empty();
} }
} }
} }

View file

@ -24,6 +24,7 @@ import com.google.gson.*;
import io.bisq.common.crypto.LimitedKeyStrengthException; import io.bisq.common.crypto.LimitedKeyStrengthException;
import javafx.scene.input.*; import javafx.scene.input.*;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.bitcoinj.core.Utils; import org.bitcoinj.core.Utils;
@ -56,11 +57,11 @@ public class Utilities {
// TODO check out Jackson lib // TODO check out Jackson lib
public static String objectToJson(Object object) { public static String objectToJson(Object object) {
Gson gson = new GsonBuilder() Gson gson = new GsonBuilder()
.setExclusionStrategies(new AnnotationExclusionStrategy()) .setExclusionStrategies(new AnnotationExclusionStrategy())
/*.excludeFieldsWithModifiers(Modifier.TRANSIENT)*/ /*.excludeFieldsWithModifiers(Modifier.TRANSIENT)*/
/* .setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE)*/ /* .setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE)*/
.setPrettyPrinting() .setPrettyPrinting()
.create(); .create();
return gson.toJson(object); return gson.toJson(object);
} }
@ -76,11 +77,11 @@ public class Utilities {
int maximumPoolSize, int maximumPoolSize,
long keepAliveTimeInSec) { long keepAliveTimeInSec) {
final ThreadFactory threadFactory = new ThreadFactoryBuilder() final ThreadFactory threadFactory = new ThreadFactoryBuilder()
.setNameFormat(name) .setNameFormat(name)
.setDaemon(true) .setDaemon(true)
.build(); .build();
ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTimeInSec, ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTimeInSec,
TimeUnit.SECONDS, new ArrayBlockingQueue<>(maximumPoolSize), threadFactory); TimeUnit.SECONDS, new ArrayBlockingQueue<>(maximumPoolSize), threadFactory);
executor.allowCoreThreadTimeOut(true); executor.allowCoreThreadTimeOut(true);
executor.setRejectedExecutionHandler((r, e) -> log.debug("RejectedExecutionHandler called")); executor.setRejectedExecutionHandler((r, e) -> log.debug("RejectedExecutionHandler called"));
return executor; return executor;
@ -93,10 +94,10 @@ public class Utilities {
int maximumPoolSize, int maximumPoolSize,
long keepAliveTimeInSec) { long keepAliveTimeInSec) {
final ThreadFactory threadFactory = new ThreadFactoryBuilder() final ThreadFactory threadFactory = new ThreadFactoryBuilder()
.setNameFormat(name) .setNameFormat(name)
.setDaemon(true) .setDaemon(true)
.setPriority(Thread.MIN_PRIORITY) .setPriority(Thread.MIN_PRIORITY)
.build(); .build();
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(corePoolSize, threadFactory); ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
executor.setKeepAliveTime(keepAliveTimeInSec, TimeUnit.SECONDS); executor.setKeepAliveTime(keepAliveTimeInSec, TimeUnit.SECONDS);
executor.allowCoreThreadTimeOut(true); executor.allowCoreThreadTimeOut(true);
@ -134,8 +135,8 @@ public class Utilities {
String arch = System.getenv("PROCESSOR_ARCHITECTURE"); String arch = System.getenv("PROCESSOR_ARCHITECTURE");
String wow64Arch = System.getenv("PROCESSOR_ARCHITEW6432"); String wow64Arch = System.getenv("PROCESSOR_ARCHITEW6432");
return arch.endsWith("64") return arch.endsWith("64")
|| wow64Arch != null && wow64Arch.endsWith("64") || wow64Arch != null && wow64Arch.endsWith("64")
? "64" : "32"; ? "64" : "32";
} else if (osArch.contains("arm")) { } else if (osArch.contains("arm")) {
// armv8 is 64 bit, armv7l is 32 bit // armv8 is 64 bit, armv7l is 32 bit
return osArch.contains("64") || osArch.contains("v8") ? "64" : "32"; return osArch.contains("64") || osArch.contains("v8") ? "64" : "32";
@ -148,12 +149,12 @@ public class Utilities {
public static void printSysInfo() { public static void printSysInfo() {
log.info("System info: os.name={}; os.version={}; os.arch={}; sun.arch.data.model={}; JRE={}; JVM={}", log.info("System info: os.name={}; os.version={}; os.arch={}; sun.arch.data.model={}; JRE={}; JVM={}",
System.getProperty("os.name"), System.getProperty("os.name"),
System.getProperty("os.version"), System.getProperty("os.version"),
System.getProperty("os.arch"), System.getProperty("os.arch"),
getJVMArchitecture(), getJVMArchitecture(),
(System.getProperty("java.runtime.version", "-") + " (" + System.getProperty("java.vendor", "-") + ")"), (System.getProperty("java.runtime.version", "-") + " (" + System.getProperty("java.vendor", "-") + ")"),
(System.getProperty("java.vm.version", "-") + " (" + System.getProperty("java.vm.name", "-") + ")") (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 { public static void openURI(URI uri) throws IOException {
if (!isLinux() if (!isLinux()
&& isDesktopSupported() && isDesktopSupported()
&& getDesktop().isSupported(Action.BROWSE)) { && getDesktop().isSupported(Action.BROWSE)) {
getDesktop().browse(uri); getDesktop().browse(uri);
} else { } else {
// Maybe Application.HostServices works in those cases? // Maybe Application.HostServices works in those cases?
@ -192,8 +193,8 @@ public class Utilities {
public static void openFile(File file) throws IOException { public static void openFile(File file) throws IOException {
if (!isLinux() if (!isLinux()
&& isDesktopSupported() && isDesktopSupported()
&& getDesktop().isSupported(Action.OPEN)) { && getDesktop().isSupported(Action.OPEN)) {
getDesktop().open(file); getDesktop().open(file);
} else { } else {
// Maybe Application.HostServices works in those cases? // Maybe Application.HostServices works in those cases?
@ -258,7 +259,7 @@ public class Utilities {
public static <T> T jsonToObject(String jsonString, Class<T> classOfT) { public static <T> T jsonToObject(String jsonString, Class<T> classOfT) {
Gson gson = 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); return gson.fromJson(jsonString, classOfT);
} }
@ -372,13 +373,29 @@ public class Utilities {
public static boolean isCtrlPressed(KeyCode keyCode, KeyEvent keyEvent) { public static boolean isCtrlPressed(KeyCode keyCode, KeyEvent keyEvent) {
return new KeyCodeCombination(keyCode, KeyCombination.SHORTCUT_DOWN).match(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) { public static boolean isAltPressed(KeyCode keyCode, KeyEvent keyEvent) {
return new KeyCodeCombination(keyCode, KeyCombination.ALT_DOWN).match(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 { private static class AnnotationExclusionStrategy implements ExclusionStrategy {
@Override @Override
public boolean shouldSkipField(FieldAttributes f) { public boolean shouldSkipField(FieldAttributes f) {
@ -503,6 +520,6 @@ public class Utilities {
final String name = System.getProperty("java.runtime.name"); final String name = System.getProperty("java.runtime.name");
final String ver = System.getProperty("java.version"); final String ver = System.getProperty("java.version");
return name != null && name.equals("Java(TM) SE Runtime Environment") 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"));
} }
} }

View file

@ -55,7 +55,7 @@ message NetworkEnvelope {
GetBsqBlocksRequest get_bsq_blocks_request = 28; GetBsqBlocksRequest get_bsq_blocks_request = 28;
GetBsqBlocksResponse get_bsq_blocks_response = 29; GetBsqBlocksResponse get_bsq_blocks_response = 29;
NewBsqBlockBroadcastMessage new_bsq_block_broadcast_message = 30; NewBsqBlockBroadcastMessage new_bsq_block_broadcast_message = 30;
AddPersistableNetworkPayloadMessage add_persistable_network_payload_message = 31; AddPersistableNetworkPayloadMessage add_persistable_network_payload_message = 31;
} }
} }
@ -131,10 +131,10 @@ message OfferAvailabilityResponse {
} }
message RefreshOfferMessage { message RefreshOfferMessage {
bytes hash_of_data_and_seq_nr = 1; bytes hash_of_data_and_seq_nr = 1;
bytes signature = 2; bytes signature = 2;
bytes hash_of_payload = 3; bytes hash_of_payload = 3;
int32 sequence_number = 4; int32 sequence_number = 4;
} }
@ -195,8 +195,9 @@ message PayDepositRequest {
NodeAddress arbitrator_node_address = 19; NodeAddress arbitrator_node_address = 19;
NodeAddress mediator_node_address = 20; NodeAddress mediator_node_address = 20;
string uid = 21; string uid = 21;
bytes account_age_witness_nonce = 22; bytes account_age_witness_signature_of_account_data = 22;
bytes account_age_witness_signature_of_nonce = 23; bytes account_age_witness_nonce = 23;
bytes account_age_witness_signature_of_nonce = 24;
} }
message PublishDepositTxRequest { message PublishDepositTxRequest {
@ -211,8 +212,9 @@ message PublishDepositTxRequest {
bytes maker_multi_sig_pub_key = 9; bytes maker_multi_sig_pub_key = 9;
NodeAddress sender_node_address = 10; NodeAddress sender_node_address = 10;
string uid = 11; string uid = 11;
bytes account_age_witness_nonce = 12; bytes account_age_witness_signature_of_account_data = 12;
bytes account_age_witness_signature_of_nonce = 13; bytes account_age_witness_nonce = 13;
bytes account_age_witness_signature_of_nonce = 14;
} }
message DepositTxPublishedMessage { message DepositTxPublishedMessage {
@ -498,7 +500,7 @@ message Tx {
int64 burnt_fee = 4; int64 burnt_fee = 4;
TxType tx_type = 5; TxType tx_type = 5;
} }
message BsqBlock { message BsqBlock {
int32 height = 1; int32 height = 1;
string hash = 2; string hash = 2;
@ -560,7 +562,7 @@ message Filter {
bytes owner_pub_key_bytes = 5; bytes owner_pub_key_bytes = 5;
map<string, string> extra_data = 6; map<string, string> extra_data = 6;
repeated string banned_currencies = 7; repeated string banned_currencies = 7;
repeated string banned_payment_methods = 8; repeated string banned_payment_methods = 8;
} }
message TradeStatistics { message TradeStatistics {
@ -606,7 +608,7 @@ message OfferPayload {
double market_price_margin = 7; double market_price_margin = 7;
bool use_market_based_price = 8; bool use_market_based_price = 8;
int64 amount = 9; int64 amount = 9;
int64 min_amount = 10; int64 min_amount = 10;
string base_currency_code = 11; string base_currency_code = 11;
string counter_currency_code = 12; string counter_currency_code = 12;
repeated NodeAddress arbitrator_node_addresses = 13; repeated NodeAddress arbitrator_node_addresses = 13;
@ -661,9 +663,7 @@ message CompensationRequestPayload {
message AccountAgeWitness { message AccountAgeWitness {
bytes hash = 1; bytes hash = 1;
bytes sig_pub_key_hash = 2; int64 date = 2;
bytes signature = 3;
int64 date = 4;
} }
@ -926,20 +926,20 @@ message PersistableEnvelope {
PeerList peer_list = 3; PeerList peer_list = 3;
AddressEntryList address_entry_list = 4; AddressEntryList address_entry_list = 4;
NavigationPath navigation_path = 5; NavigationPath navigation_path = 5;
TradableList tradable_list = 6; TradableList tradable_list = 6;
TradeStatisticsList trade_statistics_list = 7; TradeStatisticsList trade_statistics_list = 7;
DisputeList dispute_list = 8; DisputeList dispute_list = 8;
PreferencesPayload preferences_payload = 9; PreferencesPayload preferences_payload = 9;
UserPayload user_payload = 10; UserPayload user_payload = 10;
PaymentAccountList payment_account_list = 11; PaymentAccountList payment_account_list = 11;
// TODO not fully implemented yet // TODO not fully implemented yet
CompensationRequestPayload compensation_request_payload = 12; CompensationRequestPayload compensation_request_payload = 12;
VoteItemsList vote_items_list = 13; VoteItemsList vote_items_list = 13;
BsqChainState bsq_chain_state = 14; BsqChainState bsq_chain_state = 14;
PersistableNetworkPayloadList persistable_network_payload_list = 15; PersistableNetworkPayloadList persistable_network_payload_list = 15;
} }
} }
@ -1198,8 +1198,9 @@ message TradingPeer {
repeated RawTransactionInput raw_transaction_inputs = 9; repeated RawTransactionInput raw_transaction_inputs = 9;
int64 change_output_value = 10; int64 change_output_value = 10;
string change_output_address = 11; string change_output_address = 11;
bytes account_age_witness_nonce = 12; bytes account_age_witness_signature_of_account_data = 12;
bytes account_age_witness_signature_of_nonce = 13; bytes account_age_witness_nonce = 13;
bytes account_age_witness_signature_of_nonce = 14;
} }
message AccountAgeWitnessMap { message AccountAgeWitnessMap {

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
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})));
}
}

View file

@ -787,7 +787,7 @@ public class BtcWalletService extends WalletService {
throw new AddressEntryException("No Addresses for withdraw found in our wallet"); throw new AddressEntryException("No Addresses for withdraw found in our wallet");
sendRequest.coinSelector = new BtcCoinSelector(walletsSetup.getAddressesFromAddressEntries(addressEntries)); sendRequest.coinSelector = new BtcCoinSelector(walletsSetup.getAddressesFromAddressEntries(addressEntries));
Optional<AddressEntry> addressEntryOptional = Optional.empty(); Optional<AddressEntry> addressEntryOptional = Optional.<AddressEntry>empty();
AddressEntry changeAddressAddressEntry = null; AddressEntry changeAddressAddressEntry = null;
if (changeAddress != null) if (changeAddress != null)
addressEntryOptional = findAddressEntry(changeAddress, AddressEntry.Context.AVAILABLE); addressEntryOptional = findAddressEntry(changeAddress, AddressEntry.Context.AVAILABLE);

View file

@ -105,16 +105,16 @@ public class Offer implements NetworkPayload, PersistablePayload {
public void checkOfferAvailability(OfferAvailabilityModel model, ResultHandler resultHandler, public void checkOfferAvailability(OfferAvailabilityModel model, ResultHandler resultHandler,
ErrorMessageHandler errorMessageHandler) { ErrorMessageHandler errorMessageHandler) {
availabilityProtocol = new OfferAvailabilityProtocol(model, availabilityProtocol = new OfferAvailabilityProtocol(model,
() -> { () -> {
cancelAvailabilityRequest(); cancelAvailabilityRequest();
resultHandler.handleResult(); resultHandler.handleResult();
}, },
(errorMessage) -> { (errorMessage) -> {
if (availabilityProtocol != null) if (availabilityProtocol != null)
availabilityProtocol.cancel(); availabilityProtocol.cancel();
log.error(errorMessage); log.error(errorMessage);
errorMessageHandler.handleErrorMessage(errorMessage); errorMessageHandler.handleErrorMessage(errorMessage);
}); });
availabilityProtocol.sendOfferAvailabilityRequest(); availabilityProtocol.sendOfferAvailabilityRequest();
} }
@ -134,28 +134,28 @@ public class Offer implements NetworkPayload, PersistablePayload {
double marketPriceMargin = offerPayload.getMarketPriceMargin(); double marketPriceMargin = offerPayload.getMarketPriceMargin();
if (CurrencyUtil.isCryptoCurrency(currencyCode)) { if (CurrencyUtil.isCryptoCurrency(currencyCode)) {
factor = getDirection() == OfferPayload.Direction.SELL ? factor = getDirection() == OfferPayload.Direction.SELL ?
1 - marketPriceMargin : 1 + marketPriceMargin; 1 - marketPriceMargin : 1 + marketPriceMargin;
} else { } else {
factor = getDirection() == OfferPayload.Direction.BUY ? factor = getDirection() == OfferPayload.Direction.BUY ?
1 - marketPriceMargin : 1 + marketPriceMargin; 1 - marketPriceMargin : 1 + marketPriceMargin;
} }
double marketPriceAsDouble = marketPrice.getPrice(); double marketPriceAsDouble = marketPrice.getPrice();
double targetPriceAsDouble = marketPriceAsDouble * factor; double targetPriceAsDouble = marketPriceAsDouble * factor;
try { try {
int precision = CurrencyUtil.isCryptoCurrency(currencyCode) ? int precision = CurrencyUtil.isCryptoCurrency(currencyCode) ?
Altcoin.SMALLEST_UNIT_EXPONENT : Altcoin.SMALLEST_UNIT_EXPONENT :
Fiat.SMALLEST_UNIT_EXPONENT; Fiat.SMALLEST_UNIT_EXPONENT;
double scaled = MathUtils.scaleUpByPowerOf10(targetPriceAsDouble, precision); double scaled = MathUtils.scaleUpByPowerOf10(targetPriceAsDouble, precision);
final long roundedToLong = MathUtils.roundDoubleToLong(scaled); final long roundedToLong = MathUtils.roundDoubleToLong(scaled);
return Price.valueOf(currencyCode, roundedToLong); return Price.valueOf(currencyCode, roundedToLong);
} catch (Exception e) { } catch (Exception e) {
log.error("Exception at getPrice / parseToFiat: " + e.toString() + "\n" + log.error("Exception at getPrice / parseToFiat: " + e.toString() + "\n" +
"That case should never happen."); "That case should never happen.");
return null; return null;
} }
} else { } else {
log.debug("We don't have a market price.\n" + 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; return null;
} }
} else { } else {
@ -164,7 +164,7 @@ public class Offer implements NetworkPayload, PersistablePayload {
} }
public void checkTradePriceTolerance(long takersTradePrice) throws TradePriceOutOfToleranceException, public void checkTradePriceTolerance(long takersTradePrice) throws TradePriceOutOfToleranceException,
MarketPriceNotAvailableException, IllegalArgumentException { MarketPriceNotAvailableException, IllegalArgumentException {
Price tradePrice = Price.valueOf(getCurrencyCode(), takersTradePrice); Price tradePrice = Price.valueOf(getCurrencyCode(), takersTradePrice);
Price offerPrice = getPrice(); Price offerPrice = getPrice();
if (offerPrice == null) if (offerPrice == null)
@ -179,8 +179,8 @@ public class Offer implements NetworkPayload, PersistablePayload {
// from one provider. // from one provider.
if (Math.abs(1 - factor) > 0.01) { 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" + String msg = "Taker's trade price is too far away from our calculated price based on the market price.\n" +
"tradePrice=" + tradePrice.getValue() + "\n" + "tradePrice=" + tradePrice.getValue() + "\n" +
"offerPrice=" + offerPrice.getValue(); "offerPrice=" + offerPrice.getValue();
log.warn(msg); log.warn(msg);
throw new TradePriceOutOfToleranceException(msg); throw new TradePriceOutOfToleranceException(msg);
} }
@ -270,8 +270,8 @@ public class Offer implements NetworkPayload, PersistablePayload {
public PaymentMethod getPaymentMethod() { public PaymentMethod getPaymentMethod() {
return new PaymentMethod(offerPayload.getPaymentMethodId(), return new PaymentMethod(offerPayload.getPaymentMethodId(),
offerPayload.getMaxTradePeriod(), offerPayload.getMaxTradePeriod(),
Coin.valueOf(offerPayload.getMaxTradeLimit())); Coin.valueOf(offerPayload.getMaxTradeLimit()));
} }
// utils // utils
@ -302,11 +302,11 @@ public class Offer implements NetworkPayload, PersistablePayload {
} }
public Optional<String> getAccountAgeWitnessHash() { public Optional<String> getAccountAgeWitnessHashAsHex() {
if (getExtraDataMap() != null && getExtraDataMap().containsKey(OfferPayload.ACCOUNT_AGE_WITNESS_HASH)) if (getExtraDataMap() != null && getExtraDataMap().containsKey(OfferPayload.ACCOUNT_AGE_WITNESS_HASH))
return Optional.of(getExtraDataMap().get(OfferPayload.ACCOUNT_AGE_WITNESS_HASH)); return Optional.of(getExtraDataMap().get(OfferPayload.ACCOUNT_AGE_WITNESS_HASH));
else else
return Optional.empty(); return Optional.<String>empty();
} }
// domain properties // domain properties
@ -365,8 +365,8 @@ public class Offer implements NetworkPayload, PersistablePayload {
public String getCurrencyCode() { public String getCurrencyCode() {
return CurrencyUtil.isCryptoCurrency(offerPayload.getBaseCurrencyCode()) ? return CurrencyUtil.isCryptoCurrency(offerPayload.getBaseCurrencyCode()) ?
offerPayload.getBaseCurrencyCode() : offerPayload.getBaseCurrencyCode() :
offerPayload.getCounterCurrencyCode(); offerPayload.getCounterCurrencyCode();
} }
public long getProtocolVersion() { public long getProtocolVersion() {
@ -473,9 +473,9 @@ public class Offer implements NetworkPayload, PersistablePayload {
@Override @Override
public String toString() { public String toString() {
return "Offer{" + return "Offer{" +
"getErrorMessage()='" + getErrorMessage() + '\'' + "getErrorMessage()='" + getErrorMessage() + '\'' +
", state=" + getState() + ", state=" + getState() +
", offerPayload=" + offerPayload + ", offerPayload=" + offerPayload +
'}'; '}';
} }
} }

View file

@ -67,7 +67,7 @@ public final class OfferPayload implements ProtectedStoragePayload, RequiresOwne
} }
// Keys for extra map // 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; private final boolean isPrivateOffer;
@Nullable @Nullable
private final String hashOfChallenge; 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 // 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 // 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. // field in a class would break that hash and therefore break the storage mechanism.
// extraDataMap used from v0.6 on for hashOfPaymentAccount // extraDataMap used from v0.6 on for hashOfPaymentAccount
// key ACCOUNT_AGE_WITNESS, value: hex string of hashOfPaymentAccount byte array // key ACCOUNT_AGE_WITNESS, value: hex string of hashOfPaymentAccount byte array
@Nullable @Nullable
@ -355,7 +355,7 @@ public final class OfferPayload implements ProtectedStoragePayload, RequiresOwne
// In the offer we support base and counter currency // In the offer we support base and counter currency
// Fiat offers have base currency BTC and counterCurrency Fiat // Fiat offers have base currency BTC and counterCurrency Fiat
// Altcoins have base currency Altcoin and counterCurrency BTC // 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 // so we map here for convenience
public String getCurrencyCode() { public String getCurrencyCode() {
return CurrencyUtil.isCryptoCurrency(getBaseCurrencyCode()) ? getBaseCurrencyCode() : getCounterCurrencyCode(); return CurrencyUtil.isCryptoCurrency(getBaseCurrencyCode()) ? getBaseCurrencyCode() : getCounterCurrencyCode();

View file

@ -31,31 +31,21 @@ import lombok.extern.slf4j.Slf4j;
import java.util.Date; import java.util.Date;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
// Object has about 94 raw bytes (about 101 bytes is size of PB object) // Object has about 28 raw bytes (29 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, // 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 not be loaded over the P2P network. // so only the newly added objects since the last release will be retrieved 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)
@Slf4j @Slf4j
@Value @Value
public class AccountAgeWitness implements LazyProcessedPayload, PersistableNetworkPayload, PersistableEnvelope, PublishDateVerifiedPayload { public class AccountAgeWitness implements LazyProcessedPayload, PersistableNetworkPayload, PersistableEnvelope, PublishDateVerifiedPayload {
private static final long TOLERANCE = TimeUnit.DAYS.toMillis(1); private static final long TOLERANCE = TimeUnit.DAYS.toMillis(1);
private final byte[] hash; // Ripemd160(Sha256(data)) hash 20 bytes private final byte[] hash; // Ripemd160(Sha256(concatenated accountHash, signature and sigPubKey)); 20 bytes
private final byte[] sigPubKeyHash; // Ripemd160(Sha256(sigPubKey)) hash 20 bytes
private final byte[] signature; // about 46 bytes
private final long date; // 8 byte private final long date; // 8 byte
public AccountAgeWitness(byte[] hash, public AccountAgeWitness(byte[] hash,
byte[] sigPubKeyHash,
byte[] signature,
long date) { long date) {
this.hash = hash; this.hash = hash;
this.sigPubKeyHash = sigPubKeyHash;
this.signature = signature;
this.date = date; 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 @Override
public PB.PersistableNetworkPayload toProtoMessage() { public PB.PersistableNetworkPayload toProtoMessage() {
final PB.AccountAgeWitness.Builder builder = PB.AccountAgeWitness.newBuilder() final PB.AccountAgeWitness.Builder builder = PB.AccountAgeWitness.newBuilder()
.setHash(ByteString.copyFrom(hash)) .setHash(ByteString.copyFrom(hash))
.setSigPubKeyHash(ByteString.copyFrom(sigPubKeyHash)) .setDate(date);
.setSignature(ByteString.copyFrom(signature))
.setDate(date);
return PB.PersistableNetworkPayload.newBuilder().setAccountAgeWitness(builder).build(); return PB.PersistableNetworkPayload.newBuilder().setAccountAgeWitness(builder).build();
} }
@ -80,10 +68,8 @@ public class AccountAgeWitness implements LazyProcessedPayload, PersistableNetwo
public static AccountAgeWitness fromProto(PB.AccountAgeWitness proto) { public static AccountAgeWitness fromProto(PB.AccountAgeWitness proto) {
return new AccountAgeWitness( return new AccountAgeWitness(
proto.getHash().toByteArray(), proto.getHash().toByteArray(),
proto.getSigPubKeyHash().toByteArray(), proto.getDate());
proto.getSignature().toByteArray(),
proto.getDate());
} }
@ -101,13 +87,6 @@ public class AccountAgeWitness implements LazyProcessedPayload, PersistableNetwo
// Getters // 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() { public P2PDataStorage.ByteArray getHashAsByteArray() {
return new P2PDataStorage.ByteArray(hash); return new P2PDataStorage.ByteArray(hash);
} }
@ -115,10 +94,8 @@ public class AccountAgeWitness implements LazyProcessedPayload, PersistableNetwo
@Override @Override
public String toString() { public String toString() {
return "AccountAgeWitness{" + return "AccountAgeWitness{" +
"\n hash=" + Utilities.bytesAsHexString(hash) + "\n hash=" + Utilities.bytesAsHexString(hash) +
",\n sigPubKeyHash=" + Utilities.bytesAsHexString(sigPubKeyHash) + ",\n date=" + new Date(date) +
",\n signature=" + Utilities.bytesAsHexString(signature) + "\n}";
",\n date=" + new Date(date) +
"\n}";
} }
} }

View file

@ -18,8 +18,8 @@
package io.bisq.core.payment; package io.bisq.core.payment;
import io.bisq.common.crypto.CryptoException; import io.bisq.common.crypto.CryptoException;
import io.bisq.common.crypto.Hash;
import io.bisq.common.crypto.KeyRing; import io.bisq.common.crypto.KeyRing;
import io.bisq.common.crypto.PubKeyRing;
import io.bisq.common.crypto.Sig; import io.bisq.common.crypto.Sig;
import io.bisq.common.handlers.ErrorMessageHandler; import io.bisq.common.handlers.ErrorMessageHandler;
import io.bisq.common.locale.CurrencyUtil; 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.P2PService;
import io.bisq.network.p2p.storage.P2PDataStorage; import io.bisq.network.p2p.storage.P2PDataStorage;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.bitcoinj.core.Coin; import org.bitcoinj.core.Coin;
import javax.inject.Inject; import javax.inject.Inject;
@ -52,12 +51,23 @@ public class AccountAgeWitnessService {
private final P2PService p2PService; private final P2PService p2PService;
private final Map<P2PDataStorage.ByteArray, AccountAgeWitness> accountAgeWitnessMap = new HashMap<>(); private final Map<P2PDataStorage.ByteArray, AccountAgeWitness> accountAgeWitnessMap = new HashMap<>();
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
@Inject @Inject
public AccountAgeWitnessService(KeyRing keyRing, P2PService p2PService) { public AccountAgeWitnessService(KeyRing keyRing, P2PService p2PService) {
this.keyRing = keyRing; this.keyRing = keyRing;
this.p2PService = p2PService; this.p2PService = p2PService;
} }
///////////////////////////////////////////////////////////////////////////////////////////
// Lifecycle
///////////////////////////////////////////////////////////////////////////////////////////
public void onAllServicesInitialized() { public void onAllServicesInitialized() {
p2PService.getP2PDataStorage().addPersistableNetworkPayloadMapListener(payload -> { p2PService.getP2PDataStorage().addPersistableNetworkPayloadMapListener(payload -> {
if (payload instanceof AccountAgeWitness) if (payload instanceof AccountAgeWitness)
@ -71,49 +81,29 @@ public class AccountAgeWitnessService {
}); });
} }
///////////////////////////////////////////////////////////////////////////////////////////
// API
///////////////////////////////////////////////////////////////////////////////////////////
private void addToMap(AccountAgeWitness accountAgeWitness) { private void addToMap(AccountAgeWitness accountAgeWitness) {
log.debug("addToMap hash=" + Utilities.bytesAsHexString(accountAgeWitness.getHash())); log.debug("addToMap hash=" + Utilities.bytesAsHexString(accountAgeWitness.getHash()));
if (!accountAgeWitnessMap.containsKey(accountAgeWitness.getHashAsByteArray())) if (!accountAgeWitnessMap.containsKey(accountAgeWitness.getHashAsByteArray()))
accountAgeWitnessMap.put(accountAgeWitness.getHashAsByteArray(), accountAgeWitness); accountAgeWitnessMap.put(accountAgeWitness.getHashAsByteArray(), accountAgeWitness);
} }
public void publishAccountAgeWitness(PaymentAccountPayload paymentAccountPayload) { public void publishMyAccountAgeWitness(PaymentAccountPayload paymentAccountPayload) {
try { AccountAgeWitness accountAgeWitness = getMyWitness(paymentAccountPayload);
AccountAgeWitness accountAgeWitness = getAccountAgeWitness(paymentAccountPayload); if (!accountAgeWitnessMap.containsKey(accountAgeWitness.getHashAsByteArray()))
if (!accountAgeWitnessMap.containsKey(accountAgeWitness.getHashAsByteArray())) p2PService.addPersistableNetworkPayload(accountAgeWitness);
p2PService.addPersistableNetworkPayload(accountAgeWitness);
} catch (CryptoException e) {
e.printStackTrace();
log.error(e.toString());
}
} }
public Optional<AccountAgeWitness> getWitnessByHash(String hashAsHex) { ///////////////////////////////////////////////////////////////////////////////////////////
P2PDataStorage.ByteArray hashAsByteArray = new P2PDataStorage.ByteArray(Utilities.decodeFromHex(hashAsHex)); // Generic
return accountAgeWitnessMap.containsKey(hashAsByteArray) ? Optional.of(accountAgeWitnessMap.get(hashAsByteArray)) : Optional.<AccountAgeWitness>empty(); ///////////////////////////////////////////////////////////////////////////////////////////
}
public Optional<AccountAgeWitness> getWitnessByPaymentAccountPayload(PaymentAccountPayload paymentAccountPayload) { public byte[] getAccountInputDataWithSalt(PaymentAccountPayload paymentAccountPayload) {
return getWitnessByHash(getWitnessHashAsHex(paymentAccountPayload)); return Utilities.concatenateByteArrays(paymentAccountPayload.getAgeWitnessInputData(), paymentAccountPayload.getSalt());
}
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<AccountAgeWitness> accountAgeWitnessOptional) {
if (accountAgeWitnessOptional.isPresent()) {
return new Date().getTime() - accountAgeWitnessOptional.get().getDate();
} else {
return 0L;
}
} }
public long getAccountAge(AccountAgeWitness accountAgeWitness) { public long getAccountAge(AccountAgeWitness accountAgeWitness) {
@ -130,65 +120,17 @@ public class AccountAgeWitnessService {
} }
} }
private AccountAgeWitness getAccountAgeWitness(PaymentAccountPayload paymentAccountPayload) throws CryptoException { private long getTradeLimit(PaymentMethod paymentMethod, String currencyCode, Optional<AccountAgeWitness> accountAgeWitnessOptional) {
byte[] hash = getWitnessHash(paymentAccountPayload); final long maxTradeLimit = paymentMethod.getMaxTradeLimitAsCoin(currencyCode).value;
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;
if (CurrencyUtil.isFiatCurrency(currencyCode)) { if (CurrencyUtil.isFiatCurrency(currencyCode)) {
double factor; double factor;
// TODO test
/*Optional<AccountAgeWitness> accountAgeWitnessOptional = paymentAccount.getName() != null ?
getWitnessByHash(getWitnessHashAsHex(paymentAccountPayload)) :
Optional.empty();*/
Optional<AccountAgeWitness> accountAgeWitnessOptional = getWitnessByHash(getWitnessHashAsHex(paymentAccountPayload));
AccountAge accountAgeCategory = accountAgeWitnessOptional.isPresent() ? AccountAge accountAgeCategory = accountAgeWitnessOptional.isPresent() ?
getAccountAgeCategory(getAccountAge((accountAgeWitnessOptional.get()))) : getAccountAgeCategory(getAccountAge((accountAgeWitnessOptional.get()))) :
AccountAgeWitnessService.AccountAge.LESS_ONE_MONTH; AccountAgeWitnessService.AccountAge.LESS_ONE_MONTH;
// TODO Fade in by date can be removed after feb 2018 // 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. // we deploy that feature.
final Date now = new Date(); final Date now = new Date();
/* final Date dez = new GregorianCalendar(2017, GregorianCalendar.DECEMBER, 1).getTime(); /* 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<AccountAgeWitness> getPeersWitnessByHash(byte[] hash) {
P2PDataStorage.ByteArray hashAsByteArray = new P2PDataStorage.ByteArray(hash);
return accountAgeWitnessMap.containsKey(hashAsByteArray) ? Optional.of(accountAgeWitnessMap.get(hashAsByteArray)) : Optional.<AccountAgeWitness>empty();
}
public Optional<AccountAgeWitness> getPeersWitnessByHashAsHex(String hashAsHex) {
return getPeersWitnessByHash(Utilities.decodeFromHex(hashAsHex));
}
public long getPeersAccountAge(Offer offer) {
final Optional<String> accountAgeWitnessHash = offer.getAccountAgeWitnessHashAsHex();
final Optional<AccountAgeWitness> witnessByHashAsHex = accountAgeWitnessHash.isPresent() ?
getPeersWitnessByHashAsHex(accountAgeWitnessHash.get()) :
Optional.<AccountAgeWitness>empty();
return witnessByHashAsHex.isPresent() ? getAccountAge(witnessByHashAsHex.get()) : 0L;
}
public long getPeersTradeLimit(PaymentAccountPayload paymentAccountPayload, String currencyCode, Optional<AccountAgeWitness> 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) // 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 // TODO set date before releasing
if (!isTradeDateAfterReleaseDate(witness.getDate(), new GregorianCalendar(2017, GregorianCalendar.OCTOBER, 17).getTime(), errorMessageHandler)) if (!isTradeDateAfterReleaseDate(witness.getDate(), new GregorianCalendar(2017, GregorianCalendar.OCTOBER, 17).getTime(), errorMessageHandler))
return false; return false;
// Check if peer's pubkey is matching the one from the witness data final byte[] peersAccountInputDataWithSalt = Utilities.concatenateByteArrays(peersPaymentAccountPayload.getAgeWitnessInputData(), peersPaymentAccountPayload.getSalt());
if (!verifySigPubKeyHash(witness.getSigPubKeyHash(), peersPublicKey, errorMessageHandler)) byte[] hash = Utilities.concatenateByteArrays(peersAccountInputDataWithSalt, peersSignatureOfAccountHash, peersPubKeyRing.getSignaturePubKeyBytes());
return false;
final byte[] combined = ArrayUtils.addAll(peersAgeWitnessInputData, peersSalt); // Check if the hash in the witness data matches the hash derived from the data provided by the peer
byte[] hash = Hash.getSha256Ripemd160hash(combined);
// Check if the hash in the witness data matches the peer's payment account input data + salt
if (!verifyWitnessHash(witness.getHash(), hash, errorMessageHandler)) if (!verifyWitnessHash(witness.getHash(), hash, errorMessageHandler))
return false; return false;
// Check if the witness signature is correct // Check if the witness signature is correct
if (!verifySignature(peersPublicKey, hash, witness.getSignature(), errorMessageHandler)) if (!verifyPeersTradeLimit(offer, peersPaymentAccountPayload, errorMessageHandler))
return false; return false;
// Check if the signature of the nonce is correct // Check if the witness signature is correct
return verifySignatureOfNonce(peersPublicKey, nonce, signatureOfNonce, errorMessageHandler); 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) { boolean isTradeDateAfterReleaseDate(long witnessDateAsLong, Date ageWitnessReleaseDate, ErrorMessageHandler errorMessageHandler) {
// Release date minus 1 day as tolerance for not synced clocks // Release date minus 1 day as tolerance for not synced clocks
Date releaseDateWithTolerance = new Date(ageWitnessReleaseDate.getTime() - TimeUnit.DAYS.toMillis(1)); Date releaseDateWithTolerance = new Date(ageWitnessReleaseDate.getTime() - TimeUnit.DAYS.toMillis(1));
@ -275,35 +292,38 @@ public class AccountAgeWitnessService {
final boolean result = witnessDate.after(releaseDateWithTolerance); final boolean result = witnessDate.after(releaseDateWithTolerance);
if (!result) { if (!result) {
final String msg = "Trade date is earlier than release date of ageWitness minus 1 day. " + 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); log.warn(msg);
errorMessageHandler.handleErrorMessage(msg); errorMessageHandler.handleErrorMessage(msg);
} }
return result; return result;
} }
boolean verifySigPubKeyHash(byte[] sigPubKeyHash, boolean verifyWitnessHash(byte[] witnessHash,
PublicKey peersPublicKey, byte[] hash,
ErrorMessageHandler errorMessageHandler) { 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) {
final boolean result = Arrays.equals(witnessHash, hash); final boolean result = Arrays.equals(witnessHash, hash);
if (!result) { if (!result) {
final String msg = "witnessHash is not matching peers hash. " + 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<String> offerHashAsHexOptional = offer.getAccountAgeWitnessHashAsHex();
Optional<AccountAgeWitness> accountAgeWitnessOptional = offerHashAsHexOptional.isPresent() ? getPeersWitnessByHashAsHex(offerHashAsHexOptional.get()) : Optional.<AccountAgeWitness>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); log.warn(msg);
errorMessageHandler.handleErrorMessage(msg); errorMessageHandler.handleErrorMessage(msg);
} }
@ -323,8 +343,8 @@ public class AccountAgeWitnessService {
} }
if (!result) { if (!result) {
final String msg = "Signature of PaymentAccountAgeWitness is not correct. " + final String msg = "Signature of PaymentAccountAgeWitness is not correct. " +
"peersPublicKey=" + peersPublicKey + ", data=" + Utilities.bytesAsHexString(data) + "peersPublicKey=" + peersPublicKey + ", data=" + Utilities.bytesAsHexString(data) +
", signature=" + Utilities.bytesAsHexString(signature); ", signature=" + Utilities.bytesAsHexString(signature);
log.warn(msg); log.warn(msg);
errorMessageHandler.handleErrorMessage(msg); errorMessageHandler.handleErrorMessage(msg);
} }
@ -344,38 +364,8 @@ public class AccountAgeWitnessService {
} }
if (!result) { if (!result) {
final String msg = "Signature of nonce is not correct. " + final String msg = "Signature of nonce is not correct. " +
"peersPublicKey=" + peersPublicKey + ", nonce(hex)=" + Utilities.bytesAsHexString(nonce) + "peersPublicKey=" + peersPublicKey + ", nonce(hex)=" + Utilities.bytesAsHexString(nonce) +
", signature=" + Utilities.bytesAsHexString(signature); ", 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();
log.warn(msg); log.warn(msg);
errorMessageHandler.handleErrorMessage(msg); errorMessageHandler.handleErrorMessage(msg);
} }

View file

@ -1,7 +1,6 @@
package io.bisq.core.payment; package io.bisq.core.payment;
import io.bisq.common.locale.TradeCurrency; import io.bisq.common.locale.TradeCurrency;
import io.bisq.common.util.Utilities;
import io.bisq.core.offer.Offer; import io.bisq.core.offer.Offer;
import io.bisq.core.payment.payload.PaymentMethod; import io.bisq.core.payment.payload.PaymentMethod;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
@ -9,7 +8,6 @@ import javafx.collections.ObservableList;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import java.util.*; import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
@ -27,8 +25,8 @@ public class PaymentAccountUtil {
public static ObservableList<PaymentAccount> getPossiblePaymentAccounts(Offer offer, Set<PaymentAccount> paymentAccounts) { public static ObservableList<PaymentAccount> getPossiblePaymentAccounts(Offer offer, Set<PaymentAccount> paymentAccounts) {
ObservableList<PaymentAccount> result = FXCollections.observableArrayList(); ObservableList<PaymentAccount> result = FXCollections.observableArrayList();
result.addAll(paymentAccounts.stream() result.addAll(paymentAccounts.stream()
.filter(paymentAccount -> isPaymentAccountValidForOffer(offer, paymentAccount)) .filter(paymentAccount -> isPaymentAccountValidForOffer(offer, paymentAccount))
.collect(Collectors.toList())); .collect(Collectors.toList()));
return result; return result;
} }
@ -36,16 +34,16 @@ public class PaymentAccountUtil {
public static String getInfoForMismatchingPaymentMethodLimits(Offer offer, PaymentAccount paymentAccount) { public static String getInfoForMismatchingPaymentMethodLimits(Offer offer, PaymentAccount paymentAccount) {
// dont translate atm as it is not used so far in the UI just for logs // 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" + return "Payment methods have different trade limits or trade periods.\n" +
"Our local Payment method: " + paymentAccount.getPaymentMethod().toString() + "\n" + "Our local Payment method: " + paymentAccount.getPaymentMethod().toString() + "\n" +
"Payment method from offer: " + offer.getPaymentMethod().toString(); "Payment method from offer: " + offer.getPaymentMethod().toString();
} }
//TODO not tested with all combinations yet.... //TODO not tested with all combinations yet....
public static boolean isPaymentAccountValidForOffer(Offer offer, PaymentAccount paymentAccount) { public static boolean isPaymentAccountValidForOffer(Offer offer, PaymentAccount paymentAccount) {
// check if we have a matching currency // check if we have a matching currency
Set<String> paymentAccountCurrencyCodes = paymentAccount.getTradeCurrencies().stream() Set<String> paymentAccountCurrencyCodes = paymentAccount.getTradeCurrencies().stream()
.map(TradeCurrency::getCode) .map(TradeCurrency::getCode)
.collect(Collectors.toSet()); .collect(Collectors.toSet());
boolean matchesCurrencyCode = paymentAccountCurrencyCodes.contains(offer.getCurrencyCode()); boolean matchesCurrencyCode = paymentAccountCurrencyCodes.contains(offer.getCurrencyCode());
if (!matchesCurrencyCode) if (!matchesCurrencyCode)
return false; return false;
@ -54,7 +52,7 @@ public class PaymentAccountUtil {
final boolean arePaymentMethodsEqual = paymentAccount.getPaymentMethod().equals(offer.getPaymentMethod()); final boolean arePaymentMethodsEqual = paymentAccount.getPaymentMethod().equals(offer.getPaymentMethod());
if (!arePaymentMethodsEqual && if (!arePaymentMethodsEqual &&
paymentAccount.getPaymentMethod().getId().equals(offer.getPaymentMethod().getId())) paymentAccount.getPaymentMethod().getId().equals(offer.getPaymentMethod().getId()))
log.warn(getInfoForMismatchingPaymentMethodLimits(offer, paymentAccount)); log.warn(getInfoForMismatchingPaymentMethodLimits(offer, paymentAccount));
if (paymentAccount instanceof CountryBasedPaymentAccount) { if (paymentAccount instanceof CountryBasedPaymentAccount) {
@ -62,14 +60,14 @@ public class PaymentAccountUtil {
// check if we have a matching country // check if we have a matching country
boolean matchesCountryCodes = offer.getAcceptedCountryCodes() != null && countryBasedPaymentAccount.getCountry() != null && boolean matchesCountryCodes = offer.getAcceptedCountryCodes() != null && countryBasedPaymentAccount.getCountry() != null &&
offer.getAcceptedCountryCodes().contains(countryBasedPaymentAccount.getCountry().code); offer.getAcceptedCountryCodes().contains(countryBasedPaymentAccount.getCountry().code);
if (!matchesCountryCodes) if (!matchesCountryCodes)
return false; return false;
if (paymentAccount instanceof SepaAccount || offer.getPaymentMethod().equals(PaymentMethod.SEPA)) { if (paymentAccount instanceof SepaAccount || offer.getPaymentMethod().equals(PaymentMethod.SEPA)) {
return arePaymentMethodsEqual; return arePaymentMethodsEqual;
} else if (offer.getPaymentMethod().equals(PaymentMethod.SAME_BANK) || } else if (offer.getPaymentMethod().equals(PaymentMethod.SAME_BANK) ||
offer.getPaymentMethod().equals(PaymentMethod.SPECIFIC_BANKS)) { offer.getPaymentMethod().equals(PaymentMethod.SPECIFIC_BANKS)) {
final List<String> acceptedBankIds = offer.getAcceptedBankIds(); final List<String> acceptedBankIds = offer.getAcceptedBankIds();
checkNotNull(acceptedBankIds, "offer.getAcceptedBankIds() must not be null"); checkNotNull(acceptedBankIds, "offer.getAcceptedBankIds() must not be null");
@ -105,30 +103,14 @@ public class PaymentAccountUtil {
public static Optional<PaymentAccount> getMostMaturePaymentAccountForOffer(Offer offer, public static Optional<PaymentAccount> getMostMaturePaymentAccountForOffer(Offer offer,
Set<PaymentAccount> paymentAccounts, Set<PaymentAccount> paymentAccounts,
AccountAgeWitnessService accountAgeWitnessService) { AccountAgeWitnessService service) {
List<PaymentAccount> list = paymentAccounts.stream() List<PaymentAccount> list = paymentAccounts.stream()
.filter(paymentAccount -> isPaymentAccountValidForOffer(offer, paymentAccount)) .filter(paymentAccount -> isPaymentAccountValidForOffer(offer, paymentAccount))
.sorted((o1, o2) -> { .sorted((o1, o2) -> {
final Optional<AccountAgeWitness> witness1 = accountAgeWitnessService.getWitnessByPaymentAccountPayload(o1.getPaymentAccountPayload()); return new Long(service.getAccountAge(service.getMyWitness(o2.getPaymentAccountPayload())))
log.debug("witness1 isPresent={}", witness1.isPresent()); .compareTo(service.getAccountAge(service.getMyWitness(o1.getPaymentAccountPayload())));
if (witness1.isPresent()) }).collect(Collectors.toList());
log.debug("witness1 HashAsHex={}, date={}", Utilities.bytesAsHexString(witness1.get().getHash()), new Date(witness1.get().getDate())); list.stream().forEach(e -> log.error("getMostMaturePaymentAccountForOffer AccountName={}, witnessHashAsHex={}", e.getAccountName(), service.getMyWitnessHashAsHex(e.getPaymentAccountPayload())));
long age1 = witness1.isPresent() ? accountAgeWitnessService.getAccountAge(witness1.get()) : 0;
final Optional<AccountAgeWitness> 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())));
final Optional<PaymentAccount> first = list.stream().findFirst(); final Optional<PaymentAccount> first = list.stream().findFirst();
if (first.isPresent()) if (first.isPresent())
log.debug("first={}", first.get().getAccountName()); log.debug("first={}", first.get().getAccountName());

View file

@ -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 // added in v 0.6. can be null if we trade with an older peer
@Nullable @Nullable
private final byte[] accountAgeWitnessSignatureOfAccountData;
@Nullable
private final byte[] accountAgeWitnessNonce; private final byte[] accountAgeWitnessNonce;
@Nullable @Nullable
private final byte[] accountAgeWitnessSignatureOfNonce; private final byte[] accountAgeWitnessSignatureOfNonce;
@ -88,6 +90,7 @@ public final class PayDepositRequest extends TradeMessage {
NodeAddress mediatorNodeAddress, NodeAddress mediatorNodeAddress,
String uid, String uid,
int messageVersion, int messageVersion,
@Nullable byte[] accountAgeWitnessSignatureOfAccountData,
@Nullable byte[] accountAgeWitnessNonce, @Nullable byte[] accountAgeWitnessNonce,
@Nullable byte[] accountAgeWitnessSignatureOfNonce) { @Nullable byte[] accountAgeWitnessSignatureOfNonce) {
super(messageVersion, tradeId); super(messageVersion, tradeId);
@ -111,6 +114,7 @@ public final class PayDepositRequest extends TradeMessage {
this.arbitratorNodeAddress = arbitratorNodeAddress; this.arbitratorNodeAddress = arbitratorNodeAddress;
this.mediatorNodeAddress = mediatorNodeAddress; this.mediatorNodeAddress = mediatorNodeAddress;
this.uid = uid; this.uid = uid;
this.accountAgeWitnessSignatureOfAccountData = accountAgeWitnessSignatureOfAccountData;
this.accountAgeWitnessNonce = accountAgeWitnessNonce; this.accountAgeWitnessNonce = accountAgeWitnessNonce;
this.accountAgeWitnessSignatureOfNonce = accountAgeWitnessSignatureOfNonce; this.accountAgeWitnessSignatureOfNonce = accountAgeWitnessSignatureOfNonce;
} }
@ -123,98 +127,101 @@ public final class PayDepositRequest extends TradeMessage {
@Override @Override
public PB.NetworkEnvelope toProtoNetworkEnvelope() { public PB.NetworkEnvelope toProtoNetworkEnvelope() {
PB.PayDepositRequest.Builder builder = PB.PayDepositRequest.newBuilder() PB.PayDepositRequest.Builder builder = PB.PayDepositRequest.newBuilder()
.setTradeId(tradeId) .setTradeId(tradeId)
.setSenderNodeAddress(senderNodeAddress.toProtoMessage()) .setSenderNodeAddress(senderNodeAddress.toProtoMessage())
.setTradeAmount(tradeAmount) .setTradeAmount(tradeAmount)
.setTradePrice(tradePrice) .setTradePrice(tradePrice)
.setTxFee(txFee) .setTxFee(txFee)
.setTakerFee(takerFee) .setTakerFee(takerFee)
.setIsCurrencyForTakerFeeBtc(isCurrencyForTakerFeeBtc) .setIsCurrencyForTakerFeeBtc(isCurrencyForTakerFeeBtc)
.addAllRawTransactionInputs(rawTransactionInputs.stream() .addAllRawTransactionInputs(rawTransactionInputs.stream()
.map(RawTransactionInput::toProtoMessage).collect(Collectors.toList())) .map(RawTransactionInput::toProtoMessage).collect(Collectors.toList()))
.setChangeOutputValue(changeOutputValue) .setChangeOutputValue(changeOutputValue)
.setTakerMultiSigPubKey(ByteString.copyFrom(takerMultiSigPubKey)) .setTakerMultiSigPubKey(ByteString.copyFrom(takerMultiSigPubKey))
.setTakerPayoutAddressString(takerPayoutAddressString) .setTakerPayoutAddressString(takerPayoutAddressString)
.setTakerPubKeyRing(takerPubKeyRing.toProtoMessage()) .setTakerPubKeyRing(takerPubKeyRing.toProtoMessage())
.setTakerPaymentAccountPayload((PB.PaymentAccountPayload) takerPaymentAccountPayload.toProtoMessage()) .setTakerPaymentAccountPayload((PB.PaymentAccountPayload) takerPaymentAccountPayload.toProtoMessage())
.setTakerAccountId(takerAccountId) .setTakerAccountId(takerAccountId)
.setTakerFeeTxId(takerFeeTxId) .setTakerFeeTxId(takerFeeTxId)
.addAllAcceptedArbitratorNodeAddresses(acceptedArbitratorNodeAddresses.stream() .addAllAcceptedArbitratorNodeAddresses(acceptedArbitratorNodeAddresses.stream()
.map(NodeAddress::toProtoMessage).collect(Collectors.toList())) .map(NodeAddress::toProtoMessage).collect(Collectors.toList()))
.addAllAcceptedMediatorNodeAddresses(acceptedMediatorNodeAddresses.stream() .addAllAcceptedMediatorNodeAddresses(acceptedMediatorNodeAddresses.stream()
.map(NodeAddress::toProtoMessage).collect(Collectors.toList())) .map(NodeAddress::toProtoMessage).collect(Collectors.toList()))
.setArbitratorNodeAddress(arbitratorNodeAddress.toProtoMessage()) .setArbitratorNodeAddress(arbitratorNodeAddress.toProtoMessage())
.setMediatorNodeAddress(mediatorNodeAddress.toProtoMessage()) .setMediatorNodeAddress(mediatorNodeAddress.toProtoMessage())
.setUid(uid); .setUid(uid);
Optional.ofNullable(changeOutputAddress).ifPresent(builder::setChangeOutputAddress); Optional.ofNullable(changeOutputAddress).ifPresent(builder::setChangeOutputAddress);
Optional.ofNullable(accountAgeWitnessNonce).ifPresent(accountAgeWitnessNonce -> builder.setAccountAgeWitnessNonce(ByteString.copyFrom(accountAgeWitnessNonce))); Optional.ofNullable(accountAgeWitnessSignatureOfAccountData).ifPresent(e -> builder.setAccountAgeWitnessSignatureOfAccountData(ByteString.copyFrom(e)));
Optional.ofNullable(accountAgeWitnessSignatureOfNonce).ifPresent(accountAgeWitnessSignatureOfNonce -> builder.setAccountAgeWitnessSignatureOfNonce(ByteString.copyFrom(accountAgeWitnessSignatureOfNonce))); 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(); return getNetworkEnvelopeBuilder().setPayDepositRequest(builder).build();
} }
public static PayDepositRequest fromProto(PB.PayDepositRequest proto, CoreProtoResolver coreProtoResolver, int messageVersion) { public static PayDepositRequest fromProto(PB.PayDepositRequest proto, CoreProtoResolver coreProtoResolver, int messageVersion) {
List<RawTransactionInput> rawTransactionInputs = proto.getRawTransactionInputsList().stream() List<RawTransactionInput> rawTransactionInputs = proto.getRawTransactionInputsList().stream()
.map(rawTransactionInput -> new RawTransactionInput(rawTransactionInput.getIndex(), .map(rawTransactionInput -> new RawTransactionInput(rawTransactionInput.getIndex(),
rawTransactionInput.getParentTransaction().toByteArray(), rawTransactionInput.getValue())) rawTransactionInput.getParentTransaction().toByteArray(), rawTransactionInput.getValue()))
.collect(Collectors.toList()); .collect(Collectors.toList());
List<NodeAddress> acceptedArbitratorNodeAddresses = proto.getAcceptedArbitratorNodeAddressesList().stream() List<NodeAddress> acceptedArbitratorNodeAddresses = proto.getAcceptedArbitratorNodeAddressesList().stream()
.map(NodeAddress::fromProto).collect(Collectors.toList()); .map(NodeAddress::fromProto).collect(Collectors.toList());
List<NodeAddress> acceptedMediatorNodeAddresses = proto.getAcceptedMediatorNodeAddressesList().stream() List<NodeAddress> acceptedMediatorNodeAddresses = proto.getAcceptedMediatorNodeAddressesList().stream()
.map(NodeAddress::fromProto).collect(Collectors.toList()); .map(NodeAddress::fromProto).collect(Collectors.toList());
return new PayDepositRequest(proto.getTradeId(), return new PayDepositRequest(proto.getTradeId(),
NodeAddress.fromProto(proto.getSenderNodeAddress()), NodeAddress.fromProto(proto.getSenderNodeAddress()),
proto.getTradeAmount(), proto.getTradeAmount(),
proto.getTradePrice(), proto.getTradePrice(),
proto.getTxFee(), proto.getTxFee(),
proto.getTakerFee(), proto.getTakerFee(),
proto.getIsCurrencyForTakerFeeBtc(), proto.getIsCurrencyForTakerFeeBtc(),
rawTransactionInputs, rawTransactionInputs,
proto.getChangeOutputValue(), proto.getChangeOutputValue(),
ProtoUtil.stringOrNullFromProto(proto.getChangeOutputAddress()), ProtoUtil.stringOrNullFromProto(proto.getChangeOutputAddress()),
proto.getTakerMultiSigPubKey().toByteArray(), proto.getTakerMultiSigPubKey().toByteArray(),
proto.getTakerPayoutAddressString(), proto.getTakerPayoutAddressString(),
PubKeyRing.fromProto(proto.getTakerPubKeyRing()), PubKeyRing.fromProto(proto.getTakerPubKeyRing()),
coreProtoResolver.fromProto(proto.getTakerPaymentAccountPayload()), coreProtoResolver.fromProto(proto.getTakerPaymentAccountPayload()),
proto.getTakerAccountId(), proto.getTakerAccountId(),
proto.getTakerFeeTxId(), proto.getTakerFeeTxId(),
acceptedArbitratorNodeAddresses, acceptedArbitratorNodeAddresses,
acceptedMediatorNodeAddresses, acceptedMediatorNodeAddresses,
NodeAddress.fromProto(proto.getArbitratorNodeAddress()), NodeAddress.fromProto(proto.getArbitratorNodeAddress()),
NodeAddress.fromProto(proto.getMediatorNodeAddress()), NodeAddress.fromProto(proto.getMediatorNodeAddress()),
proto.getUid(), proto.getUid(),
messageVersion, messageVersion,
proto.getAccountAgeWitnessNonce().isEmpty() ? null : proto.getAccountAgeWitnessNonce().toByteArray(), ProtoUtil.byteArrayOrNullFromProto(proto.getAccountAgeWitnessSignatureOfAccountData()),
proto.getAccountAgeWitnessSignatureOfNonce().isEmpty() ? null : proto.getAccountAgeWitnessSignatureOfNonce().toByteArray()); ProtoUtil.byteArrayOrNullFromProto(proto.getAccountAgeWitnessNonce()),
ProtoUtil.byteArrayOrNullFromProto(proto.getAccountAgeWitnessSignatureOfNonce()));
} }
@Override @Override
public String toString() { public String toString() {
return "PayDepositRequest{" + return "PayDepositRequest{" +
"\n senderNodeAddress=" + senderNodeAddress + "\n senderNodeAddress=" + senderNodeAddress +
",\n tradeAmount=" + tradeAmount + ",\n tradeAmount=" + tradeAmount +
",\n tradePrice=" + tradePrice + ",\n tradePrice=" + tradePrice +
",\n txFee=" + txFee + ",\n txFee=" + txFee +
",\n takerFee=" + takerFee + ",\n takerFee=" + takerFee +
",\n isCurrencyForTakerFeeBtc=" + isCurrencyForTakerFeeBtc + ",\n isCurrencyForTakerFeeBtc=" + isCurrencyForTakerFeeBtc +
",\n rawTransactionInputs=" + rawTransactionInputs + ",\n rawTransactionInputs=" + rawTransactionInputs +
",\n changeOutputValue=" + changeOutputValue + ",\n changeOutputValue=" + changeOutputValue +
",\n changeOutputAddress='" + changeOutputAddress + '\'' + ",\n changeOutputAddress='" + changeOutputAddress + '\'' +
",\n takerMultiSigPubKey=" + Utilities.bytesAsHexString(takerMultiSigPubKey) + ",\n takerMultiSigPubKey=" + Utilities.bytesAsHexString(takerMultiSigPubKey) +
",\n takerPayoutAddressString='" + takerPayoutAddressString + '\'' + ",\n takerPayoutAddressString='" + takerPayoutAddressString + '\'' +
",\n takerPubKeyRing=" + takerPubKeyRing + ",\n takerPubKeyRing=" + takerPubKeyRing +
",\n takerPaymentAccountPayload=" + takerPaymentAccountPayload + ",\n takerPaymentAccountPayload=" + takerPaymentAccountPayload +
",\n takerAccountId='" + takerAccountId + '\'' + ",\n takerAccountId='" + takerAccountId + '\'' +
",\n takerFeeTxId='" + takerFeeTxId + '\'' + ",\n takerFeeTxId='" + takerFeeTxId + '\'' +
",\n acceptedArbitratorNodeAddresses=" + acceptedArbitratorNodeAddresses + ",\n acceptedArbitratorNodeAddresses=" + acceptedArbitratorNodeAddresses +
",\n acceptedMediatorNodeAddresses=" + acceptedMediatorNodeAddresses + ",\n acceptedMediatorNodeAddresses=" + acceptedMediatorNodeAddresses +
",\n arbitratorNodeAddress=" + arbitratorNodeAddress + ",\n arbitratorNodeAddress=" + arbitratorNodeAddress +
",\n mediatorNodeAddress=" + mediatorNodeAddress + ",\n mediatorNodeAddress=" + mediatorNodeAddress +
",\n uid='" + uid + '\'' + ",\n uid='" + uid + '\'' +
",\n accountAgeWitnessNonce=" + Utilities.bytesAsHexString(accountAgeWitnessNonce) + ",\n accountAgeWitnessSignatureOfAccountData=" + Utilities.bytesAsHexString(accountAgeWitnessSignatureOfAccountData) +
",\n accountAgeWitnessSignatureOfNonce=" + Utilities.bytesAsHexString(accountAgeWitnessSignatureOfNonce) + ",\n accountAgeWitnessNonce=" + Utilities.bytesAsHexString(accountAgeWitnessNonce) +
"\n} " + super.toString(); ",\n accountAgeWitnessSignatureOfNonce=" + Utilities.bytesAsHexString(accountAgeWitnessSignatureOfNonce) +
"\n} " + super.toString();
} }
} }

View file

@ -19,6 +19,7 @@ package io.bisq.core.trade.messages;
import com.google.protobuf.ByteString; import com.google.protobuf.ByteString;
import io.bisq.common.app.Version; import io.bisq.common.app.Version;
import io.bisq.common.proto.ProtoUtil;
import io.bisq.common.util.Utilities; import io.bisq.common.util.Utilities;
import io.bisq.core.btc.data.RawTransactionInput; import io.bisq.core.btc.data.RawTransactionInput;
import io.bisq.core.payment.payload.PaymentAccountPayload; 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 // added in v 0.6. can be null if we trade with an older peer
@Nullable @Nullable
private final byte[] accountAgeWitnessSignatureOfAccountData;
@Nullable
private final byte[] accountAgeWitnessNonce; private final byte[] accountAgeWitnessNonce;
@Nullable @Nullable
private final byte[] accountAgeWitnessSignatureOfNonce; private final byte[] accountAgeWitnessSignatureOfNonce;
@ -69,22 +72,24 @@ public final class PublishDepositTxRequest extends TradeMessage implements Mailb
List<RawTransactionInput> makerInputs, List<RawTransactionInput> makerInputs,
NodeAddress senderNodeAddress, NodeAddress senderNodeAddress,
String uid, String uid,
@Nullable byte[] accountAgeWitnessSignatureOfAccountData,
@Nullable byte[] accountAgeWitnessNonce, @Nullable byte[] accountAgeWitnessNonce,
@Nullable byte[] accountAgeWitnessSignatureOfNonce) { @Nullable byte[] accountAgeWitnessSignatureOfNonce) {
this(tradeId, this(tradeId,
makerPaymentAccountPayload, makerPaymentAccountPayload,
makerAccountId, makerAccountId,
makerMultiSigPubKey, makerMultiSigPubKey,
makerContractAsJson, makerContractAsJson,
makerContractSignature, makerContractSignature,
makerPayoutAddressString, makerPayoutAddressString,
preparedDepositTx, preparedDepositTx,
makerInputs, makerInputs,
senderNodeAddress, senderNodeAddress,
uid, uid,
Version.getP2PMessageVersion(), Version.getP2PMessageVersion(),
accountAgeWitnessNonce, accountAgeWitnessSignatureOfAccountData,
accountAgeWitnessSignatureOfNonce); accountAgeWitnessNonce,
accountAgeWitnessSignatureOfNonce);
} }
@ -104,6 +109,7 @@ public final class PublishDepositTxRequest extends TradeMessage implements Mailb
NodeAddress senderNodeAddress, NodeAddress senderNodeAddress,
String uid, String uid,
int messageVersion, int messageVersion,
@Nullable byte[] accountAgeWitnessSignatureOfAccountData,
@Nullable byte[] accountAgeWitnessNonce, @Nullable byte[] accountAgeWitnessNonce,
@Nullable byte[] accountAgeWitnessSignatureOfNonce) { @Nullable byte[] accountAgeWitnessSignatureOfNonce) {
super(messageVersion, tradeId); super(messageVersion, tradeId);
@ -117,6 +123,7 @@ public final class PublishDepositTxRequest extends TradeMessage implements Mailb
this.makerInputs = makerInputs; this.makerInputs = makerInputs;
this.senderNodeAddress = senderNodeAddress; this.senderNodeAddress = senderNodeAddress;
this.uid = uid; this.uid = uid;
this.accountAgeWitnessSignatureOfAccountData = accountAgeWitnessSignatureOfAccountData;
this.accountAgeWitnessNonce = accountAgeWitnessNonce; this.accountAgeWitnessNonce = accountAgeWitnessNonce;
this.accountAgeWitnessSignatureOfNonce = accountAgeWitnessSignatureOfNonce; this.accountAgeWitnessSignatureOfNonce = accountAgeWitnessSignatureOfNonce;
} }
@ -124,63 +131,66 @@ public final class PublishDepositTxRequest extends TradeMessage implements Mailb
@Override @Override
public PB.NetworkEnvelope toProtoNetworkEnvelope() { public PB.NetworkEnvelope toProtoNetworkEnvelope() {
final PB.PublishDepositTxRequest.Builder builder = PB.PublishDepositTxRequest.newBuilder() final PB.PublishDepositTxRequest.Builder builder = PB.PublishDepositTxRequest.newBuilder()
.setTradeId(tradeId) .setTradeId(tradeId)
.setMakerPaymentAccountPayload((PB.PaymentAccountPayload) makerPaymentAccountPayload.toProtoMessage()) .setMakerPaymentAccountPayload((PB.PaymentAccountPayload) makerPaymentAccountPayload.toProtoMessage())
.setMakerAccountId(makerAccountId) .setMakerAccountId(makerAccountId)
.setMakerMultiSigPubKey(ByteString.copyFrom(makerMultiSigPubKey)) .setMakerMultiSigPubKey(ByteString.copyFrom(makerMultiSigPubKey))
.setMakerContractAsJson(makerContractAsJson) .setMakerContractAsJson(makerContractAsJson)
.setMakerContractSignature(makerContractSignature) .setMakerContractSignature(makerContractSignature)
.setMakerPayoutAddressString(makerPayoutAddressString) .setMakerPayoutAddressString(makerPayoutAddressString)
.setPreparedDepositTx(ByteString.copyFrom(preparedDepositTx)) .setPreparedDepositTx(ByteString.copyFrom(preparedDepositTx))
.addAllMakerInputs(makerInputs.stream().map(RawTransactionInput::toProtoMessage).collect(Collectors.toList())) .addAllMakerInputs(makerInputs.stream().map(RawTransactionInput::toProtoMessage).collect(Collectors.toList()))
.setSenderNodeAddress(senderNodeAddress.toProtoMessage()) .setSenderNodeAddress(senderNodeAddress.toProtoMessage())
.setUid(uid); .setUid(uid);
Optional.ofNullable(accountAgeWitnessNonce).ifPresent(accountAgeWitnessNonce ->builder.setAccountAgeWitnessNonce(ByteString.copyFrom(accountAgeWitnessNonce))); Optional.ofNullable(accountAgeWitnessSignatureOfAccountData).ifPresent(e -> builder.setAccountAgeWitnessSignatureOfAccountData(ByteString.copyFrom(e)));
Optional.ofNullable(accountAgeWitnessSignatureOfNonce).ifPresent(accountAgeWitnessSignatureOfNonce ->builder.setAccountAgeWitnessSignatureOfNonce(ByteString.copyFrom(accountAgeWitnessSignatureOfNonce))); Optional.ofNullable(accountAgeWitnessNonce).ifPresent(e -> builder.setAccountAgeWitnessNonce(ByteString.copyFrom(e)));
Optional.ofNullable(accountAgeWitnessSignatureOfNonce).ifPresent(e -> builder.setAccountAgeWitnessSignatureOfNonce(ByteString.copyFrom(e)));
return getNetworkEnvelopeBuilder() return getNetworkEnvelopeBuilder()
.setPublishDepositTxRequest(builder) .setPublishDepositTxRequest(builder)
.build(); .build();
} }
public static PublishDepositTxRequest fromProto(PB.PublishDepositTxRequest proto, CoreProtoResolver coreProtoResolver, int messageVersion) { public static PublishDepositTxRequest fromProto(PB.PublishDepositTxRequest proto, CoreProtoResolver coreProtoResolver, int messageVersion) {
List<RawTransactionInput> makerInputs = proto.getMakerInputsList().stream() List<RawTransactionInput> makerInputs = proto.getMakerInputsList().stream()
.map(RawTransactionInput::fromProto) .map(RawTransactionInput::fromProto)
.collect(Collectors.toList()); .collect(Collectors.toList());
return new PublishDepositTxRequest(proto.getTradeId(), return new PublishDepositTxRequest(proto.getTradeId(),
coreProtoResolver.fromProto(proto.getMakerPaymentAccountPayload()), coreProtoResolver.fromProto(proto.getMakerPaymentAccountPayload()),
proto.getMakerAccountId(), proto.getMakerAccountId(),
proto.getMakerMultiSigPubKey().toByteArray(), proto.getMakerMultiSigPubKey().toByteArray(),
proto.getMakerContractAsJson(), proto.getMakerContractAsJson(),
proto.getMakerContractSignature(), proto.getMakerContractSignature(),
proto.getMakerPayoutAddressString(), proto.getMakerPayoutAddressString(),
proto.getPreparedDepositTx().toByteArray(), proto.getPreparedDepositTx().toByteArray(),
makerInputs, makerInputs,
NodeAddress.fromProto(proto.getSenderNodeAddress()), NodeAddress.fromProto(proto.getSenderNodeAddress()),
proto.getUid(), proto.getUid(),
messageVersion, messageVersion,
proto.getAccountAgeWitnessNonce().isEmpty() ? null : proto.getAccountAgeWitnessNonce().toByteArray(), ProtoUtil.byteArrayOrNullFromProto(proto.getAccountAgeWitnessSignatureOfAccountData()),
proto.getAccountAgeWitnessSignatureOfNonce().isEmpty() ? null : proto.getAccountAgeWitnessSignatureOfNonce().toByteArray()); ProtoUtil.byteArrayOrNullFromProto(proto.getAccountAgeWitnessNonce()),
ProtoUtil.byteArrayOrNullFromProto(proto.getAccountAgeWitnessSignatureOfNonce()));
} }
@Override @Override
public String toString() { public String toString() {
return "PublishDepositTxRequest{" + return "PublishDepositTxRequest{" +
"\n makerPaymentAccountPayload=" + makerPaymentAccountPayload + "\n makerPaymentAccountPayload=" + makerPaymentAccountPayload +
",\n makerAccountId='" + makerAccountId + '\'' + ",\n makerAccountId='" + makerAccountId + '\'' +
",\n makerMultiSigPubKey=" + Utilities.bytesAsHexString(makerMultiSigPubKey) + ",\n makerMultiSigPubKey=" + Utilities.bytesAsHexString(makerMultiSigPubKey) +
",\n makerContractAsJson='" + makerContractAsJson + '\'' + ",\n makerContractAsJson='" + makerContractAsJson + '\'' +
",\n makerContractSignature='" + makerContractSignature + '\'' + ",\n makerContractSignature='" + makerContractSignature + '\'' +
",\n makerPayoutAddressString='" + makerPayoutAddressString + '\'' + ",\n makerPayoutAddressString='" + makerPayoutAddressString + '\'' +
",\n preparedDepositTx=" + Utilities.bytesAsHexString(preparedDepositTx) + ",\n preparedDepositTx=" + Utilities.bytesAsHexString(preparedDepositTx) +
",\n makerInputs=" + makerInputs + ",\n makerInputs=" + makerInputs +
",\n senderNodeAddress=" + senderNodeAddress + ",\n senderNodeAddress=" + senderNodeAddress +
",\n uid='" + uid + '\'' + ",\n uid='" + uid + '\'' +
",\n accountAgeWitnessNonce=" + Utilities.bytesAsHexString(accountAgeWitnessNonce) + ",\n accountAgeWitnessSignatureOfAccountData=" + Utilities.bytesAsHexString(accountAgeWitnessSignatureOfAccountData) +
",\n accountAgeWitnessSignatureOfNonce=" + Utilities.bytesAsHexString(accountAgeWitnessSignatureOfNonce) + ",\n accountAgeWitnessNonce=" + Utilities.bytesAsHexString(accountAgeWitnessNonce) +
"\n} " + super.toString(); ",\n accountAgeWitnessSignatureOfNonce=" + Utilities.bytesAsHexString(accountAgeWitnessSignatureOfNonce) +
"\n} " + super.toString();
} }
} }

View file

@ -127,7 +127,6 @@ public class BuyerAsTakerProtocol extends TradeProtocol implements BuyerProtocol
TakerProcessPublishDepositTxRequest.class, TakerProcessPublishDepositTxRequest.class,
CheckIfPeerIsBanned.class, CheckIfPeerIsBanned.class,
TakerVerifyMakerAccount.class, TakerVerifyMakerAccount.class,
TakerVerifyOffersAccountAgeWitnessHash.class,
VerifyPeersAccountAgeWitness.class, VerifyPeersAccountAgeWitness.class,
TakerVerifyMakerFeePayment.class, TakerVerifyMakerFeePayment.class,
TakerVerifyAndSignContract.class, TakerVerifyAndSignContract.class,

View file

@ -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.CheckIfPeerIsBanned;
import io.bisq.core.trade.protocol.tasks.PublishAccountAgeWitness; import io.bisq.core.trade.protocol.tasks.PublishAccountAgeWitness;
import io.bisq.core.trade.protocol.tasks.VerifyPeersAccountAgeWitness; 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.SellerBroadcastPayoutTx;
import io.bisq.core.trade.protocol.tasks.seller.SellerProcessCounterCurrencyTransferStartedMessage; import io.bisq.core.trade.protocol.tasks.seller.SellerProcessCounterCurrencyTransferStartedMessage;
import io.bisq.core.trade.protocol.tasks.seller.SellerSendPayoutTxPublishedMessage; import io.bisq.core.trade.protocol.tasks.seller.SellerSendPayoutTxPublishedMessage;
@ -123,7 +122,6 @@ public class SellerAsTakerProtocol extends TradeProtocol implements SellerProtoc
TakerProcessPublishDepositTxRequest.class, TakerProcessPublishDepositTxRequest.class,
CheckIfPeerIsBanned.class, CheckIfPeerIsBanned.class,
TakerVerifyMakerAccount.class, TakerVerifyMakerAccount.class,
TakerVerifyOffersAccountAgeWitnessHash.class,
VerifyPeersAccountAgeWitness.class, VerifyPeersAccountAgeWitness.class,
TakerVerifyMakerFeePayment.class, TakerVerifyMakerFeePayment.class,
TakerVerifyAndSignContract.class, TakerVerifyAndSignContract.class,

View file

@ -60,6 +60,10 @@ public final class TradingPeer implements PersistablePayload {
private long changeOutputValue; private long changeOutputValue;
@Nullable @Nullable
private String changeOutputAddress; private String changeOutputAddress;
// added in v 0.6
@Nullable
private byte[] accountAgeWitnessSignatureOfAccountData;
@Nullable @Nullable
private byte[] accountAgeWitnessNonce; private byte[] accountAgeWitnessNonce;
@Nullable @Nullable
@ -71,7 +75,7 @@ public final class TradingPeer implements PersistablePayload {
@Override @Override
public Message toProtoMessage() { public Message toProtoMessage() {
final PB.TradingPeer.Builder builder = PB.TradingPeer.newBuilder() final PB.TradingPeer.Builder builder = PB.TradingPeer.newBuilder()
.setChangeOutputValue(changeOutputValue); .setChangeOutputValue(changeOutputValue);
Optional.ofNullable(accountId).ifPresent(builder::setAccountId); Optional.ofNullable(accountId).ifPresent(builder::setAccountId);
Optional.ofNullable(paymentAccountPayload).ifPresent(e -> builder.setPaymentAccountPayload((PB.PaymentAccountPayload) e.toProtoMessage())); Optional.ofNullable(paymentAccountPayload).ifPresent(e -> builder.setPaymentAccountPayload((PB.PaymentAccountPayload) e.toProtoMessage()));
Optional.ofNullable(payoutAddressString).ifPresent(builder::setPayoutAddressString); 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(multiSigPubKey).ifPresent(e -> builder.setMultiSigPubKey(ByteString.copyFrom(e)));
Optional.ofNullable(rawTransactionInputs).ifPresent(e -> builder.addAllRawTransactionInputs(ProtoUtil.collectionToProto(e))); Optional.ofNullable(rawTransactionInputs).ifPresent(e -> builder.addAllRawTransactionInputs(ProtoUtil.collectionToProto(e)));
Optional.ofNullable(changeOutputAddress).ifPresent(builder::setChangeOutputAddress); 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(accountAgeWitnessNonce).ifPresent(e -> builder.setAccountAgeWitnessNonce(ByteString.copyFrom(e)));
Optional.ofNullable(accountAgeWitnessSignatureOfNonce).ifPresent(e -> builder.setAccountAgeWitnessSignatureOfNonce(ByteString.copyFrom(e))); Optional.ofNullable(accountAgeWitnessSignatureOfNonce).ifPresent(e -> builder.setAccountAgeWitnessSignatureOfNonce(ByteString.copyFrom(e)));
return builder.build(); return builder.build();
@ -102,12 +107,13 @@ public final class TradingPeer implements PersistablePayload {
tradingPeer.setPubKeyRing(proto.hasPubKeyRing() ? PubKeyRing.fromProto(proto.getPubKeyRing()) : null); tradingPeer.setPubKeyRing(proto.hasPubKeyRing() ? PubKeyRing.fromProto(proto.getPubKeyRing()) : null);
tradingPeer.setMultiSigPubKey(ProtoUtil.byteArrayOrNullFromProto(proto.getMultiSigPubKey())); tradingPeer.setMultiSigPubKey(ProtoUtil.byteArrayOrNullFromProto(proto.getMultiSigPubKey()));
List<RawTransactionInput> rawTransactionInputs = proto.getRawTransactionInputsList().isEmpty() ? List<RawTransactionInput> rawTransactionInputs = proto.getRawTransactionInputsList().isEmpty() ?
null : null :
proto.getRawTransactionInputsList().stream() proto.getRawTransactionInputsList().stream()
.map(RawTransactionInput::fromProto) .map(RawTransactionInput::fromProto)
.collect(Collectors.toList()); .collect(Collectors.toList());
tradingPeer.setRawTransactionInputs(rawTransactionInputs); tradingPeer.setRawTransactionInputs(rawTransactionInputs);
tradingPeer.setChangeOutputAddress(ProtoUtil.stringOrNullFromProto(proto.getChangeOutputAddress())); tradingPeer.setChangeOutputAddress(ProtoUtil.stringOrNullFromProto(proto.getChangeOutputAddress()));
tradingPeer.setAccountAgeWitnessNonce(ProtoUtil.byteArrayOrNullFromProto(proto.getAccountAgeWitnessSignatureOfAccountData()));
tradingPeer.setAccountAgeWitnessNonce(ProtoUtil.byteArrayOrNullFromProto(proto.getAccountAgeWitnessNonce())); tradingPeer.setAccountAgeWitnessNonce(ProtoUtil.byteArrayOrNullFromProto(proto.getAccountAgeWitnessNonce()));
tradingPeer.setAccountAgeWitnessSignatureOfNonce(ProtoUtil.byteArrayOrNullFromProto(proto.getAccountAgeWitnessSignatureOfNonce())); tradingPeer.setAccountAgeWitnessSignatureOfNonce(ProtoUtil.byteArrayOrNullFromProto(proto.getAccountAgeWitnessSignatureOfNonce()));
return tradingPeer; return tradingPeer;

View file

@ -32,7 +32,7 @@ public class PublishAccountAgeWitness extends TradeTask {
protected void run() { protected void run() {
try { try {
runInterceptHook(); runInterceptHook();
processModel.getAccountAgeWitnessService().publishAccountAgeWitness(processModel.getPaymentAccountPayload(trade)); processModel.getAccountAgeWitnessService().publishMyAccountAgeWitness(processModel.getPaymentAccountPayload(trade));
complete(); complete();
} catch (Throwable t) { } catch (Throwable t) {
failed(t); failed(t);

View file

@ -19,10 +19,12 @@ package io.bisq.core.trade.protocol.tasks;
import io.bisq.common.crypto.PubKeyRing; import io.bisq.common.crypto.PubKeyRing;
import io.bisq.common.taskrunner.TaskRunner; import io.bisq.common.taskrunner.TaskRunner;
import io.bisq.core.offer.Offer;
import io.bisq.core.payment.AccountAgeWitness; import io.bisq.core.payment.AccountAgeWitness;
import io.bisq.core.payment.AccountAgeWitnessService; import io.bisq.core.payment.AccountAgeWitnessService;
import io.bisq.core.payment.payload.PaymentAccountPayload; import io.bisq.core.payment.payload.PaymentAccountPayload;
import io.bisq.core.trade.Trade; import io.bisq.core.trade.Trade;
import io.bisq.core.trade.protocol.TradingPeer;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import java.util.Date; import java.util.Date;
@ -45,49 +47,46 @@ public class VerifyPeersAccountAgeWitness extends TradeTask {
runInterceptHook(); runInterceptHook();
final AccountAgeWitnessService accountAgeWitnessService = processModel.getAccountAgeWitnessService(); final AccountAgeWitnessService accountAgeWitnessService = processModel.getAccountAgeWitnessService();
final PaymentAccountPayload peersPaymentAccountPayload = checkNotNull(processModel.getTradingPeer().getPaymentAccountPayload(), final TradingPeer tradingPeer = processModel.getTradingPeer();
"Peers peersPaymentAccountPayload must not be null"); final PaymentAccountPayload peersPaymentAccountPayload = checkNotNull(tradingPeer.getPaymentAccountPayload(),
"Peers peersPaymentAccountPayload must not be null");
final String[] errorMsg1 = new String[1]; final PubKeyRing peersPubKeyRing = checkNotNull(tradingPeer.getPubKeyRing(), "peersPubKeyRing must not be null");
boolean result = accountAgeWitnessService.verifyTradeLimit(trade.getOffer(), peersPaymentAccountPayload, errorMessage -> errorMsg1[0] = errorMessage); final Offer offer = trade.getOffer();
if (result) { final Optional<String> accountAgeWitnessHashAsHex = offer.getAccountAgeWitnessHashAsHex();
byte[] nonce = processModel.getTradingPeer().getAccountAgeWitnessNonce(); Optional<AccountAgeWitness> witnessOptional = accountAgeWitnessHashAsHex.isPresent() ?
byte[] signatureOfNonce = processModel.getTradingPeer().getAccountAgeWitnessSignatureOfNonce(); accountAgeWitnessService.getPeersWitnessByHashAsHex(accountAgeWitnessHashAsHex.get())
Optional<AccountAgeWitness> witnessOptional = accountAgeWitnessService.getWitnessByPaymentAccountPayload(peersPaymentAccountPayload); : Optional.<AccountAgeWitness>empty();
if (witnessOptional.isPresent() && nonce != null && signatureOfNonce != null) { byte[] nonce = tradingPeer.getAccountAgeWitnessNonce();
AccountAgeWitness witness = witnessOptional.get(); byte[] signatureOfNonce = tradingPeer.getAccountAgeWitnessSignatureOfNonce();
final PubKeyRing pubKeyRing = processModel.getTradingPeer().getPubKeyRing(); if (witnessOptional.isPresent() && nonce != null && signatureOfNonce != null) {
checkNotNull(pubKeyRing, "processModel.getTradingPeer().getPubKeyRing() must not be null"); AccountAgeWitness witness = witnessOptional.get();
final String[] errorMsg2 = new String[1]; final String[] errorMsg = new String[1];
result = accountAgeWitnessService.verifyAccountAgeWitness(peersPaymentAccountPayload.getAgeWitnessInputData(), byte[] peersSignatureOfAccountHash = tradingPeer.getAccountAgeWitnessSignatureOfAccountData();
witness, boolean result = accountAgeWitnessService.verifyPeersAccountAgeWitness(offer,
peersPaymentAccountPayload.getSalt(), peersPaymentAccountPayload,
pubKeyRing.getSignaturePubKey(), witness,
nonce, peersPubKeyRing,
signatureOfNonce, peersSignatureOfAccountHash,
errorMessage -> errorMsg2[0] = errorMessage); nonce,
if (result) signatureOfNonce,
complete(); errorMessage -> errorMsg[0] = errorMessage);
else if (result)
failed(errorMsg2[0]); complete();
} else { else
String msg = !witnessOptional.isPresent() ? failed(errorMsg[0]);
"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();
}
}
} else { } else {
String msg = "The offer verification failed.\nReason: " + errorMsg1[0]; String msg = !witnessOptional.isPresent() ?
log.error(msg); "Peers AccountAgeWitness is not found." :
failed(msg); "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) { } catch (Throwable t) {
failed(t); failed(t);

View file

@ -66,13 +66,14 @@ public class MakerProcessPayDepositRequest extends TradeTask {
if (payDepositRequest.getAcceptedArbitratorNodeAddresses().isEmpty()) if (payDepositRequest.getAcceptedArbitratorNodeAddresses().isEmpty())
failed("acceptedArbitratorNames must not be empty"); failed("acceptedArbitratorNames must not be empty");
processModel.getTradingPeer().setAccountAgeWitnessSignatureOfAccountData(payDepositRequest.getAccountAgeWitnessSignatureOfAccountData());
final byte[] accountAgeWitnessNonce = payDepositRequest.getAccountAgeWitnessNonce(); final byte[] accountAgeWitnessNonce = payDepositRequest.getAccountAgeWitnessNonce();
processModel.getTradingPeer().setAccountAgeWitnessNonce(accountAgeWitnessNonce); processModel.getTradingPeer().setAccountAgeWitnessNonce(accountAgeWitnessNonce);
processModel.getTradingPeer().setAccountAgeWitnessSignatureOfNonce(payDepositRequest.getAccountAgeWitnessSignatureOfNonce()); 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) // 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. // 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())); checkArgument(Arrays.equals(accountAgeWitnessNonce, trade.getOffer().getId().getBytes()));
trade.setArbitratorNodeAddress(checkNotNull(payDepositRequest.getArbitratorNodeAddress())); trade.setArbitratorNodeAddress(checkNotNull(payDepositRequest.getArbitratorNodeAddress()));
trade.setMediatorNodeAddress(checkNotNull(payDepositRequest.getMediatorNodeAddress())); trade.setMediatorNodeAddress(checkNotNull(payDepositRequest.getMediatorNodeAddress()));
@ -98,4 +99,4 @@ public class MakerProcessPayDepositRequest extends TradeTask {
failed(t); failed(t);
} }
} }
} }

View file

@ -21,6 +21,7 @@ import io.bisq.common.crypto.Sig;
import io.bisq.common.taskrunner.TaskRunner; import io.bisq.common.taskrunner.TaskRunner;
import io.bisq.core.btc.AddressEntry; import io.bisq.core.btc.AddressEntry;
import io.bisq.core.btc.wallet.BtcWalletService; 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.Trade;
import io.bisq.core.trade.messages.PublishDepositTxRequest; import io.bisq.core.trade.messages.PublishDepositTxRequest;
import io.bisq.core.trade.protocol.tasks.TradeTask; import io.bisq.core.trade.protocol.tasks.TradeTask;
@ -32,6 +33,7 @@ import java.util.Optional;
import java.util.UUID; import java.util.UUID;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
@Slf4j @Slf4j
public class MakerSendPublishDepositTxRequest extends TradeTask { public class MakerSendPublishDepositTxRequest extends TradeTask {
@ -52,60 +54,66 @@ public class MakerSendPublishDepositTxRequest extends TradeTask {
AddressEntry makerPayoutAddressEntry = walletService.getOrCreateAddressEntry(id, AddressEntry.Context.TRADE_PAYOUT); AddressEntry makerPayoutAddressEntry = walletService.getOrCreateAddressEntry(id, AddressEntry.Context.TRADE_PAYOUT);
byte[] makerMultiSigPubKey = processModel.getMyMultiSigPubKey(); byte[] makerMultiSigPubKey = processModel.getMyMultiSigPubKey();
checkArgument(Arrays.equals(makerMultiSigPubKey, checkArgument(Arrays.equals(makerMultiSigPubKey,
addressEntryOptional.get().getPubKey()), addressEntryOptional.get().getPubKey()),
"makerMultiSigPubKey from AddressEntry must match the one from the trade data. trade id =" + id); "makerMultiSigPubKey from AddressEntry must match the one from the trade data. trade id =" + id);
final byte[] preparedDepositTx = processModel.getPreparedDepositTx(); 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. // 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[] accountAgeWitnessNonce = preparedDepositTx;
byte[] accountAgeWitnessSignatureOfNonce = Sig.sign(processModel.getKeyRing().getSignatureKeyPair().getPrivate(), accountAgeWitnessNonce); byte[] accountAgeWitnessSignatureOfNonce = Sig.sign(processModel.getKeyRing().getSignatureKeyPair().getPrivate(), accountAgeWitnessNonce);
PublishDepositTxRequest message = new PublishDepositTxRequest( PublishDepositTxRequest message = new PublishDepositTxRequest(
processModel.getOfferId(), processModel.getOfferId(),
processModel.getPaymentAccountPayload(trade), paymentAccountPayload,
processModel.getAccountId(), processModel.getAccountId(),
makerMultiSigPubKey, makerMultiSigPubKey,
trade.getContractAsJson(), trade.getContractAsJson(),
trade.getMakerContractSignature(), trade.getMakerContractSignature(),
makerPayoutAddressEntry.getAddressString(), makerPayoutAddressEntry.getAddressString(),
preparedDepositTx, preparedDepositTx,
processModel.getRawTransactionInputs(), processModel.getRawTransactionInputs(),
processModel.getMyNodeAddress(), processModel.getMyNodeAddress(),
UUID.randomUUID().toString(), UUID.randomUUID().toString(),
accountAgeWitnessNonce, accountAgeWitnessSignatureOfAccountData,
accountAgeWitnessSignatureOfNonce); accountAgeWitnessNonce,
accountAgeWitnessSignatureOfNonce);
trade.setState(Trade.State.MAKER_SENT_PUBLISH_DEPOSIT_TX_REQUEST); trade.setState(Trade.State.MAKER_SENT_PUBLISH_DEPOSIT_TX_REQUEST);
processModel.getP2PService().sendEncryptedMailboxMessage( processModel.getP2PService().sendEncryptedMailboxMessage(
trade.getTradingPeerNodeAddress(), trade.getTradingPeerNodeAddress(),
processModel.getTradingPeer().getPubKeyRing(), processModel.getTradingPeer().getPubKeyRing(),
message, message,
new SendMailboxMessageListener() { new SendMailboxMessageListener() {
@Override @Override
public void onArrived() { public void onArrived() {
log.info("Message arrived at peer. tradeId={}", id); log.info("Message arrived at peer. tradeId={}", id);
trade.setState(Trade.State.MAKER_SAW_ARRIVED_PUBLISH_DEPOSIT_TX_REQUEST); trade.setState(Trade.State.MAKER_SAW_ARRIVED_PUBLISH_DEPOSIT_TX_REQUEST);
complete(); 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);
}
} }
@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) { } catch (Throwable t) {

View file

@ -54,7 +54,7 @@ public class MakerSetupDepositTxListener extends TradeTask {
if (walletService.getBalanceForAddress(address).isZero()) { if (walletService.getBalanceForAddress(address).isZero()) {
trade.setState(Trade.State.MAKER_SAW_DEPOSIT_TX_IN_NETWORK); trade.setState(Trade.State.MAKER_SAW_DEPOSIT_TX_IN_NETWORK);
swapReservedForTradeEntry(); swapReservedForTradeEntry();
processModel.getAccountAgeWitnessService().publishAccountAgeWitness(processModel.getPaymentAccountPayload(trade)); processModel.getAccountAgeWitnessService().publishMyAccountAgeWitness(processModel.getPaymentAccountPayload(trade));
} else { } else {
listener = new BalanceListener(address) { listener = new BalanceListener(address) {
@Override @Override
@ -62,7 +62,7 @@ public class MakerSetupDepositTxListener extends TradeTask {
if (balance.isZero() && trade.getState().getPhase() == Trade.Phase.TAKER_FEE_PUBLISHED) { if (balance.isZero() && trade.getState().getPhase() == Trade.Phase.TAKER_FEE_PUBLISHED) {
trade.setState(Trade.State.MAKER_SAW_DEPOSIT_TX_IN_NETWORK); trade.setState(Trade.State.MAKER_SAW_DEPOSIT_TX_IN_NETWORK);
swapReservedForTradeEntry(); swapReservedForTradeEntry();
processModel.getAccountAgeWitnessService().publishAccountAgeWitness(processModel.getPaymentAccountPayload(trade)); processModel.getAccountAgeWitnessService().publishMyAccountAgeWitness(processModel.getPaymentAccountPayload(trade));
} }
} }
}; };

View file

@ -56,10 +56,11 @@ public class TakerProcessPublishDepositTxRequest extends TradeTask {
final byte[] preparedDepositTx = publishDepositTxRequest.getPreparedDepositTx(); final byte[] preparedDepositTx = publishDepositTxRequest.getPreparedDepositTx();
processModel.setPreparedDepositTx(checkNotNull(preparedDepositTx)); processModel.setPreparedDepositTx(checkNotNull(preparedDepositTx));
processModel.getTradingPeer().setAccountAgeWitnessSignatureOfAccountData(publishDepositTxRequest.getAccountAgeWitnessSignatureOfAccountData());
final byte[] accountAgeWitnessNonce = publishDepositTxRequest.getAccountAgeWitnessNonce(); final byte[] accountAgeWitnessNonce = publishDepositTxRequest.getAccountAgeWitnessNonce();
processModel.getTradingPeer().setAccountAgeWitnessNonce(accountAgeWitnessNonce); processModel.getTradingPeer().setAccountAgeWitnessNonce(accountAgeWitnessNonce);
processModel.getTradingPeer().setAccountAgeWitnessSignatureOfNonce(publishDepositTxRequest.getAccountAgeWitnessSignatureOfNonce()); 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. // 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)); checkArgument(Arrays.equals(accountAgeWitnessNonce, preparedDepositTx));
@ -74,4 +75,4 @@ public class TakerProcessPublishDepositTxRequest extends TradeTask {
failed(t); failed(t);
} }
} }
} }

View file

@ -22,6 +22,7 @@ import io.bisq.common.crypto.Sig;
import io.bisq.common.taskrunner.TaskRunner; import io.bisq.common.taskrunner.TaskRunner;
import io.bisq.core.btc.AddressEntry; import io.bisq.core.btc.AddressEntry;
import io.bisq.core.btc.wallet.BtcWalletService; 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.Trade;
import io.bisq.core.trade.messages.PayDepositRequest; import io.bisq.core.trade.messages.PayDepositRequest;
import io.bisq.core.trade.protocol.tasks.TradeTask; import io.bisq.core.trade.protocol.tasks.TradeTask;
@ -61,7 +62,7 @@ public class TakerSendPayDepositRequest extends TradeTask {
String id = processModel.getOffer().getId(); String id = processModel.getOffer().getId();
checkArgument(!walletService.getAddressEntry(id, AddressEntry.Context.MULTI_SIG).isPresent(), 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); AddressEntry addressEntry = walletService.getOrCreateAddressEntry(id, AddressEntry.Context.MULTI_SIG);
byte[] takerMultiSigPubKey = addressEntry.getPubKey(); byte[] takerMultiSigPubKey = addressEntry.getPubKey();
processModel.setMyMultiSigPubKey(takerMultiSigPubKey); processModel.setMyMultiSigPubKey(takerMultiSigPubKey);
@ -70,55 +71,59 @@ public class TakerSendPayDepositRequest extends TradeTask {
String takerPayoutAddressString = takerPayoutAddressEntry.getAddressString(); String takerPayoutAddressString = takerPayoutAddressEntry.getAddressString();
final String offerId = processModel.getOfferId(); 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) // 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. // 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[] accountAgeWitnessNonce = offerId.getBytes();
byte[] accountAgeWitnessSignatureOfNonce = Sig.sign(processModel.getKeyRing().getSignatureKeyPair().getPrivate(), accountAgeWitnessNonce); byte[] accountAgeWitnessSignatureOfNonce = Sig.sign(processModel.getKeyRing().getSignatureKeyPair().getPrivate(), accountAgeWitnessNonce);
PayDepositRequest message = new PayDepositRequest( PayDepositRequest message = new PayDepositRequest(
offerId, offerId,
processModel.getMyNodeAddress(), processModel.getMyNodeAddress(),
trade.getTradeAmount().value, trade.getTradeAmount().value,
trade.getTradePrice().getValue(), trade.getTradePrice().getValue(),
trade.getTxFee().getValue(), trade.getTxFee().getValue(),
trade.getTakerFee().getValue(), trade.getTakerFee().getValue(),
trade.isCurrencyForTakerFeeBtc(), trade.isCurrencyForTakerFeeBtc(),
processModel.getRawTransactionInputs(), processModel.getRawTransactionInputs(),
processModel.getChangeOutputValue(), processModel.getChangeOutputValue(),
processModel.getChangeOutputAddress(), processModel.getChangeOutputAddress(),
takerMultiSigPubKey, takerMultiSigPubKey,
takerPayoutAddressString, takerPayoutAddressString,
processModel.getPubKeyRing(), processModel.getPubKeyRing(),
processModel.getPaymentAccountPayload(trade), paymentAccountPayload,
processModel.getAccountId(), processModel.getAccountId(),
trade.getTakerFeeTxId(), trade.getTakerFeeTxId(),
new ArrayList<>(acceptedArbitratorAddresses), new ArrayList<>(acceptedArbitratorAddresses),
new ArrayList<>(acceptedMediatorAddresses), new ArrayList<>(acceptedMediatorAddresses),
trade.getArbitratorNodeAddress(), trade.getArbitratorNodeAddress(),
trade.getMediatorNodeAddress(), trade.getMediatorNodeAddress(),
UUID.randomUUID().toString(), UUID.randomUUID().toString(),
Version.getP2PMessageVersion(), Version.getP2PMessageVersion(),
accountAgeWitnessNonce, accountAgeWitnessSignatureOfAccountData,
accountAgeWitnessSignatureOfNonce); accountAgeWitnessNonce,
accountAgeWitnessSignatureOfNonce);
processModel.getP2PService().sendEncryptedDirectMessage( processModel.getP2PService().sendEncryptedDirectMessage(
trade.getTradingPeerNodeAddress(), trade.getTradingPeerNodeAddress(),
processModel.getTradingPeer().getPubKeyRing(), processModel.getTradingPeer().getPubKeyRing(),
message, message,
new SendDirectMessageListener() { new SendDirectMessageListener() {
@Override @Override
public void onArrived() { public void onArrived() {
log.debug("Message arrived at peer. tradeId={}, message{}", id, message); log.debug("Message arrived at peer. tradeId={}, message{}", id, message);
complete(); complete();
}
@Override
public void onFault() {
appendToErrorMessage("Sending message failed: message=" + message + "\nerrorMessage=" + errorMessage);
failed();
}
} }
@Override
public void onFault() {
appendToErrorMessage("Sending message failed: message=" + message + "\nerrorMessage=" + errorMessage);
failed();
}
}
); );
} catch (Throwable t) { } catch (Throwable t) {
failed(t); failed(t);

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
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<String, String> 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);
}
}
}

View file

@ -71,14 +71,6 @@ public class AccountAgeWitnessServiceTest {
assertFalse(service.isTradeDateAfterReleaseDate(tradeDate.getTime(), ageWitnessReleaseDate, errorMessage -> {})); 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 @Test
public void testVerifySignature() throws CryptoException { public void testVerifySignature() throws CryptoException {
byte[] ageWitnessInputData = "test".getBytes(Charset.forName("UTF-8")); byte[] ageWitnessInputData = "test".getBytes(Charset.forName("UTF-8"));

View file

@ -50,14 +50,14 @@ public class PeerInfoIcon extends Group {
peerTagMap = preferences.getPeerTagMap(); peerTagMap = preferences.getPeerTagMap();
boolean hasTraded = numTrades > 0; boolean hasTraded = numTrades > 0;
String accountAge = formatter.formatAccountAge(accountAgeWitnessService.getAccountAge(offer)); String accountAge = formatter.formatAccountAge(accountAgeWitnessService.getPeersAccountAge(offer));
tooltipText = hasTraded ? tooltipText = hasTraded ?
Res.get("peerInfoIcon.tooltip.trade.traded", role, hostName, numTrades, accountAge) : Res.get("peerInfoIcon.tooltip.trade.traded", role, hostName, numTrades, accountAge) :
Res.get("peerInfoIcon.tooltip.trade.notTraded", role, hostName, accountAge); Res.get("peerInfoIcon.tooltip.trade.notTraded", role, hostName, accountAge);
// outer circle // outer circle
Color ringColor; Color ringColor;
switch (accountAgeWitnessService.getAccountAgeCategory(accountAgeWitnessService.getAccountAge(offer))) { switch (accountAgeWitnessService.getAccountAgeCategory(accountAgeWitnessService.getPeersAccountAge(offer))) {
case TWO_MONTHS_OR_MORE: case TWO_MONTHS_OR_MORE:
ringColor = Color.rgb(0, 225, 0); // > 2 months green ringColor = Color.rgb(0, 225, 0); // > 2 months green
break; break;

View file

@ -151,10 +151,10 @@ public abstract class PaymentMethodForm {
CurrencyUtil.getDefaultTradeCurrency(); CurrencyUtil.getDefaultTradeCurrency();
final boolean isAddAccountScreen = paymentAccount.getAccountName() == null; 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", addLabelTextField(gridPane, ++gridRow, Res.get("payment.limitations"), Res.get("payment.maxPeriodAndLimit",
getTimeText(hours), getTimeText(hours),
formatter.formatCoinWithCode(Coin.valueOf(accountAgeWitnessService.getTradeLimit(paymentAccount, tradeCurrency.getCode()))), formatter.formatCoinWithCode(Coin.valueOf(accountAgeWitnessService.getMyTradeLimit(paymentAccount, tradeCurrency.getCode()))),
formatter.formatAccountAge(accountAge))); formatter.formatAccountAge(accountAge)));
if (isAddAccountScreen) { if (isAddAccountScreen) {
@ -165,7 +165,7 @@ public abstract class PaymentMethodForm {
try { try {
// test if input is hex // test if input is hex
Utilities.decodeFromHex(newValue); Utilities.decodeFromHex(newValue);
paymentAccount.setSaltAsHex(newValue); paymentAccount.setSaltAsHex(newValue);
} catch (Throwable t) { } catch (Throwable t) {
new Popup().warning(Res.get("payment.error.noHexSalt")).show(); new Popup().warning(Res.get("payment.error.noHexSalt")).show();

View file

@ -1199,12 +1199,12 @@ public class MainViewModel implements ViewModel {
user.addPaymentAccount(okPayAccount); user.addPaymentAccount(okPayAccount);
if (p2PService.isBootstrapped()) { if (p2PService.isBootstrapped()) {
accountAgeWitnessService.publishAccountAgeWitness(okPayAccount.getPaymentAccountPayload()); accountAgeWitnessService.publishMyAccountAgeWitness(okPayAccount.getPaymentAccountPayload());
} else { } else {
p2PService.addP2PServiceListener(new BootstrapListener() { p2PService.addP2PServiceListener(new BootstrapListener() {
@Override @Override
public void onBootstrapComplete() { public void onBootstrapComplete() {
accountAgeWitnessService.publishAccountAgeWitness(okPayAccount.getPaymentAccountPayload()); accountAgeWitnessService.publishMyAccountAgeWitness(okPayAccount.getPaymentAccountPayload());
} }
}); });
} }

View file

@ -60,7 +60,7 @@ class AltCoinAccountsDataModel extends ActivatableDataModel {
OpenOfferManager openOfferManager, OpenOfferManager openOfferManager,
TradeManager tradeManager, TradeManager tradeManager,
AccountAgeWitnessService accountAgeWitnessService, AccountAgeWitnessService accountAgeWitnessService,
Stage stage, Stage stage,
PersistenceProtoResolver persistenceProtoResolver) { PersistenceProtoResolver persistenceProtoResolver) {
this.user = user; this.user = user;
this.preferences = preferences; this.preferences = preferences;
@ -115,7 +115,7 @@ class AltCoinAccountsDataModel extends ActivatableDataModel {
}); });
} }
accountAgeWitnessService.publishAccountAgeWitness(paymentAccount.getPaymentAccountPayload()); accountAgeWitnessService.publishMyAccountAgeWitness(paymentAccount.getPaymentAccountPayload());
} }
public boolean onDeleteAccount(PaymentAccount paymentAccount) { public boolean onDeleteAccount(PaymentAccount paymentAccount) {

View file

@ -115,8 +115,8 @@ class FiatAccountsDataModel extends ActivatableDataModel {
preferences.addCryptoCurrency((CryptoCurrency) tradeCurrency); preferences.addCryptoCurrency((CryptoCurrency) tradeCurrency);
}); });
} }
accountAgeWitnessService.publishAccountAgeWitness(paymentAccount.getPaymentAccountPayload()); accountAgeWitnessService.publishMyAccountAgeWitness(paymentAccount.getPaymentAccountPayload());
} }
public boolean onDeleteAccount(PaymentAccount paymentAccount) { public boolean onDeleteAccount(PaymentAccount paymentAccount) {

View file

@ -180,7 +180,7 @@ public class LockedView extends ActivatableView<VBox, Void> {
} else if (openOfferManager.getOpenOfferById(offerId).isPresent()) { } else if (openOfferManager.getOpenOfferById(offerId).isPresent()) {
return Optional.of(openOfferManager.getOpenOfferById(offerId).get()); return Optional.of(openOfferManager.getOpenOfferById(offerId).get());
} else { } else {
return Optional.empty(); return Optional.<Tradable>empty();
} }
} }

View file

@ -180,7 +180,7 @@ public class ReservedView extends ActivatableView<VBox, Void> {
} else if (openOfferManager.getOpenOfferById(offerId).isPresent()) { } else if (openOfferManager.getOpenOfferById(offerId).isPresent()) {
return Optional.of(openOfferManager.getOpenOfferById(offerId).get()); return Optional.of(openOfferManager.getOpenOfferById(offerId).get());
} else { } else {
return Optional.empty(); return Optional.<Tradable>empty();
} }
} }

View file

@ -401,7 +401,7 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
} else if (failedTradesManager.getTradeById(offerId).isPresent()) { } else if (failedTradesManager.getTradeById(offerId).isPresent()) {
return Optional.of(failedTradesManager.getTradeById(offerId).get()); return Optional.of(failedTradesManager.getTradeById(offerId).get());
} else { } else {
return Optional.empty(); return Optional.<Tradable>empty();
} }
} }

View file

@ -347,8 +347,8 @@ class CreateOfferDataModel extends ActivatableDataModel {
HashMap<String, String> extraDataMap = new HashMap<>(); HashMap<String, String> extraDataMap = new HashMap<>();
if (CurrencyUtil.isFiatCurrency(currencyCode)) { if (CurrencyUtil.isFiatCurrency(currencyCode)) {
final String hashOfPaymentAccountAsHex = accountAgeWitnessService.getWitnessHashAsHex(paymentAccount.getPaymentAccountPayload()); final String myWitnessHashAsHex = accountAgeWitnessService.getMyWitnessHashAsHex(paymentAccount.getPaymentAccountPayload());
extraDataMap.put(OfferPayload.ACCOUNT_AGE_WITNESS_HASH, hashOfPaymentAccountAsHex); extraDataMap.put(OfferPayload.ACCOUNT_AGE_WITNESS_HASH, myWitnessHashAsHex);
} }
Coin buyerSecurityDepositAsCoin = buyerSecurityDeposit.get(); Coin buyerSecurityDepositAsCoin = buyerSecurityDeposit.get();
@ -553,7 +553,7 @@ class CreateOfferDataModel extends ActivatableDataModel {
long getMaxTradeLimit() { long getMaxTradeLimit() {
if (paymentAccount != null) if (paymentAccount != null)
return accountAgeWitnessService.getTradeLimit(paymentAccount, tradeCurrencyCode.get()); return accountAgeWitnessService.getMyTradeLimit(paymentAccount, tradeCurrencyCode.get());
else else
return 0; return 0;
} }

View file

@ -401,10 +401,10 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
} else if (isInsufficientTradeLimit) { } else if (isInsufficientTradeLimit) {
final Optional<PaymentAccount> account = model.getMostMaturePaymentAccountForOffer(offer); final Optional<PaymentAccount> account = model.getMostMaturePaymentAccountForOffer(offer);
if (account.isPresent()) { 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<>() new Popup<>()
.warning(Res.get("offerbook.warning.tradeLimitNotMatching", .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(Coin.valueOf(tradeLimit)),
formatter.formatCoinWithCode(offer.getMinAmount()))) formatter.formatCoinWithCode(offer.getMinAmount())))
.show(); .show();

View file

@ -464,7 +464,7 @@ class OfferBookViewModel extends ActivatableViewModel {
boolean isInsufficientTradeLimit(Offer offer) { boolean isInsufficientTradeLimit(Offer offer) {
Optional<PaymentAccount> accountOptional = getMostMaturePaymentAccountForOffer(offer); Optional<PaymentAccount> 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; final long offerMinAmount = offer.getMinAmount().value;
log.debug("isInsufficientTradeLimit accountOptional={}, myTradeLimit={}, offerMinAmount={}, ", log.debug("isInsufficientTradeLimit accountOptional={}, myTradeLimit={}, offerMinAmount={}, ",
accountOptional.isPresent() ? accountOptional.get().getAccountName() : "null", accountOptional.isPresent() ? accountOptional.get().getAccountName() : "null",

View file

@ -362,7 +362,7 @@ class TakeOfferDataModel extends ActivatableDataModel {
long getMaxTradeLimit() { long getMaxTradeLimit() {
if (paymentAccount != null) if (paymentAccount != null)
return accountAgeWitnessService.getTradeLimit(paymentAccount, getCurrencyCode()); return accountAgeWitnessService.getMyTradeLimit(paymentAccount, getCurrencyCode());
else else
return 0; return 0;
} }

View file

@ -119,8 +119,8 @@ public abstract class Overlay<T extends Overlay> {
protected Pane owner; protected Pane owner;
protected GridPane gridPane; protected GridPane gridPane;
protected Button closeButton; protected Button closeButton;
protected Optional<Runnable> closeHandlerOptional = Optional.empty(); protected Optional<Runnable> closeHandlerOptional = Optional.<Runnable>empty();
protected Optional<Runnable> actionHandlerOptional = Optional.empty(); protected Optional<Runnable> actionHandlerOptional = Optional.<Runnable>empty();
protected Stage stage; protected Stage stage;
protected boolean showReportErrorButtons; protected boolean showReportErrorButtons;
protected Label messageLabel; protected Label messageLabel;

View file

@ -66,7 +66,7 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
private final BtcWalletService walletService; private final BtcWalletService walletService;
private final TradeWalletService tradeWalletService; private final TradeWalletService tradeWalletService;
private Dispute dispute; private Dispute dispute;
private Optional<Runnable> finalizeDisputeHandlerOptional = Optional.empty(); private Optional<Runnable> finalizeDisputeHandlerOptional = Optional.<Runnable>empty();
private ToggleGroup tradeAmountToggleGroup, reasonToggleGroup; private ToggleGroup tradeAmountToggleGroup, reasonToggleGroup;
private DisputeResult disputeResult; private DisputeResult disputeResult;
private RadioButton buyerGetsTradeAmountRadioButton, sellerGetsTradeAmountRadioButton, private RadioButton buyerGetsTradeAmountRadioButton, sellerGetsTradeAmountRadioButton,

View file

@ -65,8 +65,8 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
private Offer offer; private Offer offer;
private Coin tradeAmount; private Coin tradeAmount;
private Price tradePrice; private Price tradePrice;
private Optional<Runnable> placeOfferHandlerOptional = Optional.empty(); private Optional<Runnable> placeOfferHandlerOptional = Optional.<Runnable>empty();
private Optional<Runnable> takeOfferHandlerOptional = Optional.empty(); private Optional<Runnable> takeOfferHandlerOptional = Optional.<Runnable>empty();
private BusyAnimation busyAnimation; private BusyAnimation busyAnimation;

View file

@ -79,7 +79,7 @@ public class BisqInstaller {
try { try {
return Optional.of(downloadFiles(fileDescriptors, Utilities.getDownloadOfHomeDir())); return Optional.of(downloadFiles(fileDescriptors, Utilities.getDownloadOfHomeDir()));
} catch (IOException exception) { } catch (IOException exception) {
return Optional.empty(); return Optional.<DownloadTask>empty();
} }
} }

View file

@ -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); 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"), 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); field.setCopyWithoutCurrencyPostFix(true);
String myPaymentDetails = ""; String myPaymentDetails = "";
@ -219,8 +219,8 @@ public class SellerStep3View extends TradeStepView {
protected String getWarningText() { protected String getWarningText() {
setWarningHeadline(); setWarningHeadline();
String substitute = model.isBlockChainMethod() ? String substitute = model.isBlockChainMethod() ?
Res.get("portfolio.pending.step3_seller.warn.part1a", model.dataModel.getCurrencyCode()) : 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.part1b");
return Res.get("portfolio.pending.step3_seller.warn.part2", substitute, model.getDateForOpenDispute()); 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"); message += Res.get("portfolio.pending.step3_seller.onPaymentReceived.note");
new Popup<>() new Popup<>()
.headLine(Res.get("portfolio.pending.step3_seller.onPaymentReceived.confirm.headline")) .headLine(Res.get("portfolio.pending.step3_seller.onPaymentReceived.confirm.headline"))
.confirmation(message) .confirmation(message)
.width(700) .width(700)
.actionButtonText(Res.get("portfolio.pending.step3_seller.onPaymentReceived.confirm.yes")) .actionButtonText(Res.get("portfolio.pending.step3_seller.onPaymentReceived.confirm.yes"))
.onAction(this::confirmPaymentReceived) .onAction(this::confirmPaymentReceived)
.closeButtonText(Res.get("shared.cancel")) .closeButtonText(Res.get("shared.cancel"))
.show(); .show();
} else { } else {
confirmPaymentReceived(); confirmPaymentReceived();
} }
@ -316,8 +316,8 @@ public class SellerStep3View extends TradeStepView {
if (!DevEnv.DEV_MODE && DontShowAgainLookup.showAgain(key)) { if (!DevEnv.DEV_MODE && DontShowAgainLookup.showAgain(key)) {
DontShowAgainLookup.dontShowAgain(key, true); DontShowAgainLookup.dontShowAgain(key, true);
new Popup<>().headLine(Res.get("popup.attention.forTradeWithId", id)) new Popup<>().headLine(Res.get("popup.attention.forTradeWithId", id))
.attention(message) .attention(message)
.show(); .show();
} }
} }
@ -350,9 +350,9 @@ public class SellerStep3View extends TradeStepView {
else if (paymentAccountPayload instanceof SepaAccountPayload) else if (paymentAccountPayload instanceof SepaAccountPayload)
return Optional.of(((SepaAccountPayload) paymentAccountPayload).getHolderName()); return Optional.of(((SepaAccountPayload) paymentAccountPayload).getHolderName());
else else
return Optional.empty(); return Optional.<String>empty();
} else { } else {
return Optional.empty(); return Optional.<String>empty();
} }
} }
} }

View file

@ -103,7 +103,7 @@ public class Connection implements MessageListener {
private OutputStream protoOutputStream; private OutputStream protoOutputStream;
// mutable data, set from other threads but not changed internally. // mutable data, set from other threads but not changed internally.
private Optional<NodeAddress> peersNodeAddressOptional = Optional.empty(); private Optional<NodeAddress> peersNodeAddressOptional = Optional.<NodeAddress>empty();
private volatile boolean stopped; private volatile boolean stopped;
private PeerType peerType; private PeerType peerType;
private final ObjectProperty<NodeAddress> peersNodeAddressProperty = new SimpleObjectProperty<>(); private final ObjectProperty<NodeAddress> peersNodeAddressProperty = new SimpleObjectProperty<>();

View file

@ -56,7 +56,7 @@ public class RequestDataManager implements MessageListener, ConnectionListener,
private final Map<NodeAddress, RequestDataHandler> handlerMap = new HashMap<>(); private final Map<NodeAddress, RequestDataHandler> handlerMap = new HashMap<>();
private final Map<String, GetDataRequestHandler> getDataRequestHandlers = new HashMap<>(); private final Map<String, GetDataRequestHandler> getDataRequestHandlers = new HashMap<>();
private Optional<NodeAddress> nodeAddressOfPreliminaryDataRequest = Optional.empty(); private Optional<NodeAddress> nodeAddressOfPreliminaryDataRequest = Optional.<NodeAddress>empty();
private Timer retryTimer; private Timer retryTimer;
private boolean dataUpdateRequested; private boolean dataUpdateRequested;
private boolean stopped; private boolean stopped;