Skip to content

Add Dynamic MPT (XLS-0094) workload - #89

Open
manasip-prog wants to merge 1 commit into
mainfrom
add-dynamic-mpt-workload
Open

Add Dynamic MPT (XLS-0094) workload#89
manasip-prog wants to merge 1 commit into
mainfrom
add-dynamic-mpt-workload

Conversation

@manasip-prog

Copy link
Copy Markdown
Collaborator

Adds a DynamicMPTSet workload exercising XLS-0094 (mutable MPT issuances), submitted on-ledger as MPTokenIssuanceSet.

Model — opt-in mutability

An MPT issuance is immutable by default; mutability is granted only when a create-time MutableFlags (tmfMPT*) bit declares a capability/field as mutable. A mutating MPTokenIssuanceSet then either:

  • enables a capability via a MutableFlags set-enable bit (each requires the matching CAN_ENABLE_* declared at create),
  • rewrites MPTokenMetadata (requires CAN_MUTATE_METADATA), or
  • sets TransferFee (requires CAN_MUTATE_TRANSFER_FEE and an already-enabled CanTransfer).

All three ride typed xrpl-py fields; only the oversize-metadata malformation needs submit_raw.

Setup cohorts

  • Mutable cohort (accounts 53–55): created with _DYNAMIC_MUTABLE_FLAGS declaring every capability enable-able + metadata/transfer-fee mutable — feeds the valid paths.
  • Immutable cohort (accounts 56–58): created with NO MutableFlags, so every later flag-enable / metadata / transfer-fee mutation fails with tecNO_PERMISSION — feeds a curated failure vector.

Both are seeded through the _run_phase setup infrastructure.

Faulty vectors

fuzz (generative), fake_issuance (tecOBJECT_NOT_FOUND), non_issuer (tecNO_PERMISSION), immutable_mutation (tecNO_PERMISSION), and oversize_metadata (temMALFORMED, via submit_raw since xrpl-py rejects the length at construction).

State tracking

MPTokenIssuance gains a mutable_flags field; _on_mpt_create populates it from the create tx's MutableFlags. ws_listener routes validated MPTokenIssuanceSet txns carrying MutableFlags / MPTokenMetadata / TransferFee into the synthetic DynamicMPTSet bucket.

Packaging

xrpl-py pinned to the pre-3.3-release-group branch (carries the XLS-0094 mutable-flag models the workload needs).

Verification

  • check-imports, check-endpoints, check-fuzz-coverage, check-modifier-coverage, check-assembler-roundtrip — all pass. DynamicMPTSet is auto-classified by every Modifier via _TX_NAMES.
  • tests/test_mpt_dynamic.py — 13 tests pass.

Testing note

The workload image relies on the target xrpld being built with XLS-0094 enabled. Run against staging/3.3.x from xrpld-private (per team guidance — not rippled/develop).


Co-authored by Augment Code


Pull Request opened by Augment Code with guidance from the PR author

DynamicMPTSet handler submitted as MPTokenIssuanceSet using the opt-in mutable_flags model from xrpl-py pre-3.3-release-group. Valid paths cover flag-enable, metadata, and transfer-fee mutations on a mutable cohort (accounts 53-55); faulty paths cover fake issuance, non-issuer, immutable-cohort (56-58) mutation, oversize metadata, and generative fuzz. Includes setup cohorts, state tracking of mutable_flags/can_transfer, ws_listener routing, registry/ticket wiring, driver script, and unit tests.
@manasip-prog
manasip-prog marked this pull request as ready for review July 27, 2026 18:22

@vvysokikh1 vvysokikh1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

CLAUDE.md needs updating in the same change — setup chain, MPT cohorts section, synthetic-names list.

"/mpt/set/dynamic/random",
mpt_issuance_set_dynamic,
lambda w: (w.accounts, w.mpt_issuances, w.client),
None,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nothing updates tracked state when a set-enable lands. Flip CanTrade on-ledger and MPTokenIssuance.can_trade stays False — these issuances sit in the mpt_dex no-trade fault pool, so that curated tecNO_PERMISSION vector silently becomes a real trade. Add an updater on the real "MPTokenIssuanceSet" row (same trick as _on_payment_maybe_sponsored_account on "Payment") that ORs the set bits into the tracked flags.

Comment thread workload/pyproject.toml

[dependency-groups]
dev = [
"pytest>=9.1.1",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nothing runs these tests — CI doesn't call pytest and neither does the pre-push list. Wire it into checks.yml and CLAUDE.md, or they'll rot.

return [m for m in mpt_issuances if m.mutable_flags and m.issuer in accounts]


def _immutable_issuances(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This matches every zero-mutable_flags issuance, including all the regular step-4 cohorts — so the dedicated 56–58 cohort only buys guaranteed existence. Drop it, or keep it and say why in the setup comment.

_IMMUTABLE_MPT_RANGE = range(56, 59) # accounts[56..58]
# Opt-in create-time MutableFlags for the mutable cohort: declare every
# capability enable-able + metadata/transfer-fee mutable.
_DYNAMIC_MUTABLE_FLAGS = (

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

All three issuances declare CAN_ENABLE_REQUIRE_AUTH, and enables are one-way (no clear bits in the pinned xrpl-py). Holders get these tokens in step 5 with no issuer-side auth, so the first RequireAuth flip locks them out permanently — over a long run all three converge to that and the cohort goes dark.

Split it: one blockable cohort that declares CAN_ENABLE_REQUIRE_AUTH (holders getting locked out is the point), one safe cohort without it (RequireAuth there = deterministic tecNO_PERMISSION, and its holders can never be blocked). Keeps valid traffic alive for the whole run.

transfer_fee=params.mpt_transfer_fee(),
)
else:
# set-enable latch; re-enabling an already-set capability is a no-op tesSUCCESS.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Six one-way latches × three issuances — everything's latched early in a run, then this arm is a permanent no-op tesSUCCESS. Weight the metadata/fee arms higher.

Comment thread workload/pyproject.toml
# core wheel this installs and is built separately in the Antithesis image; see
# scripts/setup-confidential-crypto.sh.
[tool.uv.sources]
xrpl-py = { git = "https://github.com/XRPLF/xrpl-py.git", branch = "pre-3.3-release-group" }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

XLS-0094 models now also hang off this moving branch pin, which already broke the build once (flag rename). Pin a rev — fine as a follow-up.


# tmfMPTSet* set-enable bits: which capability a mutation turns on. Each requires
# the matching TMF_MPT_CAN_ENABLE_* declared in the create-time MutableFlags.
_SET_ENABLE_FLAGS = [

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

xrpl-py has seven set bits, this list has six — TMF_MPT_SET_CAN_HOLD_CONFIDENTIAL_BALANCE is missing (and the matching CAN_ENABLE at create). Deliberate? If so, comment why. If not, an issuance turning confidential-capable mid-run is worth having.

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