External calls require a synchronizer running protocol version 36 or later and a Daml package
targeting LF 2.4 or later.
externalCall function. For how calls travel through the transaction
and what the participants verify, see
External Calls.
A Worked Example
Suppose the parties of a workflow want transactions to record an instrument price attested by a price oracle that each participant operator runs as an extension service. Run the oracle as a sidecar on the same machine as Canton. The examples below assume the participant can reach the service at the loopback address127.0.0.1.
Each participant that submits or confirms these transactions configures the oracle under the
same extension identifier, here price-oracle:
externalCall:
FetchPrice is exercised, the submitting participant sends the configuration and input
payloads to its price-oracle service, records the returned price in the transaction, and the
choice returns it as a hex-encoded byte string. At confirmation time, the participants hosting
the checking parties re-execute the same call against their own price-oracle service and
approve only if the outputs match.
Configuring an Extension Service
Extension services are configured per participant undercanton.participants.<participant>.parameters.engine.extensions, keyed by the extension
identifier that Daml code passes to externalCall:
ExtensionServiceConfig for the full reference):
address,port,version: the endpoint of the extension service’s HTTP API.tls: enable TLS towards the service, withtls.trust-collection-filenaming the trust anchors.auth: optional bearer-token authentication (type = bearer-token-filewithtoken-file); the token is never logged.connect-timeout,request-timeout,max-retries,retry-initial-delay,retry-max-delay: connection handling; retries apply per logical call.max-response-body-bytes: upper bound on accepted service responses.validate-on-startup: probe the service’s version endpoint when the participant starts.
The externalCall Function
The function is provided by the Daml standard library moduleDA.ExternalCall:
externalCall extensionId functionId config input requests a call to function functionId
of the extension configured on the participant under extensionId. The config argument
is the extension configuration hash — the value the parties use to pin the service
configuration they agreed on, as in the example above — and input is the call input; both
are hex-encoded byte strings, and the empty string represents zero bytes.
Payloads are canonicalized to lowercase before execution, so two calls that differ only in hex
casing are the same call. The result is the service response, again as a hex-encoded byte
string. Malformed payloads, missing extension configuration, extension-service failures, and
invalid service output fail the update; runtime and service errors include the extension and
function context.
Next Steps
- External Calls — How calls travel through the transaction: the flow, validation, and the trust model.
- Error Codes Reference — The external-call validation error codes carry explanations and resolutions generated from the participant sources.