From 5dd4ca5922e282539a3a06fc6033b564556e71f4 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Wed, 26 Aug 2026 06:50:42 -0500 Subject: [PATCH] stake: Correct off by one in revoke create helper. The helper method in the stake package for creating revocations does not currently allow zero-valued revocations even though they are valid by consensus. The error message even indicates the minimum allowed is 0. This corrects the check so it is accurate and allows zero as intended. It also adds a test to ensure proper functionality. --- blockchain/stake/staketx.go | 2 +- blockchain/stake/staketx_test.go | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/blockchain/stake/staketx.go b/blockchain/stake/staketx.go index 0f73d32f1b..01811c4a55 100644 --- a/blockchain/stake/staketx.go +++ b/blockchain/stake/staketx.go @@ -1408,7 +1408,7 @@ func CreateRevocationFromTicket(ticketHash *chainhash.Hash, feeApplied := false for i, payToHash := range payToHashes { // Ensure amount is in the valid range for monetary amounts. - if amounts[i] <= 0 || amounts[i] > dcrutil.MaxAmount { + if amounts[i] < 0 || amounts[i] > dcrutil.MaxAmount { str := fmt.Sprintf("invalid output amount: %v (min: 0, max: %v)", amounts[i], dcrutil.MaxAmount) return nil, stakeRuleError(ErrSStxBadCommitAmount, str) diff --git a/blockchain/stake/staketx_test.go b/blockchain/stake/staketx_test.go index 844f1418a2..44297bddb2 100644 --- a/blockchain/stake/staketx_test.go +++ b/blockchain/stake/staketx_test.go @@ -1522,6 +1522,23 @@ func TestCreateRevocationFromTicket(t *testing.T) { autoRevocationsTxFee := dcrutil.Amount(0) autoRevocationsTxVersion := TxVersionAutoRevocations + // Ticket commitment with a zero commitment amount. + ticketOutZeroCommitment := &MinimalOutput{ + PkScript: hexToBytes("6a1e86c6da62556f5e21fbce3564b7374724d65f0cbb000" + + "00000000000000058"), + Value: 0, + Version: 0, + } + ticketMinOutsZeroCommitment := []*MinimalOutput{ + ticketOut1, + ticketOutZeroCommitment, + ticketOut3, + ticketOut4, + ticketOut5, + } + zeroCommitmentRevocationTxHash := mustParseHash("9a2e88b9f6703e6fa941cb390" + + "34fb88a7a57714ca264309e5b79ecc6f8beec5a") + // Invalid script version. ticketOutInvalidScriptVersion := &MinimalOutput{ PkScript: hexToBytes("6a1e86c6da62556f5e21fbce3564b7374724d65f0cbb51c66d0" + @@ -1585,6 +1602,14 @@ func TestCreateRevocationFromTicket(t *testing.T) { revocationTxVersion: revocationTxVersion, prevHeaderBytes: prevHeaderBytes, wantTxHash: *revocationHash, + }, { + name: "valid with zero commitment amount", + ticketHash: ticketHash, + ticketMinOuts: ticketMinOutsZeroCommitment, + revocationTxFee: revocationTxFee, + revocationTxVersion: revocationTxVersion, + prevHeaderBytes: prevHeaderBytes, + wantTxHash: *zeroCommitmentRevocationTxHash, }, { name: "valid with P2SH and P2PKH outputs (auto revocations " + "enabled",