Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 109 additions & 0 deletions proposals/0503-static-sysvars.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
---
simd: '0503'
title: Static Sysvars
authors:
- Dean Little (Blueshift)
- Joe Caulfield (Anza)
category: Standard
type: Core
status: Idea
created: 2026-03-25
feature: (fill in with feature key and github tracking issues once accepted)
---

## Summary

Leverage existing static linking infrastructure of JIT compilation to enable
Copy link
Copy Markdown
Contributor

@Lichtso Lichtso Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

static linking

Nit on terminology: I know we called them "static syscalls" but they are not static linking (that would imply we would inline their implementation into the SBPF ELF at or before deployment), instead they are still dynamic linking but relocation-less.

existing ... infrastructure

The infrastructure for "static syscalls" is for syscalls only, as the name implies. Linking of (in this case readonly) data is a different process and there is no existing infrastructure to utilize.

JIT compilation

I know we have used JIT-only mode on MNB in Agave for years but with the next version we could have tiered compilation (Interpreter & JIT hybrid). Also Firedancer is using an Interpreter.

static resolution of sysvars.

## Motivation

In order to access Sysvar values, developers currently have three options:

1. Invoke a specific getter syscall
2. Invoke the get_sysvar syscall, or
3. Include a Sysvar account in their program.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Obligatory https://xkcd.com/927/.

That said, yes we could improve upon sysvars and the sysvar syscalls are not great.


The downsides of all of these approaches are threefold:

1. Sysvar values are globals that are always available to the validator, but
aren't exposed as globals during execution. This is a clunky anti-pattern
Copy link
Copy Markdown
Contributor

@Lichtso Lichtso Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sysvar accounts are already loaded for all transactions even if their message does not mention the sysvar key.

Scratch that, it only applies to the sysvar cache but it should be easy to expand to transaction accounts too.

resulting in degraded developer experience.
2. Invoking a syscall to access a global requires both a stack allocation and
halting execution – an immense amount of overhead just to read a value that
is already readily available.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, sysvar syscalls are overkill for reading constant data.

3. Having to pass in an account to access a global results in a 10kb penalty
to data serialization and has negative implications for composability.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additionally, depending on the design of the entrypoint a program must also find the instruction account of the sysvar, but that will be fixed by SIMD-0449.

10kb penalty to data serialization

That part will be gone after direct mapping and the CU charging adjustments of SIMD-0452, which I still have to rewrite.

negative implications for composability

I think that is the remaining actual downside of sysvar accounts: They waste key space in the instruction invocation.


If these globals were simply exposed to the VM, as is common in kernel BPF,
and resolved JIT, we could dramatically improve developer experience, whilst
also reducing the runtime overhead of accessing them to just 2 CUs. This is
generalizable to all Sysvars, however the majority of gains are realized by
simply implementing `Rent` and `Clock`.

## New Terminology

Static Sysvars - A static global variable pointing to current sysvar values,
accessible within the VM by a pointer to its murmur hash code resolved during
JIT compilation.

## Detailed Design

As with static syscalls, we define the hash code for a sysvar as the murmur32
hash of its respective name:

```rust
// murmur3(SOL_RENT_SYSVAR) = 0x494df715
const SOL_RENT_SYSVAR: *const u8 = 0x494df715u64 as *const u8;
// murmur3(SOL_CLOCK_SYSVAR) = 0xff395088
const SOL_CLOCK_SYSVAR: *const u8 = 0xff395088u64 as *const u8;
```

We cast this value to a pointer, which is then consumed in a program:

```rust
let lamports_per_byte: u64 = unsafe { *(SOL_RENT_SYSVAR as *const u64) };
```

This produces the following bytecode:

```asm
lddw r3, 0x494df715 // SOL_RENT_SYSVAR
ldxdw r3, [r3+0]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would benefit from explaining that sysvars are mapped in as byte slices starting at the murmur hash as address. Otherwise it invites the interpretation that all sysvars are supposed to be accessed via a single u64 value, which would limit them to 8 bytes.

```

In this case, the murmur hash value of `0x494df715` is then resolved JIT to a
memory address containing the current `Rent` sysvar value. The same applies to
other sysvar accounts, such as the murmur hash of `0xff395088` for `Clock`.

Ergo, we can safely and performantly expose any available global variable to
the VM without the overhead of additonal account loads or syscall invocation.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, this thinks about the JIT only, which is not protocol, it is one possible implementation. What about an interpreter? It would have to do this in address translation on every memory access.

Also, while maybe not that impactful, it would also make the JIT implementation more complex and thus compilation slower as this is a form of macro-op fusion which requires state to be tracked between the instructions. Currently we can compile every instruction independently.


## Alternatives Considered

- Leverage JIT intrinsics to provide similar syscall functionality.
- Don't improve the existing design of sysvars/syscalls.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Think taking another look at solving this problem using sysvar accounts is worthwhile. The gap to bridge there might be relatively small (see https://github.com/solana-foundation/solana-improvement-documents/pull/503/changes#r3002020193).


## Impact

1. Improved program composability
2. Fewer stack allocations
3. Reduced complexity of calculating rent exemption
4. Reduced cost of resolving sysvar values to 2 CUs

## Security Considerations

1. We must ensure no intra-slot mutability of any exposed globals.
2. We must ensure static sysvar pointers remain synchronized with SysvarCache
at the slot boundary.
3. Despite being 32-bit hashes, it is important that we cast to u64 first as
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternatively one could also only use the 31 LSBs of the hash / mask out the 1 MSB and always load a i32 immediate value.

50% of 32-bit murmur hashes sign extend to negative 64-bit addresses. If
our toolchain reliably generated `mov32` without requiring inline assembly,
this would be more ideal, as it would save 8 bytes of binary size.

## Backwards Compatibility

This feature is a breaking change that will require feature-gated activation.
Realizing the performance benefits of static sysvars will require adoption by
all relevant programs and SDKs. All existing Syscall/Sysvar APIs will continue
to function as normal.
Loading