Merge remote-tracking branch 'upstream/master'

This commit is contained in:
ghubstan 2019-08-09 14:45:57 -03:00
commit 2709e61875
No known key found for this signature in database
GPG Key ID: E35592D6800A861E
52 changed files with 12725 additions and 1187 deletions

View File

@ -33,4 +33,8 @@ public class EtherAddressValidator extends RegexAddressValidator {
public EtherAddressValidator() {
super("^(0x)?[0-9a-fA-F]{40}$");
}
public EtherAddressValidator(String errorMessageI18nKey) {
super("^(0x)?[0-9a-fA-F]{40}$", errorMessageI18nKey);
}
}

View File

@ -0,0 +1,8 @@
package bisq.asset;
import java.util.ResourceBundle;
public class I18n {
public static ResourceBundle DISPLAY_STRINGS = ResourceBundle.getBundle("i18n.displayStrings-assets");
}

View File

@ -18,11 +18,19 @@
package bisq.asset.coins;
import bisq.asset.Coin;
import bisq.asset.DefaultAddressValidator;
import bisq.asset.I18n;
import bisq.asset.RegexAddressValidator;
public class Counterparty extends Coin {
public Counterparty() {
super("Counterparty", "XCP", new DefaultAddressValidator());
super("Counterparty", "XCP", new XcpAddressValidator());
}
public static class XcpAddressValidator extends RegexAddressValidator {
public XcpAddressValidator() {
super("^[1][a-zA-Z0-9]{33}", I18n.DISPLAY_STRINGS.getString("account.altcoin.popup.validation.XCP"));
}
}
}

View File

