From 694c569c089204f0beea31b3394c271e26b08f5b Mon Sep 17 00:00:00 2001 From: CleverWild Date: Wed, 15 Apr 2026 19:45:59 +0200 Subject: [PATCH] feat(integrity): introduce sealed provenance markers for `Verified` --- .../arbiter-server/src/actors/client/auth.rs | 4 +- .../arbiter-server/src/actors/evm/mod.rs | 5 +- .../arbiter-server/src/crypto/integrity/v1.rs | 24 +- .../src/crypto/integrity/v1/verified.rs | 518 +++++++++++------- server/crates/arbiter-server/src/evm/mod.rs | 2 +- 5 files changed, 346 insertions(+), 207 deletions(-) diff --git a/server/crates/arbiter-server/src/actors/client/auth.rs b/server/crates/arbiter-server/src/actors/client/auth.rs index 8b858b5..ba96bc2 100644 --- a/server/crates/arbiter-server/src/actors/client/auth.rs +++ b/server/crates/arbiter-server/src/actors/client/auth.rs @@ -221,7 +221,8 @@ async fn insert_client( .map_err(|e| { error!(error = ?e, "Failed to sign integrity tag for new client key"); Error::DatabaseOperationFailed - })?; + })? + .unqualify_origin(); Ok(verified_id) }) @@ -368,6 +369,7 @@ where })? .inherit() .entity_id + .unqualify_origin() } None => { approve_new_client( diff --git a/server/crates/arbiter-server/src/actors/evm/mod.rs b/server/crates/arbiter-server/src/actors/evm/mod.rs index b7bb2e0..e491f2c 100644 --- a/server/crates/arbiter-server/src/actors/evm/mod.rs +++ b/server/crates/arbiter-server/src/actors/evm/mod.rs @@ -129,7 +129,7 @@ impl EvmActor { .map_err(|_| Error::KeyholderSend)?; let mut conn = self.db.get().await.map_err(DatabaseError::from)?; - let wallet_id = insert_into(schema::evm_wallet::table) + let wallet_id: i32 = insert_into(schema::evm_wallet::table) .values(&models::NewEvmWallet { address: address.as_slice().to_vec(), aead_encrypted_id: aead_id, @@ -146,7 +146,8 @@ impl EvmActor { }; let verified_wallet_id = integrity::sign_entity(&mut conn, &self.keyholder, &wallet_integrity, wallet_id) - .await?; + .await? + .unqualify_origin(); Ok((verified_wallet_id, address)) } diff --git a/server/crates/arbiter-server/src/crypto/integrity/v1.rs b/server/crates/arbiter-server/src/crypto/integrity/v1.rs index c3093f2..8744516 100644 --- a/server/crates/arbiter-server/src/crypto/integrity/v1.rs +++ b/server/crates/arbiter-server/src/crypto/integrity/v1.rs @@ -27,7 +27,7 @@ pub const CURRENT_PAYLOAD_VERSION: i32 = 1; pub const INTEGRITY_SUBKEY_TAG: &[u8] = b"arbiter/db-integrity-key/v1"; pub type HmacSha256 = Hmac; -pub use self::verified::Verified; +pub use self::verified::{Nested, Root, VerificationOrigin, Verified}; #[derive(Debug, thiserror::Error)] pub enum Error { @@ -101,7 +101,7 @@ pub async fn lookup_verified( keyholder: &ActorRef, entity_id: Id, load: F, -) -> Result>, Error> +) -> Result, Nested>, Error> where C: AsyncConnection, E: Integrable, @@ -117,7 +117,7 @@ pub async fn lookup_verified_from_query( conn: &mut C, keyholder: &ActorRef, load: F, -) -> Result>, Error> +) -> Result, Nested>, Error> where C: AsyncConnection + Send, E: Integrable, @@ -137,7 +137,7 @@ pub async fn sign_entity + Clone>( keyholder: &ActorRef, entity: &E, as_entity_id: Id, -) -> Result, Error> { +) -> Result>, Error> { let payload_hash = payload_hash(entity); let entity_id = as_entity_id.clone().into(); @@ -174,7 +174,7 @@ pub async fn sign_entity + Clone>( .await .map_err(db::DatabaseError::from)?; - Ok(Verified::new(as_entity_id)) + Ok(Verified::>::new(as_entity_id)) } pub async fn check_entity_attestation( @@ -247,9 +247,12 @@ pub async fn verify_entity + Clone>( keyholder: &ActorRef, entity: E, entity_id: Id, -) -> Result>, Error> { +) -> Result, Nested>, Error> { match check_entity_attestation(conn, keyholder, &entity, entity_id.clone()).await? { - AttestationStatus::Attested => Ok(Verified::new(Entity { entity, entity_id })), + AttestationStatus::Attested => Ok(Verified::, Nested>::new(Entity { + entity, + entity_id, + })), AttestationStatus::Unavailable => Err(Error::Keyholder(keyholder::Error::NotBootstrapped)), } } @@ -259,9 +262,12 @@ pub async fn verify_entity_ref<'e, E: Integrable, Id: Into + Clone>( keyholder: &ActorRef, entity: &'e E, entity_id: Id, -) -> Result>, Error> { +) -> Result, Nested>, Error> { match check_entity_attestation(conn, keyholder, entity, entity_id.clone()).await? { - AttestationStatus::Attested => Ok(Verified::new(Entity { entity, entity_id })), + AttestationStatus::Attested => Ok(Verified::, Nested>::new(Entity { + entity, + entity_id, + })), AttestationStatus::Unavailable => Err(Error::Keyholder(keyholder::Error::NotBootstrapped)), } } diff --git a/server/crates/arbiter-server/src/crypto/integrity/v1/verified.rs b/server/crates/arbiter-server/src/crypto/integrity/v1/verified.rs index 362e87d..062f51d 100644 --- a/server/crates/arbiter-server/src/crypto/integrity/v1/verified.rs +++ b/server/crates/arbiter-server/src/crypto/integrity/v1/verified.rs @@ -1,222 +1,98 @@ use std::ops::Deref; -// todo! rewrite macro_rules to derive crate -#[macro_export] -macro_rules! VerifiedFields { - // --- Entry point --- - ( - $(#$attr:tt)* - $vis:vis struct $name:ident $(<$($gen:tt),*>)? - { - $( - $field_vis:vis $field_name:ident : $field_ty:ty - ),* $(,)? - } - ) => { - // Attribute-list checks run in isolation — they only receive the attrs, - // not the struct body. - $crate::VerifiedFields!(@require_repr [$(#$attr)*]); - $crate::VerifiedFields!(@reject_packed [$(#$attr)*]); +use super::Integrable; - paste::paste! { - #[doc = concat!( - "Field-wise verified counterpart of [`", stringify!($name), "`]." - )] - // - // `#[repr(C)]` is required for the pointer casts in `inherit_ref` - // and `inherit` to be sound. Both the source struct (enforced by - // `@require_repr`) and this counterpart carry `#[repr(C)]`, which - // guarantees matching field offsets. Combined with each - // `Verified` being `#[repr(transparent)]` over `F`, the two - // structs have identical memory layout. - // - // `#[repr(transparent)]` is not usable here because it only permits - // a single non-ZST field; multi-field structs would fail to compile. - #[repr(C)] - $vis struct [] $(<$($gen),*>)? - { - $( - $field_vis $field_name : $crate::crypto::integrity::Verified<$field_ty> - ),* - } - - impl $(<$($gen),*>)? - $crate::crypto::integrity::v1::verified::VerifiedFieldsAccessor - for $crate::crypto::integrity::Verified<$name $(<$($gen),*>)?> - { - type Counterpart = [] $(<$($gen),*>)?; - - fn inherit_ref(&self) -> &Self::Counterpart { - // SAFETY: `Self` is `Verified` (transparent over - // `T #[repr(C)]`) and `Self::Counterpart` is `#[repr(C)]` - // with the same fields in the same order, each wrapped in - // a `#[repr(transparent)]` `Verified`. The two types - // therefore have identical memory layout, which - // `reinterpret_layout_ref` re-checks as size/align - // equality at monomorphization. - unsafe { - $crate::crypto::integrity::v1::verified::reinterpret_layout_ref::< - Self, - Self::Counterpart, - >(self) - } - } - - fn inherit(self) -> Self::Counterpart { - // SAFETY: identical layout — see `inherit_ref`. The owned - // helper additionally suppresses the source destructor so - // the returned counterpart owns the original bytes (no - // double-drop is possible). - unsafe { - $crate::crypto::integrity::v1::verified::reinterpret_layout::< - Self, - Self::Counterpart, - >(self) - } - } - } - } - }; - - // --- @require_repr: ensure `#[repr(C)]` appears in the attribute list --- - (@require_repr [#[repr(C)] $($rest:tt)*]) => {}; - (@require_repr [#$other:tt $($rest:tt)*]) => { - $crate::VerifiedFields!(@require_repr [$($rest)*]); - }; - (@require_repr []) => { - ::std::compile_error!( - "VerifiedFields requires `#[repr(C)]` on the struct to guarantee field layout" - ); - }; - - // --- @reject_packed: walk attrs and reject any `#[repr(..., packed, ...)]`. - // - // Without this, a packed struct would still fail at monomorphization via - // the const assertions inside the `reinterpret_layout*` helpers, but the - // diagnostic would be much harder to read. `align(N)` is *not* rejected - // here because const assertions catch alignment mismatches cleanly, and - // forbidding it would be unnecessarily restrictive. - (@reject_packed [#[repr($($inner:tt)*)] $($rest:tt)*]) => { - $crate::VerifiedFields!(@reject_packed_inner [$($inner)*]); - $crate::VerifiedFields!(@reject_packed [$($rest)*]); - }; - (@reject_packed [#$other:tt $($rest:tt)*]) => { - $crate::VerifiedFields!(@reject_packed [$($rest)*]); - }; - (@reject_packed []) => {}; - - (@reject_packed_inner [packed $($rest:tt)*]) => { - ::std::compile_error!( - "VerifiedFields does not support packed layouts; the generated \ - counterpart would not share layout with the source struct" - ); - }; - (@reject_packed_inner [$first:tt $($rest:tt)*]) => { - $crate::VerifiedFields!(@reject_packed_inner [$($rest)*]); - }; - (@reject_packed_inner []) => {}; +mod private { + pub trait Sealed {} } -/// Implemented on `Verified` by [`VerifiedFields!`], exposing the field-wise counterpart. +/// Marker trait for type-level verification provenance. /// -/// ## Disclaimer -/// Do not implement this trait manually. It is intended to be implemented only -/// by the `VerifiedFields!` macro, which generates the necessary layout -/// guarantees for sound pointer casts. -/// -/// ## Soundness -/// When [`verify_entity`][crate::crypto::integrity::verify_entity] attests an -/// entity, it returns `Verified` — an aggregate proof over the whole value. -/// This trait converts that wrapper into `Counterpart` (e.g. -/// `VerifiedMyStruct`), where every field is individually wrapped in -/// [`Verified`], allowing verified data to flow into functions that require -/// `Verified` without re-verifying. -/// -/// ## Safety -/// The conversion is a zero-cost reinterpretation — no copying (beyond a -/// bitwise move in the owned variant) or HMAC work occurs. Soundness rests on -/// identical memory layout between `Verified` and `Counterpart`: -/// -/// - `T` carries `#[repr(C)]` (enforced by `@require_repr` in the macro). -/// - `T` does **not** carry `packed` (enforced by `@reject_packed`). -/// - `Counterpart` also carries `#[repr(C)]`, with the same fields in the same -/// order. -/// - Each `Verified` field is `#[repr(transparent)]` over `F`, so its size -/// and alignment match `F` exactly. -/// - `Verified` itself is `#[repr(transparent)]` over `T`. -/// -/// As an additional machine-checked guard, [`reinterpret_layout`] and -/// [`reinterpret_layout_ref`] assert size/align equality of the two types at -/// monomorphization time. -/// -/// The trait is implemented directly on `Verified` (not on `T`), so no -/// `Deref`-coercion or auto-ref stripping is needed at call sites — the impl -/// is unambiguous. -pub trait VerifiedFieldsAccessor { - /// The field-wise verified counterpart, e.g. `VerifiedMyStruct`. - type Counterpart; - - /// Reinterprets `&self` as `&Counterpart` via a layout-preserving pointer cast. - /// - /// No data is copied and no re-verification occurs. The returned reference - /// borrows from `self` and has the same lifetime. - fn inherit_ref(&self) -> &Self::Counterpart; - - /// Consumes `self` and returns `Counterpart` via a layout-preserving - /// bitwise move. - /// - /// The original `Verified` is moved without running its destructor - /// (there is none — `Verified` is a transparent wrapper with no heap - /// allocation), and the returned counterpart owns the original bytes. No - /// re-verification occurs. - fn inherit(self) -> Self::Counterpart; +/// This trait is intentionally sealed so external code cannot invent arbitrary +/// provenance tags and bypass the intended type-level guarantees. +pub trait VerificationOrigin: private::Sealed { + type Origin: VerificationOrigin; +} + +/// Root provenance marker for values directly produced by integrity APIs. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +pub struct Root; + +/// Nested provenance marker carrying the source integrable type and previous +/// provenance marker in the chain. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct Nested(core::marker::PhantomData<(From, P)>); + +impl private::Sealed for Root {} +impl VerificationOrigin for Root { + type Origin = Self; +} + +impl private::Sealed for Nested {} +impl VerificationOrigin for Nested { + type Origin = P; } -/// A value whose integrity has been verified against the HMAC envelope stored -/// in the database. -/// -/// `Verified` is a zero-cost transparent wrapper produced exclusively by -/// [`crate::crypto::integrity`](super) module's functions. Holding one is proof -/// that the underlying value passed an HMAC check keyed with the vault's -/// integrity subkey. -/// -/// The wrapper is intentionally narrow: it does not expose a constructor and -/// the inner value cannot be moved out without explicitly calling -/// [`drop_verification_provenance`][Verified::drop_verification_provenance], -/// making accidental provenance loss visible at the call site. #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(transparent)] #[must_use = "Verified is a proof-bearing wrapper; use self.drop_verification_provenance() to explicitly discard integrity provenance when needed"] -pub struct Verified(T); +pub struct Verified { + inner: T, + origin: core::marker::PhantomData, +} -impl AsRef> for Verified<&T> { - fn as_ref(&self) -> &Verified { +impl AsRef> for Verified<&T, O> { + fn as_ref(&self) -> &Verified { // SAFETY: `Verified` is `#[repr(transparent)]` over `T`, so `&T` // and `&Verified` have identical layout. - unsafe { reinterpret_layout_ref::>(self.0) } + unsafe { reinterpret_layout_ref::>(self.inner) } } } -impl Deref for Verified { +impl Deref for Verified> { + type Target = Verified; + + fn deref(&self) -> &Self::Target { + // SAFETY: `Verified>` is `#[repr(transparent)]` over `T`, so `&Verified>` + // and `&Nested` have identical layout. + unsafe { reinterpret_layout_ref::>(self) } + } +} +impl Deref for Verified { type Target = T; fn deref(&self) -> &Self::Target { - &self.0 + &self.inner } } -impl Verified { +impl Verified { /// Unwraps the verified value, discarding the integrity provenance. /// /// The name is intentionally verbose — call sites where provenance is /// dropped should be easy to find and audit. pub fn drop_verification_provenance(self) -> T { - self.0 + self.inner + } + + /// Downgrades the origin provenance to any lower nestedness level, + /// e.g. `Verified>` to `Verified`. + pub fn unqualify_origin(self) -> Verified + where + O: VerificationOrigin, + { + Verified { + inner: self.inner, + origin: core::marker::PhantomData, + } } /// Constructs a `Verified` by wrapping a `T`. pub(super) fn new(value: T) -> Self { - Self(value) + Self { + inner: value, + origin: core::marker::PhantomData, + } } /// Constructs a `Verified` from a raw value without performing any @@ -224,7 +100,10 @@ impl Verified { /// module's functions to obtain a `Verified` in production code. #[cfg(test)] pub(crate) fn new_unchecked(value: T) -> Self { - Self(value) + Self { + inner: value, + origin: core::marker::PhantomData, + } } /// Reinterprets `&T` as `&Verified`. @@ -301,6 +180,253 @@ pub const unsafe fn reinterpret_layout_ref(value: &From) -> &To { unsafe { &*(value as *const From as *const To) } } +/// Implemented on `Verified` by [`VerifiedFields!`], exposing the field-wise counterpart. +/// +/// ## Disclaimer +/// Do not implement this trait manually. It is intended to be implemented only +/// by the `VerifiedFields!` macro, which generates the necessary layout +/// guarantees for sound pointer casts. +/// +/// ## Soundness +/// When [`verify_entity`][crate::crypto::integrity::verify_entity] attests an +/// entity, it returns `Verified` — an aggregate proof over the whole value. +/// This trait converts that wrapper into `Counterpart` (e.g. +/// `VerifiedMyStruct`), where every field is individually wrapped in +/// [`Verified`], allowing verified data to flow into functions that require +/// `Verified` without re-verifying. +/// +/// ## Safety +/// The conversion is a zero-cost reinterpretation — no copying (beyond a +/// bitwise move in the owned variant) or HMAC work occurs. Soundness rests on +/// identical memory layout between `Verified` and `Counterpart`: +/// +/// - `T` carries `#[repr(C)]` (enforced by `@require_repr` in the macro). +/// - `T` does **not** carry `packed` (enforced by `@reject_packed`). +/// - `Counterpart` also carries `#[repr(C)]`, with the same fields in the same +/// order. +/// - Each `Verified` field is `#[repr(transparent)]` over `F`, so its size +/// and alignment match `F` exactly. +/// - `Verified` itself is `#[repr(transparent)]` over `T`. +/// +/// As an additional machine-checked guard, [`reinterpret_layout`] and +/// [`reinterpret_layout_ref`] assert size/align equality of the two types at +/// monomorphization time. +/// +/// The trait is implemented directly on `Verified` (not on `T`), so no +/// `Deref`-coercion or auto-ref stripping is needed at call sites — the impl +/// is unambiguous. +pub trait VerifiedFieldsAccessor { + /// The field-wise verified counterpart, e.g. `VerifiedMyStruct`. + type Counterpart; + + /// Reinterprets `&self` as `&Counterpart` via a layout-preserving pointer cast. + /// + /// No data is copied and no re-verification occurs. The returned reference + /// borrows from `self` and has the same lifetime. + fn inherit_ref(&self) -> &Self::Counterpart; + + /// Consumes `self` and returns `Counterpart` via a layout-preserving + /// bitwise move. + /// + /// The original `Verified` is moved without running its destructor + /// (there is none — `Verified` is a transparent wrapper with no heap + /// allocation), and the returned counterpart owns the original bytes. No + /// re-verification occurs. + fn inherit(self) -> Self::Counterpart; +} + +// todo! rewrite macro_rules to derive crate +#[macro_export] +macro_rules! VerifiedFields { + // --- Entry point (no source generics) --- + ( + $(#$attr:tt)* + $vis:vis struct $name:ident + { + $( + $field_vis:vis $field_name:ident : $field_ty:ty + ),* $(,)? + } + ) => { + // Attribute-list checks run in isolation — they only receive the attrs, + // not the struct body. + $crate::VerifiedFields!(@require_repr [$(#$attr)*]); + $crate::VerifiedFields!(@reject_packed [$(#$attr)*]); + + paste::paste! { + #[doc = concat!( + "Field-wise verified counterpart of [`", stringify!($name), "`]." + )] + // + // `#[repr(C)]` is required for the pointer casts in `inherit_ref` + // and `inherit` to be sound. Both the source struct (enforced by + // `@require_repr`) and this counterpart carry `#[repr(C)]`, which + // guarantees matching field offsets. Combined with each + // `Verified` being `#[repr(transparent)]` over `F`, the two + // structs have identical memory layout. + // + // `#[repr(transparent)]` is not usable here because it only permits + // a single non-ZST field; multi-field structs would fail to compile. + #[repr(C)] + $vis struct [] + { + $( + $field_vis $field_name : $crate::crypto::integrity::Verified<$field_ty, P> + ),* + } + + impl + $crate::crypto::integrity::v1::verified::VerifiedFieldsAccessor + for $crate::crypto::integrity::Verified<$name, P> + { + type Counterpart = []

; + + fn inherit_ref(&self) -> &Self::Counterpart { + // SAFETY: `Self` is `Verified` (transparent over + // `T #[repr(C)]`) and `Self::Counterpart` is `#[repr(C)]` + // with the same fields in the same order, each wrapped in + // a `#[repr(transparent)]` `Verified`. The two types + // therefore have identical memory layout, which + // `reinterpret_layout_ref` re-checks as size/align + // equality at monomorphization. + unsafe { + $crate::crypto::integrity::v1::verified::reinterpret_layout_ref::< + Self, + Self::Counterpart, + >(self) + } + } + + fn inherit(self) -> Self::Counterpart { + // SAFETY: identical layout — see `inherit_ref`. The owned + // helper additionally suppresses the source destructor so + // the returned counterpart owns the original bytes (no + // double-drop is possible). + unsafe { + $crate::crypto::integrity::v1::verified::reinterpret_layout::< + Self, + Self::Counterpart, + >(self) + } + } + } + } + }; + + // --- Entry point (source has generics) --- + ( + $(#$attr:tt)* + $vis:vis struct $name:ident <$($gen:tt),*> + { + $( + $field_vis:vis $field_name:ident : $field_ty:ty + ),* $(,)? + } + ) => { + // Attribute-list checks run in isolation — they only receive the attrs, + // not the struct body. + $crate::VerifiedFields!(@require_repr [$(#$attr)*]); + $crate::VerifiedFields!(@reject_packed [$(#$attr)*]); + + paste::paste! { + #[doc = concat!( + "Field-wise verified counterpart of [`", stringify!($name), "`]." + )] + // + // `#[repr(C)]` is required for the pointer casts in `inherit_ref` + // and `inherit` to be sound. Both the source struct (enforced by + // `@require_repr`) and this counterpart carry `#[repr(C)]`, which + // guarantees matching field offsets. Combined with each + // `Verified` being `#[repr(transparent)]` over `F`, the two + // structs have identical memory layout. + // + // `#[repr(transparent)]` is not usable here because it only permits + // a single non-ZST field; multi-field structs would fail to compile. + #[repr(C)] + $vis struct []<$($gen),*, P: $crate::crypto::integrity::v1::verified::VerificationOrigin> + { + $( + $field_vis $field_name : $crate::crypto::integrity::Verified<$field_ty, P> + ),* + } + + impl<$($gen),*, P: $crate::crypto::integrity::v1::verified::VerificationOrigin> + $crate::crypto::integrity::v1::verified::VerifiedFieldsAccessor + for $crate::crypto::integrity::Verified<$name<$($gen),*>, P> + { + type Counterpart = []<$($gen),*, P>; + + fn inherit_ref(&self) -> &Self::Counterpart { + // SAFETY: `Self` is `Verified` (transparent over + // `T #[repr(C)]`) and `Self::Counterpart` is `#[repr(C)]` + // with the same fields in the same order, each wrapped in + // a `#[repr(transparent)]` `Verified`. The two types + // therefore have identical memory layout, which + // `reinterpret_layout_ref` re-checks as size/align + // equality at monomorphization. + unsafe { + $crate::crypto::integrity::v1::verified::reinterpret_layout_ref::< + Self, + Self::Counterpart, + >(self) + } + } + + fn inherit(self) -> Self::Counterpart { + // SAFETY: identical layout — see `inherit_ref`. The owned + // helper additionally suppresses the source destructor so + // the returned counterpart owns the original bytes (no + // double-drop is possible). + unsafe { + $crate::crypto::integrity::v1::verified::reinterpret_layout::< + Self, + Self::Counterpart, + >(self) + } + } + } + } + }; + + // --- @require_repr: ensure `#[repr(C)]` appears in the attribute list --- + (@require_repr [#[repr(C)] $($rest:tt)*]) => {}; + (@require_repr [#$other:tt $($rest:tt)*]) => { + $crate::VerifiedFields!(@require_repr [$($rest)*]); + }; + (@require_repr []) => { + ::std::compile_error!( + "VerifiedFields requires `#[repr(C)]` on the struct to guarantee field layout" + ); + }; + + // --- @reject_packed: walk attrs and reject any `#[repr(..., packed, ...)]`. + // + // Without this, a packed struct would still fail at monomorphization via + // the const assertions inside the `reinterpret_layout*` helpers, but the + // diagnostic would be much harder to read. `align(N)` is *not* rejected + // here because const assertions catch alignment mismatches cleanly, and + // forbidding it would be unnecessarily restrictive. + (@reject_packed [#[repr($($inner:tt)*)] $($rest:tt)*]) => { + $crate::VerifiedFields!(@reject_packed_inner [$($inner)*]); + $crate::VerifiedFields!(@reject_packed [$($rest)*]); + }; + (@reject_packed [#$other:tt $($rest:tt)*]) => { + $crate::VerifiedFields!(@reject_packed [$($rest)*]); + }; + (@reject_packed []) => {}; + + (@reject_packed_inner [packed $($rest:tt)*]) => { + ::std::compile_error!( + "VerifiedFields does not support packed layouts; the generated \ + counterpart would not share layout with the source struct" + ); + }; + (@reject_packed_inner [$first:tt $($rest:tt)*]) => { + $crate::VerifiedFields!(@reject_packed_inner [$($rest)*]); + }; + (@reject_packed_inner []) => {}; +} + #[cfg(test)] mod tests { use super::*; @@ -314,7 +440,10 @@ mod tests { } fn verify(t: T) -> Verified { - Verified(t) + Verified { + inner: t, + origin: core::marker::PhantomData, + } } // --- inherit_ref --- @@ -356,8 +485,9 @@ mod tests { field1: "x".into(), field2: 7u32, }); - let fields: &VerifiedMyStruct = v.inherit_ref(); - let back_ptr = fields as *const VerifiedMyStruct as *const Verified>; + let fields: &VerifiedMyStruct = v.inherit_ref(); + let back_ptr = + fields as *const VerifiedMyStruct as *const Verified>; assert_eq!( back_ptr as *const u8, &v as *const _ as *const u8, "cast of counterpart must point back to the same Verified" @@ -375,7 +505,7 @@ mod tests { pub val: u64, } - let v = Verified(WithZst { unit: (), val: 777 }); + let v = Verified::::new_unchecked(WithZst { unit: (), val: 777 }); let fields = v.inherit_ref(); assert_eq!(*fields.val, 777); assert_eq!(*fields.unit, ()); @@ -419,7 +549,7 @@ mod tests { DROP_COUNT.store(0, Ordering::Relaxed); { - let v = Verified(WithDrop { val: DropCounter }); + let v = Verified::::new_unchecked(WithDrop { val: DropCounter }); let _ = v.inherit(); } assert_eq!( @@ -453,7 +583,7 @@ mod tests { #[test] fn verified_ref_as_ref_is_same_address() { let val = 99u32; - let vref: Verified<&u32> = Verified(&val); + let vref: Verified<&u32> = Verified::new_unchecked(&val); let v: &Verified = vref.as_ref(); assert_eq!( &val as *const u32 as *const u8, v as *const _ as *const u8, diff --git a/server/crates/arbiter-server/src/evm/mod.rs b/server/crates/arbiter-server/src/evm/mod.rs index 3af0e1a..f9084bb 100644 --- a/server/crates/arbiter-server/src/evm/mod.rs +++ b/server/crates/arbiter-server/src/evm/mod.rs @@ -295,7 +295,7 @@ impl Engine { }) .await?; - Ok(id) + Ok(id.unqualify_origin()) } async fn list_one_kind(