Skip to content

Make account creation silently skip creating an account that already exists where necessary - #85

Open
fedgiac wants to merge 11 commits into
mainfrom
pda-creation-idempotent
Open

Make account creation silently skip creating an account that already exists where necessary#85
fedgiac wants to merge 11 commits into
mainfrom
pda-creation-idempotent

Conversation

@fedgiac

@fedgiac fedgiac commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Closes #37.

Introduce idempotent PDA creation so two parties racing to create the same canonical account don't step on each other's toes, especially when multiple PDAs are created in the same transaction. This happens during an auction when solvers concurrently create the same token buffer, or the same partially-fillable order from a signature.

With these changes, the loser of the race succeeds as a no-op instead of reverting with the system program's AccountAlreadyInUse.

All three creation sites that went through CanonicalPda::create now split into two methods over the same allocation:

  • create_idempotent: this is for buffer creation.
  • create_new: this is for order and state PDA creation.
    (Note: creating orders from a user signature should use create_idempotent. But right now only a user signature can create an order, and it's better if the user sees an error when trying to recreate a new order again.)

How to test

New/updated tests in CI.

@fedgiac
fedgiac requested a review from a team as a code owner July 31, 2026 15:11
Comment thread programs/settlement/src/processor.rs Outdated
Comment thread programs/settlement/tests/reclaim_order.rs Outdated
Comment thread programs/settlement/src/create_order.rs Outdated
Comment thread programs/settlement/src/create_order.rs
Comment thread programs/settlement/tests/create_buffer.rs
Comment on lines +44 to +47
/// Here we assume that we will never create an account for the same seeds
/// but for a different owner. If the caller does, then the function
/// still tries to create the account, which then reverts with the system
/// program's `AccountAlreadyInUse` because the account already exists.

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 comment sent me into a bit of confusion with how this would work for CreateBuffer accounts, as those accounts are owned by the token program even though they are created by the settlement program. Eventually I realized its because the settlement program sets the owner on creation and at no point is the ownership set to the settlement even though it initialized it.

What I am actually still confused by though is why the strategy for seeing if an account is created or not is by checking the owner, and not by, ex. is_data_empty or even owner, which returns the owner directly so we can see if it is address 0 instead of having to expect it to be the specified owner. I think the reasoning should probably be documented in the code somewhere here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done, does this clarify the motivation? e489ee1
To be fair, it wouldn't be unreasonable to check whether it's initialized or not instead.
Also note that there's no meaningful is_allocated function.

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.

        // ...We confirm the owner is the same, rather than checking that it isn't
        // the system owner, to make sure we don't try to reuse the same address
        // if the owner is a different parameter (execution continues and
        // eventually reverts).

I don't think this explains why not use the straight owner() function to see if it returns address(0) (or the solana equivalent) or not. Seems like that would be a more reliable way to check if the program is initialized or not, right?

@kaze-cow kaze-cow 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.

one comment, otherwise looks ok 👍

@fedgiac fedgiac changed the title Make account creation idempotent where necessary Make account creation silently skip creating an account that already exists where necessary Aug 4, 2026
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.

Make PDA creation idempotent

2 participants