External calls
Real apps often need data from outside the validator process: a price feed, a weather API, a model provider, or a webhook. Gora apps reach external endpoints through a sandboxedfetch-like host function. The committee then has to agree on what came back. This page explains how that works and how to design your app so consensus succeeds.
The host function
Inside your app you call:gora.fetch is provided by the Gora runtime, not by your language’s built-in fetch. It enforces:
| Limit | Default | Why |
|---|---|---|
| Total timeout | 5 s | A slow upstream cannot stall the round. |
| Response size | 256 KB | Avoid memory exhaustion. |
| Concurrent calls per request | 4 | Predictable resource use. |
| Allowed schemes | https:// | No raw IP, no http:// for production policy. |
| Allowlist | Declared in policy.json | The app states up front which hosts it talks to. |
How the committee agrees
Validators run your app independently. If they each made their own live HTTP call, they would get slightly different responses (caches, timing, server clocks, rate limits) and never agree. Two strategies keep responses consistent.Strategy A — Proposer fetches, committee verifies
This is the default for deterministic apps.Strategy B — Quorum fetch (consensus-grade data)
For requests where the upstream value is itself the thing being attested (a price oracle, an event finality check), the app setsconsensus: "quorum" on the fetch:
Time and the wall clock
Every fetch in proposer-fetch mode captures the proposer’s clock as part of the transcript. Verifiers see the proposer’sfetch_started_at instead of their own Date.now() so re-execution stays deterministic. If your app needs wall-clock time between fetches, read it from req.now_ms, which is the round’s pinned timestamp — not from Date.now().
What to put in the response, what to keep out
A fetch transcript is part of the attestation. Keep it minimal.| Keep | Avoid |
|---|---|
| The URL, method, status, and the body fields you actually use | Full HTML pages, tracking cookies, vendor X- headers |
| A hash of the body | The raw body verbatim if it’s larger than 8 KB |
Headers you read in the app (e.g. Etag, Retry-After) | Bearer tokens, API keys, Authorization headers |
Authorization, Cookie, X-Api-Key) from the transcript. Anything else you want stripped, set redact_request_headers: [...] on the fetch call.
Errors and round-fail
Network failures during proposer fetch behave like any other proposer execution error: the proposer broadcasts a round-fail with the reason, and the network retries with a new sequence. In quorum mode, a fetch that does not reach two-thirds usable responses also round-fails. Both cases are recorded in the round log so you can see why a request didn’t land.Combining VRF with external data
A common pattern: pick a winner from an externally-fetched list, using Gora VRF as the source of randomness.What’s intentionally not supported
| Not supported | Why |
|---|---|
| Long-lived sockets / SSE | Round timing forbids it. |
| Raw TCP / UDP | Out of scope for the host function. |
| Calls that depend on the validator’s IP geolocation | Different validators would see different content. |
| Background fetches after the app returns | The app result is the round’s output. |
| Per-validator API keys | Keys live in app config and are uniform across the committee. |
Related
- Randomness and VRF — combine external data with verifiable randomness.
- Validators and consensus — what “committee re-runs” actually means.
- Set policy and payments — declare your network allowlist.