mirror of
https://github.com/bisq-network/bisq.git
synced 2025-02-23 23:06:39 +01:00
Only use accumulated hash in Witness object
This commit is contained in:
parent
a33923cc1e
commit
e56fc44956
43 changed files with 666 additions and 713 deletions
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
35
common/src/test/java/io/bisq/common/util/UtilitiesTest.java
Normal file
35
common/src/test/java/io/bisq/common/util/UtilitiesTest.java
Normal 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})));
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
|
|
@ -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 +
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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}";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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"));
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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<>();
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Add table
Reference in a new issue