Compute Units
Understand what Doppler's low compute unit usage does and does not include.
Doppler benchmarks at 21 compute units (CUs) per oracle update when using the default payload schema with a single u64 field. That number measures only what the generated program instruction consumes — not the full transaction.
Surfpool logs for a single price-feed update show the program line explicitly:
Program fastRQJt3nLdY3QA7n8eZ8ETEVefy56ryfUGVkfZokm consumed 21 of 21 compute unitsThe same transaction reports 471 CUs total once compute-budget instructions, signature verification, and account loading are included.
Default Payload: 21 CU Breakdown
The generator's default schema is a single u64 price field:
payload: {
price: "u64",
}That produces an oracle account of 16 bytes:
8 bytes sequence little-endian u64
8 bytes price little-endian u64The generated SDKs model program CU cost as:
sequence check 5 CUs
admin verification 6 CUs
payload write 6 CUs
account data term floor(oracle account size / 4)For the default payload, floor(16 / 4) = 4, so:
5 + 6 + 6 + 4 = 21 CUs| Component | CUs | What the program does |
|---|---|---|
| Sequence check | 5 | Reads the stored sequence from the oracle account and the new sequence from instruction data, then rejects the update if new_sequence <= current_sequence. |
| Admin verification | 6 | Confirms the admin account is a non-duplicate signer and matches the hardcoded admin pubkey embedded in the program bytecode. |
| Payload write | 6 | Reads the new payload from instruction data and writes the updated sequence and payload bytes into the oracle account. |
| Account data term | 4 | Solana charges CUs proportional to writable account data touched. For a 16-byte oracle account, floor(16 / 4) = 4. |
On-Chain Update Path
Each update instruction passes two accounts and fixed-size instruction data:
| Account | Role | Access |
|---|---|---|
| Admin | Readonly signer | Read |
| Oracle | Writable | Read/write |
Instruction data for the default payload is 16 bytes:
offset 0 sequence u64 8 bytes
offset 8 price u64 8 bytesThe program entrypoint runs two steps:
Admin::check— verify the signer is the embedded admin.Oracle::check_and_update— validate monotonic sequence, then write sequence and payload.
There is no deserialization, no heap allocation, and no external CPI. The program reads and writes at fixed offsets using direct memory operations.
Scaling With Larger Payloads
The account data term grows with oracle account size. Larger fixed-size payloads cost more than 21 CUs, but the first three terms stay constant.
| Payload schema | Oracle size | Account data term | Total CUs |
|---|---|---|---|
{ price: "u64" } (default) | 16 bytes | 4 | 21 |
{ bid: "u64", ask: "u64" } | 24 bytes | 6 | 23 |
{ price: "u64", volume: "u64", confidence: "u32" } | 28 bytes | 7 | 24 |
The SDK helper oracleUpdateComputeUnits(serializer) applies the same formula for any generated schema.
Program CUs vs Transaction CUs
Use the 21 CU figure precisely: it is the Doppler instruction cost, not the cost of landing a transaction.
A production update transaction typically includes compute-budget instructions and normal Solana overhead:
- transaction signature verification
- account loading
SetComputeUnitLimitSetLoadedAccountsDataSizeLimitSetComputeUnitPricewhen you pass a priority fee- any other instructions in the transaction
A single price-feed update with optimized compute-budget settings consumes roughly 471 CUs end to end while the Doppler program itself still reports 21 CUs.
Setting SetLoadedAccountsDataSizeLimit to the actual loaded account data size (for example, 111 bytes for a minimal single-feed transaction) avoids paying the default 64 MB data-size penalty and materially improves priority score. See Anza's CU optimization guide for the scheduling math.
Compute Budget Guidance
The generated SDK transaction builders add:
- a loaded accounts data size limit instruction
- a compute unit limit instruction
- a compute unit price instruction when you pass a priority fee
Request enough CUs for the full transaction, not just the 21 CU program path. The builders start from compute-budget instruction overhead and add oracleUpdateComputeUnits(serializer) per update.
For high-frequency updates, set a priority fee when timely inclusion matters:
await client.updateOracle(
oracleAddress,
{
sequence: BigInt(Date.now()),
payload: { price: 42_000_000n },
},
serializer,
1_000n,
);Tune the fee and batching strategy against current cluster conditions rather than hard-coding one number permanently.
Batching Multiple Updates
Each Doppler update in a transaction still costs 21 CUs at the program level (for the default payload). Batching multiple oracle updates into one transaction amortizes signature verification and compute-budget overhead across feeds:
3 updates in one transaction → 3 × 21 = 63 program CUs
same 3 updates as separate transactions → 3 × 21 program CUs, but ~3× transaction overheadThe SDK TransactionBuilder accumulates CU and loaded-data-size estimates as you append updates.