Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
dd01f80
Initial implementation for alternative interface hashing
techraed Nov 19, 2025
c61de53
implement derive for the ReflectHash trait
techraed Nov 20, 2025
2b0ebd6
rebase
techraed Nov 21, 2025
c85f3fd
remove redundant
techraed Nov 24, 2025
9352fd1
fix after review calc for interface id
techraed Nov 24, 2025
94721ac
apply review results
techraed Dec 3, 2025
ccb1b97
implement header for idlv2/sails-binary protocol
techraed Dec 3, 2025
73e428c
add header impl
techraed Dec 3, 2025
cc69b8c
add tests, apply ai-review results
techraed Dec 8, 2025
2985359
adjsut check for reserved byte
techraed Dec 8, 2025
18beeaf
apply review results
techraed Dec 8, 2025
8387069
remove header builder
techraed Dec 8, 2025
fefc0bb
implement draft sails binary protocol
techraed Dec 8, 2025
abd5a34
chore: support routing by interface_id (draft)
m62624 Jan 7, 2026
e8cf6c6
wip: merge master-idl-v2, refactroing
vobradovich Jan 7, 2026
50f68c8
Merge branch 'master-idl-v2' into vo/idl-v2-macros
vobradovich Jan 7, 2026
f4f5581
fix: client generator routing
m62624 Jan 8, 2026
08dce58
fix: encode_params
m62624 Jan 8, 2026
fa9f938
refactor: move message header to idl-meta
m62624 Jan 8, 2026
d742b3b
feat: generate interface and route ID constants
m62624 Jan 8, 2026
3bd4404
wip: macros
vobradovich Jan 8, 2026
d55bdc9
chore: minor updates
m62624 Jan 9, 2026
e69b349
refactor: replace with an Identifiable trait
m62624 Jan 9, 2026
a5e0840
feat: refactor Service and PendingCall to remove interface_id field
m62624 Jan 9, 2026
96a1216
feat: inherit CallCodec and Event from Identifiable
m62624 Jan 9, 2026
7bca8a2
refactor: clean up redundant Identifiable bounds
m62624 Jan 9, 2026
6f2757f
refactor: move interface_id to ServiceCall and Event traits
m62624 Jan 9, 2026
040f021
wip: macros
vobradovich Jan 9, 2026
d9524c3
fix: optimize event decoding
m62624 Jan 12, 2026
2ac7ee3
wip: macros 2 1/2
vobradovich Jan 12, 2026
d59b1d7
wip: fix examples
vobradovich Jan 13, 2026
4c4cde9
wip: macros ethexe
vobradovich Jan 13, 2026
6d4109b
fix(ethexe): service route idx
vobradovich Jan 14, 2026
005f3a6
feat: macros routing
vobradovich Jan 14, 2026
8bbd250
fix: review
vobradovich Jan 14, 2026
270553b
Merge branch 'feat/client-gen-interface-id' into vo/idl-v2-macros
vobradovich Jan 14, 2026
067a179
wip: macros & client working routing
vobradovich Jan 14, 2026
7025dca
fix: sort event variants for deterministic hashing (#1177)
m62624 Jan 15, 2026
4ce25b0
fix: bench
vobradovich Jan 15, 2026
c48b99d
refactor: simplify client traits (#1178)
m62624 Jan 16, 2026
ad2919b
fix: review
vobradovich Jan 16, 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
36 changes: 18 additions & 18 deletions benchmarks/bench_data.json
Original file line number Diff line number Diff line change
@@ -1,32 +1,32 @@
{
"compute": {
"median": 450514036959
"median": 450554650806
},
"alloc": {
"0": 564376739,
"12": 567864696,
"143": 727298127,
"986": 828290311,
"10945": 2019067671,
"46367": 6404351520,
"121392": 16859084038,
"317810": 43147409792
"0": 601838097,
"12": 605326124,
"143": 764788566,
"986": 865780806,
"10945": 2196386851,
"46367": 6441842127,
"121392": 16896609428,
"317810": 43184935210
},
"counter": {
"async_call": 851480134,
"sync_call": 678859589
"async_call": 882890228,
"sync_call": 711875426
},
"cross_program": {
"median": 2436719419
"median": 2438503869
},
"redirect": {
"median": 3473474864
"median": 3543826931
},
"message_stack": {
"0": 799109045,
"1": 3769557503,
"5": 15692980666,
"10": 29591871735,
"20": 63988962371
"0": 824309364,
"1": 3877712516,
"5": 16133299136,
"10": 33110719037,
"20": 66299847951
}
}
13 changes: 10 additions & 3 deletions benchmarks/ping-pong/app/src/ping_pong_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
#[allow(unused_imports)]
use sails_rs::{client::*, collections::*, prelude::*};
pub struct PingPongProgram;
impl PingPongProgram {
pub const ROUTE_ID_PING_PONG_SERVICE: u8 = 1;
}
impl sails_rs::client::Program for PingPongProgram {}
pub trait PingPong {
type Env: sails_rs::client::GearEnv;
Expand All @@ -14,7 +17,7 @@ impl<E: sails_rs::client::GearEnv> PingPong for sails_rs::client::Actor<PingPong
fn ping_pong_service(
&self,
) -> sails_rs::client::Service<ping_pong_service::PingPongServiceImpl, Self::Env> {
self.service(stringify!(PingPongService))
self.service(PingPongProgram::ROUTE_ID_PING_PONG_SERVICE)
}
}
pub trait PingPongCtors {
Expand All @@ -36,7 +39,7 @@ impl<E: sails_rs::client::GearEnv> PingPongCtors

pub mod io {
use super::*;
sails_rs::io_struct_impl!(NewForBench () -> ());
sails_rs::io_struct_impl!(NewForBench () -> (), 0);
}

pub mod ping_pong_service {
Expand All @@ -59,6 +62,10 @@ pub mod ping_pong_service {
) -> sails_rs::client::PendingCall<io::Ping, Self::Env>;
}
pub struct PingPongServiceImpl;
impl sails_rs::client::Identifiable for PingPongServiceImpl {
const INTERFACE_ID: sails_rs::InterfaceId =
sails_rs::InterfaceId::from_bytes_8([106, 114, 150, 138, 76, 98, 231, 215]);
}
impl<E: sails_rs::client::GearEnv> PingPongService
for sails_rs::client::Service<PingPongServiceImpl, E>
{
Expand All @@ -73,6 +80,6 @@ pub mod ping_pong_service {

pub mod io {
use super::*;
sails_rs::io_struct_impl!(Ping (payload: super::PingPongPayload) -> super::PingPongPayload);
sails_rs::io_struct_impl!(Ping (payload: super::PingPongPayload) -> super::PingPongPayload, 0, <super::PingPongServiceImpl as sails_rs::client::Identifiable>::INTERFACE_ID);
}
}
13 changes: 10 additions & 3 deletions benchmarks/src/alloc_stress_program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
#[allow(unused_imports)]
use sails_rs::{client::*, collections::*, prelude::*};
pub struct AllocStressProgram;
impl AllocStressProgram {
pub const ROUTE_ID_ALLOC_STRESS: u8 = 1;
}
impl sails_rs::client::Program for AllocStressProgram {}
pub trait AllocStress {
type Env: sails_rs::client::GearEnv;
Expand All @@ -10,7 +13,7 @@ pub trait AllocStress {
impl<E: sails_rs::client::GearEnv> AllocStress for sails_rs::client::Actor<AllocStressProgram, E> {
type Env = E;
fn alloc_stress(&self) -> sails_rs::client::Service<alloc_stress::AllocStressImpl, Self::Env> {
self.service(stringify!(AllocStress))
self.service(AllocStressProgram::ROUTE_ID_ALLOC_STRESS)
}
}
pub trait AllocStressCtors {
Expand All @@ -32,7 +35,7 @@ impl<E: sails_rs::client::GearEnv> AllocStressCtors

pub mod io {
use super::*;
sails_rs::io_struct_impl!(NewForBench () -> ());
sails_rs::io_struct_impl!(NewForBench () -> (), 0);
}

pub mod alloc_stress {
Expand All @@ -52,6 +55,10 @@ pub mod alloc_stress {
) -> sails_rs::client::PendingCall<io::AllocStress, Self::Env>;
}
pub struct AllocStressImpl;
impl sails_rs::client::Identifiable for AllocStressImpl {
const INTERFACE_ID: sails_rs::InterfaceId =
sails_rs::InterfaceId::from_bytes_8([9, 48, 193, 195, 84, 117, 173, 52]);
}
impl<E: sails_rs::client::GearEnv> AllocStress for sails_rs::client::Service<AllocStressImpl, E> {
type Env = E;
fn alloc_stress(
Expand All @@ -64,6 +71,6 @@ pub mod alloc_stress {

pub mod io {
use super::*;
sails_rs::io_struct_impl!(AllocStress (n: u32) -> super::AllocStressResult);
sails_rs::io_struct_impl!(AllocStress (n: u32) -> super::AllocStressResult, 0, <super::AllocStressImpl as sails_rs::client::Identifiable>::INTERFACE_ID);
}
}
68 changes: 41 additions & 27 deletions benchmarks/src/benchmarks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,23 @@
//! ```

use crate::clients::{
alloc_stress_client::{AllocStress as _, AllocStressCtors, alloc_stress::*},
compute_stress_client::{ComputeStress as _, ComputeStressCtors, compute_stress::*},
counter_bench_client::{CounterBench as _, CounterBenchCtors, counter_bench::*},
alloc_stress_client::{
AllocStress as _, AllocStressCtors, AllocStressProgram, alloc_stress::*,
},
compute_stress_client::{
ComputeStress as _, ComputeStressCtors, ComputeStressProgram, compute_stress::*,
},
counter_bench_client::{
CounterBench as _, CounterBenchCtors, CounterBenchProgram, counter_bench::*,
},
};
use gtest::{System, constants::DEFAULT_USER_ALICE};
use itertools::{Either, Itertools};
use ping_pong_bench_app::client::{PingPong, PingPongCtors, ping_pong_service::*};
use ping_pong_bench_app::client::{PingPong, PingPongCtors, PingPongProgram, ping_pong_service::*};
use redirect_client::{RedirectClient, RedirectClientCtors, redirect::*};
use redirect_proxy_client::{RedirectProxyClient, RedirectProxyClientCtors, proxy::*};
use redirect_proxy_client::{
RedirectProxyClient, RedirectProxyClientCtors, RedirectProxyClientProgram, proxy::*,
};
use sails_rs::{client::*, prelude::*};
use std::{collections::BTreeMap, sync::atomic::AtomicU64};

Expand Down Expand Up @@ -67,11 +75,10 @@ async fn compute_stress_bench() {
.map(|_| {
let message_id = service.compute_stress(input_value).send_one_way().unwrap();
let (payload, gas) = extract_reply_and_gas(env.system(), message_id);
let stress_resp = crate::clients::compute_stress_client::compute_stress::io::ComputeStress::decode_reply_with_prefix(
"ComputeStress",
payload.as_slice(),
)
.unwrap();
// Low-level approach: decoding using generated io module
let stress_resp =
crate::clients::compute_stress_client::compute_stress::io::ComputeStress::decode_reply(ComputeStressProgram::ROUTE_ID_COMPUTE_STRESS, payload.as_slice())
.unwrap();
assert_eq!(stress_resp.res, expected_sum);
gas
})
Expand Down Expand Up @@ -99,8 +106,9 @@ async fn counter_bench() {
let gas = if is_sync {
let message_id = service.inc().send_one_way().unwrap();
let (payload, gas) = extract_reply_and_gas(env.system(), message_id);
let stress_resp = crate::clients::counter_bench_client::counter_bench::io::Inc::decode_reply_with_prefix(
"CounterBench",
// Low-level approach: decoding using generated io module
let stress_resp = crate::clients::counter_bench_client::counter_bench::io::Inc::decode_reply(
CounterBenchProgram::ROUTE_ID_COUNTER_BENCH,
payload.as_slice(),
)
.unwrap();
Expand All @@ -111,8 +119,9 @@ async fn counter_bench() {
} else {
let message_id = service.inc_async().send_one_way().unwrap();
let (payload, gas) = extract_reply_and_gas(env.system(), message_id);
let stress_resp = crate::clients::counter_bench_client::counter_bench::io::IncAsync::decode_reply_with_prefix(
"CounterBench",
// Low-level approach: decoding using generated io module
let stress_resp = crate::clients::counter_bench_client::counter_bench::io::IncAsync::decode_reply(
CounterBenchProgram::ROUTE_ID_COUNTER_BENCH,
payload.as_slice(),
)
.unwrap();
Expand Down Expand Up @@ -158,9 +167,10 @@ async fn cross_program_bench() {
.send_one_way()
.unwrap();
let (payload, gas) = extract_reply_and_gas(env.system(), message_id);
// Low-level approach: decoding using generated io module
let stress_resp =
ping_pong_bench_app::client::ping_pong_service::io::Ping::decode_reply_with_prefix(
"PingPongService",
ping_pong_bench_app::client::ping_pong_service::io::Ping::decode_reply(
PingPongProgram::ROUTE_ID_PING_PONG_SERVICE,
payload.as_slice(),
)
.unwrap();
Expand Down Expand Up @@ -199,8 +209,9 @@ async fn redirect_bench() {
.send_one_way()
.unwrap();
let (payload, _gas) = extract_reply_and_gas(env.system(), message_id);
let resp = redirect_proxy_client::proxy::io::GetProgramId::decode_reply_with_prefix(
"Proxy",
// Low-level approach: decoding using generated io module
let resp = redirect_proxy_client::proxy::io::GetProgramId::decode_reply(
RedirectProxyClientProgram::ROUTE_ID_PROXY,
payload.as_slice(),
)
.unwrap();
Expand All @@ -223,8 +234,9 @@ async fn redirect_bench() {
.send_one_way()
.unwrap();
let (payload, gas) = extract_reply_and_gas(env.system(), message_id);
let resp = redirect_proxy_client::proxy::io::GetProgramId::decode_reply_with_prefix(
"Proxy",
// Low-level approach: decoding using generated io module
let resp = redirect_proxy_client::proxy::io::GetProgramId::decode_reply(
RedirectProxyClientProgram::ROUTE_ID_PROXY,
payload.as_slice(),
)
.unwrap();
Expand Down Expand Up @@ -269,11 +281,13 @@ async fn alloc_stress_test(n: u32) -> (usize, u64) {
let mut service = program.alloc_stress();
let message_id = service.alloc_stress(n).send_one_way().unwrap();
let (payload, gas) = extract_reply_and_gas(env.system(), message_id);
let stress_resp = crate::clients::alloc_stress_client::alloc_stress::io::AllocStress::decode_reply_with_prefix(
"AllocStress",
payload.as_slice(),
)
.unwrap();
// Low-level approach: decoding using generated io module
let stress_resp =
crate::clients::alloc_stress_client::alloc_stress::io::AllocStress::decode_reply(
AllocStressProgram::ROUTE_ID_ALLOC_STRESS,
payload.as_slice(),
)
.unwrap();

let expected_len = alloc_stress::fibonacci_sum(n) as usize;
assert_eq!(stress_resp.inner.len(), expected_len);
Expand Down Expand Up @@ -313,7 +327,7 @@ fn create_env() -> GtestEnv {

async fn deploy_for_bench<
P: Program,
IO: CallCodec,
IO: ServiceCall,
F: FnOnce(Deployment<P, GtestEnv>) -> PendingCtor<P, IO, GtestEnv>,
>(
env: &GtestEnv,
Expand All @@ -326,7 +340,7 @@ async fn deploy_for_bench<

async fn deploy_code_for_bench<
P: Program,
IO: CallCodec,
IO: ServiceCall,
F: FnOnce(Deployment<P, GtestEnv>) -> PendingCtor<P, IO, GtestEnv>,
>(
env: &GtestEnv,
Expand Down
13 changes: 10 additions & 3 deletions benchmarks/src/compute_stress_program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
#[allow(unused_imports)]
use sails_rs::{client::*, collections::*, prelude::*};
pub struct ComputeStressProgram;
impl ComputeStressProgram {
pub const ROUTE_ID_COMPUTE_STRESS: u8 = 1;
}
impl sails_rs::client::Program for ComputeStressProgram {}
pub trait ComputeStress {
type Env: sails_rs::client::GearEnv;
Expand All @@ -16,7 +19,7 @@ impl<E: sails_rs::client::GearEnv> ComputeStress
fn compute_stress(
&self,
) -> sails_rs::client::Service<compute_stress::ComputeStressImpl, Self::Env> {
self.service(stringify!(ComputeStress))
self.service(ComputeStressProgram::ROUTE_ID_COMPUTE_STRESS)
}
}
pub trait ComputeStressCtors {
Expand All @@ -38,7 +41,7 @@ impl<E: sails_rs::client::GearEnv> ComputeStressCtors

pub mod io {
use super::*;
sails_rs::io_struct_impl!(NewForBench () -> ());
sails_rs::io_struct_impl!(NewForBench () -> (), 0);
}

pub mod compute_stress {
Expand All @@ -58,6 +61,10 @@ pub mod compute_stress {
) -> sails_rs::client::PendingCall<io::ComputeStress, Self::Env>;
}
pub struct ComputeStressImpl;
impl sails_rs::client::Identifiable for ComputeStressImpl {
const INTERFACE_ID: sails_rs::InterfaceId =
sails_rs::InterfaceId::from_bytes_8([254, 138, 70, 56, 122, 195, 121, 54]);
}
impl<E: sails_rs::client::GearEnv> ComputeStress
for sails_rs::client::Service<ComputeStressImpl, E>
{
Expand All @@ -72,6 +79,6 @@ pub mod compute_stress {

pub mod io {
use super::*;
sails_rs::io_struct_impl!(ComputeStress (n: u32) -> super::ComputeStressResult);
sails_rs::io_struct_impl!(ComputeStress (n: u32) -> super::ComputeStressResult, 0, <super::ComputeStressImpl as sails_rs::client::Identifiable>::INTERFACE_ID);
}
}
15 changes: 11 additions & 4 deletions benchmarks/src/counter_bench_program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
#[allow(unused_imports)]
use sails_rs::{client::*, collections::*, prelude::*};
pub struct CounterBenchProgram;
impl CounterBenchProgram {
pub const ROUTE_ID_COUNTER_BENCH: u8 = 1;
}
impl sails_rs::client::Program for CounterBenchProgram {}
pub trait CounterBench {
type Env: sails_rs::client::GearEnv;
Expand All @@ -16,7 +19,7 @@ impl<E: sails_rs::client::GearEnv> CounterBench
fn counter_bench(
&self,
) -> sails_rs::client::Service<counter_bench::CounterBenchImpl, Self::Env> {
self.service(stringify!(CounterBench))
self.service(CounterBenchProgram::ROUTE_ID_COUNTER_BENCH)
}
}
pub trait CounterBenchCtors {
Expand All @@ -38,7 +41,7 @@ impl<E: sails_rs::client::GearEnv> CounterBenchCtors

pub mod io {
use super::*;
sails_rs::io_struct_impl!(NewForBench () -> ());
sails_rs::io_struct_impl!(NewForBench () -> (), 0);
}

pub mod counter_bench {
Expand All @@ -49,6 +52,10 @@ pub mod counter_bench {
fn inc_async(&mut self) -> sails_rs::client::PendingCall<io::IncAsync, Self::Env>;
}
pub struct CounterBenchImpl;
impl sails_rs::client::Identifiable for CounterBenchImpl {
const INTERFACE_ID: sails_rs::InterfaceId =
sails_rs::InterfaceId::from_bytes_8([149, 170, 24, 82, 218, 19, 238, 13]);
}
impl<E: sails_rs::client::GearEnv> CounterBench for sails_rs::client::Service<CounterBenchImpl, E> {
type Env = E;
fn inc(&mut self) -> sails_rs::client::PendingCall<io::Inc, Self::Env> {
Expand All @@ -61,7 +68,7 @@ pub mod counter_bench {

pub mod io {
use super::*;
sails_rs::io_struct_impl!(Inc () -> u64);
sails_rs::io_struct_impl!(IncAsync () -> u64);
sails_rs::io_struct_impl!(Inc () -> u64, 0, <super::CounterBenchImpl as sails_rs::client::Identifiable>::INTERFACE_ID);
sails_rs::io_struct_impl!(IncAsync () -> u64, 1, <super::CounterBenchImpl as sails_rs::client::Identifiable>::INTERFACE_ID);
}
}
File renamed without changes.
File renamed without changes.
Loading