Skip to content
Merged
Show file tree
Hide file tree
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
5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ v0.2. Live ingest is v1, proven on devnet, not yet mainnet-scale.

Backfill has replayed a full snapshot-to-snapshot mainnet window, 50,079 slots, verified two independent ways: every slot's bank hash checked against the consensus hash carried in that block's own vote transactions, and the end state diffed byte-for-byte against the official snapshot at the end of the range, 8,412,739 accounts with zero mismatches.

That run is epoch 808. Other epochs need the feature gating in [Roadmap](#roadmap) first, since builtin registration and precompiles currently assume the feature set at that floor. Fidelity has a tail still being closed, so the replay records coverage up to the last verified slot and never guesses.
That run is epoch 808, the only range verified so far. Builtin registration and precompile verification key off the per-slot feature set the replay builds from the on-chain feature accounts, so a range elsewhere in history gets the programs that actually existed at those slots, as long as it stays inside one epoch (see [Roadmap](#roadmap)). Fidelity has a tail still being closed, so the replay records coverage up to the last verified slot and never guesses.

## How it works

Expand Down Expand Up @@ -229,9 +229,8 @@ cargo test --workspace -- --test-threads=1

## Roadmap

- **Feature gating for other epochs.** Builtin registration and precompile verification currently assume the feature set at the epoch-808 floor, so an earlier range would use programs that weren't active yet. Gate them on the per-slot feature set the replay already builds.
- **Backfill fidelity.** Close the remaining tail of historical transactions the replay can't yet reproduce, a class at a time.
- **Multi-epoch backfill.** Span successive snapshot windows to reconstruct a whole epoch and beyond.
- **Multi-epoch backfill.** Span successive snapshot windows to reconstruct a whole epoch and beyond. A range has to stay inside one epoch for now: the feature set is built once from the range's first slot, and features activate on epoch boundaries, so a range that crosses one would replay its tail against the previous epoch's set.
- **Gap repair.** Heal recorded coverage holes from incremental snapshots while they're still in retention.
- **Durable source.** Ingest from a replayable stream (Triton's Fumarole, Helius's LaserStream, and the like), so a reconnect rewinds and most gaps heal on their own.
- **asOfTime.** Query by timestamp, not just slot.
Expand Down
79 changes: 79 additions & 0 deletions slate-replay/examples/check_gated_features.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// One-shot: is the feature-gating change actually a no-op at the verified epoch-808 window?
// Reads the real seeded store and reports the activation state of every gated builtin/precompile.
// Usage: cargo run --release --example check_gated_features -- <accounts.redb> <slot>
use slate_replay::{ReplayBank, build_feature_set, store::DiskStore};

fn main() -> anyhow::Result<()> {
let mut args = std::env::args().skip(1);
let path = args.next().expect("usage: <accounts.redb> <slot>");
let slot: u64 = args
.next()
.expect("usage: <accounts.redb> <slot>")
.parse()?;

let store = DiskStore::create(&path, 1 << 30)?;
let bank = ReplayBank::with_store(Box::new(store));
let feature_set = build_feature_set(&bank, slot);

println!("store {path}\nslot {slot}\n");

println!("gated BUILTINS (solana_builtins::BUILTINS):");
for b in solana_builtins::BUILTINS {
if let Some(fid) = b.enable_feature_id {
let active = feature_set.is_active(&fid);
println!(
" {:<22} {:<7} feature {fid}",
b.name,
if active { "ACTIVE" } else { "INACTIVE" }
);
}
}

println!("\ngated PRECOMPILE:");
let r1 = agave_feature_set::enable_secp256r1_precompile::id();
println!(
" secp256r1 {:<7} feature {r1}",
if feature_set.is_active(&r1) {
"ACTIVE"
} else {
"INACTIVE"
}
);

let ed = agave_feature_set::ed25519_precompile_verify_strict::id();
println!(
" ed25519 verify_strict {:<7} feature {ed}",
if feature_set.is_active(&ed) {
"ACTIVE"
} else {
"INACTIVE"
}
);

// add_builtin only stubs an account when the store lacks one, so store presence decides whether
// registering an inactive builtin wrote phantom state or merely populated the program cache.
println!("\nprogram account present in the seeded store?");
for b in solana_builtins::BUILTINS {
if b.enable_feature_id.is_some() {
let present = bank.store().get(&b.program_id).is_some();
println!(
" {:<24} {}",
b.name,
if present {
"PRESENT (no stub written)"
} else {
"ABSENT (old code stubbed it)"
}
);
}
}

println!(
"\ntotal active features: {}",
agave_feature_set::FEATURE_NAMES
.keys()
.filter(|id| feature_set.is_active(id))
.count()
);
Ok(())
}
4 changes: 3 additions & 1 deletion slate-replay/src/backfill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,10 @@ pub async fn backfill(
let result = if let Some(&first_slot) = replay_slots.first() {
let epoch = first_slot / 432_000;
let feature_set = build_feature_set(&bank, first_slot);
// The bank needs its own copy: the SVM reaches the precompile callbacks through the bank, not the replayer.
bank.set_feature_set(feature_set.clone());
let replayer = Replayer::new_with_feature_set(first_slot, epoch, feature_set);
register_builtins(&mut bank, &replayer.processor);
register_builtins(&mut bank, &replayer.processor, replayer.feature_set());
// Compat: re-supply native builtins agave deleted post core-BPF migration (e.g. Stake), gated per feature so it's a no-op once active.
compat::register_removed_builtins(&mut bank, &replayer.processor, replayer.feature_set());

Expand Down
Loading
Loading