Add TransactionProposal invariants for Cosign - #8130
Open
ckeshava wants to merge 3 commits into
Open
Conversation
|
This PR has conflicts, please resolve them in order for the PR to be reviewed. |
Introduce ValidTransactionProposal, a global invariant that enforces the four properties a TransactionProposal ledger entry must hold: - The proposed transaction is immutable except for its signature fields and PreviousTxn bookkeeping. SponsorshipTransfer may reassign the outer Sponsor field and nothing else. - Owner reserve moves by the proposal's own reserve size when a proposal is created or deleted, including the sponsored and sponsoring counts when its reserve is sponsored. - Only transaction types that implement a proposal lifecycle operation may create, modify, or delete a proposal, with the exact counts the transaction result allows. - Collected signer arrays stay sorted, unique, and within their bounds. Reserve reconciliation is applied only once a transaction has touched a proposal, because owner counts also move for offers, escrows, and for the ticket a transaction consumes to pay for itself. Add thirteen invariant test cases: eleven that each violate one rule, and two negative controls that reuse the failure cases' setup so every failure is pinned to the defect it names.
The monolithic Invariants_test.cpp was split into per-topic files under src/test/app/invariants/. Place the TransactionProposal cases in their own file alongside the other feature suites.
ckeshava
force-pushed
the
cosign-invariants-v1
branch
from
August 27, 2026 01:39
af03979 to
d39803c
Compare
|
All conflicts have been resolved. Assigned reviewers can now start or resume their review. |
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
The checked-in wrapper is stale, so check-autogen fails. This is pre-existing on the base branch rather than caused by the invariant work: XRPLF#8001 collapsed the transactions.macro settings into a TxSettings struct, which renders an unset .privileges from a default that is now enum-qualified. TransactionProposalCreate sets no .privileges, and the merge that brought the refactor into this branch converted the macro without re-running the generator. Comment-only, and the output of: cmake --build build/codegen --target code_gen
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
High Level Overview of Change
Adds
ValidTransactionProposal, a global invariant for theTransactionProposalledger entry, plus tests. No behavior change for valid transactions.The invariant enforces four properties:
ProposedTransactionmay change only in its signature fields (SigningPubKey,TxnSignature,Signers,CounterpartySignature,SponsorSignature,BatchSigners, and nestedSigners), plusPreviousTxnbookkeeping.SponsorshipTransfermay reassign the object'sSponsorand nothing else.OwnerCountby that proposal's own reserve size (5, or 10 for a proposedBatch), and movesSponsoredOwnerCount/SponsoringOwnerCountconsistently when the reserve is sponsored.TransactionProposalCreatemust leave no trace; a successful one must create exactly one entry.STTx::kMaxMultiSigners(32) andkMaxBatchSigners(24).Context of Change
This is the invariant layer for the On-Chain Cosigner work (XLS-0103). Properties 1 and 4 restate spec sections 4.2.1 and 6.1; property 2 restates section 4.4.
It is implemented as a global invariant rather than in
TransactionProposalCreate::visitInvariantEntry, because the properties are about the ledger entry itself and must hold no matter which transactor touches it. That is what makes property 3 meaningful: asTransactionProposalSignandTransactionProposalCancelland, each has to be added to the whitelist deliberately, and until then no other transaction type can manufacture or mutate a proposal.Reserve reconciliation is applied only once a transaction has actually touched a proposal. Owner counts also move for offers, escrows, and for the ticket a transaction consumes to pay for itself, so the modelled deltas describe the ledger accurately only when a proposal is in play.
API Impact
libxrplchange (any change that may affectlibxrplor dependents oflibxrpl)The invariant is gated on
featureCosign, so it cannot change behavior on a ledger where the amendment is not enabled.Test Plan
Thirteen cases in
Invariants_test.cpp. Eleven violate exactly one rule: a mutatedTicketSequence; an insertion with noOwnerCountbump; an insertion fromAccountSet; and eight signer-array cases covering duplicates, descending order, both length limits, an entry with noAccount, and duplicates nested underCounterpartySignature,SponsorSignature, and aBatchSigner.Two are negative controls asserting
tesSUCCESS: a well-formed create, and a proposal left untouched. The first reuses the setup of the two failure cases above it and differs only in theOwnerCountbump and the transaction type, which pins each of those failures to the defect it names rather than to the hand-built ledger state.The success path is also covered indirectly, since invariants run on every transaction in every test: the existing
TransactionProposalCreatesuite (17 cases, 1067 tests) exercises this invariant returning true, including sponsored create and sponsorship transfer.