#[non_exhaustive]pub enum InboundDelegateMsg<'a> {
ApplicationMessage(ApplicationMessage),
UserResponse(UserInputResponse<'a>),
GetContractResponse(GetContractResponse),
PutContractResponse(PutContractResponse),
UpdateContractResponse(UpdateContractResponse),
SubscribeContractResponse(SubscribeContractResponse),
ContractNotification(ContractNotification),
DelegateMessage(DelegateMessage),
UnsubscribeContractResponse(UnsubscribeContractResponse),
WakeupFired {
tag: Vec<u8>,
},
}Expand description
Messages delivered into a delegate’s process() function.
This is the inbound counterpart of OutboundDelegateMsg and sits on the
host↔delegate wire boundary.
Marked #[non_exhaustive] so future variants can be added without a
source-level break; downstream match sites must include a wildcard arm.
OutboundDelegateMsg is deliberately not marked, and the asymmetry is
the point — see the rationale on that enum. (An earlier version of this
comment asserted that OutboundDelegateMsg already carried the attribute.
It never has.)
§Wire format and compatibility
bincode, variant index 0..=N in declaration order. Two rules follow, and the compiler enforces neither:
- Never insert or reorder a variant. That silently reassigns every later
tag, so delegate WASM compiled against an older stdlib decodes the same
bytes into a different variant — no error, just a message quietly
reinterpreted as another one.
delegate_msg_variant_tags_are_pinnedpins the tag of every variant of both enums so a reorder fails CI instead. - Appending is compatible in exactly one direction. An old sender’s old
variant always decodes on a new receiver. A new sender’s new
variant does not decode on an old receiver: bincode rejects the
unknown tag — as
ErrorKind::Custom("invalid value: integerN, expected variant index 0 <= i < M"), since bincode hands the index to serde’s derived visitor rather than validating it itself. (NotInvalidTagEncoding, which bincode only ever produces for a badOptiondiscriminant.)#[non_exhaustive]does not change this — it is a source-level attribute with no effect on the encoding, and serde has no unknown-variant fallback to fall back to.
For this enum the incompatible direction is a new host → old delegate,
and it is mostly unreachable in practice: the host emits a response variant
only in reply to the matching request variant, so a delegate that never
emits a request added in stdlib version X never receives the response added
in X. Deployed delegate WASM therefore keeps working against an upgraded
node. The genuinely constrained direction is delegate → host; see
OutboundDelegateMsg.
The compatibility claims above are asserted, not merely asserted-in-prose,
by the delegate_wire_compat test module at the bottom of this file.
Variants (Non-exhaustive)§
This enum is marked as non-exhaustive
ApplicationMessage(ApplicationMessage)
UserResponse(UserInputResponse<'a>)
GetContractResponse(GetContractResponse)
PutContractResponse(PutContractResponse)
UpdateContractResponse(UpdateContractResponse)
SubscribeContractResponse(SubscribeContractResponse)
ContractNotification(ContractNotification)
DelegateMessage(DelegateMessage)
UnsubscribeContractResponse(UnsubscribeContractResponse)
WakeupFired
Delivered by the host when a wakeup previously requested via
DelegateCtx::schedule_wakeup fires. tag is the opaque
value the delegate supplied when scheduling, echoed back verbatim so
the delegate can identify which wakeup fired. Owned ('static).
§Currently unreachable, and deliberately kept — do not delete it
This is the delivery half of scheduled wakeup. Its request half,
DelegateCtx::schedule_wakeup, was removed in 0.11.0 because no
released freenet-core ever registered the
__frnt__delegate__schedule_wakeup host import it called. Nothing can
ask for a wakeup today, so this variant never arrives.
That makes it an orphan, and an orphan invites tidying. Three reasons not to:
- Unreachable is not harmful. The removed externs were removed because a delegate calling one compiles and then fails at module instantiation, leaving a healthy-looking node running a broken app. A variant that never arrives does none of that. Only the first problem justifies a breaking change.
- This one is on the wire. Deleting it is a wire-format change on a
pinned enum, which is a much heavier act than deleting an unused
externdeclaration — and the tag-pinning test below exists to stop it happening casually. - The feature is expected back. freenet-core’s host-side
implementation exists on the unmerged branch
feat/3972-delegate-wakeup-core. Removing the delivery half now buys nothing and costs a second wire change when it lands.
Restoring the feature means landing both halves together: the host
registration in freenet-core and the stdlib extern plus its
host_imports::DECLARED_HOST_IMPORTS entry. See freenet-core#5717 for
the check that makes that ordering visible.
§What the context cache holds during a wakeup
Nothing the delegate should read. freenet-core’s delegate context cache
is keyed per delegate, not per conversation, and entries are pruned
after DELEGATE_CONTEXT_TTL (10 minutes). Two consequences, both
arguing the same way:
- Any wakeup worth scheduling is far longer than 10 minutes, so whatever context existed when it was scheduled is gone by the time it fires.
- If the delegate happens to have a live context from some other in-flight exchange inside that window, it belongs to that exchange. Reading it during a wakeup would be reading another conversation’s working state.
This is why the variant carries no DelegateContext: there is no
coherent value to put in it. A delegate needing state across a wakeup
reads it from its secrets, which is what core’s own cache doc
recommends for exactly this case.
Appended at tag 9, after UnsubscribeContractResponse at tag 8.