> subsystem-summary-of-rust
read this skill for a token-efficient summary of the rust subsystem
curl "https://skillshub.wtf/stellar/stellar-core/subsystem-summary-of-rust?format=md"Rust Subsystem (Non-Soroban) — Technical Summary
Overview
The rust subsystem provides a Rust static library (rust_stellar_core) that is linked into the stellar-core C++ binary. It uses the cxx crate (v1.0.97) to define a bidirectional FFI bridge between C++ and Rust. The subsystem's primary responsibilities are:
- Soroban host function invocation — dispatching to the correct protocol-versioned soroban host.
- Fee computation — transaction resource fees, rent fees, and rent write fees.
- Module caching — pre-compiled WASM module cache for Soroban contracts.
- 128-bit integer arithmetic — exposing Rust's native
i128to C++. - Base64 encoding/decoding — used for XDR serialization interop.
- Ed25519 signature verification — using
ed25519-dalekfor faster verification. - Logging bridge — routing Rust
logcrate output to the C++ spdlog system. - Quorum intersection checking — using the
stellar-quorum-analyzerSAT solver. - Utility functions — rustc version, executable path, backtrace capture, XDR version checks.
The crate is built as crate-type = ["staticlib"] (edition 2021, rust-version 1.82.0). Optional features include tracy (profiling), next (pre-release protocol), testutils (test-only code), and unified (IDE-friendly single cargo build).
File Layout
| File | Role |
|---|---|
Cargo.toml | Crate metadata, multi-host soroban dependencies, feature flags |
src/lib.rs | Crate root; declares modules, re-exports bridge symbols, defines tracy_span! macro |
src/bridge.rs | #[cxx::bridge] module — all FFI type/function declarations |
src/common.rs | RustBuf/CxxBuf/BridgeError impls; get_rustc_version, current_exe, capture_cxx_backtrace, check_xdr_version_identities |
src/b64.rs | to_base64 / from_base64 |
src/ed25519_verify.rs | verify_ed25519_signature_dalek (unsafe raw-pointer FFI) |
src/i128.rs | i128_add, i128_sub, overflow/underflow checks, conversion |
src/log.rs | StellarLogger implementing log::Log, routes to C++ spdlog |
src/quorum_checker.rs | network_enjoys_quorum_intersection wrapping stellar-quorum-analyzer |
src/soroban_invoke.rs | invoke_host_function, fee computation, transaction parsing dispatchers |
src/soroban_module_cache.rs | SorobanModuleCache struct; per-protocol caches |
src/soroban_proto_all.rs | Protocol-versioned host modules (p21–p26), dispatch table, adaptors |
src/soroban_proto_any.rs | Protocol-agnostic host invocation code, mounted inside each pN module |
CppShims.h | Thin C++ shim functions (shim_isLogLevelAtLeast, shim_logAtPartitionAndLevel) |
RustBridge.h | cxx-generated C++ header with all bridge types and function declarations |
RustBridge.cpp | cxx-generated C++ implementation (extern "C" thunks, Vec/Box specializations) |
RustVecXdrMarshal.h | Declares rust::Vec<uint8_t> as valid xdrpp byte buffer type |
The CXX Bridge Mechanism
How it works
The bridge is defined in src/bridge.rs inside a #[cxx::bridge] attribute macro on mod rust_bridge. This module contains three sections:
-
Shared types — structs and enums visible to both sides, defined once:
CxxBuf(C++→Rust data: wrapsUniquePtr<CxxVector<u8>>)RustBuf(Rust→C++ data: wrapsVec<u8>)XDRFileHash,InvokeHostFunctionOutput,CxxLedgerInfo,CxxTransactionResources,CxxFeeConfiguration,CxxLedgerEntryRentChange,CxxRentFeeConfiguration,CxxRentWriteFeeConfiguration,CxxI128,FeePair,SorobanVersionInfo- Enums:
LogLevel(shared withstellar::LogLevel),BridgeError,QuorumCheckerStatus QuorumSplit,QuorumCheckerResource
-
extern "Rust"block (#[namespace = "stellar::rust_bridge"]) — Rust functions callable from C++:- All functions listed in the "Key Functions" section below.
- The opaque type
SorobanModuleCachewith its methods.
-
extern "C++"block (#[namespace = "stellar"]) — C++ functions callable from Rust:shim_isLogLevelAtLeast(partition: &CxxString, level: LogLevel) -> Result<bool>shim_logAtPartitionAndLevel(partition: &CxxString, level: LogLevel, msg: &CxxString) -> Result<()>
Data passing convention
- C++ → Rust: Data is passed as
CxxBufcontainingUniquePtr<CxxVector<u8>>(a C++-allocatedstd::vector<uint8_t>). The Rust side reads from it viadata.as_slice(). - Rust → C++: Data is returned as
RustBufcontainingVec<u8>(Rust-allocated). The C++ side reads fromdata(arust::Vec<uint8_t>). - XDR serialization/deserialization is done with
ReadXdr/WriteXdrusingnon_metered_xdr_from_cxx_bufandnon_metered_xdr_to_rust_bufhelper functions with a depth limit of 1000 and length limit matching the buffer size. RustVecXdrMarshal.hallows xdrpp to directly unmarshal fromrust::Vec<uint8_t>.
Generated files
RustBridge.h and RustBridge.cpp are generated by the cxxbridge tool. They contain:
- Full implementations of
rust::String,rust::Slice<T>,rust::Box<T>,rust::Vec<T>,rust::Opaque,rust::Error. - C struct definitions mirroring the shared types.
static_assertchecks ensuringLogLevelenum values match between C++ and Rust.extern "C"function declarations for the mangled bridge symbols.- C++ wrapper functions in
namespace stellar::rust_bridgethat call through extern "C" thunks and translate Rust errors to C++ exceptions (rust::Error). - Template specializations for
rust::Vec<RustBuf>,rust::Vec<XDRFileHash>,rust::Vec<CxxBuf>, etc. rust::Box<SorobanModuleCache>alloc/dealloc/drop specializations.
CppShims.h
Provides simple inline wrapper functions that cxx.rs can call, bridging to C++ APIs that are too complex for cxx to handle directly (e.g., static member functions):
shim_isLogLevelAtLeast→Logging::isLogLevelAtLeastshim_logAtPartitionAndLevel→Logging::logAtPartitionAndLevel
Key Data Structures
CxxBuf / RustBuf
Directional byte-buffer wrappers for passing XDR-serialized data across the FFI boundary. CxxBuf owns a std::unique_ptr<std::vector<uint8_t>> (C++ allocated). RustBuf owns a Vec<u8> (Rust allocated). Both implement AsRef<[u8]>.
CxxI128
Split representation of 128-bit integer: { hi: i64, lo: u64 }. Used because C++ lacks native i128 on all platforms. Converted to/from Rust i128 via int128_helpers::{i128_from_pieces, i128_hi, i128_lo}.
InvokeHostFunctionOutput
Return value of invoke_host_function. Contains:
success: bool,is_internal_error: booldiagnostic_events: Vec<RustBuf>(XDR-encodedDiagnosticEvent)cpu_insns,mem_bytes,time_nsecs(and excluding-VM-instantiation variants)result_value: RustBuf,contract_events: Vec<RustBuf>,modified_ledger_entries: Vec<RustBuf>,rent_fee: i64
SorobanModuleCache
An opaque Rust type exposed to C++ via rust::Box<SorobanModuleCache>. Holds per-protocol ProtocolSpecificModuleCache instances (p23, p24, p25, and optionally p26 with next feature). Each ProtocolSpecificModuleCache contains a ModuleCache (from soroban-env-host, threadsafe via internal locking) and an AtomicU64 tracking memory consumption. Methods:
compile(&mut self, ledger_protocol: u32, wasm: &[u8])— parse and cache a WASM module for the given protocol.shallow_clone(&self) -> Box<SorobanModuleCache>— clone shared ownership handles for multithreaded compilation.evict_contract_code(&mut self, key: &[u8])— remove a module from all protocol caches by 32-byte hash.clear(&mut self)— clear all protocol caches.contains_module(&self, protocol: u32, key: &[u8]) -> boolget_mem_bytes_consumed(&self, protocol: u32) -> u64
HostModule
A dispatch table struct (not crossing FFI) containing function pointers for a specific protocol version's soroban host. Fields include max_proto, invoke_host_function, compute_transaction_resource_fee, compute_rent_fee, compute_rent_write_fee_per_1kb, contract_code_memory_size_for_rent, can_parse_transaction, and get_soroban_version_info. The static array HOST_MODULES holds one entry per protocol version (p21–p25/p26), populated via the proto_versioned_functions_for_module! macro.
ProtocolSpecificModuleCache
Per-protocol cache wrapper (defined in soroban_proto_any.rs). Wraps a ModuleCache from the protocol's soroban-env-host and a CoreCompilationContext (unlimited budget for compilation). Supports compile, evict, clear, contains_module, get_mem_bytes_consumed, and shallow_clone.
CoreCompilationContext
Implements CompilationContext (= ErrorHandler + AsBudget) with an unlimited budget, used for compiling WASM modules outside of transaction execution.
Key Functions (Exported Rust → C++)
Soroban Host Invocation
invoke_host_function(config_max_protocol: u32, enable_diagnostics: bool, instruction_limit: u32, hf_buf: &CxxBuf, resources: CxxBuf, restored_rw_entry_indices: &Vec<u32>, source_account: &CxxBuf, auth_entries: &Vec<CxxBuf>, ledger_info: CxxLedgerInfo, ledger_entries: &Vec<CxxBuf>, ttl_entries: &Vec<CxxBuf>, base_prng_seed: &CxxBuf, rent_fee_configuration: CxxRentFeeConfiguration, module_cache: &SorobanModuleCache) -> Result<InvokeHostFunctionOutput>— Dispatches to the correct protocol-versioned host viaget_host_module_for_protocol. Wraps the call inpanic::catch_unwind.
Fee Computation
compute_transaction_resource_fee(config_max_protocol: u32, protocol_version: u32, tx_resources: CxxTransactionResources, fee_config: CxxFeeConfiguration) -> Result<FeePair>— Returns(non_refundable_fee, refundable_fee).compute_rent_fee(config_max_protocol: u32, protocol_version: u32, changed_entries: &Vec<CxxLedgerEntryRentChange>, fee_config: CxxRentFeeConfiguration, current_ledger_seq: u32) -> Result<i64>compute_rent_write_fee_per_1kb(config_max_protocol: u32, protocol_version: u32, bucket_list_size: i64, fee_config: CxxRentWriteFeeConfiguration) -> Result<i64>contract_code_memory_size_for_rent(config_max_protocol: u32, protocol_version: u32, contract_code_entry: &CxxBuf, cpu_cost_params: &CxxBuf, mem_cost_params: &CxxBuf) -> Result<u32>— Only valid for protocol ≥ 23.
Transaction Parsing
can_parse_transaction(config_max_protocol: u32, protocol_version: u32, xdr: &CxxBuf, depth_limit: u32) -> Result<bool>— Checks if aTransactionEnvelopeXDR can be deserialized in the given protocol.
128-bit Integer Arithmetic
i128_add(lhs: &CxxI128, rhs: &CxxI128) -> Result<CxxI128>i128_sub(lhs: &CxxI128, rhs: &CxxI128) -> Result<CxxI128>i128_add_will_overflow(lhs: &CxxI128, rhs: &CxxI128) -> Result<bool>i128_sub_will_underflow(lhs: &CxxI128, rhs: &CxxI128) -> Result<bool>i128_from_i64(val: i64) -> Result<CxxI128>i128_is_negative(val: &CxxI128) -> Result<bool>i128_i64_eq(lhs: &CxxI128, rhs: i64) -> Result<bool>
Ed25519 Verification
verify_ed25519_signature_dalek(public_key_ptr: *const u8, signature_ptr: *const u8, message_ptr: *const u8, message_len: usize) -> bool— Unsafe raw-pointer interface. Usesed25519-dalek'sverify_strict(rejects small-order points, matching libsodium). Never panics; returns false for invalid input.
Base64
to_base64(b: &CxxVector<u8>, s: Pin<&mut CxxString>)— Encode bytes to base64.from_base64(s: &CxxString, b: Pin<&mut CxxVector<u8>>)— Decode base64 with error-tolerant stripping of invalid characters.
Logging
init_logging(maxLevel: LogLevel) -> Result<()>— Initializes theStellarLoggeras the global Rust logger, routing to C++ spdlog. UsesAtomicBoolfor one-time initialization. Log partitions (e.g.,TX,Ledger,SCP) are defined inlog::partitionand must matchutil/LogPartitions.defon the C++ side.
Quorum Checker
network_enjoys_quorum_intersection(nodes: &Vec<CxxBuf>, quorum_set: &Vec<CxxBuf>, potential_split: &mut QuorumSplit, resource_limit: &QuorumCheckerResource, resource_usage: &mut QuorumCheckerResource) -> Result<QuorumCheckerStatus>— ReturnsUNSAT(quorum intersection holds),SAT(split found, populatespotential_split), orUNKNOWN. Time limit enforced internally; memory limit is a hard abort via global allocator.
Module Cache
new_module_cache() -> Result<Box<SorobanModuleCache>>- Methods on
SorobanModuleCache:compile,shallow_clone,evict_contract_code,clear,contains_module,get_mem_bytes_consumed.
Utility
get_rustc_version() -> Stringcurrent_exe() -> Result<String>capture_cxx_backtrace() -> String— Usesbacktracecrate; filters out initial Rust frames and libc frames.get_soroban_version_info(core_max_proto: u32) -> Vec<SorobanVersionInfo>— Returns version info for all linked soroban hosts. Panics if no host supports the given protocol.check_sensible_soroban_config_for_protocol(core_max_proto: u32)— Validates HOST_MODULES are in ascending order and cover the max protocol.check_xdr_version_identities() -> Result<()>— Compares XDR file SHA256 hashes across crates.
Multi-Protocol Soroban Host Architecture
Design
stellar-core links multiple versions of soroban-env-host simultaneously, one per protocol version range. Each is labeled by its maximum supported protocol (e.g., soroban-env-host-p21 supports protocols up to 21). At runtime, get_host_module_for_protocol(config_max_proto, ledger_protocol) selects the appropriate host.
Implementation pattern
soroban_proto_all.rs defines adaptor modules p21, p22, p23, p24, p25, and conditionally p26 (behind next feature). Each adaptor:
- Imports its specific
soroban_env_host_pNNcrate and re-exports it assoroban_env_host. - Provides adapter functions for API differences between host versions (e.g., different field names in
TransactionResources,RentFeeConfiguration). - Mounts
soroban_proto_any.rsas a child module — this file is the same source but "sees" a differentsuper::soroban_env_hostin each context. - Defines stub types (
ModuleCache,ErrorHandler,CompilationContext) for older protocols (p21, p22) that don't support the reusable module cache API.
Protocol dispatch
The HOST_MODULES static array maps protocol ranges to HostModule structs containing function pointers. get_host_module_for_protocol iterates this array: each entry's implied minimum protocol is one more than the previous entry's max_proto (first entry starts at 0).
Aliases
soroban_curr— alias for the latest non-next host (p25, or p26 withnext).protocol_agnostic— re-exports from p24 that are stable across versions (e.g.,int128_helpers,make_error).
Key Data Flows
C++ → Soroban Invocation → C++
- C++ constructs
CxxBufobjects containing XDR-serialized data (host function, resources, ledger entries, etc.) and aCxxLedgerInfo. - Calls
stellar::rust_bridge::invoke_host_function(...)which crosses the FFI boundary. - Rust dispatches to the correct
HostModulebased on(config_max_protocol, ledger_info.protocol_version). - The protocol-specific
invoke_host_functioninsoroban_proto_any.rsdeserializes XDR, creates aBudget, optional trace hook, and calls through tosoroban_env_host::e2e_invoke::invoke_host_function. - Results are re-serialized to
RustBufvectors and returned asInvokeHostFunctionOutput. - The C++ wrapper in
RustBridge.cppunwraps the result or throwsrust::Erroron failure.
Logging (Rust → C++)
- Rust code calls
log::info!()etc. StellarLogger::log()converts the level and callsshim_logAtPartitionAndLevelvia the extern "C++" bridge.- The shim calls
Logging::logAtPartitionAndLevelin C++.
Module Cache Lifecycle
- C++ calls
new_module_cache()to get arust::Box<SorobanModuleCache>. - Calls
compile(protocol, wasm_bytes)to cache WASM modules (typically on startup and during catchup). - The cache is passed by reference to
invoke_host_function. shallow_clone()creates shared-ownership handles for multithreaded use.evict_contract_code(key)removes entries;clear()empties all caches.
Error Handling
- All fallible Rust functions return
Result<T, Box<dyn std::error::Error>>(orResult<T, HostError>). - cxx converts Rust
Errreturns into C++rust::Errorexceptions. invoke_host_functionandnetwork_enjoys_quorum_intersectionadditionally wrap their core logic inpanic::catch_unwindto convert Rust panics into errors rather than unwinding across the FFI boundary.- The quorum checker's memory limit is a hard abort (non-catchable) by design.
CoreHostErrorenum wraps either aHostErrorfrom soroban or a generalStringmessage.
Dependencies
| Crate | Purpose |
|---|---|
cxx 1.0.97 | C++/Rust FFI bridge framework |
base64 0.13.1 | Base64 encode/decode |
log 0.4.19 | Rust logging facade |
ed25519-dalek 2.1.1 | Ed25519 signature verification |
itertools 0.10.5 | Iterator utilities |
backtrace 0.3.76 | C++ backtrace capture (with cpp_demangle) |
rand 0.8.5 | RNG (must match soroban's version) |
rustc-simple-version 0.1.0 | Compile-time rustc version string |
tracy-client 0.17.0 | Tracy profiling (optional) |
stellar-quorum-analyzer | SAT-based quorum intersection checking |
soroban-env-host-pNN | Protocol-specific Soroban hosts (p21–p26) |
soroban-test-wasms | Pre-compiled test WASM binaries |
soroban-synth-wasm | Random WASM generation for testing |
Build Notes
- The default build does not use the optional
soroban-env-host-pNNdeps from Cargo.toml. Instead, each host is built as a separate cargo invocation and linked in (seesrc/Makefile.am). This avoids Cargo's dependency unification. - The
unifiedfeature enables all hosts as direct dependencies for IDE usage. This perturbsCargo.lock— changes should not be committed. - Tracy feature flags must match between the Rust crate and the C++
lib/tracysubmodule version.
> related_skills --same-repo
> validating-a-change
comprehensive validation of a change to ensure it is correct and ready for a pull request
> regenerating a technical summary of stellar-core
Instructions for regenerating the full set of subsystem and whole-system technical summary skill documents for stellar-core
> subsystem-summary-of-work
read this skill for a token-efficient summary of the work subsystem
> subsystem-summary-of-util
read this skill for a token-efficient summary of the util subsystem