March Docs

RemoteCall

RemoteCall: the L4 remote-procedure-call safety core (P1 L4).

A remote function reference is {module, name, sig_hash, impl_hash}, stamped at compile time for a function the author has enrolled as a remote target. Node.call frames {fref, msgpack(args), reply_to, deadline} over the net-kernel; the remote runs a CAS admission check before invoking:

  • sig_hash mismatch -> Reject(TypeMismatch) — incompatible signature, a
  hard type error; never invoke.
* impl_hash mismatch -> Reject(VersionSkew)   — same type, different body;
  the peer could (P6) ship the matching body, otherwise reject.
* both match          -> Accept               — invoke the local native copy.

Failure isolation: deadline expiry, netsplit, or a remote crash come back as a CallError (DeadlineExceeded / NoConnection / RemoteExit), never a hang.

This module is the pure core: the reference, the wire protocol (MessagePack codecs for request/reply, framable inside a NetFrame), the error taxonomy, and the admission decision. The enroll/stub/registry runtime mechanism (the actual function-by-identity dispatch) and the socket transport are separate layers.

Types

typeRemoteRefRemoteRef = { module_name : String, fn_name : String, sig_hash : String, impl_hash : String }#

A compile-time-stamped reference to an enrolled remote target. sig_hash pins the (argument, return) TYPE; impl_hash pins the compiled body (a Merkle root over the call graph + type usage, from the CAS).

typeCallErrorCallError = DeadlineExceeded | NoConnection | RemoteExit(String) | TypeMismatch | VersionSkew | NoTarget | Forbidden#

Why a remote call could not return its target's result. NoTarget = the peer has no function enrolled under this reference (wrong node / not enrolled). Forbidden = certificate mode (step 11b), and this node's or the peer's certificate lacks raw_send: RemoteCall is a raw primitive.

typeVerdictVerdict = Accept | Reject(CallError)#

The CAS admission decision for an inbound call against the local target.

typeReplyResultReplyResult = Returned(List(Int)) | Failed(CallError)#

A call result: the MessagePack-encoded return value, or a failure.

typeCallRequestCallRequest = { fref : RemoteRef, args : List(Int), reply_to : Pid, deadline : Int, correlation : Int }#

A framed call. args is the MessagePack-encoded argument tuple; reply_to is the caller's global Pid; deadline is an absolute time (ms) after which the caller stops waiting; correlation matches a reply to its request.

typeCallReplyCallReply = { correlation : Int, result : ReplyResult }#

Functions

fndecode_replydecode_reply(bytes : List(Int)) : Result(CallReply, String)#

Decode the bytes of encode_reply. Err for bytes that are not MessagePack or a value of the wrong shape (including an unknown error code).

fndecode_requestdecode_request(bytes : List(Int)) : Result(CallRequest, String)#

Decode the bytes of encode_request. Err for bytes that are not MessagePack, a value of the wrong shape ("RemoteCall: malformed CallRequest" / "malformed RemoteRef"), or a reply-to pid GlobalPid cannot decode.

fnencode_replyencode_reply(rep : CallReply) : List(Int)#

The MessagePack wire bytes of [rep]: [correlation, [0, Bin(payload)]] for a returned value, [correlation, [1, error]] for a failure, the error as [code] or [2, reason] for RemoteExit.

fnencode_requestencode_request(req : CallRequest) : List(Int)#

The MessagePack wire bytes of [req] (frame them with NetFrame.encode): [[module, fn, sig_hash, impl_hash], Bin(args), reply_to, deadline, correlation], reply_to in GlobalPid's encoding.

fnerr_replyerr_reply(correlation : Int, e : CallError) : CallReply#

A failed reply to request [correlation]: Failed(e).

fnerror_messageerror_message(e : CallError) : String#

A one-line, human-readable description of [e], e.g. "deadline exceeded" or, for RemoteExit(reason), "remote process exited: <reason>".

fnis_acceptis_accept(v : Verdict) : Bool#

Is [v] Accept?

fnok_replyok_reply(correlation : Int, payload : List(Int)) : CallReply#

A successful reply to request [correlation]: Returned(payload).

fnremote_refremote_ref(module_name : String, fn_name : String, sig_hash : String, impl_hash : String) : RemoteRef#

A reference to the remote target [module_name].[fn_name] with the given signature and implementation hashes.

fnrequestrequest(fref : RemoteRef, args : List(Int), reply_to : Pid, deadline : Int, correlation : Int) : CallRequest#

A call request for [fref] with MessagePack-encoded [args], replying to [reply_to], giving up at [deadline] (absolute unix ms) and matched to its reply by [correlation].

fnverifyverify(local_sig : String, local_impl : String, fref : RemoteRef) : Verdict#

CAS admission: does the inbound [fref] agree with the local target's hashes? Reject(TypeMismatch) when the sig_hash differs (checked first), Reject(VersionSkew) when only the impl_hash differs, else Accept. The names are not compared.

RemoteCall.verify("s1", "i1", RemoteCall.remote_ref("M", "f", "s1", "i2")) == Reject(VersionSkew)