Skip to main content

RPC

Draft specification

Maturity: Draft — not yet validated by a reference implementation. Subject to change during Runtime development.

See Protocol Specifications for reading order and the full specification index.

Abstract

This specification defines the Faberio RPC service — the internal synchronous request-response mechanism used by the Runtime to implement replication between nodes within an information space.

RPC is a runtime-internal protocol. Applications do not invoke or handle RPC calls directly. The Replication service uses RPC to fetch remote state, verify consistency, and coordinate synchronous replication operations.


1. Scope

This specification defines:

  • request and response format
  • RPC method naming
  • call semantics and timeouts
  • information space scoping
  • security requirements for RPC
  • runtime-internal usage constraints
  • implementation model

Applications MUST NOT access the RPC service directly. See section 3.5.

This specification does not define:


2. Motivation

Replication requires both asynchronous and synchronous communication between nodes.

Messaging notifies remote nodes that state has changed. RPC complements messaging by enabling the Runtime to request specific data and coordinate synchronous operations when replication requires an immediate response:

  • fetching object state from a remote node
  • transferring full state during extended offline recovery
  • comparing versions before applying an update
  • resolving replication conflicts
  • verifying consistency after synchronization

Applications interact with replication through the database and file storage APIs. See Distributed Database and Distributed File Storage for replication models. They neither initiate nor handle RPC calls. The Runtime uses RPC internally when messaging alone is insufficient for state synchronization.


3. Concepts

3.1 Request

A request is a signed message sent from one node's Replication engine to another, asking for a specific operation to be performed.

3.2 Response

A response is a signed reply to a request, containing the operation result or an error.

3.3 Caller

A caller is a Runtime replication component that sends RPC requests. Applications do not act as callers.

3.4 Handler

A handler is a Runtime replication component that receives and processes RPC requests. Applications do not act as handlers.

3.5 Application Access

Applications MUST NOT use the RPC service directly.

Applications do not invoke RPC methods, register RPC handlers, or receive RPC calls. All RPC is performed by the Runtime as part of replication implementation.

When replication requires synchronous coordination — for example, fetching the latest version of a record from a remote node — the Runtime issues RPC calls automatically. Application code remains unaware of the underlying RPC layer.


4. RPC Architecture

4.1 Implementation Model

RPC is a transport-layer control mechanism for replication — not a replicated database table. Like Messaging, RPC operates on the control plane and does not store application data.

LayerMechanismNature
Data planeReplicated database and file storagePersistent application state
Control planeRPC and MessagingEphemeral replication signals

RPC requests and responses are transmitted over transport connections and are not persisted in the distributed database. The Runtime MAY maintain a local pending-requests table for timeout and correlation tracking — this table is local and not replicated.

Typical replication flow combining both mechanisms:

  1. Application writes to replicated state on Node A.
  2. Messaging notifies Node B that state has changed.
  3. RPC fetches the current object version from Node A.
  4. Replication engine on Node B applies the update to local state.

5. Request and Response Format

5.1 Request

Every RPC request MUST contain the following fields:

FieldTypeDescription
idUUIDv7Unique request identifier
information_space_idUUIDv7Information space the request belongs to
source_node_idstringCryptographic Node ID of the caller
target_node_idstringCryptographic Node ID of the handler
methodstringPlatform-defined RPC method
payloadbytesRequest parameters
timestampintegerUnix timestamp in milliseconds
signaturebytesEd25519 signature over the request payload

5.2 Response

Every RPC response MUST contain the following fields:

FieldTypeDescription
idUUIDv7Unique response identifier
request_idUUIDv7Identifier of the originating request
information_space_idUUIDv7Information space the response belongs to
source_node_idstringCryptographic Node ID of the handler
statusstringok or error
payloadbytesResponse data or error details
timestampintegerUnix timestamp in milliseconds
signaturebytesEd25519 signature over the response payload

5.3 Signing

Requests and responses MUST be signed by the sending node's private key. The signature covers all fields except signature itself, serialized in canonical format.

Receiving nodes MUST verify the signature before processing the request or response.


6. RPC Methods

6.1 Method Naming

RPC methods are defined by the platform. Applications MUST NOT define custom RPC methods.

Methods MUST use the following naming format:

platform.replication.<operation>

6.2 Relationship to Messaging

Replication uses two runtime-internal channels with distinct roles:

ChannelPatternExamplesPurpose
MessagingAsynchronous publish/subscribeplatform.replication.sync, platform.replication.changed, platform.replication.conflictChange notifications, full-sync requests, conflict signals
RPC (this spec)Synchronous request/responseplatform.replication.fetch, platform.replication.snapshot, platform.replication.compare, platform.replication.resolveFetch object state, transfer snapshots, compare versions, merge conflicts

Message types (message_type in the Messaging envelope) MUST NOT be invoked as RPC methods, and RPC methods MUST NOT be sent as messaging payloads. Typical extended-offline recovery: the reconnecting node sends platform.replication.sync via Messaging; the peer responds with state through platform.replication.snapshot via RPC. See Messaging — Message Types and Distributed Database §9.2.

6.3 Standard Methods

MethodDescription
platform.replication.fetchFetch object state by UUIDv7 identifier
platform.replication.snapshotFetch full state for an information space (monolithic in baseline; paginated in future — see Distributed Database §9.4)
platform.replication.compareCompare object version between nodes
platform.replication.verifyVerify consistency of replicated state
platform.replication.resolveResolve a replication conflict

