Conversation
Transplant 3 xahaud review-fix commits (dbd5903e8, 23fd210e2, 8d9a38e44) on top of the initial rippled backport (0b5220b). - Add shared helper functions (isLeafSigner, isNestedSigner, isValidSignerEntry, countPresentFields) and depth constants (nestedMultiSignMaxDepth, legacyMultiSignMaxDepth) to STTx.h - Rewrite Transactor::checkMultiSign with recursive validation, cycle detection via ancestors set, and cyclic lockout relaxation - Update calculateBaseFee with depth guard and helper usage - Refactor STTx.cpp multiSignHelper to use helpers and add malformed signer entry detection - Replace TransactionSign.cpp signer validation with recursive validateSignersRecursive using helpers - Add test_countPresentFields unit test and nested fee calculation test cases (Test Cases 16-17) - Update STTx_test.cpp for optional sfSigningPubKey with validation-layer helper checks - Fix feature-disabled test expectation (telENV_RPC_FAILED)
- fix nested signer array bounds check using wrong variable (signers vs signersArray) in STTx.cpp multiSignHelper - move auth check before cyclic skip in Transactor.cpp so unauthorized cyclic signer entries are rejected instead of silently ignored - add tests for nested array cardinality (empty/oversized) - add tests for unauthorized vs authorized cyclic signer entries
Add testNestedMultiSignEdgeCases with 10 tests targeting uncovered code paths across the three validation layers: multiSignHelper (depth overflow, corrupt pubkey, malformed entries, unsorted signers), Transactor::checkMultiSign (fee calculation, non-phantom signers, cyclic quorum), and transactionSubmitMultiSigned (RPC shape and depth validation). Includes a direct checkSign test for the depth-exceeded path using manually-constructed STObjects.
Add nestedMultiSignMaxLeafSigners (64) to bound worst-case signature verification cost. The leaf counter in multiSignHelper increments before each verify() call and rejects with "Too many leaf signers." when exceeded. Only enforced when featureNestedMultiSign is enabled. Tests: leaf cap exceeded (65 leaves → temMALFORMED) and at-cap succeeds (64 leaves via 2×32 nested tree → tesSUCCESS).
checkSign rejects >64 leaves before the transaction enters the engine, so env() cannot extract a TER code and returns telENV_RPC_FAILED rather than temMALFORMED.
Plain assert is compiled out in release builds, dropping these consensus-critical invariant checks in production.
feat: nested multi-sign tests and review fixes
|
Hi @RichardAH, thanks for the contribution! Before we can move forward with this PR, we need to track this as an XLS Specification in the XRPL-Standards repository. Could you please open a discussion and a PR there. You can check out the guidelines here for the full process. Thanks! |
| auto const txnAccountID = &sigObject != this ? std::nullopt : std::optional<AccountID>(getAccountID(sfAccount)); | ||
|
|
||
| // Set max depth based on feature flag | ||
| int const maxDepth = rules.enabled(featureNestedMultiSign) ? 4 : 1; |
There was a problem hiding this comment.
This variable was introduced by the duplicate commit (e45514f3) and is unused — depth limiting is already handled inside multiSignHelper using the nestedMultiSignMaxDepth / legacyMultiSignMaxDepth constants. Safe to drop these 3 lines.
I can write you an XLS if you want, but I would point out, as the creator of the XLS standards system, simple amendments that provide small enhancements in existing functionality were never supposed to become XLS entries. XLS is intended for public-facing standards that many parties need to agree on in advance to have their software work correctly together... similar to RFC. Reply again if you really need one and I'll write one. |
Hi @RichardAH, We genuinely appreciate your role in establishing the XLS framework; it has been foundational for the ecosystem. However, as the ecosystem has grown, our governance processes have evolved. To ensure consistency and comprehensive documentation for all changes, we mandate an XLS Specification for all new feature amendments, regardless of their scope. Please proceed with drafting the XLS. For reference, you can find the mandated XLS templates here Respectfully, |
|
NestedMultiSign Amendment
Note: this is a back port of Xahau/xahaud#675 to Xrpld. It may need further attention to ensure compatibility with Xrpld-only features.
Specification: XRPLF/XRPL-Standards#472
Overview
This amendment introduces nested multi-signature validation, allowing signer lists to delegate signing authority to other accounts that themselves have signer lists. This enables hierarchical organizational structures where, for example, a company account can require signatures from department accounts, which in turn require signatures from authorized individuals.
Key Features
Hierarchical Signing (up to 4 levels deep)
Company → Departments → Teams → IndividualsCycle Detection & Quorum Relaxation
effectiveQuorum == 0(all signers cyclic) correctly fail withtefBAD_QUORUMTransaction Structure
Nested signers are represented by including an
sfSignersarray instead ofsfSigningPubKey/sfTxnSignature:{ "Signers": [{ "Signer": { "Account": "DepartmentA", "Signers": [{ "Signer": { "Account": "Employee1", "SigningPubKey": "...", "TxnSignature": "..." } }] } }] }Validation Rules
SigningPubKeyandTxnSignatureError Codes
tefBAD_SIGNATUREtefBAD_QUORUMtefNOT_MULTI_SIGNINGtefMASTER_DISABLEDtefINTERNALBackward Compatibility
When
featureNestedMultiSignis disabled, nested signer arrays are rejected withtemMALFORMED, preserving existing behavior.Type of Change
.gitignore, formatting, dropping support for older tooling)API Impact
libxrplchange (any change that may affectlibxrplor dependents oflibxrpl)