Merge pull request #6337 from jmacxx/bsq_supply_stats_fixes

Fix bugs in BSQ Supply screen
This commit is contained in:
Christoph Atteneder 2022-10-06 09:44:06 +02:00 committed by GitHub
commit 4a7b76916c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 144 additions and 62 deletions

View File

@ -2628,13 +2628,13 @@ dao.factsAndFigures.supply.totalIssued=Total issued BSQ
dao.factsAndFigures.supply.totalIssued.tooltip=Total issued BSQ is the sum of compensation requests and reimbursement requests.\n\
First reimbursement requests started in Oct 2019.
dao.factsAndFigures.supply.totalBurned=Total burned BSQ
dao.factsAndFigures.supply.totalBurned.tooltip=Total burned BSQ is the sum of BSQ trade fees and all 'Proof of Burn' transactions.\n\
'Proof of Burn' transactions started in Dec 2019.
dao.factsAndFigures.supply.totalBurned.tooltip=Total burned BSQ is the sum of all transactions that include a burn element, \n\
e.g. trade fees, 'Proof of Burn' transactions, or DAO participation fees.
dao.factsAndFigures.supply.totalSupply=Total BSQ supply
dao.factsAndFigures.supply.totalSupply.tooltip=Total BSQ supply is 'Change of BSQ supply' + genesis issuance
dao.factsAndFigures.supply.totalSupply.tooltip=Total BSQ supply is the cumulative sum of 'Change of BSQ supply' + genesis issuance
dao.factsAndFigures.supply.supplyChange=Change of BSQ supply
dao.factsAndFigures.supply.supplyChange.tooltip=Change of BSQ supply reflects the change of all issued BSQ (compensation requests + reimbursement requests)\n\
minus all burned BSQ (BSQ trade fees, Burned BSQ from BTC trade fees, burned BSQ from arbitration cases).
dao.factsAndFigures.supply.supplyChange.tooltip=Change of BSQ supply reflects the change of all issued BSQ \
minus all burned BSQ.
dao.factsAndFigures.supply.chart.tradeFee.toolTip={0}\n{1}
dao.factsAndFigures.supply.burnt=BSQ burnt
@ -2660,6 +2660,9 @@ dao.factsAndFigures.supply.bsqTradeFeeAfterTagging=BSQ Trade fees (post tagging)
dao.factsAndFigures.supply.btcFees=BTC trade fees (proof of Burn)
dao.factsAndFigures.supply.arbitration=From arbitration (proof of Burn)
dao.factsAndFigures.supply.proofOfBurn=Proof of Burn
dao.factsAndFigures.supply.miscBurn=Miscellaneous Burn
dao.factsAndFigures.supply.miscBurn.tooltip=Miscellaneous BSQ burns such as DAO proposal, voting fees\n\
and any BSQ burns not covered by other chart series.
dao.factsAndFigures.supply.arbitrationDiff=Reimbursement costs
dao.factsAndFigures.supply.arbitrationDiff.tooltip=Reimbursement requests minus burned BSQ from arbitration cases.\n\
Should tend to zero long term. As there is considerable time delays between reimbursement requests and burn intervals \n\

View File

@ -1886,6 +1886,14 @@ textfield */
-fx-background-color: -bs-chart-dao-line14, -bs-chart-dao-line14;
}
#charts-dao .default-color14.chart-series-line {
-fx-stroke: -bs-chart-dao-line15;
}
#charts-dao .default-color14.chart-line-symbol {
-fx-background-color: -bs-chart-dao-line15, -bs-chart-dao-line15;
}
#charts-legend-toggle0 {
-jfx-toggle-color: -bs-chart-dao-line1
@ -1943,6 +1951,10 @@ textfield */
-jfx-toggle-color: -bs-chart-dao-line14;
}
#charts-legend-toggle14 {
-jfx-toggle-color: -bs-chart-dao-line15;
}
#charts-dao .chart-series-line {
-fx-stroke-width: 2px;
}

View File

