diff --git a/harnesses/terminal-fill-quality/README.md b/harnesses/terminal-fill-quality/README.md index 648c0f89..1cf18eea 100644 --- a/harnesses/terminal-fill-quality/README.md +++ b/harnesses/terminal-fill-quality/README.md @@ -399,6 +399,9 @@ stats plus the last 400 samples (`method_version`, `min_priced`, | `RPC_RPS` | `8` | pacing, calls per second | | `TICK_SECONDS` | `60` | sweep interval | | `DAILY_TARGET` | `400` | swaps read per terminal per day (random draw from the feed) | +| `SANDWICH` | `1` | `0` turns the sandwich screen off and skips the pool neighbourhood read when the exact mid is known (about a fifth of the Solana reads) | +| `FAIL_SCAN_BLOCKS` | code defaults | blocks read in full per chain per poll for the EVM fail rate, e.g. `bnb=3,robinhood=0,base=2,ethereum=1` (0 = no fail rate on that chain's event-fed rows; Binance's rows need at least a few, the block sample is their feed) | +| `NATIVE_POLL_EVERY` | `1` | the EVM log feed polls every N ticks (one `eth_getLogs` per chain per poll) | | `EVM_DAILY_TARGET` | `1000` | the same rate for the Relay and native EVM rows (one chain each, so a product's per-chain entry fills at this rate; production runs them at 1,000 so the per-chain windows fill within hours) | | `PURGE_EVM_BEFORE` | unset | at load, drop the cross-chain and native EVM rows older than this unix time (once, after a pricing change); the variable stays in the container's env until the next deploy resets it | | `PURGE_TERMINALS` | unset | at load, drop every row of these slugs (comma-separated), once, after a feed or attribution change; same caveat | diff --git a/harnesses/terminal-fill-quality/cmd/script/main.go b/harnesses/terminal-fill-quality/cmd/script/main.go index 34af51c7..08e1535d 100644 --- a/harnesses/terminal-fill-quality/cmd/script/main.go +++ b/harnesses/terminal-fill-quality/cmd/script/main.go @@ -323,6 +323,17 @@ func main() { rpcURL := rpcURLs[0] log.Printf("solana reads: %d endpoint(s), primary %s", len(rpcURLs), redactURL(rpcURL, rpcURL)) tick := time.Duration(envInt("TICK_SECONDS", 60)) * time.Second + sandwichOn = envInt("SANDWICH", 1) == 1 + nativePollEvery = max(1, envInt("NATIVE_POLL_EVERY", 1)) + if v := os.Getenv("FAIL_SCAN_BLOCKS"); v != "" { // e.g. "bnb=3,robinhood=0,base=2,ethereum=1" + for _, kv := range strings.Split(v, ",") { + if k, n, ok := strings.Cut(strings.TrimSpace(kv), "="); ok { + if i, err := strconv.Atoi(strings.TrimSpace(n)); err == nil { + failScanBlocks[strings.TrimSpace(k)] = i + } + } + } + } dailyTarget := envInt("DAILY_TARGET", 400) // swaps read per terminal per day perTick := float64(dailyTarget) * tick.Seconds() / 86400 evmDailyTarget := envInt("EVM_DAILY_TARGET", 1000) // the Relay and native EVM rows: their own rate (one chain each) @@ -626,6 +637,12 @@ func priceSwap(ctx context.Context, rpc *rpcClient, sw *Swap, tx *parsedTx, pool if sw.PoolVault == "" { return } + // The pool neighbourhood costs one signature list plus a transaction + // read; with the screen off it is only read when the reference is + // still missing (the previous-trade fallback). + if !sandwichOn && sw.RefSrc != "" { + return + } nb, err := poolNeighbours(ctx, rpc, sw) if err != nil { return @@ -653,6 +670,9 @@ func priceSwap(ctx context.Context, rpc *rpcClient, sw *Swap, tx *parsedTx, pool break } } + if !sandwichOn { + return + } if sd, ok := screenSandwich(ctx, rpc, sw, nb, prevTx, solUSD, now); ok { sw.Scanned = true sw.Sandwich = sd @@ -660,6 +680,11 @@ func priceSwap(ctx context.Context, rpc *rpcClient, sw *Swap, tx *parsedTx, pool } } +// sandwichOn: SANDWICH=0 turns the neighbour screen off (it is not a +// published column; the reads it costs are about a fifth of the Solana +// budget). Set at start. +var sandwichOn = true + // sampleXchain drains the Relay feed: counts every final request of each // cross-chain app for its fail rate, draws the tick's quota of successful // token settlements on Solana and measures them (see xchain.go). diff --git a/harnesses/terminal-fill-quality/cmd/script/native.go b/harnesses/terminal-fill-quality/cmd/script/native.go index 3f96dae3..77ba0f11 100644 --- a/harnesses/terminal-fill-quality/cmd/script/native.go +++ b/harnesses/terminal-fill-quality/cmd/script/native.go @@ -421,8 +421,17 @@ func (f *nativeFeed) drain(slug string) (seen int, sample []string, total int) { } // sampleNative draws the tick's quota per native EVM terminal and measures. +// nativePollEvery: the EVM log feed polls every N ticks (the cursor +// keeps every block, a poll then covers N minutes of chain); 1 = each tick. +var nativePollEvery = 1 +var nativeTick int + func sampleNative(ctx context.Context, httpc *http.Client, st *State, nf *nativeFeed, gas map[string]float64, quota map[string]float64, perTick float64) (added, seen int) { nf.funded = st.Funded + nativeTick++ + if nativeTick%nativePollEvery != 0 { + return 0, 0 + } nf.poll(ctx) now := time.Now().Unix() nf.failScan(ctx, st, gas, now) @@ -431,8 +440,9 @@ func sampleNative(ctx context.Context, httpc *http.Client, st *State, nf *native seen += n0 st.record(t.Slug, now, n0, 0, 0, nil) // The quota accrues every tick (a sparse row, one swap a minute, - // would otherwise need several active ticks per sample). - quota[t.Slug] += perTick + // would otherwise need several active ticks per sample); a poll + // every N ticks accrues N ticks' worth. + quota[t.Slug] += perTick * float64(nativePollEvery) if cap := math.Max(3*perTick, 2); quota[t.Slug] > cap { quota[t.Slug] = cap }