spend change from notification transactions only if necessary

This commit is contained in:
Craig Raw 2022-07-21 12:29:21 +02:00
parent 40dab59337
commit b2f5f5ffeb
3 changed files with 35 additions and 8 deletions

View file

@ -174,6 +174,10 @@ public class PaymentCode {
if(scriptChunks.get(1).getData() != null && scriptChunks.get(1).getData().length != 80) { if(scriptChunks.get(1).getData() != null && scriptChunks.get(1).getData().length != 80) {
return null; return null;
} }
byte[] data = scriptChunks.get(1).getData();
if(data[0] != 0x01 || (data[2] != 0x02 && data[2] != 0x03)) {
return null;
}
return scriptChunks; return scriptChunks;
} }

View file

@ -20,6 +20,7 @@ public class OutputGroup {
private long longTermFee = 0; private long longTermFee = 0;
private int depth = Integer.MAX_VALUE; private int depth = Integer.MAX_VALUE;
private boolean allInputsFromWallet = true; private boolean allInputsFromWallet = true;
private boolean spendLast;
public OutputGroup(ScriptType scriptType, int walletBlockHeight, long inputWeightUnits, double feeRate, double longTermFeeRate) { public OutputGroup(ScriptType scriptType, int walletBlockHeight, long inputWeightUnits, double feeRate, double longTermFeeRate) {
this.scriptType = scriptType; this.scriptType = scriptType;
@ -29,7 +30,7 @@ public class OutputGroup {
this.longTermFeeRate = longTermFeeRate; this.longTermFeeRate = longTermFeeRate;
} }
public void add(BlockTransactionHashIndex utxo, boolean allInputsFromWallet) { public void add(BlockTransactionHashIndex utxo, boolean allInputsFromWallet, boolean spendLast) {
utxos.add(utxo); utxos.add(utxo);
value += utxo.getValue(); value += utxo.getValue();
effectiveValue += utxo.getValue() - (long)(inputWeightUnits * feeRate / WITNESS_SCALE_FACTOR); effectiveValue += utxo.getValue() - (long)(inputWeightUnits * feeRate / WITNESS_SCALE_FACTOR);
@ -37,6 +38,7 @@ public class OutputGroup {
longTermFee += (long)(inputWeightUnits * longTermFeeRate / WITNESS_SCALE_FACTOR); longTermFee += (long)(inputWeightUnits * longTermFeeRate / WITNESS_SCALE_FACTOR);
depth = utxo.getHeight() <= 0 ? 0 : Math.min(depth, walletBlockHeight - utxo.getHeight() + 1); depth = utxo.getHeight() <= 0 ? 0 : Math.min(depth, walletBlockHeight - utxo.getHeight() + 1);
this.allInputsFromWallet &= allInputsFromWallet; this.allInputsFromWallet &= allInputsFromWallet;
this.spendLast |= spendLast;
} }
public void remove(BlockTransactionHashIndex utxo) { public void remove(BlockTransactionHashIndex utxo) {
@ -80,21 +82,27 @@ public class OutputGroup {
return allInputsFromWallet; return allInputsFromWallet;
} }
public boolean isSpendLast() {
return spendLast;
}
public static class Filter { public static class Filter {
private final int minWalletConfirmations; private final int minWalletConfirmations;
private final int minExternalConfirmations; private final int minExternalConfirmations;
private final boolean includeSpendLast;
public Filter(int minWalletConfirmations, int minExternalConfirmations) { public Filter(int minWalletConfirmations, int minExternalConfirmations, boolean includeSpendLast) {
this.minWalletConfirmations = minWalletConfirmations; this.minWalletConfirmations = minWalletConfirmations;
this.minExternalConfirmations = minExternalConfirmations; this.minExternalConfirmations = minExternalConfirmations;
this.includeSpendLast = includeSpendLast;
} }
public boolean isEligible(OutputGroup outputGroup) { public boolean isEligible(OutputGroup outputGroup) {
if(outputGroup.isAllInputsFromWallet()) { if(outputGroup.isAllInputsFromWallet()) {
return outputGroup.getDepth() >= minWalletConfirmations; return outputGroup.getDepth() >= minWalletConfirmations && (includeSpendLast || !outputGroup.isSpendLast());
} }
return outputGroup.getDepth() >= minExternalConfirmations; return outputGroup.getDepth() >= minExternalConfirmations && (includeSpendLast || !outputGroup.isSpendLast());
} }
} }
} }

View file

@ -1163,10 +1163,13 @@ public class Wallet extends Persistable implements Comparable<Wallet> {
List<OutputGroup> utxoPool = getGroupedUtxos(utxoFilters, feeRate, longTermFeeRate, groupByAddress, includeSpentMempoolOutputs); List<OutputGroup> utxoPool = getGroupedUtxos(utxoFilters, feeRate, longTermFeeRate, groupByAddress, includeSpentMempoolOutputs);
List<OutputGroup.Filter> filters = new ArrayList<>(); List<OutputGroup.Filter> filters = new ArrayList<>();
filters.add(new OutputGroup.Filter(1, 6)); filters.add(new OutputGroup.Filter(1, 6, false));
filters.add(new OutputGroup.Filter(1, 1)); filters.add(new OutputGroup.Filter(1, 1, false));
if(includeMempoolOutputs) { if(includeMempoolOutputs) {
filters.add(new OutputGroup.Filter(0, 0)); filters.add(new OutputGroup.Filter(0, 0, false));
filters.add(new OutputGroup.Filter(0, 0, true));
} else {
filters.add(new OutputGroup.Filter(1, 1, true));
} }
if(sendMax) { if(sendMax) {
@ -1237,7 +1240,7 @@ public class Wallet extends Persistable implements Comparable<Wallet> {
outputGroups.add(outputGroup); outputGroups.add(outputGroup);
} }
outputGroup.add(utxo, allInputsFromWallet(walletTransactions, walletTxos, utxo.getHash())); outputGroup.add(utxo, allInputsFromWallet(walletTransactions, walletTxos, utxo.getHash()), isNotificationChange(walletTransactions, utxo.getHash()));
} }
} }
} }
@ -1280,6 +1283,18 @@ public class Wallet extends Persistable implements Comparable<Wallet> {
return true; return true;
} }
private boolean isNotificationChange(Map<Sha256Hash, BlockTransaction> walletTransactions, Sha256Hash txId) {
BlockTransaction utxoBlkTx = walletTransactions.get(txId);
try {
PaymentCode.getOpReturnData(utxoBlkTx.getTransaction());
return true;
} catch(IllegalArgumentException e) {
//ignore, not a notification tx
}
return false;
}
/** /**
* Determines the maximum total amount this wallet can send for the number and type of addresses at the given fee rate * Determines the maximum total amount this wallet can send for the number and type of addresses at the given fee rate
* *