Skip to content

blockchain: Test invalid ticket submission input. - #3800

Merged
davecgh merged 1 commit into
decred:masterfrom
matthawkins90:test_invalid_vote_input
Sep 17, 2026
Merged

davecgh merged 1 commit into
decred:masterfrom
matthawkins90:test_invalid_vote_input

Conversation

@matthawkins90

Copy link
Copy Markdown
Contributor

This is work towards #1182.

This adds test coverage for the checkTicketSubmissionInput site of ErrInvalidVoteInput (previously named ErrInvalidSSGenInput before #1468) and ErrInvalidRevokeInput (previously named ErrInvalidSSRtxInput before #1468).

The old comments used to say:

// ErrInvalidSSGenInput
// It doesn't look like this one can actually be hit since checking if
// IsSSGen should fail first.
// ErrInvalidSSRtxInput
// It seems impossible to hit this from a block test because it fails when
// it can't detect the relevant tickets in the missed ticket database
// bucket.

Each error kind has two sites. The first rejects a ticket input with a nonzero index. For votes, it is dead because CheckSSGenVotes rejects that index during classification, as noted in #3786. For revocations it is live and covered by brt7 (#3786) and TestAutoRevocations (#3787). The second site is the same for both: checkTicketSubmissionInput rejects a ticket input that references a stake output which is not a ticket submission output. Neither comment above is about this site, and nothing covered it.

checkTicketRedeemers only allows votes for winning tickets and revocations for missed or expired tickets, and the index checks pin the input to output 0, so a block can only reach the check with a real ticket submission output. The mempool doesn't run checkTicketRedeemers, so it depends on CheckTransactionInputs to reject a vote or a revocation that references some other stake output. This is the same situation as #3797, and the test uses the same shape: it calls CheckTransactionInputs the way the mempool does.

The test mines a block that misses a vote and a block that revokes it, then repoints a vote's and a revocation's ticket input at output 0 of that revocation.

@davecgh davecgh added this to the 2.2.0 milestone Sep 17, 2026

@davecgh davecgh left a comment •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for working through all of these cases.

It's not something to worry about for this PR (or this series you've been working on), but I would point out that since several of these are really only targeting CheckTransactionInputs they are doing a whole lot more work than is strictly necessary. They're creating a full chain with ~150 fully solved blocks (e.g. g.AdvanceToStakeValidationHeight, etc). Those in turn create an on-disk database for the blocks, utxoset, etc.

I understand why, because the chain generator has a lot of really nice infrastructure in place which greatly simplifies the testing by handling a lot of the minutia, so I'm not against it by any means.

I'm primarily mentioning it so that once you get done with the rest of the cases you're working on, if you're willing to take a stab it, something I think would be valuable is to implement something similar to a TestCheckTransactionInputs which would allow directly targeting every branch in the function. It is a free-standing function that doesn't require a full or synthetic chain or a functional ticket database. All it primarily needs, aside from the transaction being tested and agenda flags, is a SubsidyCache, a UtxoViewpoint, and a fake previous block header, all of which are independent entities that don't need a ton of interdependent setup.

Those tests could still potentially make use of Generator.CreateRevocationTx, Generator.CreateVoteTx, etc, though I'm not 100% on that point. They might need to be refactored to free-standing funcs that take more parameters which the generator methods call with the right params in order to support that.

With that in place, several of these types of tests would be significantly faster to run via that path.

Comment thread internal/blockchain/validate_test.go Outdated
This adds a test which ensures that the transaction input checks reject
a vote or a revocation whose ticket input references an unspent stake
output that is not part of a ticket purchase and accept them when the
ticket input references a ticket purchase.

The block validation path cannot trigger the rejection.  The ticket
redeemer checks run first and only allow votes for winning tickets and
revocations for missed or expired tickets, and the ticket input must
reference the first output, so it always references the first output of
a ticket purchase.  The mempool does not run the ticket redeemer checks,
so it relies on the transaction input checks directly.  The test calls
the same function with the next block height a mempool caller would
use.

The rejected cases reference the first output of a revocation since it
is an unspent stake output that is not part of a ticket purchase,
whereas the first output of a vote is an OP_RETURN output that is never
part of the utxo set.
@matthawkins90
matthawkins90 force-pushed the test_invalid_vote_input branch from 8a7337f to 6138f93 Compare September 17, 2026 14:55
@matthawkins90

Copy link
Copy Markdown
Contributor Author

Also yes, great idea. I'm definitely interested in working on that!

@davecgh
davecgh merged commit b6c6757 into decred:master Sep 17, 2026
32 checks passed
@matthawkins90
matthawkins90 deleted the test_invalid_vote_input branch September 23, 2026 03:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants