Skip to main content

RpcSnapshotSource

Struct RpcSnapshotSource 

Source
pub struct RpcSnapshotSource { /* private fields */ }
Expand description

A SnapshotSource backed by a Soroban RPC + local cache.

Cache semantics:

  • Some(Some(entry)) → we’ve seen it, entry exists.
  • Some(None) → we’ve asked, RPC said the entry doesn’t exist. Negative cache — stops us re-asking for keys we know are absent.
  • None → we haven’t asked yet.

Thread-safety: this type is Send + Sync. Wrap it in Arc to share across threads — for example, between a future RPC-server worker pool and the Env instances handed to each request. The SDK’s SnapshotSource trait still expects an Rc at its boundary, so a fresh Rc<LedgerEntry> is built per get call from cached bytes; the Rc never escapes its caller’s thread.

Implementations§

Source§

impl RpcSnapshotSource

Source

pub fn new(client: Arc<RpcClient>) -> Self

Wrap the given RPC client. Arc so the source can be cloned cheaply and shared with other harnesses (e.g. a pre-warmer).

Source

pub fn with_fetch_mode(self, mode: FetchMode) -> Self

Set the fetch mode. Builder-style — consumes self and returns it.

Source

pub fn preload( &self, entries: impl IntoIterator<Item = (LedgerKey, LedgerEntry, Option<u32>)>, )

Pre-populate the cache from a snapshot file. Entries loaded this way do not count towards fetch_count.

Source

pub fn fetch_count(&self) -> u32

How many RPC fetches this source has attempted since creation (counts both successful and failed attempts — the counter increments before the network call, so a connect timeout still shows up here). Useful for asserting cache hit-rates in tests.

Source

pub fn set_entry( &self, key: LedgerKey, entry: LedgerEntry, live_until: Option<u32>, )

Force-write a single LedgerEntry into the cache, replacing whatever was there (or creating a fresh entry if the key was absent). Powers the JSON-RPC fork_setLedgerEntry extension — clients hand us an XDR-encoded entry, we trust them and install it. Subsequent reads (including via the host’s recording-mode storage in simulateTransaction / sendTransaction) see the new entry.

Stellar’s storage model maps every piece of network state to one LedgerEntry per key, so this single primitive covers every flavor of fork-mode state mutation: oracle-price rewrites (a ContractData entry), token balance overrides (a Trustline or ContractData entry), contract code replacement (a ContractCode entry). Higher-level wrappers (setBalance, setCode, etc.) compose on top.

live_until carries forward an optional TTL hint — pass None for entries that don’t have one (Account, Trustline) or when the test doesn’t care about expiry.

Source

pub fn bump_account_seq(&self, account_id: &AccountId) -> Option<i64>

Bump the seq_num of an Account ledger entry that’s already in the cache. Returns the new sequence on success, None if the account isn’t cached or the cached entry isn’t an AccountEntry (so the caller can decide whether absence is an error or just “first send from a never-touched account”).

Stellar’s transaction validation expects tx.seq_num == account.seq_num + 1 and post-success leaves the account at tx.seq_num. The fork’s trust mode skips the pre-check but still must increment so the next envelope a JS-SDK client builds (via getAccounttx.seq_num + 1) lines up with what the host expects.

Source

pub fn apply_changes<I>(&self, changes: I) -> u32

Apply a batch of LedgerEntryChanges back to the cache so that subsequent reads see the writes. Powers the JSON-RPC server’s sendTransaction — recording-mode invocation gives us a list of changes; we walk them and update the cached bytes.

Semantics per change:

  • read_only == true → ignored. The host won’t have produced a new_value and TTL bumps don’t change entry contents.
  • encoded_new_value == Some(bytes) → overwrite the cached entry. Existing live-until is kept (TTL changes are tracked separately by the host but not yet plumbed here).
  • encoded_new_value == None (read-write) → entry was removed; flip the cache to the negative-cache None marker so subsequent gets see absence locally without re-asking upstream RPC.

key and entry decode panics in this method are the same “structural bug, not recoverable” class as elsewhere in this file: bytes came directly from the host that just produced them, so a decode failure means the host violated its own XDR-shape invariant.

