Skip to content

router-perf@1.0 — Erlang Execution Device for Performance-Based Routing#741

Open
Lucifer0x17 wants to merge 12 commits intoneo/edgefrom
feat/permissionless-id-fetch
Open

router-perf@1.0 — Erlang Execution Device for Performance-Based Routing#741
Lucifer0x17 wants to merge 12 commits intoneo/edgefrom
feat/permissionless-id-fetch

Conversation

@Lucifer0x17
Copy link

Continuation of #737

Summary

Introduces dev_router_perf.erl, an Erlang execution device for process@1.0 that provides performance-based routing with automatic weight adjustment. It replaces dynamic-router.lua for Arweave gateway routing, supporting match/with route format — Arweave gateways use match/with instead of prefix/price/topup

How It Works

The device runs as a process@1.0 node process. The feedback loop:

           ┌─────────────────────────────────────────────────┐
           │                                                 │
           ▼                                                 │
   HTTP Request arrives                                      │
           │                                                 │
           ▼                                                 │
   dev_router:route                                          │
     └─ load_routes via provider ──► GET /perf-router~       │
        node-process@1.0/now/routes                          │
     └─ choose(N, "By-Weight") uses weights                  │
     └─ apply_route injects http_reference                   │
           │                                                 │
           ▼                                                 │
   hb_http_client fans out to selected gateways              │
           │                                                 │
           ▼                                                 │
   Response completes                                        │
     └─ record_duration → maybe_invoke_monitor               │
     └─ POST to /perf-router~node-process@1.0/schedule       │
        with {duration, reference, ...}                      │
           │                                                 │
           ▼                                                 │
   dev_router_perf:compute                                   │
     └─ duration/3 updates node performance via EMA ─────────┘
        new_perf = old * (1 - 1/period) + duration * (1/period)

Actions

Action Description
register Add a node to a route. Supports match/with and prefix formats. Sets http_reference for the feedback loop.
duration Update a node's performance score using exponential moving average (EMA). Matches node by http_reference.
recalculate Recompute weights for all nodes using decay-based percentile scoring. Called automatically after each register.

Configuration

Set these on the node process definition:

These are example values can be configured differently.

Key Default Description
performance-period 1000 EMA smoothing period. Lower = more responsive.
initial-performance 30000 Starting perf score (ms) for new nodes.
sampling-rate 0.1 Fraction of random sampling to prevent starvation.
performance-weight 1 Weight factor for performance in scoring.
pricing-weight 1 Weight factor for price in scoring.
score-preference 1 Decay exponent — higher values penalize slower nodes more aggressively.

Production Setup

1. Node configuration:

AdditionalOpts = #{
    http_monitor => #{
        <<"method">> => <<"POST">>,
        <<"path">> => <<"/perf-router~node-process@1.0/schedule">>
    },
    router_opts => #{
        <<"provider">> => #{
            <<"path">> => <<"/perf-router~node-process@1.0/now/routes">>
        }
    },
    node_processes => #{
        <<"perf-router">> => #{
            <<"device">> => <<"process@1.0">>,
            <<"execution-device">> => <<"router-perf@1.0">>,
            <<"scheduler-device">> => <<"scheduler@1.0">>,
            <<"performance-period">> => 6,
            <<"initial-performance">> => 30000
        }
    },
    routes => [
        #{<<"template">> => <<"^/arweave">>,
          <<"nodes">> => BootstrapNodes,
          <<"parallel">> => true,
          <<"admissible-status">> => 200}
    ]
}).

2. Register gateways (once, at startup or via admin script):

lists:foreach( fun(GatewayNode) ->
    Body = 
           hb_message:commit(#{
                  <<"action">> => <<"register">>,
                  <<"route">> => 
                          maps:merge(
                                   GatewayNode, 
                                   #{
                                          <<"template">> => <<"^/arweave">>,
                                          <<"parallel">> => true,
                                          <<"strategy">> => <<"Random">>,
                                          <<"choose">> => 10,
                                          <<"admissible-status">> => 200
                                    }
                           )
                  }, 
                  Opts
           ),
    hb_http:post(
         Node, 
         #{
              <<"path">> => <<"/perf-router~node-process@1.0/schedule">>,
              <<"method">> => <<"POST">>,
              <<"body">> => Body
         }, 
         Opts
    )
end, GatewayNodes).

3. Verify:

# Check routes and weights
curl "http://localhost:PORT/perf-router~node-process@1.0/now/routes?require-codec=application/json&accept-bundle=true"

# Check a specific node's performance score
curl "http://localhost:PORT/perf-router~node-process@1.0/now/routes/1/nodes/1/performance"

samcamwilliams and others added 10 commits March 4, 2026 04:55
Arweave v2 TXIDs are SHA-256(signature), which differs from the unsigned
  content hash used by HyperBEAM messages. Add a fallback in is_tx_admissible
  that checks the commitment-based ID via hb_message:id(CommittedMsg, all, Opts)
  when the unsigned content hash doesn't match.
…ed routing

Introduces dev_router_perf.erl, an Erlang execution device for process@1.0 that replaces dynamic-router.lua for Arweave gateway routing. Fixes gaps in the Lua version: supports match/with route format.

Key functionality:
   - register: adds nodes to routes with http_reference for the feedback loop
   - duration: updates node performance via exponential weighted average (EMA)
   - recalculate: recomputes weights using decay-based percentile scoring
   - Supports both match/with and prefix

Registers router-perf@1.0 in hb_opts preloaded_devices.

Comments added in the file by: Claude Opus 4.6 <noreply@anthropic.com>
Add `is_admissible_hook_routed_test_` that validates the full perf-router feedback loop: gateway registration, TX fetch through routed stack, async monitor duration posts, and performance score updates via EMA.
@Lucifer0x17 Lucifer0x17 self-assigned this Mar 9, 2026
@Lucifer0x17 Lucifer0x17 added the enhancement New feature or request label Mar 9, 2026
@samcamwilliams
Copy link
Collaborator

Amazing! dynamic-router.lua takes a new, faster form 🫡

If it is like the original the registration process should just be either:

  1. Permissioned: Hard-coded in the node message on start. If it is like the Lua script you should just be able to literally put the starting routes in your local process. In this mode is-admissible would always return false.
  2. Permissionless: In this case, if the deployment is going to use the ~arweave@2.9/admissible-tx-response flow then there is no need to gate access at all. Anyone should be able to register on the /ID route.
    ...in either case, no need for the lists:foreach(...) custom code.

Congrats! Let's ship it and test a beta 🙂

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants