CIDs

A CID (Content Identifier) is an immutable blob record managed by ip.cid. Every binary file that crosses a swarm boundary — attachments, avatars, arbitrary payloads — is transferred by content hash rather than by URL, so any node that holds the blob can serve it and duplicates are automatically merged.

The cid field is a transport-specific checksum: SHA-1 for HTTP, CIDv1 for Kubo/IPFS. Once a CID record is created, its ip.cid.cid and ip.cid.data_raw fields are immutable — the same hash always resolves to the same bytes. New CID records are created idempotently via ip.cid.find_or_create(), which returns an existing record if the CID is already known.

See also

Technical references — sync_base.ip.cid, sync_http.ip.cid.

Fields

Field

Description

ip.cid.cid

Sync Content Identifier (CID) string

ip.cid.cid_state

State of the CID in the Sync network

See States below for the full state machine.

ip.cid.data_raw

Raw binary content of this CID, stored via ir.attachment in Odoo’s filestore. Odoo automatically detects duplicate filestore content and stores it only once.

ip.cid.file_size

Byte size of the stored raw binary content.

ip.cid.host_node_id

The node that first broadcasted this CID. Used by HTTP transport to locate the file.

See CID Resolution below.

ip.cid.event_ids

Events that reference this CID.

Inverse of ip.event.cid_ids (see Events).

States

wanted ──▶ pending ──▶ pinned
             └──▶ failed
             └──▶ oversized

State

Meaning

wanted

Referenced by an event but not yet fetched from the network.

pending

Fetch is in progress.

pinned

Content is locally available in data_raw. Any waiting events that referenced this CID are automatically unblocked and re-queued.

failed

Fetch failed permanently; check gateway logs for the error.

oversized

Blob exceeds the transport size limit (default 10 MB). Reduce the payload or raise the limit in gateway config.

CID Resolution

While the CID state machine is transport-agnostic, the mechanism for resolving a CID depends on your swarm’s network layer:

  • HTTP Transport: The node acts as a direct client. It calls ip.node.cat() on the sender’s host node (via the blob endpoint) to download bytes synchronously.

  • Kubo Transport: The node acts as a P2P participant. It relies on the Kubo daemon to locate the blob via the DHT or direct P2P connections.

The waiting state is the “buffer” for both transports—it ensures your database never imports a record until the associated binary data is fully verified and available in your local filestore.

See also

sync_base — blob endpoints (blob_content_bearer, blob_content_user) that serve CID content to authenticated callers.

Fetch Flow

  1. An inbound event references a CID string in its payload. The is_cid trait in the mapping engine creates a wanted ip.cid record and blocks the event in mapping_state: waiting.

  2. The gateway picks up the wanted CID and enqueues it for download. HTTP: _http_fetch_wanted_cids() issues a synchronous fetch. Kubo: ip.swarm._express_fetch_cids() triggers the sidecar’s priority fetch queue.

  3. The fetcher calls ip.node.cat() on host_node_id to retrieve the raw bytes.

  4. On success: data_raw is written, cid_state transitions to pinned, and host_node_id is re-anchored to the local gateway. For attachments, ir.attachment._get_sync_cid() handles the lazy CID computation and links the resulting ip.cid to the ir.attachment.cid_id field.

  5. Any events that were waiting on this CID are automatically re-queued for mapping.

  6. On failure: cid_state transitions to failed (network error) or oversized (blob exceeds the transport size limit).

Fetch Content — action_fetch_content()

Manually triggers steps 3—5 for a single CID record. Raises UserError if no host node is set or if the node returns no content.

See also