Sort getBtcFeeReceiverAddress by amount and address.

Increase minOutputAmount to 1000 sat.
Cleanups

Signed-off-by: HenrikJannsen <boilingfrog@gmx.com>
This commit is contained in:
HenrikJannsen 2022-11-04 10:56:10 -05:00
parent fa857b39ec
commit 731363d128
No known key found for this signature in database
GPG Key ID: 02AA2BAE387C8307
8 changed files with 26 additions and 31 deletions

View File

@ -29,7 +29,7 @@ import lombok.extern.slf4j.Slf4j;
@Slf4j @Slf4j
@Getter @Getter
@EqualsAndHashCode @EqualsAndHashCode
public final class BurningManCandidate implements Comparable<BurningManCandidate> { public final class BurningManCandidate {
private long accumulatedCompensationAmount; private long accumulatedCompensationAmount;
private long accumulatedDecayedCompensationAmount; private long accumulatedDecayedCompensationAmount;
private long accumulatedBurnAmount; private long accumulatedBurnAmount;
@ -39,7 +39,6 @@ public final class BurningManCandidate implements Comparable<BurningManCandidate
private double boostedIssuanceShare; private double boostedIssuanceShare;
private double burnOutputShare; // share of accumulated decayed burn amounts in relation to total burned amounts private double burnOutputShare; // share of accumulated decayed burn amounts in relation to total burned amounts
private double effectiveBurnOutputShare; // limited to boostedIssuanceShare private double effectiveBurnOutputShare; // limited to boostedIssuanceShare
private final List<CompensationModel> compensationModels = new ArrayList<>(); private final List<CompensationModel> compensationModels = new ArrayList<>();
private final List<BurnOutputModel> burnOutputModels = new ArrayList<>(); private final List<BurnOutputModel> burnOutputModels = new ArrayList<>();
@ -92,21 +91,11 @@ public final class BurningManCandidate implements Comparable<BurningManCandidate
.map(CompensationModel::getAddress); .map(CompensationModel::getAddress);
} }
//todo do sorting where its needed for better control
@Override
public int compareTo(BurningManCandidate o) {
int result = Double.compare(getBurnOutputShare(), o.getBurnOutputShare());
if (result == 0 && !compensationModels.isEmpty() && !o.compensationModels.isEmpty()) {
result = compensationModels.get(0).getTxId().compareTo(o.compensationModels.get(0).getTxId());
}
return result;
}
@Override @Override
public String toString() { public String toString() {
return "BurningManCandidate{" + return "BurningManCandidate{" +
"\r\n accumulatedIssuanceAmount=" + accumulatedCompensationAmount + "\r\n accumulatedCompensationAmount=" + accumulatedCompensationAmount +
",\r\n accumulatedDecayedIssuanceAmount=" + accumulatedDecayedCompensationAmount + ",\r\n accumulatedDecayedCompensationAmount=" + accumulatedDecayedCompensationAmount +
",\r\n accumulatedBurnAmount=" + accumulatedBurnAmount + ",\r\n accumulatedBurnAmount=" + accumulatedBurnAmount +
",\r\n accumulatedDecayedBurnAmount=" + accumulatedDecayedBurnAmount + ",\r\n accumulatedDecayedBurnAmount=" + accumulatedDecayedBurnAmount +
",\r\n allowedBurnAmount=" + allowedBurnAmount + ",\r\n allowedBurnAmount=" + allowedBurnAmount +

View File

@ -456,7 +456,7 @@ public class BurningManService implements DaoStateListener {
// Legacy BurningMan // Legacy BurningMan
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public String getBurningManAddressFromParam(int chainHeight) { public String getLegacyBurningManAddress(int chainHeight) {
return daoStateService.getParamValue(Param.RECIPIENT_BTC_ADDRESS, chainHeight); return daoStateService.getParamValue(Param.RECIPIENT_BTC_ADDRESS, chainHeight);
} }
@ -469,7 +469,7 @@ public class BurningManService implements DaoStateListener {
Map<String, BurningManCandidate> burningManCandidatesByName = getCurrentBurningManCandidatesByName(); Map<String, BurningManCandidate> burningManCandidatesByName = getCurrentBurningManCandidatesByName();
if (burningManCandidatesByName.isEmpty()) { if (burningManCandidatesByName.isEmpty()) {
// If there are no compensation requests (e.g. at dev testing) we fall back to the default address // If there are no compensation requests (e.g. at dev testing) we fall back to the default address
return getBurningManAddressFromParam(currentChainHeight); return getLegacyBurningManAddress(currentChainHeight);
} }
// It might be that we do not reach 100% if some entries had a capped effectiveBurnOutputShare. // It might be that we do not reach 100% if some entries had a capped effectiveBurnOutputShare.
@ -484,14 +484,14 @@ public class BurningManService implements DaoStateListener {
.map(effectiveBurnOutputShare -> (long) Math.floor(effectiveBurnOutputShare * 10000)) .map(effectiveBurnOutputShare -> (long) Math.floor(effectiveBurnOutputShare * 10000))
.collect(Collectors.toList()); .collect(Collectors.toList());
if (amountList.isEmpty()) { if (amountList.isEmpty()) {
return getBurningManAddressFromParam(currentChainHeight); return getLegacyBurningManAddress(currentChainHeight);
} }
int winnerIndex = getRandomIndex(amountList, new Random()); int winnerIndex = getRandomIndex(amountList, new Random());
if (winnerIndex == -1) { if (winnerIndex == -1) {
return getBurningManAddressFromParam(currentChainHeight); return getLegacyBurningManAddress(currentChainHeight);
} }
return burningManCandidates.get(winnerIndex).getMostRecentAddress() return burningManCandidates.get(winnerIndex).getMostRecentAddress()
.orElse(getBurningManAddressFromParam(currentChainHeight)); .orElse(getLegacyBurningManAddress(currentChainHeight));
} }
@ -513,7 +513,7 @@ public class BurningManService implements DaoStateListener {
Collection<BurningManCandidate> burningManCandidates = getBurningManCandidatesByName(burningManSelectionHeight).values(); Collection<BurningManCandidate> burningManCandidates = getBurningManCandidatesByName(burningManSelectionHeight).values();
if (burningManCandidates.isEmpty()) { if (burningManCandidates.isEmpty()) {
// If there are no compensation requests (e.g. at dev testing) we fall back to the legacy BM // If there are no compensation requests (e.g. at dev testing) we fall back to the legacy BM
return List.of(new Tuple2<>(inputAmount, getBurningManAddressFromParam(burningManSelectionHeight))); return List.of(new Tuple2<>(inputAmount, getLegacyBurningManAddress(burningManSelectionHeight)));
} }
// We need to use the same txFeePerVbyte value for both traders. // We need to use the same txFeePerVbyte value for both traders.
@ -530,15 +530,17 @@ public class BurningManService implements DaoStateListener {
double txSize = 278; double txSize = 278;
long txFeePerVbyte = Math.max(10, Math.round(tradeTxFee / txSize)); long txFeePerVbyte = Math.max(10, Math.round(tradeTxFee / txSize));
long spendableAmount = getSpendableAmount(burningManCandidates.size(), inputAmount, txFeePerVbyte); long spendableAmount = getSpendableAmount(burningManCandidates.size(), inputAmount, txFeePerVbyte);
// We only use outputs > 500 sat or at least 2 times the cost for the output (32 bytes). // We only use outputs > 1000 sat or at least 2 times the cost for the output (32 bytes).
// If we remove outputs it will be spent as miner fee. // If we remove outputs it will be spent as miner fee.
long minOutputAmount = Math.max(500, txFeePerVbyte * 32 * 2); long minOutputAmount = Math.max(1000, txFeePerVbyte * 32 * 2);
List<Tuple2<Long, String>> receivers = burningManCandidates.stream() List<Tuple2<Long, String>> receivers = burningManCandidates.stream()
.filter(candidate -> candidate.getMostRecentAddress().isPresent()) .filter(candidate -> candidate.getMostRecentAddress().isPresent())
.map(candidates -> new Tuple2<>(Math.round(candidates.getEffectiveBurnOutputShare() * spendableAmount), .map(candidates -> new Tuple2<>(Math.round(candidates.getEffectiveBurnOutputShare() * spendableAmount),
candidates.getMostRecentAddress().get())) candidates.getMostRecentAddress().get()))
.filter(tuple -> tuple.first >= minOutputAmount) .filter(tuple -> tuple.first >= minOutputAmount)
.sorted(Comparator.comparing(tuple -> tuple.first)) .sorted(Comparator.<Tuple2<Long, String>, Long>comparing(tuple -> tuple.first)
.thenComparing(tuple -> tuple.second))
.collect(Collectors.toList()); .collect(Collectors.toList());
long totalOutputValue = receivers.stream().mapToLong(e -> e.first).sum(); long totalOutputValue = receivers.stream().mapToLong(e -> e.first).sum();
if (totalOutputValue < spendableAmount) { if (totalOutputValue < spendableAmount) {
@ -546,7 +548,7 @@ public class BurningManService implements DaoStateListener {
// If the available is larger than 100000 sat (about 20 USD) we send it to legacy BM // If the available is larger than 100000 sat (about 20 USD) we send it to legacy BM
// Otherwise we use it as miner fee // Otherwise we use it as miner fee
if (available > 100000) { if (available > 100000) {
receivers.add(new Tuple2<>(available, getBurningManAddressFromParam(burningManSelectionHeight))); receivers.add(new Tuple2<>(available, getLegacyBurningManAddress(burningManSelectionHeight)));
} }
} }
return receivers; return receivers;

View File

@ -529,7 +529,7 @@ public final class Dispute implements NetworkPayload, PersistablePayload {
// Dispute agents might receive disputes created before activation date. // Dispute agents might receive disputes created before activation date.
// By checking if burningManSelectionHeight is > 0 we can detect if the trade was created with // By checking if burningManSelectionHeight is > 0 we can detect if the trade was created with
// the new burningmen receivers or not. // the new burningmen receivers or with legacy BM.
public boolean isUsingLegacyBurningMan() { public boolean isUsingLegacyBurningMan() {
return burningManSelectionHeight == 0; return burningManSelectionHeight == 0;
} }

View File

@ -115,6 +115,7 @@ public class DisputeValidation {
} }
} }
public static void validateSenderNodeAddress(Dispute dispute, public static void validateSenderNodeAddress(Dispute dispute,
NodeAddress senderNodeAddress) throws NodeAddressException { NodeAddress senderNodeAddress) throws NodeAddressException {
if (!senderNodeAddress.equals(dispute.getContract().getBuyerNodeAddress()) if (!senderNodeAddress.equals(dispute.getContract().getBuyerNodeAddress())
@ -309,6 +310,7 @@ public class DisputeValidation {
} }
} }
public static class AddressException extends ValidationException { public static class AddressException extends ValidationException {
AddressException(Dispute dispute, String msg) { AddressException(Dispute dispute, String msg) {
super(dispute, msg); super(dispute, msg);

View File

@ -71,6 +71,7 @@ public class TradeDataValidation {
throw new InvalidTxException(errorMsg); throw new InvalidTxException(errorMsg);
} }
// connectedOutput is null and input.getValue() is null at that point as the tx is not committed to the wallet // connectedOutput is null and input.getValue() is null at that point as the tx is not committed to the wallet
// yet. So we cannot check that the input matches but we did the amount check earlier in the trade protocol. // yet. So we cannot check that the input matches but we did the amount check earlier in the trade protocol.
@ -113,8 +114,8 @@ public class TradeDataValidation {
} }
NetworkParameters params = btcWalletService.getParams(); NetworkParameters params = btcWalletService.getParams();
String delayedPayoutTxOutputAddress = output.getScriptPubKey().getToAddress(params).toString();
if (addressConsumer != null) { if (addressConsumer != null) {
String delayedPayoutTxOutputAddress = output.getScriptPubKey().getToAddress(params).toString();
addressConsumer.accept(delayedPayoutTxOutputAddress); addressConsumer.accept(delayedPayoutTxOutputAddress);
} }
} }

View File

@ -1067,12 +1067,13 @@ public abstract class Trade extends TradeModel {
return offer != null && offer.isBsqSwapOffer(); return offer != null && offer.isBsqSwapOffer();
} }
// By checking if burningManSelectionHeight is > 0 we can detect if the trade was created with // By checking if burningManSelectionHeight is 0 we can detect if the trade was created with
// the new burningmen receivers or not. // the new burningmen receivers or with legacy BM.
public boolean isUsingLegacyBurningMan() { public boolean isUsingLegacyBurningMan() {
return processModel.getBurningManSelectionHeight() == 0; return processModel.getBurningManSelectionHeight() == 0;
} }
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Private // Private
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////

View File

@ -125,6 +125,7 @@ public class BurningmenView extends ActivatableView<ScrollPane, Void> implements
private int gridRow = 0; private int gridRow = 0;
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Constructor, lifecycle // Constructor, lifecycle
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -473,7 +474,7 @@ public class BurningmenView extends ActivatableView<ScrollPane, Void> implements
TableColumn<BurningmenListItem, BurningmenListItem> column; TableColumn<BurningmenListItem, BurningmenListItem> column;
column = new AutoTooltipTableColumn<>(Res.get("dao.burningmen.table.name")); column = new AutoTooltipTableColumn<>(Res.get("dao.burningmen.table.name"));
column.setMinWidth(80); column.setMinWidth(120);
column.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue())); column.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
column.getStyleClass().add("first-column"); column.getStyleClass().add("first-column");
column.setCellFactory(new Callback<>() { column.setCellFactory(new Callback<>() {

View File

@ -151,9 +151,8 @@ public abstract class DisputeAgentView extends DisputeView implements MultipleHo
} }
private String getValidationExceptionMessage(DisputeValidation.ValidationException exception) { private String getValidationExceptionMessage(DisputeValidation.ValidationException exception) {
Dispute dispute = exception.getDispute();
if (exception instanceof DisputeValidation.AddressException) { if (exception instanceof DisputeValidation.AddressException) {
return getAddressExceptionMessage(dispute); return getAddressExceptionMessage(exception.getDispute());
} else if (exception.getMessage() != null && !exception.getMessage().isEmpty()) { } else if (exception.getMessage() != null && !exception.getMessage().isEmpty()) {
return exception.getMessage(); return exception.getMessage();
} else { } else {