daimo-eth / daimo

Real world Ethereum
https://daimo.com
GNU General Public License v3.0
361 stars 29 forks source link

Check proximity of network resources #1116

Closed nounder closed 3 months ago

nounder commented 4 months ago

Check and measure physical proximity of related network resources:

We need this to ensure lowest latency in communication. From what I can tell now all internal cloud resources are living in the same VPC. Distance between third party RPC providers is to be measured on per-message basis.

nounder commented 4 months ago

RPC Providers

Tested around NYC, close to us-east-2 region (consistent 10ms ping), but not directly there to mimic network variability. Naively measures single RPC call (req+res time), meaning it's not TTFB nor pure response time. It's good enough to get a sense of RPC latency.

p75 below 5ms. Good enough. No further dissection necessary for current performance enhancement project.

Interesting to see higher variance and wider domain for L2 compared to L1.

The latency is actually incredible. There are only 2 intra-city hops to reach to a destination machine:

[ private cloud and data center hops truncated ] 
 7  ae-3.r24.asbnva02.us.bb.gin.ntt.net (129.250.2.144)  1.617 ms ae-2.r25.asbnva02.us.bb.gin.ntt.net (129.250.2.124)  0.762 ms ae-0.r24.asbnva02.us.bb.gin.ntt.net (129.250.3.243)  0.724 ms
 8  ae-0.a08.asbnva02.us.bb.gin.ntt.net (129.250.4.9)  0.502 ms ae-0.a00.rstnva04.us.bb.gin.ntt.net (129.250.2.246)  1.138 ms  3.133 ms
 9  140.204.218.170 (140.204.218.170)  0.864 ms 140.204.218.158 (140.204.218.158)  0.947 ms 140.204.220.182 (140.204.220.182)  0.986 ms

QuickNode L1 Mainnet

benchmark             time (avg)        iter/s             (min … max)       p75       p99      p995
---------------------------------------------------------------------- -----------------------------
getBlockNumber         2.96 ms/iter         337.4     (2.34 ms … 4.83 ms) 3.06 ms 3.71 ms 4.83 ms
getBlockByNumber      10.03 ms/iter          99.7     (8.4 ms … 23.83 ms) 10.37 ms 23.83 ms 23.83 ms

QuickNode L2 Mainnet

benchmark             time (avg)        iter/s             (min … max)       p75       p99      p995
---------------------------------------------------------------------- -----------------------------
getBlockNumber         3.87 ms/iter         258.6    (2.93 ms … 27.09 ms) 3.82 ms 10.65 ms 27.09 ms
getBlockByNumber      11.86 ms/iter          84.3    (8.01 ms … 44.17 ms) 11.83 ms 44.17 ms 44.17 ms
nounder commented 4 months ago

Shovel and app Postgers also reachable in in 1-4ms range. All good here.

nounder commented 4 months ago

New block emission consistency on QuickNode

Listened for 2h for new block on each chain via QuickNode RPC WS.

L1 Ethereum mainnet

Mean Interval: 12.04s Standard Deviation: 1.778s

NewBlock-L1-line NewBlock-L1-dist

L2 Base mainnet

Mean Interval: 1.99s Standard Deviation: 0.334s

NewBlock-L2-line NewBlock-L2-dist


WS listener

```typescript import { ethers } from "https://cdn.ethers.io/lib/ethers-5.6.esm.min.js"; let blockN = 0; let targetBlocks = 570; const provider = new ethers.providers.WebSocketProvider(Deno.args[0]); provider.on("block", (blockNumber) => { console.log(`newBlock,${blockNumber},${Date.now()}`); if (blockN >= targetBlocks) { Deno.exit(0); } blockN++; }); provider.on("error", (error) => { console.error("Subscription error:", error); Deno.exit(1); }); function printStackTrace() { console.error("Printing stack trace..."); console.trace(); } ```

Plotting

```python import polars as pl import plotly.express as px def plot_new_blocks(path, title=""): # Load the CSV data into a Polars DataFrame df = pl.read_csv(path, has_header=False) # Select the third column (timestamp) timestamps = df[:, 2] # Calculate intervals between consecutive timestamps intervals = timestamps.diff().drop_nulls().alias("intervals") # Convert intervals to seconds (assuming timestamps are in milliseconds) intervals_in_seconds = intervals / 1000 # Create a DataFrame for plotting intervals_df = pl.DataFrame({"intervals": intervals_in_seconds}) # Calculate mean and standard deviation mean_interval = intervals_in_seconds.mean() std_interval = intervals_in_seconds.std() print(f"Mean Interval: {mean_interval} seconds") print(f"Standard Deviation: {std_interval} seconds") # Plot intervals fig = px.line( intervals_df.to_pandas(), y="intervals", title=f"interval between new blocks ({title})", ) fig.update_layout( yaxis_title="Interval (seconds)", shapes=[ # Add lines for mean and standard deviation dict( type="line", x0=0, x1=len(intervals_df), y0=mean_interval, y1=mean_interval, line=dict(dash="dash", color="green"), ), dict( type="line", x0=0, x1=len(intervals_df), y0=mean_interval + std_interval, y1=mean_interval + std_interval, line=dict(dash="dot", color="red"), ), dict( type="line", x0=0, x1=len(intervals_df), y0=mean_interval - std_interval, y1=mean_interval - std_interval, line=dict(dash="dot", color="red"), ), ], ) fig.show() # Optional: Histogram of intervals fig_hist = px.histogram( intervals_df.to_pandas(), x="intervals", nbins=30, title=f"Distribution of Time Intervals {title}", ) fig_hist.update_layout(xaxis_title="Interval (seconds)", yaxis_title="Count") fig_hist.show() ```