Planned extensions (not required in the reference MVP): snapshot requests with cursor, limit, and mode (full | metadata_first); content continuation for deferred file payloads. On-demand fetches MUST enforce source-side authorization per Data Access Control.

Implementations MAY add additional platform.replication.* methods. All methods MUST be documented and MUST NOT be exposed to applications.

6.4 Payload

The payload field contains replication parameters defined by the platform. Payloads that reference objects MUST use UUIDv7 identifiers as defined in the Object Identifier specification.


7. Call Semantics

7.1 Request-Response

RPC follows a synchronous request-response pattern. The caller sends a request and waits for a response within a configured timeout period.

7.2 Timeout

Implementations MUST define a default request timeout. The recommended default is 30 seconds.

If no response is received within the timeout period, the caller MUST treat the request as failed and MAY retry according to the replication retry policy.

7.3 Retries

Failed RPC calls MAY be retried by the Replication engine. Retries MUST use the same request_id to enable idempotent handling on the server side.

The handler MUST treat duplicate requests with the same request_id as idempotent and return the same response without re-executing the operation.

7.4 Error Handling

When an operation fails, the handler MUST return a response with status: error and a payload describing the error. The caller MUST NOT apply partial state changes based on a failed response.


8. Information Space Scoping

All RPC requests and responses MUST include information_space_id. RPC calls MUST NOT cross information space boundaries.

The Runtime MUST verify that the information_space_id in the request matches the transport connection's information space.


9. Runtime Authorization

RPC is performed by the Runtime on behalf of replicated applications. Before issuing RPC calls, the Runtime MUST verify that the originating application is authorized for the target information space as defined in the Node Discovery specification.

Applications without authorization for an information space MUST NOT trigger replication — and therefore no RPC calls are generated for that space.


10. Security Requirements

Implementations MUST:

  • sign all RPC requests and responses with the sending node's private key
  • verify signatures on all received requests and responses before processing
  • transmit RPC traffic only over encrypted transport connections
  • enforce information space scoping on all RPC calls
  • verify application authorization before generating RPC calls

Implementations MUST NOT:

  • expose RPC APIs to applications
  • allow applications to register RPC handlers or invoke RPC methods
  • process unsigned requests or responses
  • forward RPC calls across information space boundaries

11. Examples

11.1 Fetch Object State

Request:

{
"id": "0195a3f0-a000-789a-abcd-000000000020",
"information_space_id": "0195a3f0-8000-7890-abcd-000000000001",
"source_node_id": "a3f8c2e17b4d9a0e5f1c8b2d6e4a7f90",
"target_node_id": "b4e9d3f28c5e0b1f6g2d9e8c7f6b5a4e1",
"method": "platform.replication.fetch",
"payload": "{ \"object_id\": \"0195a3f0-9100-7898-bcde-000000000011\" }",
"timestamp": 1718000000000,
"signature": "3c7e...8b2a"
}

Response:

{
"id": "0195a3f0-a100-789b-bcde-000000000021",
"request_id": "0195a3f0-a000-789a-abcd-000000000020",
"information_space_id": "0195a3f0-8000-7890-abcd-000000000001",
"source_node_id": "b4e9d3f28c5e0b1f6g2d9e8c7f6b5a4e1",
"status": "ok",
"payload": "{ \"object_id\": \"0195a3f0-9100-7898-bcde-000000000011\", \"version\": 3, \"data\": \"...\" }",
"timestamp": 1718000000050,
"signature": "5d1f...4e9c"
}

11.2 Replication with Messaging and RPC

1. Application updates record on Node A (via database API)
2. Runtime sends messaging notification: platform.replication.changed
3. Node B receives notification
4. Runtime on Node B issues RPC: platform.replication.fetch
5. Node A responds with current object state
6. Node B applies update to local replicated state
7. Application on Node B reads updated data via database API

11.3 Conflict Resolution

1. Concurrent updates to the same object on Node A and Node B
2. Messaging notifies both nodes of the concurrent modification
3. Runtime issues RPC: platform.replication.compare
4. Nodes exchange version and CRDT metadata
5. Runtime issues RPC: platform.replication.resolve
6. CRDT merge produces converged state on both nodes

11.4 Full State Snapshot

After an extended offline period, the reconnecting node requests a complete state copy instead of fetching individual change notifications. See Distributed Database and Distributed File Storage.

Request:

{
"id": "0195a3f0-b000-789c-cdef-000000000030",
"information_space_id": "0195a3f0-8000-7890-abcd-000000000001",
"source_node_id": "c5f0e4g39d6f1c2g7h3e0f9d8g7c6b5f2",
"target_node_id": "a3f8c2e17b4d9a0e5f1c8b2d6e4a7f90",
"method": "platform.replication.snapshot",
"payload": "{ \"scope\": \"full\" }",
"timestamp": 1718200000000,
"signature": "8e2a...3c1d"
}

Response (MAY be split into multiple chunked responses for large state):

{
"id": "0195a3f0-b100-789d-def0-000000000031",
"request_id": "0195a3f0-b000-789c-cdef-000000000030",
"information_space_id": "0195a3f0-8000-7890-abcd-000000000001",
"source_node_id": "a3f8c2e17b4d9a0e5f1c8b2d6e4a7f90",
"status": "ok",
"payload": "{ \"records\": [...], \"files\": [...], \"chunk_index\": 0, \"chunk_count\": 1 }",
"timestamp": 1718200000100,
"signature": "6f3b...9a2e"
}

12. References