@ -157,19 +157,10 @@ public abstract class ChartViewModel<T extends ChartDataModel> extends Activatab
}
}
void initBounds(List<XYChart.Data<Number, Number>> data1,
List<XYChart.Data<Number, Number>> data2) {
Tuple2<Double, Double> xMinMaxTradeFee = getMinMax(data1);
Tuple2<Double, Double> xMinMaxCompensationRequest = getMinMax(data2);
lowerBound = Math.min(xMinMaxTradeFee.first, xMinMaxCompensationRequest.first);
upperBound = Math.max(xMinMaxTradeFee.second, xMinMaxCompensationRequest.second);
}
void initBounds(List<XYChart.Data<Number, Number>> data) {
Tuple2<Double, Double> xMinMaxTradeFee = getMinMax(data);
lowerBound = xMinMaxTradeFee.first;
upperBound = xMinMaxTradeFee.second;
Tuple2<Double, Double> xMinMaxDate = getMinMaxDatesFromSeries(data);
lowerBound = xMinMaxDate.first;
upperBound = xMinMaxDate.second;
}
@ -246,7 +237,10 @@ public abstract class ChartViewModel<T extends ChartDataModel> extends Activatab
.collect(Collectors.toList());
}
private Tuple2<Double, Double> getMinMax(List<XYChart.Data<Number, Number>> chartData) {
private Tuple2<Double, Double> getMinMaxDatesFromSeries(List<XYChart.Data<Number, Number>> chartData) {
if (chartData.size() == 0) {
return new Tuple2<>(0D, 0D);
}
long min = Long.MAX_VALUE, max = 0;
for (XYChart.Data<Number, ?> data : chartData) {
long value = data.getXValue().longValue();

View File

@ -21,9 +21,11 @@ import bisq.desktop.components.chart.ChartDataModel;
import bisq.core.dao.state.DaoStateService;
import bisq.core.dao.state.model.blockchain.Tx;
import bisq.core.dao.state.model.blockchain.TxType;
import bisq.core.dao.state.model.governance.Issuance;
import bisq.core.dao.state.model.governance.IssuanceType;
import bisq.common.config.Config;
import bisq.common.util.Hex;
import javax.inject.Inject;
@ -37,7 +39,9 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@ -55,7 +59,7 @@ public class DaoChartDataModel extends ChartDataModel {
private Map<Long, Long> totalSupplyByInterval, supplyChangeByInterval, totalIssuedByInterval, compensationByInterval,
reimbursementByInterval, reimbursementByIntervalAfterTagging,
totalBurnedByInterval, bsqTradeFeeByInterval, bsqTradeFeeByIntervalAfterTagging,
proofOfBurnByInterval, proofOfBurnFromBtcFeesByInterval, proofOfBurnFromArbitrationByInterval,
proofOfBurnByInterval, miscBurnByInterval, proofOfBurnFromBtcFeesByInterval, proofOfBurnFromArbitrationByInterval,
arbitrationDiffByInterval, totalTradeFeesByInterval;
static {
@ -91,6 +95,7 @@ public class DaoChartDataModel extends ChartDataModel {
bsqTradeFeeByInterval = null;
bsqTradeFeeByIntervalAfterTagging = null;
proofOfBurnByInterval = null;
miscBurnByInterval = null;
proofOfBurnFromBtcFeesByInterval = null;
proofOfBurnFromArbitrationByInterval = null;
arbitrationDiffByInterval = null;
@ -213,9 +218,7 @@ public class DaoChartDataModel extends ChartDataModel {
return totalBurnedByInterval;
}
Map<Long, Long> tradeFee = getBsqTradeFeeByInterval();
Map<Long, Long> proofOfBurn = getProofOfBurnByInterval();
totalBurnedByInterval = getMergedMap(tradeFee, proofOfBurn, Long::sum);
totalBurnedByInterval = getBurntBsqByInterval(daoStateService.getBurntFeeTxs(), getDateFilter());
return totalBurnedByInterval;
}
@ -248,6 +251,25 @@ public class DaoChartDataModel extends ChartDataModel {
return proofOfBurnByInterval;
}
Map<Long, Long> getMiscBurnByInterval() {
if (miscBurnByInterval != null) {
return miscBurnByInterval;
}
miscBurnByInterval = daoStateService.getBurntFeeTxs().stream()
.filter(e -> e.getTxType() != TxType.PAY_TRADE_FEE)
.filter(e -> e.getTxType() != TxType.PROOF_OF_BURN)
.collect(Collectors.groupingBy(tx -> toTimeInterval(Instant.ofEpochMilli(tx.getTime()))))
.entrySet()
.stream()
.filter(entry -> dateFilter.test(entry.getKey()))
.collect(Collectors.toMap(Map.Entry::getKey,
entry -> entry.getValue().stream()
.mapToLong(Tx::getBurntBsq)
.sum()));
return miscBurnByInterval;
}
Map<Long, Long> getProofOfBurnFromBtcFeesByInterval() {
if (proofOfBurnFromBtcFeesByInterval != null) {
return proofOfBurnFromBtcFeesByInterval;
@ -285,8 +307,24 @@ public class DaoChartDataModel extends ChartDataModel {
}
long genesisValue = daoStateService.getGenesisTotalSupply().value;
totalSupplyByInterval = getSupplyChangeByInterval().entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, e -> genesisValue + e.getValue()));
Collection<Issuance> issuanceSetForType = daoStateService.getIssuanceItems();
// get all issued and burnt BSQ, not just the filtered date range
Map<Long, Long> tmpIssuedByInterval = getIssuedBsqByInterval(issuanceSetForType, e -> true);
Map<Long, Long> tmpBurnedByInterval = new TreeMap<>(getBurntBsqByInterval(daoStateService.getBurntFeeTxs(), e -> true)
.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> -e.getValue())));
Map<Long, Long> tmpSupplyByInterval = getMergedMap(tmpIssuedByInterval, tmpBurnedByInterval, Long::sum);
totalSupplyByInterval = new TreeMap<>(tmpSupplyByInterval.entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));
AtomicReference<Long> atomicSum = new AtomicReference<>(genesisValue);
totalSupplyByInterval.entrySet().forEach(e -> e.setValue(
atomicSum.accumulateAndGet(e.getValue(), Long::sum)
));
// now apply the requested date filter
totalSupplyByInterval = totalSupplyByInterval.entrySet().stream()
.filter(e -> dateFilter.test(e.getKey()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
return totalSupplyByInterval;
}
@ -296,8 +334,9 @@ public class DaoChartDataModel extends ChartDataModel {
}
Map<Long, Long> issued = getTotalIssuedByInterval();
Map<Long, Long> burned = getTotalBurnedByInterval();
supplyChangeByInterval = getMergedMap(issued, burned, (a, b) -> a - b);
Map<Long, Long> burned = new TreeMap<>(getTotalBurnedByInterval().entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, e -> -e.getValue())));
supplyChangeByInterval = getMergedMap(issued, burned, Long::sum);
return supplyChangeByInterval;
}
@ -305,7 +344,7 @@ public class DaoChartDataModel extends ChartDataModel {
// Aggregated collection data by interval
///////////////////////////////////////////////////////////////////////////////////////////
private Map<Long, Long> getIssuedBsqByInterval(Set<Issuance> issuanceSet, Predicate<Long> dateFilter) {
private Map<Long, Long> getIssuedBsqByInterval(Collection<Issuance> issuanceSet, Predicate<Long> dateFilter) {
return issuanceSet.stream()
.collect(Collectors.groupingBy(issuance ->
toTimeInterval(Instant.ofEpochMilli(blockTimeOfIssuanceFunction.apply(issuance)))))
@ -370,39 +409,41 @@ public class DaoChartDataModel extends ChartDataModel {
public final static Map<Long, Long> COMPENSATIONS_BY_CYCLE_DATE = new HashMap<>();
static {
REIMBURSEMENTS_BY_CYCLE_DATE.put(1571349571L, 60760L);
REIMBURSEMENTS_BY_CYCLE_DATE.put(1574180991L, 2621000L);
REIMBURSEMENTS_BY_CYCLE_DATE.put(1576966522L, 4769100L);
REIMBURSEMENTS_BY_CYCLE_DATE.put(1579613568L, 0L);
REIMBURSEMENTS_BY_CYCLE_DATE.put(1582399054L, 9186600L);
REIMBURSEMENTS_BY_CYCLE_DATE.put(1585342220L, 12089400L);
REIMBURSEMENTS_BY_CYCLE_DATE.put(1588025030L, 5420700L);
REIMBURSEMENTS_BY_CYCLE_DATE.put(1591004931L, 9138760L);
REIMBURSEMENTS_BY_CYCLE_DATE.put(1593654027L, 10821807L);
REIMBURSEMENTS_BY_CYCLE_DATE.put(1596407074L, 2160157L);
REIMBURSEMENTS_BY_CYCLE_DATE.put(1599175867L, 8769408L);
REIMBURSEMENTS_BY_CYCLE_DATE.put(1601861442L, 4956585L);
REIMBURSEMENTS_BY_CYCLE_DATE.put(1604845863L, 2121664L);
if (Config.baseCurrencyNetwork().isMainnet()) {
REIMBURSEMENTS_BY_CYCLE_DATE.put(1571349571L, 60760L);
REIMBURSEMENTS_BY_CYCLE_DATE.put(1574180991L, 2621000L);
REIMBURSEMENTS_BY_CYCLE_DATE.put(1576966522L, 4769100L);
REIMBURSEMENTS_BY_CYCLE_DATE.put(1579613568L, 0L);
REIMBURSEMENTS_BY_CYCLE_DATE.put(1582399054L, 9186600L);
REIMBURSEMENTS_BY_CYCLE_DATE.put(1585342220L, 12089400L);
REIMBURSEMENTS_BY_CYCLE_DATE.put(1588025030L, 5420700L);
REIMBURSEMENTS_BY_CYCLE_DATE.put(1591004931L, 9138760L);
REIMBURSEMENTS_BY_CYCLE_DATE.put(1593654027L, 10821807L);
REIMBURSEMENTS_BY_CYCLE_DATE.put(1596407074L, 2160157L);
REIMBURSEMENTS_BY_CYCLE_DATE.put(1599175867L, 8769408L);
REIMBURSEMENTS_BY_CYCLE_DATE.put(1601861442L, 4956585L);
REIMBURSEMENTS_BY_CYCLE_DATE.put(1604845863L, 2121664L);
COMPENSATIONS_BY_CYCLE_DATE.put(1555340856L, 6931863L);
COMPENSATIONS_BY_CYCLE_DATE.put(1558083590L, 2287000L);
COMPENSATIONS_BY_CYCLE_DATE.put(1560771266L, 2273000L);
COMPENSATIONS_BY_CYCLE_DATE.put(1563347672L, 2943772L);
COMPENSATIONS_BY_CYCLE_DATE.put(1566009595L, 10040170L);
COMPENSATIONS_BY_CYCLE_DATE.put(1568643566L, 8685115L);
COMPENSATIONS_BY_CYCLE_DATE.put(1571349571L, 7315879L);
COMPENSATIONS_BY_CYCLE_DATE.put(1574180991L, 12508300L);
COMPENSATIONS_BY_CYCLE_DATE.put(1576966522L, 5884500L);
COMPENSATIONS_BY_CYCLE_DATE.put(1579613568L, 8206000L);
COMPENSATIONS_BY_CYCLE_DATE.put(1582399054L, 3518364L);
COMPENSATIONS_BY_CYCLE_DATE.put(1585342220L, 6231700L);
COMPENSATIONS_BY_CYCLE_DATE.put(1588025030L, 4391400L);
COMPENSATIONS_BY_CYCLE_DATE.put(1591004931L, 3636463L);
COMPENSATIONS_BY_CYCLE_DATE.put(1593654027L, 6156631L);
COMPENSATIONS_BY_CYCLE_DATE.put(1596407074L, 5838368L);
COMPENSATIONS_BY_CYCLE_DATE.put(1599175867L, 6086442L);
COMPENSATIONS_BY_CYCLE_DATE.put(1601861442L, 5615973L);
COMPENSATIONS_BY_CYCLE_DATE.put(1604845863L, 7782667L);
COMPENSATIONS_BY_CYCLE_DATE.put(1555340856L, 6931863L);
COMPENSATIONS_BY_CYCLE_DATE.put(1558083590L, 2287000L);
COMPENSATIONS_BY_CYCLE_DATE.put(1560771266L, 2273000L);
COMPENSATIONS_BY_CYCLE_DATE.put(1563347672L, 2943772L);
COMPENSATIONS_BY_CYCLE_DATE.put(1566009595L, 10040170L);
COMPENSATIONS_BY_CYCLE_DATE.put(1568643566L, 8685115L);
COMPENSATIONS_BY_CYCLE_DATE.put(1571349571L, 7315879L);
COMPENSATIONS_BY_CYCLE_DATE.put(1574180991L, 12508300L);
COMPENSATIONS_BY_CYCLE_DATE.put(1576966522L, 5884500L);
COMPENSATIONS_BY_CYCLE_DATE.put(1579613568L, 8206000L);
COMPENSATIONS_BY_CYCLE_DATE.put(1582399054L, 3518364L);
COMPENSATIONS_BY_CYCLE_DATE.put(1585342220L, 6231700L);
COMPENSATIONS_BY_CYCLE_DATE.put(1588025030L, 4391400L);
COMPENSATIONS_BY_CYCLE_DATE.put(1591004931L, 3636463L);
COMPENSATIONS_BY_CYCLE_DATE.put(1593654027L, 6156631L);
COMPENSATIONS_BY_CYCLE_DATE.put(1596407074L, 5838368L);
COMPENSATIONS_BY_CYCLE_DATE.put(1599175867L, 6086442L);
COMPENSATIONS_BY_CYCLE_DATE.put(1601861442L, 5615973L);
COMPENSATIONS_BY_CYCLE_DATE.put(1604845863L, 7782667L);
}
}
}
}

View File

@ -52,7 +52,7 @@ public class DaoChartView extends ChartView<DaoChartViewModel> {
private XYChart.Series<Number, Number> seriesBsqTradeFee, seriesProofOfBurn, seriesCompensation,
seriesReimbursement, seriesTotalSupply, seriesSupplyChange, seriesTotalIssued, seriesTotalBurned,
seriesTotalTradeFees, seriesProofOfBurnFromBtcFees,
seriesTotalTradeFees, seriesProofOfBurnFromBtcFees, seriesMiscBurn,
seriesProofOfBurnFromArbitration, seriesArbitrationDiff,
seriesReimbursementAfterTagging, seriesBsqTradeFeeAfterTagging;
@ -112,7 +112,7 @@ public class DaoChartView extends ChartView<DaoChartViewModel> {
}
protected Collection<XYChart.Series<Number, Number>> getSeriesForLegend5() {
return List.of(seriesSupplyChange, seriesTotalSupply);
return List.of(seriesSupplyChange, seriesTotalSupply, seriesMiscBurn);
}
@ -122,7 +122,11 @@ public class DaoChartView extends ChartView<DaoChartViewModel> {
@Override
protected void initBoundsForTimelineNavigation() {
setBoundsForTimelineNavigation(seriesTotalBurned.getData());
if (seriesSupplyChange.getData().size() > 0) {
setBoundsForTimelineNavigation(seriesSupplyChange.getData());
} else {
setBoundsForTimelineNavigation(seriesTotalBurned.getData());
}
}
@ -187,6 +191,10 @@ public class DaoChartView extends ChartView<DaoChartViewModel> {
seriesSupplyChange = new XYChart.Series<>();
seriesSupplyChange.setName(Res.get("dao.factsAndFigures.supply.supplyChange"));
seriesIndexMap.put(getSeriesId(seriesSupplyChange), 13);
seriesMiscBurn = new XYChart.Series<>();
seriesMiscBurn.setName(Res.get("dao.factsAndFigures.supply.miscBurn"));
seriesIndexMap.put(getSeriesId(seriesMiscBurn), 14);
}
@Override
@ -220,6 +228,10 @@ public class DaoChartView extends ChartView<DaoChartViewModel> {
Tooltip tooltip = new Tooltip(Res.get("dao.factsAndFigures.supply.supplyChange.tooltip"));
tooltip.setShowDelay(Duration.millis(100));
Tooltip.install(toggle, tooltip);
} else if (series.equals(seriesMiscBurn)) {
Tooltip tooltip = new Tooltip(Res.get("dao.factsAndFigures.supply.miscBurn.tooltip"));
tooltip.setShowDelay(Duration.millis(100));
Tooltip.install(toggle, tooltip);
}
}
@ -301,6 +313,11 @@ public class DaoChartView extends ChartView<DaoChartViewModel> {
allFutures.add(future);
applyBsqTradeFeeAfterTagging(future);
}
if (activeSeries.contains(seriesMiscBurn)) {
CompletableFuture<Boolean> future = new CompletableFuture<>();
allFutures.add(future);
applyMiscBurn(future);
}
CompletableFuture<Boolean> task15Done = new CompletableFuture<>();
@ -467,4 +484,13 @@ public class DaoChartView extends ChartView<DaoChartViewModel> {
completeFuture.complete(true);
}));
}
private void applyMiscBurn(CompletableFuture<Boolean> completeFuture) {
model.getMiscBurnChartData()
.whenComplete((data, t) ->
mapToUserThread(() -> {
Optional.ofNullable(data).ifPresent(seriesMiscBurn.getData()::setAll);
completeFuture.complete(true);
}));
}
}

View File

@ -110,6 +110,10 @@ public class DaoChartViewModel extends ChartViewModel<DaoChartDataModel> {
return CompletableFuture.supplyAsync(() -> toChartData(dataModel.getBsqTradeFeeByIntervalAfterTagging()));
}
CompletableFuture<List<XYChart.Data<Number, Number>>> getMiscBurnChartData() {
return CompletableFuture.supplyAsync(() -> toChartData(dataModel.getMiscBurnByInterval()));
}
///////////////////////////////////////////////////////////////////////////////////////////
// Formatters/Converters

View File

@ -153,6 +153,7 @@
-bs-chart-dao-line12: #1a6b66;
-bs-chart-dao-line13: #b6239c;
-bs-chart-dao-line14: #0052ff;
-bs-chart-dao-line15: #99ba9c;
/* Monero orange color code */
-xmr-orange: #f26822;

View File

@ -120,6 +120,7 @@
-bs-chart-dao-line12: #1a6b66;
-bs-chart-dao-line13: #b6239c;
-bs-chart-dao-line14: #0052ff;
-bs-chart-dao-line15: #99ba9c;
/* Monero orange color code */
-xmr-orange: #f26822;