Compare candidate routes in isolated forks

Run competing routes, rebalances, repayments, or agent plans in separate product branches. Rank outcomes and reject unsafe paths with reasons.

Goal

Run competing candidates in isolated product branches and return one row per branch. The output marks the best valid branch as PASS and rejects failed, unsafe, or worse branches with a reason.

When to use this

Use this when a solver, execution engine, or agent wants to run a route tournament without contaminating state between trials.

This guide uses tiny bytecode candidates to keep the example focused on branch orchestration. The same pattern applies to router calldata, vault rebalances, liquidation paths, repayments, deployment branches, and agent plans.

Inputs to change

  • $transport selects the RPC endpoint.
  • The route_inputs table defines branch names, quoted amounts, expected output, and score assumptions.
  • The policy JSON requires success and caps gas at 100000.

What the query does

pin state -> execute one product branch per route -> score branches -> store decisions -> read run decisions

Query

1
-- Route tournament with isolated product branches.
2
-- Each route becomes a product candidate and branch under one eval run.
3
CREATE OR REPLACE TEMP TABLE pinned_block AS
4
SELECT number AS block_number, hash AS block_hash
5
FROM get_block($transport, 21000000);
6
 
7
CREATE OR REPLACE TEMP TABLE route_base AS
8
SELECT evm_create_sim_at(
9
1::UBIGINT,
10
block_number::UBIGINT,
11
block_hash::BYTES32,
12
'docs_route_tournament',
13
'cancun'::EVM_VERSION
14
) AS sim_id
15
FROM pinned_block;
16
 
17
CREATE OR REPLACE TEMP TABLE route_inputs AS
18
SELECT *
19
FROM (VALUES
20
(0::UINTEGER, 'route_a', parse_units('995', 6), parse_units('1000', 6), 50000::UBIGINT),
21
(1::UINTEGER, 'route_b', parse_units('1005', 6), parse_units('1000', 6), 62000::UBIGINT)
22
) AS t(route_ordinal, route_label, quoted_out, expected_out, gas_limit);
23
 
24
CREATE OR REPLACE TEMP TABLE route_workflow AS
25
SELECT evm_execute_candidate_bundle(
26
'[
27
{
28
"source_label":"route_a",
29
"member":{"role":"subject"},
30
"branch":{"role":"candidate","label":"route_a"},
31
"steps":[{"payload_kind":"bytecode","payload":{"address":"0x1111111111111111111111111111111111111111","bytecode":"0x00"}}]
32
},
33
{
34
"source_label":"route_b",
35
"member":{"role":"alternative"},
36
"branch":{"role":"candidate","label":"route_b"},
37
"steps":[{"payload_kind":"bytecode","payload":{"address":"0x2222222222222222222222222222222222222222","bytecode":"0x00"}}]
38
}
39
]'::JSON,
40
(
41
'{"base_sim_id":' ||
42
(SELECT sim_id::VARCHAR FROM route_base) ||
43
',"selected_state_policy":{},"label":"docs-route-tournament"}'
44
)::JSON,
45
'{
46
"name":"route-tournament-policy",
47
"evaluator_kind":"json_rules",
48
"rules":[
49
{"id":"gas","kind":"gas_ceiling","max_gas_used":100000},
50
{"id":"missing_state","kind":"no_unresolved_missing_state"}
51
-- 58 more lines load when JavaScript runs

Read the output

Each branch returns independently. A branch is rejected when execution fails, policy fails, or another valid branch returns more output.

scenario | decision        | reason              | gas_used | policy_status | quality_status
---------|-----------------|---------------------|----------|---------------|---------------
route_b  | PASS_BEST_ROUTE | best valid route    | ...      | pass          | OK
route_a  | REJECT_WORSE... | another route...    | ...      | pass          | OK

Inspect scenario, decision, reason, gas_used, policy_status, and quality_status. Use evm_run_asset_deltas, evm_run_touched_contracts, and evm_run_branch_comparison for deeper branch analysis.