Source

pub fn entries(&self) -> Vec<(LedgerKey, LedgerEntry, Option<u32>)>

Export the cache for persistence. Negative-cache entries (confirmed missing) are intentionally omitted — they aren’t useful across processes and bloat the on-disk snapshot.

The decode step runs outside the cache lock: we snapshot raw bytes under the lock, release it, then parse. With a 10k-entry fork this avoids blocking concurrent get and fetch calls for the duration of a few-ms parse loop.

Trait Implementations§

Source§

impl SnapshotSource for RpcSnapshotSource

Source§

fn get( &self, key: &Rc<LedgerKey>, ) -> Result<Option<EntryWithLiveUntil>, HostError>

Returns the ledger entry for the key and its live_until ledger if entry exists, or None otherwise.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T, C> Compare<&T> for C
where C: Compare<T>,

Source§

type Error = <C as Compare<T>>::Error

Source§

fn compare(&self, a: &&T, b: &&T) -> Result<Ordering, <C as Compare<&T>>::Error>

Source§

impl<T, U, E, C> Compare<(T, U)> for C
where C: Compare<T, Error = E, Error = E> + Compare<U>,

Source§

type Error = E

Source§

fn compare( &self, a: &(T, U), b: &(T, U), ) -> Result<Ordering, <C as Compare<(T, U)>>::Error>

Source§

impl<T, U, V, E, C> Compare<(T, U, V)> for C
where C: Compare<T, Error = E, Error = E, Error = E> + Compare<U> + Compare<V>,

Source§

impl<T, U, V, W, E, C> Compare<(T, U, V, W)> for C
where C: Compare<T, Error = E, Error = E, Error = E, Error = E> + Compare<U> + Compare<V> + Compare<W>,

Source§

impl<T, U, V, W, X, E, C> Compare<(T, U, V, W, X)> for C
where C: Compare<T, Error = E, Error = E, Error = E, Error = E, Error = E> + Compare<U> + Compare<V> + Compare<W> + Compare<X>,

Source§

impl<T, C> Compare<Box<T>> for C
where C: Compare<T>,

Source§

type Error = <C as Compare<T>>::Error

Source§

fn compare( &self, a: &Box<T>, b: &Box<T>, ) -> Result<Ordering, <C as Compare<Box<T>>>::Error>

Source§

impl<T, C> Compare<Option<T>> for C
where C: Compare<T>,

Source§

type Error = <C as Compare<T>>::Error

Source§

fn compare( &self, a: &Option<T>, b: &Option<T>, ) -> Result<Ordering, <C as Compare<Option<T>>>::Error>

Source§

impl<T, C> Compare<Rc<T>> for C
where C: Compare<T>,

Source§

type Error = <C as Compare<T>>::Error

Source§

fn compare( &self, a: &Rc<T>, b: &Rc<T>, ) -> Result<Ordering, <C as Compare<Rc<T>>>::Error>

Source§

impl<T, C> Compare<Vec<T>> for C
where C: Compare<T>,

Source§

type Error = <C as Compare<T>>::Error

Source§

fn compare( &self, a: &Vec<T>, b: &Vec<T>, ) -> Result<Ordering, <C as Compare<Vec<T>>>::Error>

Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Convert Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
Source§

fn as_any(&self) -> &(dyn Any + 'static)

Convert &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
Source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<T> DowncastSync for T
where T: Any + Send + Sync,

Source§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Convert Arc<Trait> (where Trait: Downcast) to Arc<Any>. Arc<Any> can then be further downcast into Arc<ConcreteType> where ConcreteType implements Trait.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<E, T, U> IntoVal<E, T> for U
where E: Env, T: FromVal<E, U>,

Source§

fn into_val(&self, e: &E) -> T

Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<E, T, U> TryIntoVal<E, T> for U
where E: Env, T: TryFromVal<E, U>,

Source§

type Error = <T as TryFromVal<E, U>>::Error

Source§

fn try_into_val(&self, env: &E) -> Result<T, <U as TryIntoVal<E, T>>::Error>

Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more