Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
48448fd
types: centralize light client store keys
May 12, 2026
62cdaf3
store: add speculative transaction overlays
May 12, 2026
e19a38e
enclave-api: add speculative command support
May 12, 2026
478f836
proto: add speculative update client stream RPC
May 12, 2026
3823fdc
service: add speculative update client execution
May 12, 2026
deb1db3
app: configure speculative service concurrency
May 12, 2026
4c395d8
Fix speculative service formatting
May 12, 2026
daad0e5
service: bound resident speculative headers
May 14, 2026
3eaae1b
service: defer speculative header digest
May 14, 2026
98ca960
Reject incomplete non-leading speculative base states
May 22, 2026
9de88e3
Require complete speculative base states
May 22, 2026
6885c75
Require seeded speculative base state
May 22, 2026
d2ae4dc
Serialize update client with speculative batches
May 29, 2026
0ab323d
Return effective speculative write sets
May 29, 2026
dee0da3
Return errors for incomplete speculative base state
May 29, 2026
9281dc5
Clarify speculative stream failure handling
May 29, 2026
e989df8
Verify canonical base before speculative stitch
May 29, 2026
9d6ea21
Simplify enclave concurrency constructors
Jun 1, 2026
b242ae0
Use serial ECALLs for CLI enclave loads
Jun 1, 2026
b83750a
Make enclave concurrency explicit
Jun 1, 2026
30a0619
Move client update lock to ELC service
Jun 1, 2026
be397ef
Run serial update clients on blocking pool
Jun 1, 2026
ccf38b8
Clear speculative headers before releasing budget
Jun 2, 2026
0e1df3d
Reject empty speculative consensus state type
Jun 2, 2026
8ad0186
Preserve first speculative scheduler failure
Jun 2, 2026
8f3acd3
service: validate speculative base by stored height
Jun 5, 2026
6142089
service: validate speculative base by stored state id
Jun 5, 2026
bfe621d
service: store light-client state id on init
Jun 8, 2026
55ae241
Verify speculative base client state
Jun 9, 2026
4f49954
Add idle timeout to speculative stream
Jun 9, 2026
b46a2eb
Align memstore speculative write extraction
Jun 9, 2026
a7673df
Reject stale speculative base client state
Jun 9, 2026
d9425c4
Prevent partial speculative stream commits
Jun 10, 2026
485e348
Tighten speculative stream resource handling
Jun 10, 2026
0630ad2
service: pin gRPC ECALL dispatch to a fixed-size worker pool
Jun 11, 2026
c6593ab
service: route speculative ECALLs through EcallPool
Jun 11, 2026
56fcda1
enclave-api: remove ECallGate (single source of truth is EcallPool)
Jun 11, 2026
4a3c459
enclave-api: verify speculative base against stored state_id only
Jun 11, 2026
a187699
fmt: apply cargo fmt to pre-existing formatting drift
Jun 12, 2026
9189c57
service: box streaming speculative batch input unit to satisfy clippy
Jun 12, 2026
9aa6643
service: prevent speculative stream hang on ECALL worker panic
Jun 12, 2026
586d6f5
service: recover per-client update lock from poisoning
Jun 12, 2026
813465c
service: time out speculative header memory reservation waits
Jun 12, 2026
a3b76bc
enclave-api: report missing stored state_id distinctly from mismatch
Jun 12, 2026
5b7f330
service: document speculative base binding scope for non-first units
Jun 12, 2026
c6fa4ce
enclave-api: drop inappropriate bincode checks from speculative base …
Jun 15, 2026
c437e30
enclave-api: tighten verify_expected_base_state_in_tx comments
Jun 16, 2026
c441ed7
service: raise speculative batch stream idle timeout to 300s
Jun 17, 2026
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
9 changes: 8 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions app/src/commands/elc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::{
use anyhow::Result;
use clap::Parser;
use enclave_api::{Enclave, EnclaveProtoAPI};
use host::store::transaction::CommitStore;
use host::store::transaction::{CommitStore, TxAccessor};
use serde::de::DeserializeOwned;
use std::path::PathBuf;

Expand Down Expand Up @@ -47,7 +47,7 @@ impl ELCOpts {
impl ELCCmd {
pub fn run<S, L>(&self, opts: &Opts, enclave_loader: L) -> Result<()>
where
S: CommitStore,
S: CommitStore + TxAccessor + 'static,
Enclave<S>: EnclaveProtoAPI<S>,
L: EnclaveLoader<S>,
{
Expand Down
59 changes: 50 additions & 9 deletions app/src/commands/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ use crate::enclave::EnclaveLoader;
use crate::opts::{EnclaveOpts, Opts};
use anyhow::Result;
use clap::Parser;
use enclave_api::{Enclave, EnclaveInfo, EnclaveProtoAPI};
use host::store::transaction::CommitStore;
use enclave_api::{Enclave, EnclaveInfo, EnclaveProtoAPI, SpeculativeEnclaveCommandAPI};
use host::store::transaction::{CommitStore, TxAccessor};
use log::*;
use service::{run_service, AppService};
use service::{run_service, ElcService};
use std::sync::Arc;
use tokio::runtime::Builder;

Expand All @@ -28,25 +28,49 @@ pub struct Start {
help = "Address of the App service"
)]
pub address: String,
/// Worker thread number the tokio `Runtime` will use
/// This value is recommended to be less than or equal to TCS_NUM in Enclave config.
/// Worker thread number the tokio `Runtime` will use.
/// This does not control enclave ECALL/TCS concurrency.
#[clap(
long = "threads",
help = "Worker thread number the tokio `Runtime` will use"
)]
pub threads: Option<usize>,
/// Size of the dedicated ECALL worker pool. All enclave ECALL execution
/// flows through this pool — both serial gRPC handlers and speculative
/// scheduler workers — so this value is the single source of truth for
/// concurrent ECALL count and cumulative TCS bindings under
/// `TCSPolicy=BIND`. Set this to a value at most equal to the loaded
/// enclave's `TCSNum`; leaving at least one TCS for the SDK runtime
/// (i.e. `--max-enclave-concurrency = TCSNum - 1`) is the conservative
/// default.
#[clap(
long = "max-enclave-concurrency",
default_value_t = 4,
help = "Size of the dedicated ECALL worker pool"
)]
pub max_enclave_concurrency: usize,
/// Maximum concurrent speculative update-client requests.
/// Prefer a value less than or equal to --max-enclave-concurrency; excess
/// speculative workers will wait on the enclave ECALL gate.
#[clap(
long = "max-speculative-concurrency",
default_value_t = 1,
help = "Maximum concurrent speculative update-client requests"
)]
pub max_speculative_concurrency: usize,
}