@ -18,11 +18,19 @@
package bisq.asset.coins;
import bisq.asset.Coin;
import bisq.asset.DefaultAddressValidator;
import bisq.asset.I18n;
import bisq.asset.RegexAddressValidator;
public class Decred extends Coin {
public Decred() {
super("Decred", "DCR", new DefaultAddressValidator());
public Decred() {
super("Decred", "DCR", new DcrAddressValidator());
}
public static class DcrAddressValidator extends RegexAddressValidator {
public DcrAddressValidator() {
super("^[Dk|Ds|De|DS|Dc|Pm][a-zA-Z0-9]{24,34}", I18n.DISPLAY_STRINGS.getString("account.altcoin.popup.validation.DCR"));
}
}
}

View File

@ -18,11 +18,12 @@
package bisq.asset.coins;
import bisq.asset.Coin;
import bisq.asset.DefaultAddressValidator;
import bisq.asset.EtherAddressValidator;
import bisq.asset.I18n;
public class EtherClassic extends Coin {
public EtherClassic() {
super("Ether Classic", "ETC", new DefaultAddressValidator());
super("Ether Classic", "ETC", new EtherAddressValidator(I18n.DISPLAY_STRINGS.getString("account.altcoin.popup.validation.ETC")));
}
}

View File

@ -17,20 +17,20 @@
package bisq.asset.coins;
import bisq.asset.Base58BitcoinAddressValidator;
import bisq.asset.Coin;
import bisq.asset.NetworkParametersAdapter;
import bisq.asset.I18n;
import bisq.asset.RegexAddressValidator;
public class Namecoin extends Coin {
public Namecoin() {
super("Namecoin", "NMC", new Base58BitcoinAddressValidator(new NamecoinChainParams()));
public Namecoin() {
super("Namecoin", "NMC", new NmcAddressValidator());
}
public static class NmcAddressValidator extends RegexAddressValidator {
public static class NamecoinChainParams extends NetworkParametersAdapter {
public NamecoinChainParams() {
addressHeader = 52;
acceptableAddressCodes = new int[]{addressHeader};
public NmcAddressValidator() {
super("^[NM][a-zA-Z0-9]{33}$", I18n.DISPLAY_STRINGS.getString("account.altcoin.popup.validation.NMC"));
}
}
}

View File

@ -18,11 +18,20 @@
package bisq.asset.coins;
import bisq.asset.Coin;
import bisq.asset.DefaultAddressValidator;
import bisq.asset.I18n;
import bisq.asset.RegexAddressValidator;
public class Siafund extends Coin {
public Siafund() {
super("Siafund", "SF", new DefaultAddressValidator());
super("Siafund", "SF", new SfAddressValidator());
}
public static class SfAddressValidator extends RegexAddressValidator {
public SfAddressValidator() {
super("^[0-9a-fA-F]{76}$", I18n.DISPLAY_STRINGS.getString("account.altcoin.popup.validation.XCP"));
}
}
}

View File

@ -18,11 +18,19 @@
package bisq.asset.coins;
import bisq.asset.Coin;
import bisq.asset.DefaultAddressValidator;
import bisq.asset.I18n;
import bisq.asset.RegexAddressValidator;
public class Unobtanium extends Coin {
public Unobtanium() {
super("Unobtanium", "UNO", new DefaultAddressValidator());
public Unobtanium() {
super("Unobtanium", "UNO", new UnoAddressValidator());
}
public static class UnoAddressValidator extends RegexAddressValidator {
public UnoAddressValidator() {
super("^[u]?[a-zA-Z0-9]{33}", I18n.DISPLAY_STRINGS.getString("account.altcoin.popup.validation.UNO"));
}
}
}

View File

@ -19,12 +19,20 @@ package bisq.asset.coins;
import bisq.asset.AltCoinAccountDisclaimer;
import bisq.asset.Coin;
import bisq.asset.DefaultAddressValidator;
import bisq.asset.I18n;
import bisq.asset.RegexAddressValidator;
@AltCoinAccountDisclaimer("account.altcoin.popup.XZC.msg")
public class Zcoin extends Coin {
public Zcoin() {
super("Zcoin", "XZC", new DefaultAddressValidator());
public Zcoin() {
super("Zcoin", "XZC", new XzcAddressValidator());
}
public static class XzcAddressValidator extends RegexAddressValidator {
public XzcAddressValidator() {
super("^a?[a-zA-Z0-9]{33}", I18n.DISPLAY_STRINGS.getString("account.altcoin.popup.validation.XZC"));
}
}
}

View File

@ -0,0 +1,28 @@
# Keep display strings organized by domain
# Naming convention: We use camelCase and dot separated name spaces.
# Use as many sub spaces as required to make the structure clear, but as little as possible.
# E.g.: [main-view].[component].[description]
# In some cases we use enum values or constants to map to display strings
# A annoying issue with property files is that we need to use 2 single quotes in display string
# containing variables (e.g. {0}), otherwise the variable will not be resolved.
# In display string which do not use a variable a single quote is ok.
# E.g. Don''t .... {1}
# We use sometimes dynamic parts which are put together in the code and therefore sometimes use line breaks or spaces
# at the end of the string. Please never remove any line breaks or spaces. They are there with a purpose!
# To make longer strings with better readable you can make a line break with \ which does not result in a line break
# in the display but only in the editor.
# Please use in all language files the exact same order of the entries, that way a comparison is easier.
# Please try to keep the length of the translated string similar to English. If it is longer it might break layout or
# get truncated. We will need some adjustments in the UI code to support that but we want to keep effort at the minimum.
account.altcoin.popup.validation.XCP=XCP address must start with '1' and must have 34 characters.
account.altcoin.popup.validation.DCR=DCR address must start with 'Dk' or 'Ds' or 'De' or 'DS' or 'Dc' or 'Pm' and must have 34 characters.
account.altcoin.popup.validation.ETC=ETC address must start with '0x' and made up of letters A to F and numbers which are 40 characters long.
account.altcoin.popup.validation.NMC=NMC address must start with 'N' or 'M' and must be 34 characters long.
account.altcoin.popup.validation.SF= Siafund address must be made up of letters A to F and numbers which are 76 characters long.
account.altcoin.popup.validation.UNO=UNO address must start with 'u' and must have 34 characters.
account.altcoin.popup.validation.XZC=XZC address must start with 'a' and must have 34 characters.

View File

@ -17,11 +17,25 @@
package bisq.asset.coins;
import bisq.asset.AbstractAssetWithDefaultValidatorTest;
import bisq.asset.AbstractAssetTest;
public class CounterpartyTest extends AbstractAssetWithDefaultValidatorTest {
public class CounterpartyTest extends AbstractAssetTest {
public CounterpartyTest() {
super(new Counterparty());
}
@Override
public void testValidAddresses() {
assertValidAddress("1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa");
assertValidAddress("1KBbojKRf1YnJKp1YK5eEz9TWlS4pFEbwS");
assertValidAddress("1AtLN6BMlW0Rwj800LNcBBR2o0k0sYVuIN");
}
@Override
public void testInvalidAddresses() {
assertInvalidAddress("MxmFPEPzF19JFPU3VPrRXvUbPjMQXnQerY");
assertInvalidAddress("122FRU9f3fx7Hty641DRK6S3sbf3");
assertInvalidAddress("MxmFPEPzF19JFPU3VPrRXvUbPjMQXnQerY");
}
}

View File

@ -17,11 +17,27 @@
package bisq.asset.coins;
import bisq.asset.AbstractAssetWithDefaultValidatorTest;
import bisq.asset.AbstractAssetTest;
public class DecredTest extends AbstractAssetWithDefaultValidatorTest {
public class DecredTest extends AbstractAssetTest {
public DecredTest() {
super(new Decred());
}
@Override
public void testValidAddresses() {
// TODO Auto-generated method stub
assertValidAddress("Dcur2mcGjmENx4DhNqDctW5wJCVyT3Qeqkx");
assertValidAddress("Dsur2mcGjmENx4DhNqDctW5wJCVyT3Qeqkx");
assertValidAddress("Deur2mcGjmENx4DhNqDctW5wJCVyT3Qeqkx");
}
@Override
public void testInvalidAddresses() {
// TODO Auto-generated method stub
assertInvalidAddress("aHu897ivzmeFuLNB6956X6gyGeVNHUBRgD");
assertInvalidAddress("a1HwTdCmQV3NspP2QqCGpehoFpi8NY4Zg3");
assertInvalidAddress("aHu897ivzmeFuLNB6956X6gyGeVNHUBRgD");
}
}

View File

@ -17,11 +17,26 @@
package bisq.asset.coins;
import bisq.asset.AbstractAssetWithDefaultValidatorTest;
import bisq.asset.AbstractAssetTest;
public class EtherClassicTest extends AbstractAssetWithDefaultValidatorTest {
public class EtherClassicTest extends AbstractAssetTest {
public EtherClassicTest() {
super(new EtherClassic());
}
@Override
public void testValidAddresses() {
assertValidAddress("0x353c13b940aa5eed75aa97d477954289e7880bb8");
assertValidAddress("0x9f5304DA62A5408416Ea58A17a92611019bD5ce3");
assertValidAddress("0x180826b05452ce96E157F0708c43381Fee64a6B8");
}
@Override
public void testInvalidAddresses() {
assertInvalidAddress("MxmFPEPzF19JFPU3VPrRXvUbPjMQXnQerY");
assertInvalidAddress("N22FRU9f3fx7Hty641D5cg95kRK6S3sbf3");
assertInvalidAddress("MxmFPEPzF19JFPU3VPrRXvUbPjMQXnQerY");
}
}

View File

@ -17,11 +17,26 @@
package bisq.asset.coins;
import bisq.asset.AbstractAssetWithDefaultValidatorTest;
import bisq.asset.AbstractAssetTest;
public class SiafundTest extends AbstractAssetWithDefaultValidatorTest {
public class SiafundTest extends AbstractAssetTest {
public SiafundTest() {
super(new Siafund());
}
@Override
public void testValidAddresses() {
assertValidAddress("949f35966a9b5f329f7419f91a02301b71b9f776568b2c767842af22b408eb8662203a02ec53");
assertValidAddress("4daae3005456559972f4902217ee8394a890e2afede6f0b49015e5cfaecdcb13f466f5543346");
assertValidAddress("da4f7fdc0fa047851a9860b09bc9b1e7424333c977e53a5d8aad74f5843a20b7cfa77a7794ae");
}
@Override
public void testInvalidAddresses() {
assertInvalidAddress("MxmFPEPzF19JFPU3VPrRXvUbPjMQXnQerY");
assertInvalidAddress("N22FRU9f3fx7Hty641D5cg95kRK6S3sbf3");
assertInvalidAddress("MxmFPEPzF19JFPU3VPrRXvUbPjMQXnQerY");
}
}

View File

@ -17,11 +17,25 @@
package bisq.asset.coins;
import bisq.asset.AbstractAssetWithDefaultValidatorTest;
import bisq.asset.AbstractAssetTest;
public class UnobtaniumTest extends AbstractAssetWithDefaultValidatorTest {
public class UnobtaniumTest extends AbstractAssetTest {
public UnobtaniumTest() {
super(new Unobtanium());
}
@Override
public void testValidAddresses() {
assertValidAddress("uXN2S9Soj4dSL7fPAuQi9twdaFmtwYndVP");
assertValidAddress("uZymbhuxhfvxzc5EDdqRWrrZKvabZibBu1");
assertValidAddress("uKdudT6DwojHYsBE9JWM43hRV28Rmp1Zm1");
}
@Override
public void testInvalidAddresses() {
assertInvalidAddress("aHu897ivzmeFuLNB6956X6gyGeVNHUBRgD");
assertInvalidAddress("a1HwTdCmQV3NspP2QqCGpehoFpi8NY4Zg3");
assertInvalidAddress("aHu897ivzmeFuLNB6956X6gyGeVNHUBRgD");
}
}

View File

@ -17,11 +17,25 @@
package bisq.asset.coins;
import bisq.asset.AbstractAssetWithDefaultValidatorTest;
import bisq.asset.AbstractAssetTest;
public class ZcoinTest extends AbstractAssetWithDefaultValidatorTest {
public class ZcoinTest extends AbstractAssetTest {
public ZcoinTest() {
super(new Zcoin());
}
@Override
public void testValidAddresses() {
assertValidAddress("aHu897ivzmeFuLNB6956X6gyGeVNHUBRgD");
assertValidAddress("a1HwTdCmQV3NspP2QqCGpehoFpi8NY4Zg3");
assertValidAddress("aHu897ivzmeFuLNB6956X6gyGeVNHUBRgD");
}
@Override
public void testInvalidAddresses() {
assertInvalidAddress("MxmFPEPzF19JFPU3VPrRXvUbPjMQXnQerY");
assertInvalidAddress("N22FRU9f3fx7Hty641D5cg95kRK6S3sbf3");
assertInvalidAddress("MxmFPEPzF19JFPU3VPrRXvUbPjMQXnQerY");
}
}

View File

@ -59,7 +59,7 @@ configure(subprojects) {
logbackVersion = '1.1.10'
lombokVersion = '1.18.2'
mockitoVersion = '2.21.0'
netlayerVersion = '0.6.5'
netlayerVersion = '0.6.5.1'
powermockVersion = '2.0.0-beta.5'
protobufVersion = '3.5.1'
pushyVersion = '0.13.2'
@ -223,10 +223,17 @@ configure(project(':common')) {
configure(project(':p2p')) {
dependencies {
compile project(':common')
<<<<<<< HEAD
compile("com.github.JesusMcCloud.netlayer:tor.native:$netlayerVersion") {
exclude(module: 'slf4j-api')
}
compile("com.github.JesusMcCloud.netlayer:tor.external:$netlayerVersion") {
=======
compile('com.github.JesusMcCloud.netlayer:tor.native:0.6.5.1') {
exclude(module: 'slf4j-api')
}
compile('com.github.JesusMcCloud.netlayer:tor.external:0.6.5.1') {
>>>>>>> upstream/master
exclude(module: 'slf4j-api')
}
compile("org.apache.httpcomponents:httpclient:$httpclientVersion") {
@ -300,7 +307,7 @@ configure(project(':desktop')) {
apply plugin: 'witness'
apply from: '../gradle/witness/gradle-witness.gradle'
version = '1.1.4-SNAPSHOT'
version = '1.1.5-SNAPSHOT'
mainClassName = 'bisq.desktop.app.BisqAppMain'

View File

@ -27,7 +27,7 @@ public class Version {
// VERSION = 0.5.0 introduces proto buffer for the P2P network and local DB and is a not backward compatible update
// Therefore all sub versions start again with 1
// We use semantic versioning with major, minor and patch
public static final String VERSION = "1.1.4";
public static final String VERSION = "1.1.5";
public static int getMajorVersion(String version) {
return getSubVersion(version, 0);

View File

@ -559,7 +559,9 @@ public class VoteResultService implements DaoStateListener, DaoSetupService {
evaluatedProposals.forEach(evaluatedProposal -> evaluatedProposalsByTxIdMap.put(evaluatedProposal.getProposalTxId(), evaluatedProposal));
// Proposals which did not get any vote need to be set as failed.
// TODO We should not use proposalListPresentation here
proposalListPresentation.getActiveOrMyUnconfirmedProposals().stream()
.filter(proposal -> periodService.isTxInCorrectCycle(proposal.getTxId(), chainHeight))
.filter(proposal -> !evaluatedProposalsByTxIdMap.containsKey(proposal.getTxId()))
.forEach(proposal -> {
ProposalVoteResult proposalVoteResult = new ProposalVoteResult(proposal, 0,

View File

@ -62,6 +62,10 @@ shared.priceWithCur=Price in {0}
shared.priceInCurForCur=Price in {0} for 1 {1}
shared.fixedPriceInCurForCur=Fixed price in {0} for 1 {1}
shared.amount=Amount
shared.txFee=Transaction Fee
shared.makerFee=Maker Fee
shared.buyerSecurityDeposit=Buyer Deposit
shared.sellerSecurityDeposit=Seller Deposit
shared.amountWithCur=Amount in {0}
shared.volumeWithCur=Volume in {0}
shared.currency=Currency
@ -302,6 +306,7 @@ market.trades.tooltip.candle.close=Close:
market.trades.tooltip.candle.high=High:
market.trades.tooltip.candle.low=Low:
market.trades.tooltip.candle.average=Average:
market.trades.tooltip.candle.median=Median:
market.trades.tooltip.candle.date=Date:
####################################################################
@ -610,7 +615,7 @@ message.state.SENT=Message sent
# suppress inspection "UnusedProperty"
message.state.ARRIVED=Message arrived at peer
# suppress inspection "UnusedProperty"
message.state.STORED_IN_MAILBOX=Message stored in mailbox
message.state.STORED_IN_MAILBOX=Message of payment sent but not yet received by peer
# suppress inspection "UnusedProperty"
message.state.ACKNOWLEDGED=Peer confirmed message receipt
# suppress inspection "UnusedProperty"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
TXT CHECKPOINTS 1
0
289
292
AAAAAAAAB+EH4QfhAAAH4AEAAABjl7tqvU/FIcDT9gcbVlA4nwtFUbxAtOawZzBpAAAAAKzkcK7NqciBjI/ldojNKncrWleVSgDfBCCn3VRrbSxXaw5/Sf//AB0z8Bkv
AAAAAAAAD8EPwQ/BAAAPwAEAAADfP83Sx8MZ9RsrnZCvqzAwqB2Ma+ZesNAJrTfwAAAAACwESaNKhvRgz6WuE7UFdFk1xwzfRY/OIdIOPzX5yaAdjnWUSf//AB0GrNq5
AAAAAAAAF6EXoRehAAAXoAEAAADonWzAaUAKd30XT3NnHKobZMnLOuHdzm/xtehsAAAAAD8cUJA6NBIHHcqPHLc4IrfHw+6mjCGu3e+wRO81EvpnMVqrSf//AB1ffy8G
@ -290,3 +290,6 @@ BkV2AoDsDE62cnaTAAjMQAAAACC/Jis5jV91U1f7bLXc1DWFEpJRbN9KCgAAAAAAAAAAAF4Pe1dyXuph
BnV8GunthUu4x0TVAAjUIAAAACDXdi8B59cAJ+SzQJf8rDogYOr1lKuFBAAAAAAAAAAAAHkiwaMxpVidI1uP2PSAZvDJ1VPm+H9LJkbMzj0NxXYueFzwXHa7JReuEDNC
Bqrp5qOY/694OiFZAAjcAAAAACBzxqRKrJh4FvPRDuMnFO3W+yo/+228DAAAAAAAAAAAABAw3deFEkJ3ewNS6pskyikSV+f0b60vDw1At9NVCQ6udvICXQP9JRc33+M3
Bt/8BpMe+l+0cvlVAAjj4AAAACA0pUTAWqILhKoJ/P6ZJlUA8/VY32WYHQAAAAAAAAAAAKQR1SRjcuTNE/r79SrUYD1HUiH5qda9A2NpSdUJXSEWEjEUXSx5IxennK4/
BxjR5kMqYX5AXwC1AAjrwAAAACCmOTRY8Cy7u4/sugJgpCO/mHoLwbZeEQAAAAAAAAAAAOZIsqYbzRmDz1PwaqkAMuLWLgo7eKT0+M9L+DDA29a5vFskXZsNHxfYMtrv
B1m9nmok83qfrm9oAAjzoAAAgCDP8OB6s52w8x1N7YG6IzkXMVW5xXg5EQAAAAAAAAAAAHotddzlmB7EIaVN9wbT1Af2bckXDx4NbkjtHoocrXck6e02XQg6Hxe8Q7EK
B5pN58sRlHzFOR//AAj7gAAAACBSYArI6b5PONfRi67pcVj7cWTbJI1rCQAAAAAAAAAAAKh1PP1FNXL/yUwEMhXpYBPx8f6iC77T2BDBwemNb+RO2JlHXTkwHBcAFrew

View File

@ -8,7 +8,7 @@
# pull base image
FROM openjdk:8-jdk
ENV version 1.1.4-SNAPSHOT
ENV version 1.1.5-SNAPSHOT
RUN apt-get update && apt-get install -y --no-install-recommends openjfx && rm -rf /var/lib/apt/lists/* &&
apt-get install -y vim fakeroot

View File

@ -6,7 +6,7 @@
# - Update version below
# - Ensure JAVA_HOME below is pointing to OracleJDK 10 directory
version=1.1.4-SNAPSHOT
version=1.1.5-SNAPSHOT
if [ ! -f "$JAVA_HOME/bin/javapackager" ]; then
if [ -d "/usr/lib/jvm/jdk-10.0.2" ]; then
JAVA_HOME=/usr/lib/jvm/jdk-10.0.2

View File

@ -4,7 +4,7 @@
# Prior to running this script:
# - Update version below
version=1.1.4-SNAPSHOT
version=1.1.5-SNAPSHOT
base_dir=$( cd "$(dirname "$0")" ; pwd -P )/../../..
package_dir=$base_dir/desktop/package
release_dir=$base_dir/desktop/release/$version

View File

@ -5,10 +5,10 @@
<!-- See: https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -->
<key>CFBundleVersion</key>
<string>1.1.4</string>
<string>1.1.5</string>
<key>CFBundleShortVersionString</key>
<string>1.1.4</string>
<string>1.1.5</string>
<key>CFBundleExecutable</key>
<string>Bisq</string>

View File

@ -6,7 +6,7 @@ mkdir -p deploy
set -e
version="1.1.4-SNAPSHOT"
version="1.1.5-SNAPSHOT"
cd ..
./gradlew :desktop:build -x test shadowJar

View File

@ -2,7 +2,7 @@
cd ../../
version="1.1.4-SNAPSHOT"
version="1.1.5-SNAPSHOT"
target_dir="releases/$version"

View File

@ -2,7 +2,7 @@
cd $(dirname $0)/../../../
version=1.1.4
version=1.1.5
find . -type f \( -name "finalize.sh" \
-o -name "create_app.sh" \

View File

@ -2,8 +2,8 @@
cd $(dirname $0)/../../../
oldVersion=1.1.3
newVersion=1.1.4
oldVersion=1.1.4
newVersion=1.1.5
find . -type f \( -name "finalize.sh" \
-o -name "create_app.sh" \

View File

@ -8,7 +8,7 @@
@echo off
set version=1.1.4-SNAPSHOT
set version=1.1.5-SNAPSHOT
if not exist "%JAVA_HOME%\bin\javapackager.exe" (
if not exist "%ProgramFiles%\Java\jdk-10.0.2" (
echo Javapackager not found. Update JAVA_HOME variable to point to OracleJDK.

View File

@ -6,7 +6,7 @@
@echo off
set version=1.1.4-SNAPSHOT
set version=1.1.5-SNAPSHOT
set release_dir=%~dp0..\..\..\releases\%version%
set package_dir=%~dp0..

View File

@ -410,7 +410,6 @@ public class MainView extends InitializableView<StackPane, MainViewModel>
public void onCheckpointFail() {
new Popup<>().attention(Res.get("dao.monitor.daoState.checkpoint.popup"))
.useShutDownButton()
.hideCloseButton()
.show();
}

View File

@ -65,6 +65,7 @@ import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
@ -304,20 +305,20 @@ class TradesChartsViewModel extends ActivatableViewModel {
long accumulatedVolume = 0;
long accumulatedAmount = 0;
long numTrades = set.size();
List<Long> tradePrices = new ArrayList<>(set.size());
for (TradeStatistics2 item : set) {
long tradePriceAsLong = item.getTradePrice().getValue();
if (CurrencyUtil.isCryptoCurrency(getCurrencyCode())) {
low = (low != 0) ? Math.max(low, tradePriceAsLong) : tradePriceAsLong;
high = (high != 0) ? Math.min(high, tradePriceAsLong) : tradePriceAsLong;
} else {
low = (low != 0) ? Math.min(low, tradePriceAsLong) : tradePriceAsLong;
high = (high != 0) ? Math.max(high, tradePriceAsLong) : tradePriceAsLong;
}
// Previously a check was done which inverted the low and high for
// crytocurrencies.
low = (low != 0) ? Math.min(low, tradePriceAsLong) : tradePriceAsLong;
high = (high != 0) ? Math.max(high, tradePriceAsLong) : tradePriceAsLong;
accumulatedVolume += (item.getTradeVolume() != null) ? item.getTradeVolume().getValue() : 0;
accumulatedAmount += item.getTradeAmount().getValue();
tradePrices.add(item.getTradePrice().getValue());
}
Collections.sort(tradePrices);
List<TradeStatistics2> list = new ArrayList<>(set);
list.sort((o1, o2) -> (o1.getTradeDate().getTime() < o2.getTradeDate().getTime() ? -1 : (o1.getTradeDate().getTime() == o2.getTradeDate().getTime() ? 0 : 1)));
@ -327,6 +328,9 @@ class TradesChartsViewModel extends ActivatableViewModel {
}
long averagePrice;
Long[] prices = new Long[tradePrices.size()];
tradePrices.toArray(prices);
long medianPrice = findMedian(prices);
boolean isBullish;
if (CurrencyUtil.isCryptoCurrency(getCurrencyCode())) {
isBullish = close < open;
@ -343,9 +347,20 @@ class TradesChartsViewModel extends ActivatableViewModel {
String dateString = tickUnit.ordinal() > TickUnit.DAY.ordinal() ?
formatter.formatDateTimeSpan(dateFrom, dateTo) :
formatter.formatDate(dateFrom) + " - " + formatter.formatDate(dateTo);
return new CandleData(tick, open, close, high, low, averagePrice, accumulatedAmount, accumulatedVolume,
return new CandleData(tick, open, close, high, low, averagePrice, medianPrice, accumulatedAmount, accumulatedVolume,
numTrades, isBullish, dateString);
}
Long findMedian(Long[] prices) {
int middle = prices.length / 2;
long median;
if (prices.length % 2 == 1) {
median = prices[middle];
} else {
median = MathUtils.roundDoubleToLong((prices[middle - 1] + prices[middle]) / 2.0);
}
return median;
}
Date roundToTick(Date time, TickUnit tickUnit) {
ZonedDateTime zdt = time.toInstant().atZone(ZoneId.systemDefault());

View File

@ -24,13 +24,14 @@ public class CandleData {
public final long high;
public final long low;
public final long average;
public final long median;
public final long accumulatedAmount;
public final long accumulatedVolume;
public final long numTrades;
public final boolean isBullish;
public final String date;
public CandleData(long tick, long open, long close, long high, long low, long average,
public CandleData(long tick, long open, long close, long high, long low, long average, long median,
long accumulatedAmount, long accumulatedVolume, long numTrades,
boolean isBullish, String date) {
this.tick = tick;
@ -39,6 +40,7 @@ public class CandleData {
this.high = high;
this.low = low;
this.average = average;
this.median = median;
this.accumulatedAmount = accumulatedAmount;
this.accumulatedVolume = accumulatedVolume;
this.numTrades = numTrades;

View File

@ -74,6 +74,7 @@ public class CandleTooltip extends GridPane {
private final Label highValue = new AutoTooltipLabel();
private final Label lowValue = new AutoTooltipLabel();
private final Label averageValue = new AutoTooltipLabel();
private final Label medianValue = new AutoTooltipLabel();
private final Label dateValue = new AutoTooltipLabel();
CandleTooltip(StringConverter<Number> priceStringConverter) {
@ -88,6 +89,7 @@ public class CandleTooltip extends GridPane {
Label high = new AutoTooltipLabel(Res.get("market.trades.tooltip.candle.high"));
Label low = new AutoTooltipLabel(Res.get("market.trades.tooltip.candle.low"));
Label average = new AutoTooltipLabel(Res.get("market.trades.tooltip.candle.average"));
Label median = new AutoTooltipLabel(Res.get("market.trades.tooltip.candle.median"));
Label date = new AutoTooltipLabel(Res.get("market.trades.tooltip.candle.date"));
setConstraints(open, 0, 0);
setConstraints(openValue, 1, 0);
@ -99,8 +101,10 @@ public class CandleTooltip extends GridPane {
setConstraints(lowValue, 1, 3);
setConstraints(average, 0, 4);
setConstraints(averageValue, 1, 4);
setConstraints(date, 0, 5);
setConstraints(dateValue, 1, 5);
setConstraints(median, 0, 5);
setConstraints(medianValue, 1, 5);
setConstraints(date, 0, 6);
setConstraints(dateValue, 1, 6);
ColumnConstraints columnConstraints1 = new ColumnConstraints();
columnConstraints1.setHalignment(HPos.RIGHT);
@ -109,7 +113,7 @@ public class CandleTooltip extends GridPane {
columnConstraints2.setHgrow(Priority.ALWAYS);
getColumnConstraints().addAll(columnConstraints1, columnConstraints2);
getChildren().addAll(open, openValue, close, closeValue, high, highValue, low, lowValue, average, averageValue, date, dateValue);
getChildren().addAll(open, openValue, close, closeValue, high, highValue, low, lowValue, average, averageValue, median, medianValue, date, dateValue);
}
public void update(CandleData candleData) {
@ -118,6 +122,7 @@ public class CandleTooltip extends GridPane {
highValue.setText(priceStringConverter.toString(candleData.high));
lowValue.setText(priceStringConverter.toString(candleData.low));
averageValue.setText(priceStringConverter.toString(candleData.average));
medianValue.setText(priceStringConverter.toString(candleData.median));
dateValue.setText(candleData.date);
}
}

View File

@ -40,6 +40,10 @@
<TableColumn fx:id="priceColumn" minWidth="100"/>
<TableColumn fx:id="amountColumn" minWidth="130"/>
<TableColumn fx:id="volumeColumn" minWidth="130"/>
<TableColumn fx:id="txFeeColumn" visible="false"/>
<TableColumn fx:id="makerFeeColumn" visible="false"/>
<TableColumn fx:id="buyerSecurityDepositColumn" visible="false"/>
<TableColumn fx:id="sellerSecurityDepositColumn" visible="false"/>
<TableColumn fx:id="directionColumn" minWidth="80"/>
<TableColumn fx:id="stateColumn" minWidth="80"/>
<TableColumn fx:id="avatarColumn" minWidth="40" maxWidth="40"/>

View File

@ -85,7 +85,7 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
@FXML
TableView<ClosedTradableListItem> tableView;
@FXML
TableColumn<ClosedTradableListItem, ClosedTradableListItem> priceColumn, amountColumn, volumeColumn,
TableColumn<ClosedTradableListItem, ClosedTradableListItem> priceColumn, amountColumn, volumeColumn, txFeeColumn, makerFeeColumn, buyerSecurityDepositColumn, sellerSecurityDepositColumn,
marketColumn, directionColumn, dateColumn, tradeIdColumn, stateColumn, avatarColumn;
@FXML
HBox footerBox;
@ -124,8 +124,12 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
this.useDevPrivilegeKeys = useDevPrivilegeKeys;
}
@Override
public void initialize() {
@Override
public void initialize() {
txFeeColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.txFee")));
makerFeeColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.makerFee")));
buyerSecurityDepositColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.buyerSecurityDeposit")));
sellerSecurityDepositColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.sellerSecurityDeposit")));
priceColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.price")));
amountColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.amountWithCur", Res.getBaseCurrencyCode())));
volumeColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.amount")));
@ -142,6 +146,10 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
setTradeIdColumnCellFactory();
setDirectionColumnCellFactory();
setAmountColumnCellFactory();
setTxFeeColumnCellFactory();
setMakerFeeColumnCellFactory();
setBuyerSecurityDepositColumnCellFactory();
setSellerSecurityDepositColumnCellFactory();
setPriceColumnCellFactory();
setVolumeColumnCellFactory();
setDateColumnCellFactory();
@ -191,6 +199,52 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
} else
return 0;
});
txFeeColumn.setComparator((o1, o2) -> {
final Tradable tradable1 = o1.getTradable();
final Tradable tradable2 = o2.getTradable();
Coin txFee1 = null;
Coin txFee2 = null;
if (tradable1 != null)
txFee1 = tradable1 instanceof Trade ? ((Trade) tradable1).getTxFee() : tradable1.getOffer().getTxFee();
if (tradable2 != null)
txFee2 = tradable2 instanceof Trade ? ((Trade) tradable2).getTxFee() : tradable2.getOffer().getTxFee();
return txFee1 != null && txFee2 != null ? txFee1.compareTo(txFee2) : 0;
});
makerFeeColumn.setComparator((o1, o2) -> {
final Tradable tradable1 = o1.getTradable();
final Tradable tradable2 = o2.getTradable();
Coin txFee1 = null;
Coin txFee2 = null;
if (tradable1 != null)
txFee1 = tradable1 instanceof Trade ? ((Trade) tradable1).getTakerFee()
: tradable1.getOffer().getMakerFee();
if (tradable2 != null)
txFee2 = tradable2 instanceof Trade ? ((Trade) tradable2).getTakerFee()
: tradable2.getOffer().getMakerFee();
return txFee1 != null && txFee2 != null ? txFee1.compareTo(txFee2) : 0;
});
buyerSecurityDepositColumn.setComparator((o1, o2) -> {
final Tradable tradable1 = o1.getTradable();
final Tradable tradable2 = o2.getTradable();
Coin txFee1 = null;
Coin txFee2 = null;
if (tradable1 != null && tradable1.getOffer() != null)
txFee1 = tradable1.getOffer().getBuyerSecurityDeposit();
if (tradable2 != null && tradable2.getOffer() != null)
txFee2 = tradable2.getOffer().getBuyerSecurityDeposit();
return txFee1 != null && txFee2 != null ? txFee1.compareTo(txFee2) : 0;
});
sellerSecurityDepositColumn.setComparator((o1, o2) -> {
final Tradable tradable1 = o1.getTradable();
final Tradable tradable2 = o2.getTradable();
Coin txFee1 = null;
Coin txFee2 = null;
if (tradable1 != null && tradable1.getOffer() != null)
txFee1 = tradable1.getOffer().getSellerSecurityDeposit();
if (tradable2 != null && tradable2.getOffer() != null)
txFee2 = tradable2.getOffer().getSellerSecurityDeposit();
return txFee1 != null && txFee2 != null ? txFee1.compareTo(txFee2) : 0;
});
stateColumn.setComparator(Comparator.comparing(model::getState));
dateColumn.setSortType(TableColumn.SortType.DESCENDING);
@ -218,21 +272,25 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
exportButton.setOnAction(event -> {
final ObservableList<TableColumn<ClosedTradableListItem, ?>> tableColumns = tableView.getColumns();
CSVEntryConverter<ClosedTradableListItem> headerConverter = transactionsListItem -> {
String[] columns = new String[7];
String[] columns = new String[11];
for (int i = 0; i < columns.length; i++)
columns[i] = tableColumns.get(i).getText();
return columns;
};
CSVEntryConverter<ClosedTradableListItem> contentConverter = item -> {
String[] columns = new String[7];
String[] columns = new String[11];
columns[0] = model.getTradeId(item);
columns[1] = model.getDate(item);
columns[2] = model.getAmount(item);
columns[3] = model.getPrice(item);
columns[4] = model.getVolume(item);
columns[5] = model.getDirectionLabel(item);
columns[6] = model.getState(item);
columns[5] = model.getTxFee(item);
columns[6] = model.getMakerFee(item);
columns[7] = model.getBuyerSecurityDeposit(item);
columns[8] = model.getSellerSecurityDeposit(item);
columns[9] = model.getDirectionLabel(item);
columns[10] = model.getState(item);
return columns;
};
@ -497,5 +555,77 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
}
});
}
}
private void setTxFeeColumnCellFactory() {
txFeeColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
txFeeColumn.setCellFactory(
new Callback<>() {
@Override
public TableCell<ClosedTradableListItem, ClosedTradableListItem> call(
TableColumn<ClosedTradableListItem, ClosedTradableListItem> column) {
return new TableCell<>() {
@Override
public void updateItem(final ClosedTradableListItem item, boolean empty) {
super.updateItem(item, empty);
setGraphic(new AutoTooltipLabel(model.getTxFee(item)));
}
};
}
});
}
private void setMakerFeeColumnCellFactory() {
makerFeeColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
makerFeeColumn.setCellFactory(
new Callback<>() {
@Override
public TableCell<ClosedTradableListItem, ClosedTradableListItem> call(
TableColumn<ClosedTradableListItem, ClosedTradableListItem> column) {
return new TableCell<>() {
@Override
public void updateItem(final ClosedTradableListItem item, boolean empty) {
super.updateItem(item, empty);
setGraphic(new AutoTooltipLabel(model.getMakerFee(item)));
}
};
}
});
}
private void setBuyerSecurityDepositColumnCellFactory() {
buyerSecurityDepositColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
buyerSecurityDepositColumn.setCellFactory(
new Callback<>() {
@Override
public TableCell<ClosedTradableListItem, ClosedTradableListItem> call(
TableColumn<ClosedTradableListItem, ClosedTradableListItem> column) {
return new TableCell<>() {
@Override
public void updateItem(final ClosedTradableListItem item, boolean empty) {
super.updateItem(item, empty);
setGraphic(new AutoTooltipLabel(model.getBuyerSecurityDeposit(item)));
}
};
}
});
}
private void setSellerSecurityDepositColumnCellFactory() {
sellerSecurityDepositColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
sellerSecurityDepositColumn.setCellFactory(
new Callback<>() {
@Override
public TableCell<ClosedTradableListItem, ClosedTradableListItem> call(
TableColumn<ClosedTradableListItem, ClosedTradableListItem> column) {
return new TableCell<>() {
@Override
public void updateItem(final ClosedTradableListItem item, boolean empty) {
super.updateItem(item, empty);
setGraphic(new AutoTooltipLabel(model.getSellerSecurityDeposit(item)));
}
};
}
});
}
}

View File

@ -82,6 +82,46 @@ class ClosedTradesViewModel extends ActivatableWithDataModel<ClosedTradesDataMod
return "";
}
String getTxFee(ClosedTradableListItem item) {
if (item == null)
return "";
Tradable tradable = item.getTradable();
if (tradable instanceof Trade)
return formatter.formatCoin(((Trade) tradable).getTxFee());
else
return formatter.formatCoin(tradable.getOffer().getTxFee());
}
String getMakerFee(ClosedTradableListItem item) {
if (item == null)
return "";
Tradable tradable = item.getTradable();
if (tradable instanceof Trade)
return formatter.formatCoin(((Trade) tradable).getTakerFee());
else
return formatter.formatCoin(tradable.getOffer().getMakerFee());
}
String getBuyerSecurityDeposit(ClosedTradableListItem item) {
if (item == null)
return "";
Tradable tradable = item.getTradable();
if (tradable.getOffer() != null)
return formatter.formatCoin(tradable.getOffer().getBuyerSecurityDeposit());
else
return "";
}
String getSellerSecurityDeposit(ClosedTradableListItem item) {
if (item == null)
return "";
Tradable tradable = item.getTradable();
if (tradable.getOffer() != null)
return formatter.formatCoin(tradable.getOffer().getSellerSecurityDeposit());
else
return "";
}
String getDirectionLabel(ClosedTradableListItem item) {
return (item != null) ? formatter.getDirectionWithCode(dataModel.getDirection(item.getTradable().getOffer()), item.getTradable().getOffer().getCurrencyCode()) : "";
}

View File

@ -143,6 +143,7 @@ public class TradesChartsViewModelTest {
long close = Fiat.parseFiat("EUR", "580").value;
long high = Fiat.parseFiat("EUR", "600").value;
long average = Fiat.parseFiat("EUR", "550").value;
long median = Fiat.parseFiat("EUR", "550").value;
long amount = Coin.parseCoin("4").value;
long volume = Fiat.parseFiat("EUR", "2200").value;
boolean isBullish = true;
@ -161,6 +162,7 @@ public class TradesChartsViewModelTest {
assertEquals(high, candleData.high);
assertEquals(low, candleData.low);
assertEquals(average, candleData.average);
assertEquals(median, candleData.median);
assertEquals(amount, candleData.accumulatedAmount);
assertEquals(volume, candleData.accumulatedVolume);
assertEquals(isBullish, candleData.isBullish);

View File

@ -23,8 +23,8 @@ dependencyVerification {
'com.googlecode.jcsv:jcsv:73ca7d715e90c8d2c2635cc284543b038245a34f70790660ed590e157b8714a2',
'com.github.sarxos:webcam-capture:d960b7ea8ec3ddf2df0725ef214c3fccc9699ea7772df37f544e1f8e4fd665f6',
'com.jfoenix:jfoenix:4739e37a05e67c3bc9d5b391a1b93717b5a48fa872992616b0964d3f827f8fe6',
'com.github.JesusMcCloud.netlayer:tor.native:6f5fbda4e85f773af0d25fe7502007b1fd14e04ddc17b7619219f22ed7d4081e',
'com.github.JesusMcCloud.netlayer:tor.external:0cef160272a8ba41dd7f7680350e9ad1c003b9b5f41ae552a1086f7a08e5cdf5',
'com.github.JesusMcCloud.netlayer:tor.native:d9a51d0559d0207ca75c33968972d62178b9bd4b2965c1cc0cb76eea252ba059',
'com.github.JesusMcCloud.netlayer:tor.external:0639eea1532cb0cfae421e851753146c63b7627d4e367e8845fcc4b807f44e28',
'org.apache.httpcomponents:httpclient:db3d1b6c2d6a5e5ad47577ad61854e2f0e0936199b8e05eb541ed52349263135',
'net.sf.jopt-simple:jopt-simple:6f45c00908265947c39221035250024f2caec9a15c1c8cf553ebeecee289f342',
'org.fxmisc.easybind:easybind:666af296dda6de68751668a62661571b5238ac6f1c07c8a204fc6f902b222aaf',
@ -44,7 +44,7 @@ dependencyVerification {
'com.google.guava:guava:36a666e3b71ae7f0f0dca23654b67e086e6c93d192f60ba5dfd5519db6c288c8',
'com.google.inject:guice:9b9df27a5b8c7864112b4137fd92b36c3f1395bfe57be42fedf2f520ead1a93e',
'com.github.bisq-network.bitcoinj:bitcoinj-core:f979c2187e61ee3b08dd4cbfc49a149734cff64c045d29ed112f2e12f34068a3',
'com.github.JesusMcCloud.netlayer:tor:35cf892e6ce3a8d942cfd2b589cfbde5aed31d49777aee873d6614e134df0b42',
'com.github.JesusMcCloud.netlayer:tor:7950f8b44609eba2524941cb6517f43ade34e53c820aea849006e22eee93a83d',
'org.jetbrains.kotlin:kotlin-stdlib-jdk8:193ab7813e4d249f2ea4fc1b968fea8c2126bcbeeb5d6127050ce1b93dbaa7c2',
'io.github.microutils:kotlin-logging:4992504fd3c6ecdf9ed10874b9508e758bb908af9e9d7af19a61e9afb6b7e27a',
'org.jetbrains.kotlin:kotlin-stdlib-jdk7:877b59bbe466b24a88275a71fd06cd97359d2085420f6f1ac1d766afa8116001',
@ -56,10 +56,10 @@ dependencyVerification {
'org.bouncycastle:bcprov-jdk15on:963e1ee14f808ffb99897d848ddcdb28fa91ddda867eb18d303e82728f878349',
'com.google.zxing:javase:0ec23e2ec12664ddd6347c8920ad647bb3b9da290f897a88516014b56cc77eb9',
'com.nativelibs4java:bridj:101bcd9b6637e6bc16e56deb3daefba62b1f5e8e9e37e1b3e56e3b5860d659cf',
'com.github.JesusMcCloud.tor-binary:tor-binary-macos:18f7f1a567821dcc22c4b2146db8c4d00a5c6945a556f1a60085b06ad6d61054',
'com.github.JesusMcCloud.tor-binary:tor-binary-linux32:5620ec4df9649ca1c482cde2bc3edda97906616c210adc0ced918943245a5edb',
'com.github.JesusMcCloud.tor-binary:tor-binary-linux64:6891fcd90029efbdcc9c58b3a3f09ce50febf7038df6c57ac338cc6c040d68e0',
'com.github.JesusMcCloud.tor-binary:tor-binary-windows:80ccf0aa44018e7d419d31f570ab87f0d6bd74e4c4a6360b3181d0643d8ef43b',
'com.github.JesusMcCloud.tor-binary:tor-binary-macos:ae2acbeb4d68c1851f2ae460ea1f6bd3e3a6f47dc32c4b4c043584a4dcb39fdf',
'com.github.JesusMcCloud.tor-binary:tor-binary-linux32:60458591479733f1adbd909dce77200d294be00839394424c2e712f389f54f4a',
'com.github.JesusMcCloud.tor-binary:tor-binary-linux64:c3532da1829ede866a759c6cfa4fa2b0187ea70e13e6ef2fed8f5c6e5a1b162b',
'com.github.JesusMcCloud.tor-binary:tor-binary-windows:0b68c013117425414f0cfcedd1e4d99f05f7458ccaf9fa30ef236efa5cf99a90',
'com.github.ravn:jsocks:3c71600af027b2b6d4244e4ad14d98ff2352a379410daebefff5d8cd48d742a4',
'org.apache.httpcomponents:httpcore:d7f853dee87680b07293d30855b39b9eb56c1297bd16ff1cd6f19ddb8fa745fb',
'commons-codec:commons-codec:ad19d2601c3abf0b946b5c3a4113e226a8c1e3305e395b90013b78dd94a723ce',
@ -72,7 +72,7 @@ dependencyVerification {
'org.bitcoinj:orchid:f836325cfa0466a011cb755c9b0fee6368487a2352eb45f4306ad9e4c18de080',
'com.squareup.okhttp:okhttp:b4c943138fcef2bcc9d2006b2250c4aabbedeafc5947ed7c0af7fd103ceb2707',
'com.google.zxing:core:11aae8fd974ab25faa8208be50468eb12349cd239e93e7c797377fa13e381729',
'com.github.JesusMcCloud.tor-binary:tor-binary-geoip:766e4400e5651cf0b11788ea440cc72721be9b92e42f20809c22d0ff129df83c',
'com.github.JesusMcCloud.tor-binary:tor-binary-geoip:8ceaf159154165e53c792f3fc8e30f6e972fe4e6e024a0d7d0e1804326ce0635',
'com.github.JesusMcCloud:jtorctl:904f7c53332179a3479c64d63fb303afa6a02b6889aabdab5b235f3efc725ca7',
'org.apache.commons:commons-compress:5f2df1e467825e4cac5996d44890c4201c000b43c0b23cffc0782d28a0beb9b0',
'org.tukaani:xz:a594643d73cc01928cf6ca5ce100e094ea9d73af760a5d4fb6b75fa673ecec96',

View File

@ -119,13 +119,17 @@ public abstract class Metric extends Configurable implements Runnable {
@Override
public void run() {
Thread.currentThread().setName("Metric: " + getName());
try {
Thread.currentThread().setName("Metric: " + getName());
// execute all the things
synchronized (this) {
log.info("{} started", getName());
execute();
log.info("{} done", getName());
// execute all the things
synchronized (this) {
log.info("{} started", getName());
execute();
log.info("{} done", getName());
}
} catch(Throwable e) {
log.error("A metric misbehaved!", e);
}
}

View File

@ -103,7 +103,6 @@ public class MarketStats extends Metric {
}
amount.find();
timestamp.find();
System.err.println(getName() + ".volume." + market.group(1) + " " + amount.group(1) + " " + timestamp.group(1).substring(0, timestamp.group(1).length() - 3));
reporter.report("volume." + market.group(1), amount.group(1), timestamp.group(1), getName());
});
} catch (IllegalStateException ignore) {

View File

@ -17,166 +17,95 @@
package bisq.monitor.metric;
import bisq.monitor.AvailableTor;
import bisq.monitor.Metric;
import bisq.monitor.Monitor;
import bisq.monitor.OnionParser;
import bisq.monitor.Reporter;
import bisq.monitor.StatisticsHelper;
import bisq.monitor.ThreadGate;
import bisq.core.proto.network.CoreNetworkProtoResolver;
import bisq.network.p2p.CloseConnectionMessage;
import bisq.network.p2p.NodeAddress;
import bisq.network.p2p.network.CloseConnectionReason;
import bisq.network.p2p.network.Connection;
import bisq.network.p2p.network.MessageListener;
import bisq.network.p2p.network.NetworkNode;
import bisq.network.p2p.network.SetupListener;
import bisq.network.p2p.network.TorNetworkNode;
import bisq.network.p2p.peers.keepalive.messages.Ping;
import bisq.network.p2p.peers.keepalive.messages.Pong;
import bisq.common.proto.network.NetworkEnvelope;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.SettableFuture;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import lombok.extern.slf4j.Slf4j;
import static com.google.common.base.Preconditions.checkNotNull;
import org.jetbrains.annotations.NotNull;
@Slf4j
public class P2PRoundTripTime extends Metric implements MessageListener, SetupListener {
public class P2PRoundTripTime extends P2PSeedNodeSnapshotBase {
private static final String SAMPLE_SIZE = "run.sampleSize";
private static final String HOSTS = "run.hosts";
private static final String TOR_PROXY_PORT = "run.torProxyPort";
private NetworkNode networkNode;
private final File torHiddenServiceDir = new File("metric_" + getName());
private int nonce;
private long start;
private List<Long> samples;
private final ThreadGate gate = new ThreadGate();
private final ThreadGate hsReady = new ThreadGate();
private Map<Integer, Long> sentAt = new HashMap<>();
private Map<NodeAddress, Statistics> measurements = new HashMap<>();
public P2PRoundTripTime(Reporter reporter) {
super(reporter);
}
@Override
protected void execute() {
/**
* Use a counter to do statistics.
*/
private class Statistics {
if (null == networkNode) {
// close the gate
hsReady.engage();
private final List<Long> samples = new ArrayList<>();
networkNode = new TorNetworkNode(Integer.parseInt(configuration.getProperty(TOR_PROXY_PORT, "9052")),
new CoreNetworkProtoResolver(), false,
new AvailableTor(Monitor.TOR_WORKING_DIR, torHiddenServiceDir.getName()));
networkNode.start(this);
// wait for the gate to be reopened
hsReady.await();
public synchronized void log(Object message) {
Pong pong = (Pong) message;
Long start = sentAt.get(pong.getRequestNonce());
if(start != null)
samples.add(System.currentTimeMillis() - start);
}
// for each configured host
for (String current : configuration.getProperty(HOSTS, "").split(",")) {
try {
// parse Url
NodeAddress target = OnionParser.getNodeAddress(current);
// init sample bucket
samples = new ArrayList<>();
while (samples.size() < Integer.parseInt(configuration.getProperty(SAMPLE_SIZE, "1"))) {
// so we do not get disconnected due to DoS protection mechanisms
Thread.sleep(200);
nonce = new Random().nextInt();
// close the gate
gate.engage();
start = System.currentTimeMillis();
SettableFuture<Connection> future = networkNode.sendMessage(target, new Ping(nonce, 42));
Futures.addCallback(future, new FutureCallback<>() {
@Override
public void onSuccess(Connection connection) {
connection.addMessageListener(P2PRoundTripTime.this);
}
@Override
public void onFailure(@NotNull Throwable throwable) {
gate.proceed();
log.error("Sending ping failed. That is expected if the peer is offline.\n\tException="
+ throwable.getMessage());
}
});
// wait for the gate to open again
gate.await();
// remove the message listener so we do not get messages we are not interested in anymore
// (especially relevant when gate.await() times out)
future.get().removeMessageListener(this);
}
// report
reporter.report(StatisticsHelper.process(samples),
getName() + "." + OnionParser.prettyPrint(target));
} catch (Exception e) {
gate.proceed(); // release the gate on error
e.printStackTrace();
}
public List<Long> values() {
return samples;
}
}
@Override
public void onMessage(NetworkEnvelope networkEnvelope, Connection connection) {
protected List<NetworkEnvelope> getRequests() {
List<NetworkEnvelope> result = new ArrayList<>();
Random random = new Random();
for (int i = 0; i < Integer.parseInt(configuration.getProperty(SAMPLE_SIZE, "1")); i++)
result.add(new Ping(random.nextInt(), 42));
return result;
}
@Override
protected void aboutToSend(NetworkEnvelope message) {
sentAt.put(((Ping) message).getNonce(), System.currentTimeMillis());
}
@Override
protected boolean treatMessage(NetworkEnvelope networkEnvelope, Connection connection) {
if (networkEnvelope instanceof Pong) {
Pong pong = (Pong) networkEnvelope;
if (pong.getRequestNonce() == nonce) {
samples.add(System.currentTimeMillis() - start);
} else {
log.warn("Nonce not matching. That should never happen.\n\t" +
"We drop that message. nonce={} / requestNonce={}",
nonce, pong.getRequestNonce());
}
checkNotNull(connection.getPeersNodeAddressProperty(),
"although the property is nullable, we need it to not be null");
measurements.putIfAbsent(connection.getPeersNodeAddressProperty().getValue(), new Statistics());
measurements.get(connection.getPeersNodeAddressProperty().getValue()).log(networkEnvelope);
connection.shutDown(CloseConnectionReason.APP_SHUT_DOWN);
// open the gate
gate.proceed();
} else if (networkEnvelope instanceof CloseConnectionMessage) {
gate.unlock();
} else {
log.warn("Got a message of type <{}>, expected <Pong>", networkEnvelope.getClass().getSimpleName());
return true;
}
return false;
}
@Override
public void onTorNodeReady() {
}
@Override
public void onHiddenServicePublished() {
hsReady.proceed();
}
@Override
public void onSetupFailed(Throwable throwable) {
}
@Override
public void onRequestCustomBridges() {
void report() {
// report
measurements.forEach(((nodeAddress, samples) ->
reporter.report(StatisticsHelper.process(samples.values()),
getName() + "." + OnionParser.prettyPrint(nodeAddress))
));
// clean up for next round
measurements = new HashMap<>();
}
}

View File

@ -190,8 +190,8 @@ public class P2PSeedNodeSnapshot extends P2PSeedNodeSnapshotBase {
try {
report.put(OnionParser.prettyPrint(host) + ".relativeNumberOfMessages." + messageType,
String.valueOf(((Counter) count).value() - referenceValues.get(messageType).value()));
} catch (MalformedURLException ignore) {
log.error("we should never got here");
} catch (MalformedURLException | NullPointerException ignore) {
log.error("we should never have gotten here", ignore);
}
});
try {

View File

@ -118,12 +118,12 @@ abstract public class P2PSeedNodeSnapshotBase extends Metric implements MessageL
NodeAddress target = OnionParser.getNodeAddress(current);
// do the data request
aboutToSend(message);
SettableFuture<Connection> future = networkNode.sendMessage(target, message);
Futures.addCallback(future, new FutureCallback<>() {
@Override
public void onSuccess(Connection connection) {
connection.removeMessageListener(P2PSeedNodeSnapshotBase.this);
connection.addMessageListener(P2PSeedNodeSnapshotBase.this);
}
@ -131,8 +131,7 @@ abstract public class P2PSeedNodeSnapshotBase extends Metric implements MessageL
public void onFailure(@NotNull Throwable throwable) {
gate.proceed();
log.error(
"Sending PreliminaryDataRequest failed. That is expected if the peer is offline.\n\tException="
+ throwable.getMessage());
"Sending {} failed. That is expected if the peer is offline.\n\tException={}", message.getClass().getSimpleName(), throwable.getMessage());
}
});
@ -153,6 +152,8 @@ abstract public class P2PSeedNodeSnapshotBase extends Metric implements MessageL
gate.await();
}
protected void aboutToSend(NetworkEnvelope message) { };
/**
* Report all the stuff. Uses the configured reporter directly.
*/
@ -168,6 +169,7 @@ abstract public class P2PSeedNodeSnapshotBase extends Metric implements MessageL
log.warn("Got an unexpected message of type <{}>",
networkEnvelope.getClass().getSimpleName());
}
connection.removeMessageListener(this);
}
abstract protected boolean treatMessage(NetworkEnvelope networkEnvelope, Connection connection);

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
1.1.4-SNAPSHOT
1.1.5-SNAPSHOT

View File

@ -34,7 +34,7 @@ import lombok.extern.slf4j.Slf4j;
@Slf4j
public class SeedNodeMain extends ExecutableForAppWithP2p {
private static final String VERSION = "1.1.4";
private static final String VERSION = "1.1.5";
private SeedNode seedNode;
public SeedNodeMain() {