mirror of
https://github.com/bisq-network/bisq.git
synced 2024-11-19 18:03:12 +01:00
Merge pull request #2614 from ManfredKarrer/add-missing-check-for-mandatory-bsq-output
Add missing check for mandatory bsq output
This commit is contained in:
commit
6e2aaecfe7
@ -524,19 +524,23 @@ public class BsqWalletService extends WalletService implements DaoStateListener
|
||||
|
||||
// We create a tx with Bsq inputs for the fee and optional BSQ change output.
|
||||
// As the fee amount will be missing in the output those BSQ fees are burned.
|
||||
public Transaction getPreparedProposalTx(Coin fee) throws InsufficientBsqException {
|
||||
return getPreparedBurnFeeTx(fee);
|
||||
public Transaction getPreparedProposalTx(Coin fee, boolean requireChangeOutput) throws InsufficientBsqException {
|
||||
return getPreparedBurnFeeTx(fee, requireChangeOutput);
|
||||
}
|
||||
|
||||
public Transaction getPreparedBurnFeeTx(Coin fee) throws InsufficientBsqException {
|
||||
return getPreparedBurnFeeTx(fee, false);
|
||||
}
|
||||
|
||||
private Transaction getPreparedBurnFeeTx(Coin fee, boolean requireChangeOutput) throws InsufficientBsqException {
|
||||
DaoKillSwitch.assertDaoIsNotDisabled();
|
||||
final Transaction tx = new Transaction(params);
|
||||
addInputsAndChangeOutputForTx(tx, fee, bsqCoinSelector);
|
||||
addInputsAndChangeOutputForTx(tx, fee, bsqCoinSelector, requireChangeOutput);
|
||||
// printTx("getPreparedFeeTx", tx);
|
||||
return tx;
|
||||
}
|
||||
|
||||
private void addInputsAndChangeOutputForTx(Transaction tx, Coin fee, BsqCoinSelector bsqCoinSelector)
|
||||
private void addInputsAndChangeOutputForTx(Transaction tx, Coin fee, BsqCoinSelector bsqCoinSelector, boolean requireChangeOutput)
|
||||
throws InsufficientBsqException {
|
||||
Coin requiredInput;
|
||||
// If our fee is less then dust limit we increase it so we are sure to not get any dust output.
|
||||
@ -550,10 +554,19 @@ public class BsqWalletService extends WalletService implements DaoStateListener
|
||||
try {
|
||||
// TODO why is fee passed to getChange ???
|
||||
Coin change = bsqCoinSelector.getChange(fee, coinSelection);
|
||||
if (requireChangeOutput) {
|
||||
checkArgument(change.isPositive(),
|
||||
"This transaction requires a mandatory BSQ change output. " +
|
||||
"You are missing " + Restrictions.getMinNonDustOutput().value / 100d +
|
||||
" BSQ for a non dust change output.");
|
||||
}
|
||||
|
||||
if (change.isPositive()) {
|
||||
checkArgument(Restrictions.isAboveDust(change),
|
||||
"The change output of " + change.value / 100d + " BSQ is below the min. dust value of "
|
||||
+ Restrictions.getMinNonDustOutput().value / 100d + " BSQ.");
|
||||
+ Restrictions.getMinNonDustOutput().value / 100d +
|
||||
" BSQ. You are missing " + (Restrictions.getMinNonDustOutput().value - change.value) / 100d +
|
||||
" BSQ for a non dust change output.");
|
||||
tx.addOutput(change, getChangeAddress());
|
||||
}
|
||||
} catch (InsufficientMoneyException e) {
|
||||
@ -572,7 +585,7 @@ public class BsqWalletService extends WalletService implements DaoStateListener
|
||||
DaoKillSwitch.assertDaoIsNotDisabled();
|
||||
Transaction tx = new Transaction(params);
|
||||
tx.addOutput(new TransactionOutput(params, tx, stake, getUnusedAddress()));
|
||||
addInputsAndChangeOutputForTx(tx, fee.add(stake), bsqCoinSelector);
|
||||
addInputsAndChangeOutputForTx(tx, fee.add(stake), bsqCoinSelector, false);
|
||||
//printTx("getPreparedBlindVoteTx", tx);
|
||||
return tx;
|
||||
}
|
||||
@ -606,7 +619,7 @@ public class BsqWalletService extends WalletService implements DaoStateListener
|
||||
Transaction tx = new Transaction(params);
|
||||
checkArgument(Restrictions.isAboveDust(lockupAmount), "The amount is too low (dust limit).");
|
||||
tx.addOutput(new TransactionOutput(params, tx, lockupAmount, getUnusedAddress()));
|
||||
addInputsAndChangeOutputForTx(tx, lockupAmount, bsqCoinSelector);
|
||||
addInputsAndChangeOutputForTx(tx, lockupAmount, bsqCoinSelector, false);
|
||||
printTx("prepareLockupTx", tx);
|
||||
return tx;
|
||||
}
|
||||
|
@ -85,16 +85,17 @@ public abstract class BaseProposalFactory<R extends Proposal> {
|
||||
// The hashOfPayload used in the opReturnData is created with the txId set to null.
|
||||
private Transaction createTransaction(R proposal) throws InsufficientMoneyException, TxException {
|
||||
try {
|
||||
final Coin fee = ProposalConsensus.getFee(daoStateService, daoStateService.getChainHeight());
|
||||
Coin fee = ProposalConsensus.getFee(daoStateService, daoStateService.getChainHeight());
|
||||
// We create a prepared Bsq Tx for the proposal fee.
|
||||
final Transaction preparedBurnFeeTx = bsqWalletService.getPreparedProposalTx(fee);
|
||||
boolean requireChangeOutput = proposal instanceof IssuanceProposal;
|
||||
Transaction preparedBurnFeeTx = bsqWalletService.getPreparedProposalTx(fee, requireChangeOutput);
|
||||
|
||||
// payload does not have txId at that moment
|
||||
byte[] hashOfPayload = ProposalConsensus.getHashOfPayload(proposal);
|
||||
byte[] opReturnData = getOpReturnData(hashOfPayload);
|
||||
|
||||
// We add the BTC inputs for the miner fee.
|
||||
final Transaction txWithBtcFee = completeTx(preparedBurnFeeTx, opReturnData, proposal);
|
||||
Transaction txWithBtcFee = completeTx(preparedBurnFeeTx, opReturnData, proposal);
|
||||
|
||||
// We sign the BSQ inputs of the final tx.
|
||||
Transaction transaction = bsqWalletService.signTx(txWithBtcFee);
|
||||
|
@ -194,15 +194,15 @@ public class TxOutputParser {
|
||||
if (optionalOpReturnType.isPresent())
|
||||
opReturnTypeCandidate = optionalOpReturnType.get();
|
||||
|
||||
TxOutputType bsqOutput;
|
||||
TxOutputType txOutputType;
|
||||
if (isFirstOutput && opReturnTypeCandidate == OpReturnType.BLIND_VOTE) {
|
||||
bsqOutput = TxOutputType.BLIND_VOTE_LOCK_STAKE_OUTPUT;
|
||||
txOutputType = TxOutputType.BLIND_VOTE_LOCK_STAKE_OUTPUT;
|
||||
optionalBlindVoteLockStakeOutput = Optional.of(txOutput);
|
||||
} else if (isFirstOutput && opReturnTypeCandidate == OpReturnType.VOTE_REVEAL) {
|
||||
bsqOutput = TxOutputType.VOTE_REVEAL_UNLOCK_STAKE_OUTPUT;
|
||||
txOutputType = TxOutputType.VOTE_REVEAL_UNLOCK_STAKE_OUTPUT;
|
||||
optionalVoteRevealUnlockStakeOutput = Optional.of(txOutput);
|
||||
} else if (isFirstOutput && opReturnTypeCandidate == OpReturnType.LOCKUP) {
|
||||
bsqOutput = TxOutputType.LOCKUP_OUTPUT;
|
||||
txOutputType = TxOutputType.LOCKUP_OUTPUT;
|
||||
|
||||
// We store the lockTime in the output which will be used as input for a unlock tx.
|
||||
// That makes parsing of that data easier as if we would need to access it from the opReturn output of
|
||||
@ -210,9 +210,9 @@ public class TxOutputParser {
|
||||
txOutput.setLockTime(lockTime);
|
||||
optionalLockupOutput = Optional.of(txOutput);
|
||||
} else {
|
||||
bsqOutput = TxOutputType.BSQ_OUTPUT;
|
||||
txOutputType = TxOutputType.BSQ_OUTPUT;
|
||||
}
|
||||
txOutput.setTxOutputType(bsqOutput);
|
||||
txOutput.setTxOutputType(txOutputType);
|
||||
utxoCandidates.add(txOutput);
|
||||
|
||||
bsqOutputFound = true;
|
||||
|
@ -330,8 +330,10 @@ public class TxParser {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!bsqOutputFound) {
|
||||
log.warn("Invalid Tx: No BSQ output found. tx=" + tempTx);
|
||||
if ((tempTx.getTxType() == TxType.COMPENSATION_REQUEST ||
|
||||
tempTx.getTxType() == TxType.REIMBURSEMENT_REQUEST)
|
||||
&& !bsqOutputFound) {
|
||||
log.warn("Invalid Tx: A compensation or reimbursement tx requires 1 BSQ output. Tx=" + tempTx);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user