Skip to content

test: lock in permit nonce consumption when the inner call reverts - #1516

Open
acyberduck wants to merge 1 commit into
masterfrom
test/call-permit-nonce-consumed-on-revert
Open

test: lock in permit nonce consumption when the inner call reverts#1516
acyberduck wants to merge 1 commit into
masterfrom
test/call-permit-nonce-consumed-on-revert

Conversation

@acyberduck

Copy link
Copy Markdown

Following up on the Discord conversation about the Call-Permit path: I offered to add a small regression test that locks in "nonce consumed on revert", and this is it. No production code is touched.

What this pins

do_dispatch_permit_signed in pallets/transaction-multi-payment/src/lib.rs maps a reverting inner call to Ok(post_info) rather than Err, with this comment:

Revert already consumed the nonce and charged gas; commit it like the unsigned path. Returning Err would roll the nonce back → replayable.

The new test, permit_nonce_is_consumed_when_inner_call_reverts_and_replay_is_rejected, exercises that end to end on the signed path:

  1. the inner call reverts (unachievable min_buy_amount) and the extrinsic still returns Ok
  2. the reverted call had no effect (the signer's DAI balance is unchanged)
  3. the permit nonce advances by exactly one
  4. re-submitting the byte-identical permit is refused with EvmPermitInvalid, before any execution
  5. the refused replay does not advance the nonce a second time

Why add it when coverage already exists

While writing it I found both halves already covered, and I would rather say so than oversell this:

  • signed_dispatch_permit_should_commit_and_consume_nonce_when_inner_call_reverts pins the nonce bump on revert
  • signed_dispatch_permit_should_fail_when_replayed_with_same_nonce pins that a spent nonce is refused, but on a permit that succeeded

What is not pinned anywhere is the composition, which is the property the comment is actually about. On the revert path the inner call had no effect, so a replay that got through would execute a call the signer authorized exactly once. Points 4 and 5 above are the part no existing test asserts. If you read this as redundant, I am happy for it to be closed; it seemed better to have the replay lock asserted directly than inferred from two separate tests.

Batch variant

I looked at a two-permit batch variant (first leg reverts, second executes, first leg's replay refused) and left it out. The shared build_permit_for_call helper signs at nonce zero, so a second permit in the same batch would need a nonce parameter threaded through that helper and every existing call site. That is more churn than a regression test justifies.

Verification

  • cargo test -p runtime-integration-tests evm_permit:: gives 43 passed, 0 failed
  • mutation check 1: flipping the assertion to expect the nonce not consumed fails as it should (left: 1, right: 0)
  • mutation check 2: locally changing do_dispatch_permit_signed to return Err(e.error.into()) on revert, which is the rollback the comment warns about, turns this test red. Reverted afterwards
  • cargo fmt --all -- --check is clean

Notes

  • Lives in integration-tests/src/evm_permit.rs, in the existing sponsored_paymaster module, reusing its paymaster_account, build_permit_for_call and assert_dispatch_permit_not_paused helpers. The pallet's own mock has no EVM, so this cannot live in the pallet's test module.
  • runtime-integration-tests bumped to 1.107.2 to satisfy the crate version check.

Happy to rename the test, trim the comment, or drop the version bump if you handle that separately.

Composes the existing revert and replay coverage on the signed
dispatch_permit path into one end-to-end lock, so a future change that
rolls the nonce back on revert fails on the replay it would enable.

Bumps runtime-integration-tests to 1.107.2 for the version check.
@github-actions

Copy link
Copy Markdown

Crate versions that have been updated:

  • runtime-integration-tests: v1.107.1 -> v1.107.2

Runtime version has not been increased.

@github-actions

Copy link
Copy Markdown

Quick benchmark at commit e3987b9 has been executed successfully.
View results

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.

1 participant