impl ServiceCmd {
pub fn run<S, L>(&self, opts: &Opts, enclave_loader: L) -> Result<()>
where
S: CommitStore + 'static,
Enclave<S>: EnclaveProtoAPI<S>,
S: CommitStore + TxAccessor + 'static,
Enclave<S>: EnclaveProtoAPI<S> + SpeculativeEnclaveCommandAPI<S>,
L: EnclaveLoader<S>,
{
match self {
Self::Start(cmd) => {
let addr = cmd.address.parse()?;
let enclave_parallelism = cmd.max_enclave_concurrency.max(1);
let enclave =
enclave_loader.load(opts, cmd.enclave.path.as_ref(), cmd.enclave.is_debug())?;
let metadata = enclave.metadata()?;
Expand All @@ -58,9 +82,26 @@ impl ServiceCmd {
&mut rb
};
let rt = Arc::new(rb.enable_all().build()?);
let srv = AppService::new(opts.get_home(), enclave);
let speculative_concurrency_limit = cmd.max_speculative_concurrency.max(1);
if speculative_concurrency_limit > enclave_parallelism {
warn!(
"max-speculative-concurrency ({}) is greater than max-enclave-concurrency ({}); speculative workers above the enclave limit will block waiting for an EcallPool slot",
speculative_concurrency_limit,
enclave_parallelism
);
}
let srv = ElcService::new(
opts.get_home(),
enclave,
speculative_concurrency_limit,
enclave_parallelism,
);

info!("start service: addr={addr} mrenclave={mrenclave}");
info!(
"start service: addr={addr} mrenclave={mrenclave} speculative_concurrency_limit={} enclave_parallelism={}",
speculative_concurrency_limit,
enclave_parallelism
);
rt.block_on(async { run_service(srv, addr).await })
}
}
Expand Down
12 changes: 11 additions & 1 deletion enclave-modules/ecall-handler/src/light_client/init_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use core::str::FromStr;
use crypto::Signer;
use ecall_commands::{InitClientInput, InitClientResponse, LightClientResponse};
use lcp_types::ClientId;
use light_client::commitments::{prove_commitment, CommitmentProof};
use light_client::commitments::{prove_commitment, CommitmentProof, ProxyMessage};
use light_client::{ClientKeeper, ClientReader, LightClientResolver};
use store::KVStore;

Expand Down Expand Up @@ -34,9 +34,19 @@ pub fn init_client<R: LightClientResolver, S: KVStore, K: Signer>(
if ctx.client_exists(&client_id) {
return Err(Error::client_already_exists(client_id.to_string()));
}
let state_id = match &res.message {
ProxyMessage::UpdateState(message) => message.post_state_id,
message => {
return Err(Error::invalid_argument(format!(
"create_client must return update-state message: actual_type={}",
message.message_type()
)))
}
};
ctx.store_client_type(client_id.clone(), client_type)?;
ctx.store_any_client_state(client_id.clone(), input.any_client_state)?;
ctx.store_any_consensus_state(client_id.clone(), res.height, input.any_consensus_state)?;
ctx.store_state_id(client_id.clone(), res.height, state_id)?;

let proof = if res.prove {
prove_commitment(ek, res.message)?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub fn update_client<R: LightClientResolver, S: KVStore, K: Signer>(
let ek = ctx.get_enclave_key();
match lc.update_client(ctx, input.client_id.clone(), input.any_header)? {
UpdateClientResult::UpdateState(mut data) => {
let post_state_id = data.message.post_state_id;
let message: ProxyMessage = {
if input.include_state && data.message.emitted_states.is_empty() {
data.message.emitted_states =
Expand All @@ -26,10 +27,11 @@ pub fn update_client<R: LightClientResolver, S: KVStore, K: Signer>(

ctx.store_any_client_state(input.client_id.clone(), data.new_any_client_state)?;
ctx.store_any_consensus_state(
input.client_id,
input.client_id.clone(),
data.height,
data.new_any_consensus_state,
)?;
ctx.store_state_id(input.client_id, data.height, post_state_id)?;

let proof = if data.prove {
prove_commitment(ek, message)?
Expand Down
2 changes: 1 addition & 1 deletion enclave-modules/host-api/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ mod tests {
assert_eq!(res.unwrap(), CommandResult::Log);
}
{
let tx = TestEnv.begin_tx(None).unwrap();
let tx = TestEnv.begin_tx(Some("test-client".to_string())).unwrap();
let res = execute_command(
StoreCommand::Set(tx.get_id(), b"k0".to_vec(), b"v0".to_vec()).into(),
);
Expand Down
2 changes: 1 addition & 1 deletion enclave/Enclave.config.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<ISVSVN>0</ISVSVN>
<StackMaxSize>0x40000</StackMaxSize>
<HeapMaxSize>0x100000</HeapMaxSize>
<TCSNum>2</TCSNum>
<TCSNum>4</TCSNum>
<TCSPolicy>0</TCSPolicy>
<DisableDebug>0</DisableDebug>
<MiscSelect>0</MiscSelect>
Expand Down
7 changes: 5 additions & 2 deletions modules/enclave-api/src/api.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
pub use command::EnclaveCommandAPI;
pub use primitive::EnclavePrimitiveAPI;
pub use command::{
EnclaveCommandAPI, SpeculativeBaseState, SpeculativeEnclaveCommandAPI,
SpeculativeUpdateClientInput, SpeculativeUpdateClientResponse,
};
pub use primitive::{EnclavePrimitiveAPI, SpeculativeEnclavePrimitiveAPI};
pub use proto::EnclaveProtoAPI;

mod command;
Expand Down
Loading
Loading