solana-autopilot: persist competitions and hold out in-flight orders - #4931
squadgazzz wants to merge 11 commits into
Conversation
…20-competition-persistence # Conflicts: # crates/autopilot-svm/example.toml # crates/autopilot-svm/src/infra/config.rs # crates/autopilot-svm/src/infra/db.rs # crates/autopilot-svm/src/infra/prices.rs # crates/autopilot-svm/src/infra/provider.rs # crates/autopilot-svm/src/run.rs # crates/autopilot-svm/src/tests.rs
… dropped The observer persists ranked and filtered-out solutions alike, so without a flag a debugger cannot tell a filtered solution from one that lost on score. Mirrors the EVM proposed_solutions.filtered_out column.
…rows The cut now holds out orders of winning solutions until their deadline slot passes, the indexer records the solver's settlement, or the execution window closes early, the shape of the EVM fetch_in_flight_orders. The hold no longer depends on a window row being opened or on the deadline sweep running, and it survives a restart. Held orders get a filtered order event, a failed lookup skips the cut. The competition inserts go through QueryBuilder, one statement per table, like the EVM save_solutions.
The competition rows carry the hold on their own, the EVM shape. The blockhash grace the map provided moves into the query as MAX_PROCESSING_AGE past the deadline slot, and a timed-out window keeps the hold for that span. The map's two release triggers were table state already: an observed settlement is a settlements row, a provable non-send a rejected window. The hold now survives a restart without any seeding.
|
@claude review please and ensure the logic mirrors the evm implementation and each line of code makes sense. we're going to have a separate settlement program instance for prod, so same auction ids from staging and prod shouldn't be a problem for indexing. |
|
Claude finished @squadgazzz's task in 6m 24s —— View job Review completeI reviewed the full diff against
One finding worth confirming (posted inline on Minor (not blocking): the |
…n any settlement by its solver Winner selection only keeps token pairs disjoint, so one solver can win several solutions of one auction. Matching the landed settlement by solver released all of them at once. Matching the settlement's trades releases exactly the orders that landed.
…ecuted its solution A settlement row carries no solution uid, and one solver may hold several windows of one auction. Matching by solver closed all of them on the first landing, with the first signature. The window's solution has persisted trade executions, so the settlement whose trades cover one of them is the one that executed it.
|
Claude finished @squadgazzz's task in 4m 35s —— View job Review completeI re-reviewed the full diff against The main finding from my previous review is fixed. Both release paths now match a settlement to a solution per order through the trades, not by solver:
Everything else checks out:
CI is green. One non-blocking note (posted inline on |
…nk position Reference scores come from the generic arbitrator, one per winning solver, and go into solana.reference_scores with the solutions, the rewards baseline accounting asked for. The persisted solution uid is now the position in ranked followed by filtered_out, as the EVM autopilot enumerates its ranking. The map keyed by (solver, solution id) collapsed two solutions sharing a key into one uid and failed the whole persist on the primary key.
The EVM columns exist but are written empty, they are not a feature the Solana table lacks.
| CREATE TABLE solana.auctions ( | ||
| id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY, | ||
| tip_slot bigint NOT NULL, | ||
| json jsonb NOT NULL | ||
| ); |
There was a problem hiding this comment.
Not super important, but since this is a singleton table, maybe it's worth adding a singleton check to enforce it, like
CREATE TABLE solana.auctions (
-- …
lock boolean NOT NULL DEFAULT true UNIQUE CHECK (lock)
);No change needed in replace_current_auction.
There was a problem hiding this comment.
Good suggestion! Even tho EVM doesn't have it, I'd add it. Thanks!
Description
The Solana autopilot keeps no record of its competitions, and the next cut can re-offer an order whose settlement is still in flight (seen on staging, one order settled twice by the same solver). Accounting and debugging need what the EVM autopilot persists, so this mirrors it with the Solana counterparts of the V072 competition tables. Auction ids come from the
solana.auctionsidentity column, so they are serial and survive restarts. Every proposed solution is stored under an autopilot-generated per-auctionuid, settlement windows key on that uid, and the cut holds out the orders of winning solutions the way the EVMfetch_in_flight_ordersdoes: until a blockhash lifetime past the deadline slot runs out, a landed settlement of the auction trades the order, or the driver rejects the solution before sending it. Landing is checked per order through the settlement's trades, sincesettlements.solution_uidis unattributed and one solver may win several solutions of one auction. S3 archival of the auction is left for later.The in-memory hold-out from #4937 and #4938 goes away. Its two release triggers were table state already: an observed settlement is a
solana.settlementsrow with itssolana.trades, a provable non-send is arejectedwindow. Its blockhash grace moves into the query asMAX_PROCESSING_AGE, and a timed-out window keeps the hold for that span. So the hold no longer waits on the deadline sweep and survives a restart without seeding. #4932 still adds the idle sweep so timed-out windows get flagged on a quiet chain.Changes
solana.auctions,solana.competition_auctions,solana.proposed_solutions(withfiltered_out),solana.proposed_trade_executions,solana.reference_scores, plus a deadline index for the hold-out querysolana.auctionssequence, like the EVMauctions.idfiltered, and skips the cycle when the lookup failsInFlightOrdersand its hold and release calls are removedHow to test
Postgres tests:
in_flight_ordersover the deadline plus blockhash lifetime, timeout, rejection and settlement, and the open-orders predicates. The full-cycle test checks the persisted competition rows and the hold across the deadline sweep.Related issues
BE-220, BE-245 (windows close one-to-one through the persisted trade executions), BE-317 (reference scores)