Skip to main content

OutboundDelegateMsg

Enum OutboundDelegateMsg 

Source
pub enum OutboundDelegateMsg {
    ApplicationMessage(ApplicationMessage),
    RequestUserInput(UserInputRequest<'static>),
    ContextUpdated(DelegateContext),
    GetContractRequest(GetContractRequest),
    PutContractRequest(PutContractRequest),
    UpdateContractRequest(UpdateContractRequest),
    SubscribeContractRequest(SubscribeContractRequest),
    SendDelegateMessage(DelegateMessage),
    UnsubscribeContractRequest(UnsubscribeContractRequest),
}
Expand description

Messages emitted out of a delegate’s process() function.

This is the outbound counterpart of InboundDelegateMsg and sits on the same host↔delegate wire boundary.

§Deliberately not #[non_exhaustive]

Adding a variant here is a source-level break for any downstream crate that matches on it exhaustively. That is the intended behaviour and it should not be “fixed” by marking the enum.

Every variant of this enum is a request the host must act on. There is one host — freenet-core — and it dispatches these in exhaustive matches with no wildcard (crates/core/src/contract.rs, in the request loop and again in the app-message filter). Marking this enum #[non_exhaustive] would force those matches to grow _ => arms, and a newly added variant would then compile against the host with no arm of its own: the delegate’s request would fall into the wildcard, the call would appear to succeed, and nothing would report that it did nothing.

The compile error is what stops that, and it is the only mechanism that does. Keep it.

Two honest limits on this argument, because it is easy to claim more:

  • It forces an arm to exist, not a handler to be correct. This crate’s own FlatBuffers encoder (client_api::client_events) has explicit arms for six outbound variants that log an error and drop the message. The compile error made someone write those arms deliberately; it could not make them do anything useful.
  • It is not the bug behind this workstream. A delegate SubscribeContractRequest is handled by the host today. Its defect is different and subtler: it registers no demand in the network, so the subscription does not pin the contract (freenet-core#4669). Do not read the compile-error argument as a fix for that; it is a guard against a different failure that has not happened yet, which is the point of a guard.

InboundDelegateMsg carries the opposite trade-off, and is marked: its consumers are third-party delegate WASM, which can reasonably ignore a variant it does not know about.

§Wire format and compatibility

bincode, variant index 0..=N in declaration order. Never insert or reorder a variant: that silently reassigns every later tag, and deployed delegate WASM built against an older stdlib would encode into what the host now reads as a different variant. delegate_msg_variant_tags_are_pinned pins every tag so a reorder fails CI rather than production.

Appending is compatible in one direction only, and this enum is the direction that bites:

  • Old delegate → new host: fine, for appended VARIANTS. The host understands every tag an older delegate can emit, so deployed delegate WASM keeps working against an upgraded node with no rebuild. This does not extend to appending a FIELD to an existing variant’s payload struct, because a field breaks in the opposite direction. See struct_field_wire_compat in client_api::client_events. (ApplicationMessage is #[non_exhaustive], which invites precisely that edit. It is the only payload struct here that is.)
  • New delegate → old host: fails, and fails loudly. bincode rejects the unknown variant tag — as ErrorKind::Custom("invalid value: integer N, expected variant index 0 <= i < M"), since it hands the index to serde’s derived visitor rather than validating it itself — so the host surfaces a decode error on that message rather than misreading it.

There is deliberately no feature-detection handshake. A delegate cannot ask the host which variants it understands, and adding a probe would itself be a wire change with the same bootstrapping problem. The rule is therefore the blunt one: a delegate that emits a variant introduced in stdlib version X requires a host built against stdlib >= X.

Where a host function exists for the same capability, it is the better choice against older hosts. Host functions are resolved by name at module instantiation, so an import an old host does not provide fails at load time with a named missing-import error, instead of mid-protocol on a decode.

That said, the freenet_delegate_contracts namespace holds only get_contract_state(_len) — a local read. There is no host function for writing or subscribing, so PutContractRequest, UpdateContractRequest and SubscribeContractRequest below are the only route for those, and the variant rule above governs them.

Variants§

§

ApplicationMessage(ApplicationMessage)

§

RequestUserInput(UserInputRequest<'static>)

§

ContextUpdated(DelegateContext)

§

GetContractRequest(GetContractRequest)

§

PutContractRequest(PutContractRequest)

§

UpdateContractRequest(UpdateContractRequest)

§

SubscribeContractRequest(SubscribeContractRequest)

§

SendDelegateMessage(DelegateMessage)

§

UnsubscribeContractRequest(UnsubscribeContractRequest)

Implementations§

Trait Implementations§

Source§

impl Clone for OutboundDelegateMsg

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for OutboundDelegateMsg

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<'de> Deserialize<'de> for OutboundDelegateMsg

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl From<ApplicationMessage> for OutboundDelegateMsg

Source§

fn from(req: ApplicationMessage) -> Self

Converts to this type from the input type.
Source§

impl From<DelegateMessage> for OutboundDelegateMsg

Source§

fn from(msg: DelegateMessage) -> Self

Converts to this type from the input type.
Source§

impl From<GetContractRequest> for OutboundDelegateMsg

Source§

fn from(req: GetContractRequest) -> Self

Converts to this type from the input type.
Source§

impl From<PutContractRequest> for OutboundDelegateMsg

Source§

fn from(req: PutContractRequest) -> Self

Converts to this type from the input type.
Source§

impl From<SubscribeContractRequest> for OutboundDelegateMsg

Source§

fn from(req: SubscribeContractRequest) -> Self

Converts to this type from the input type.
Source§

impl From<UnsubscribeContractRequest> for OutboundDelegateMsg

Source§

fn from(req: UnsubscribeContractRequest) -> Self

Converts to this type from the input type.
Source§

impl From<UpdateContractRequest> for OutboundDelegateMsg

Source§

fn from(req: UpdateContractRequest) -> Self

Converts to this type from the input type.
Source§

impl Serialize for OutboundDelegateMsg

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more

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> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

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> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

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

Source§

type Error = !

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

fn try_from(value: U) -> Result<T, !>

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<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