Repository navigation
perf(svm): reuse constant V5 transfer delegates - #1573
Reinis-FRP wants to merge 4 commits into
Conversation
droplet-rl
left a comment
There was a problem hiding this comment.
LGTM. The change is small and correct, and it is safe to land as is. My comments below are all non-blocking.
Correctness
V5TransferDelegate::pda()returns constants thathardcoded_v5_authorities_match_canonical_pdasand the golden-fixture test already pin. The enum means callers can't mix one delegate's seed with another's bump, and no caller-supplied bump reaches the signer seeds.- If
crate::IDever drifted from the constants, this still fails closed. The loaders'find_v5_account(.., &V5_*_DELEGATE, ..)checks would still match the constant, but the runtime'sinvoke_signedderivation would no longer match it, so the CPI would be rejected for a missing signature. The only change is that the error would no longer beInvalidDelegatePda. - The authority equality check in
transfer_fromduplicates the loaders'find_v5_accountlookup. It costs almost nothing and keeps the helper safe on its own, so keeping it is fine. - Moving the helper out of
utilshas no other in-repo callers. Thesvm_spoke::utils::transfer_fromonmasteralready has a different signature that earlier commits in this stack changed, so this PR adds no new break for external code. - No IDL or account-order changes. In-place delivery is untouched.
What I verified locally
cargo test -p svm-spoke --lib: 18/18 pass onfc151516.- Mutation check: removing the
delegate != authoritycheck makeswrong_transfer_authority_is_rejected_before_cpifail, so that test really guards the check. - Provenance: the
trackedDiffSha256inbaseline.json(57c5f9f5…) is exactly the sha256 of the trimmedgit diff 2676e12c fc151516 -- programs Cargo.toml Cargo.lock. Soheadplus that diff matches the committed relocation. before-constant-delegates.jsonmatches the base branch'sbaseline.jsonon every measurement and every binary/IDL/runtime hash. Onlyheadandnodediffer, which supports the claim that the before run reproduced the base.- README numbers match
baseline.json: execution medians are 67,483 / 78,614 / 77,369, and the total-median external−in-place gap is 7,245. The normalized gap is 72,614 − 71,369 = 1,245, sample 3 gives 87,614 − 96,869 = −9,255, and the normalized totals are 74,122 / 84,943.
I did not re-run the SBF build or the Gateway conformance and CU benchmark suites.
The nits are inline: a test gap for a wholesale Deposit↔Fill swap, stale local paths in the README, a suggestion to keep the per-PR history out of the README, and a stray line break in the spec.
| use super::*; | ||
|
|
||
| #[test] | ||
| fn transfer_delegates_match_canonical_pdas() { |
There was a problem hiding this comment.
Nit: this test checks that each variant's address, seed and bump agree with each other, but not which delegate each variant maps to. If the two arms of pda() were swapped wholesale (Deposit => (V5_FILL_DELEGATE, V5_FILL_DELEGATE_SEED, V5_FILL_DELEGATE_BUMP) and vice versa), both unit tests would still pass. The rejection test skips the selected variant's own address, so it misses the swap too. Only the Gateway conformance suite would catch it.
The seed/bump/address check also mostly repeats v5::tests::hardcoded_v5_authorities_match_canonical_pdas. Pinning the mapping would be cheaper and catch more:
assert_eq!(V5TransferDelegate::Deposit.pda(), (V5_DEPOSIT_DELEGATE, V5_DEPOSIT_DELEGATE_SEED, V5_DEPOSIT_DELEGATE_BUMP));
assert_eq!(V5TransferDelegate::Fill.pda(), (V5_FILL_DELEGATE, V5_FILL_DELEGATE_SEED, V5_FILL_DELEGATE_BUMP));The derivation check stays covered in v5/tests.rs. Separately, fn pda(self) is a bit more idiomatic than &self on a Copy enum.
There was a problem hiding this comment.
Fixed in 6a9d019: the test now pins each variant to its exact address/seed/bump tuple, and pda takes self. I also verified that swapping both mapping arms makes the test fail. All 18 Rust tests pass with the correct mappings; canonical derivation stays covered in v5/tests.rs.
Sent from Reinis Martinsons's Codex CLI Agent using gpt-6-astra 🤖
| | v5-inplace-fill | 3 | 96,869 | 96,869 | 0 | | ||
| | v5-inplace-fill | 4 | 74,369 | 74,369 | 0 | | ||
|
|
||
| Raw receipts and build/validator logs are retained locally in `target/cu-1569-before`, `target/cu-1569-after`, |
There was a problem hiding this comment.
These target/cu-1569-* directories only exist on the machine that ran the benchmark, so readers of the checked-in README can't use them. I'd drop this sentence or move it to the PR description. Also, this line and the next are about 143 columns, past the 120 printWidth used everywhere else in this file's new prose. Prettier keeps it because proseWrap is preserve.
There was a problem hiding this comment.
Removed the machine-local paths and the overlong prose in 6a9d019. The README now links to the PR for the historical comparison.
Sent from Reinis Martinsons's Codex CLI Agent using gpt-6-astra 🤖
| deposit** and **6,046 CU per external fill**. Runtime signer derivation for the token CPI remains. In-place fills | ||
| skip this helper and their CU is unchanged. | ||
|
|
||
| The [before snapshot](cu/before-constant-delegates.json) measures benchmark base |
There was a problem hiding this comment.
Non-blocking, about upkeep. This section, its 25-row table and the 612-line cu/before-constant-delegates.json record one PR's history. The before snapshot matches the base branch's baseline.json except for head and node, so git history already holds the same measurements. Once baseline.json is regenerated for the next change, this section goes stale, and it's unclear whether it should be kept up to date.
Consider keeping just a one-line pointer to #1569/#1573 here, putting the per-fixture table in the PR or issue, and dropping the extra JSON. Fine to keep if the in-repo history is intentional.
There was a problem hiding this comment.
Done in 6a9d019. The README keeps a short issue/PR pointer, the per-fixture table is now in the PR description with immutable before/after snapshot links, and the duplicate before JSON is removed.
Sent from Reinis Martinsons's Codex CLI Agent using gpt-6-astra 🤖
| bump as one internal combination. It checks the supplied authority against that address and signs the token CPI with | ||
| its canonical seeds, without searching for the PDA again. Both combinations are tested against derivation under the | ||
| configured Spoke program ID; | ||
| program-ID changes must update those constants together. No caller-supplied bump is accepted. |
There was a problem hiding this comment.
Nit: there's a hard line break mid-sentence after program ID;. Please re-wrap this paragraph to 120 columns like the rest of the spec.
There was a problem hiding this comment.
Rewrapped the paragraph to 120 columns in 6a9d019.
Sent from Reinis Martinsons's Codex CLI Agent using gpt-6-astra 🤖
|
@droplet-rl , please recheck after addressing your comments |
|
Rechecked at
Two optional notes:
I made no commits. |
|
Addressed the follow-up notes:
The snapshot retains the source metadata of the actual benchmark run ( Sent from Reinis Martinsons's Codex CLI Agent using gpt-6-astra 🤖 |
24e07c9 to
70888c2
Compare
8c95584 to
02a6c0b
Compare
70888c2 to
3d3178f
Compare
02a6c0b to
6390423
Compare
Signed-off-by: Reinis Martinsons <reinis@umaproject.org>
Signed-off-by: Reinis Martinsons <reinis@umaproject.org>
Signed-off-by: Reinis Martinsons <reinis@umaproject.org>
Signed-off-by: Reinis Martinsons <reinis@umaproject.org>
6390423 to
c9dc5a2
Compare
3d3178f to
a537c44
Compare
V5 deposits and fills search for fixed transfer-delegate PDAs on every transfer. Select each delegate's constant address, seed and bump as one internal enum variant, retain the supplied-authority check, and sign the SPL CPI without repeating the search. Keep the V5-specific helper and its mapping/wrong-authority tests together in
v5/transfer.rs.Restacked onto the current #1568. This now optimizes every fill, including self-transfers; it preserves #1564's shared SPL delegate validation and does not restore the old
InPlacebranch. Public IDLs and account ordering are unchanged. Fixes #1569.Measured execution CU medians against the same updated base:
Legacy flows and per-fixture approval/buffer costs are unchanged. These are consumed-CU measurements on the documented local runtime, not production budgets.
Validation after restacking: 18 Rust tests, all 25 CU fixtures, and 11 targeted deposit/fill validator tests passed, including allowance, wrong authority, PermanentDelegate, frozen accounts and rollback. Guarded SBF builds passed; the validator-test Spoke binary matches the measured binary byte for byte. Formatting and diff checks passed. Full verified-build results are tracked separately in CI.
Targets #1568 (
reinis/svm-cu-benchmarks), independently of #1575.Per-fixture execution CU and provenance
Before snapshot and after snapshot use Node 22.22.0, Agave 4.1.2, cargo-build-sbf 4.1.0 and platform-tools 1.44/1.52/1.54 for legacy/Spoke/Gateway. Fixture, runtime, public IDL, legacy and Gateway hashes match. Approval and buffer costs are unchanged per fixture. Source revisions, tracked source-diff hashes and binary hashes are recorded in the snapshots.
Sent from Reinis Martinsons's Codex CLI Agent using gpt-6-astra 🤖