add privacy-focused anti-fee-sniping recommendations for taproot transactions

This commit is contained in:
Craig Raw 2021-09-22 16:31:06 +02:00
parent 38783d68a4
commit c9e57fad01

View file

@ -701,6 +701,10 @@ public class Wallet extends Persistable {
txInput.setSequenceNumber(TransactionInput.SEQUENCE_RBF_ENABLED); txInput.setSequenceNumber(TransactionInput.SEQUENCE_RBF_ENABLED);
} }
if(getScriptType() == P2TR && currentBlockHeight != null) {
applySequenceAntiFeeSniping(transaction, selectedUtxos, currentBlockHeight);
}
for(int i = 1; i < numSets; i+=2) { for(int i = 1; i < numSets; i+=2) {
WalletNode mixNode = getFreshNode(KeyPurpose.CHANGE); WalletNode mixNode = getFreshNode(KeyPurpose.CHANGE);
txExcludedChangeNodes.add(mixNode); txExcludedChangeNodes.add(mixNode);
@ -794,6 +798,27 @@ public class Wallet extends Persistable {
} }
} }
private void applySequenceAntiFeeSniping(Transaction transaction, Map<BlockTransactionHashIndex, WalletNode> selectedUtxos, int currentBlockHeight) {
Random random = new Random();
boolean locktime = random.nextInt(2) == 0 || getScriptType() != P2TR || selectedUtxos.keySet().stream().anyMatch(utxo -> utxo.getConfirmations(currentBlockHeight) > 65535);
if(locktime) {
transaction.setLocktime(currentBlockHeight);
if(random.nextInt(10) == 0) {
transaction.setLocktime(Math.max(0, currentBlockHeight - random.nextInt(100)));
}
} else {
transaction.setLocktime(0);
int inputIndex = random.nextInt(transaction.getInputs().size());
TransactionInput txInput = transaction.getInputs().get(inputIndex);
BlockTransactionHashIndex utxo = selectedUtxos.keySet().stream().filter(ref -> ref.getHash().equals(txInput.getOutpoint().getHash()) && ref.getIndex() == txInput.getOutpoint().getIndex()).findFirst().orElseThrow();
txInput.setSequenceNumber(utxo.getConfirmations(currentBlockHeight));
if(random.nextInt(10) == 0) {
txInput.setSequenceNumber(Math.max(0, txInput.getSequenceNumber() - random.nextInt(100)));
}
}
}
private List<Long> getSetChangeAmounts(List<Map<BlockTransactionHashIndex, WalletNode>> selectedUtxoSets, long totalPaymentAmount, long feeRequiredAmt) { private List<Long> getSetChangeAmounts(List<Map<BlockTransactionHashIndex, WalletNode>> selectedUtxoSets, long totalPaymentAmount, long feeRequiredAmt) {
List<Long> changeAmts = new ArrayList<>(); List<Long> changeAmts = new ArrayList<>();
int numSets = selectedUtxoSets.size(); int numSets = selectedUtxoSets.size();