feat(external-call): protocol and transaction-hash foundation - #20
Draft
angelol wants to merge 23 commits into
Draft
Conversation
…set#537) * refactor(external-call): redesign extension service branch * fix(external-call): enforce HTTP request timeout * fix(external-call): log HTTP error bodies at debug * fix(external-call): make response body limit configurable * fix(external-call): bound protocol header values * fix(external-call): accept IPv6 service addresses * fix(external-call): cancel completed HTTP timeouts
…chemeVersion V4) Carves PR1 of the external-call split: the protocol/transaction-hash foundation plus the ViewParticipantData.externalCallResults ImmArray->Seq migration (construction sites in base, common, and participant). Includes two hunks HashingSchemeVersion.V4 transitively requires to compile standalone under -Werror (both byte-identical to the golden reference, so the union of the split still equals it): - interactive_submission_service.proto: HASHING_SCHEME_VERSION_V4 enum value (V4.toLedgerApiProto maps to ApiHashingSchemeVersion.HASHING_SCHEME_VERSION_V4). - SubmitRequestValidator.scala: the matching V4 case, otherwise the enum makes the existing match non-exhaustive. Also traces the external-call result config/input/output payloads in the V4 node hash builder: they were fed to the digest via the no-context addByteString overload, so the HashTracer recorded only their length, not their value. Passing a trace context makes the values appear in the human-readable hash trace; the digest is unchanged (the context is trace-only), so existing hash values are unaffected. Proto snapshot regenerated fresh from PR1's tree (v32 messages + V4 enum; excludes PR2's interactive_submission_data.proto additions). openapi.yaml regenerated for the V4 enum.
angelol
force-pushed
the
angelol/external-call-06-split-pr1-foundation
branch
from
June 30, 2026 12:19
8255166 to
b62f4f6
Compare
Review feedback on digital-asset#549: bind every field via `val ExternalCallResult(...) = result` so that if a field is added to ExternalCallResult the binding stops compiling, forcing a conscious decision about whether it is included in the hash. The hash value is unchanged.
Review feedback on digital-asset#549: the shared (V2/V3) exercise-node encoding silently ignored externalCallResults. It now fails (NodeHashingError.UnsupportedFeature) when results are present, so they can never be dropped from the hash unnoticed. Uses a virtual `supportsExternalCallResults` hook (default false; V4 overrides to true) rather than reading `hashingSchemeVersion` in NodeHashBuilderCommon, where that name resolves to the constructor parameter (V3) even for a V4 instance and would wrongly reject V4. Adds a test that pre-V4 schemes reject results-bearing exercise nodes.
Reference commit: d39a8b14b0
…to <=100 cols Review feedback on digital-asset#549: break the single long @resolution string into a |-margin multi-line string (no explicit .stripMargin, matching the @explanation above it).
…ashing-scheme table Review feedback on digital-asset#549.
Review feedback on digital-asset#549: 'Exercise nodes with version dev include ...'.
…tream wording Review feedback on digital-asset#549 (rst:61): the prior 'stable vs development protocol' wording was imprecise (singular dev version; non-standard 'development protocol' term). Restored the original: every new Daml/LF version maps to a new hashing version (LF V1->V2, V2->V3, dev->V4).
Review feedback on digital-asset#549 (rst:110): the line was not a change from V2 (it restated V3's PV support + V4's external_call_results exclusion). V3's PV support is in the table; external_call_results is covered in the V4 section.
…rding Review feedback on digital-asset#549 (rst:125): removed the V4 statement from the V3 section (V4 has its own section), restored the :ref: on V3, and dropped 'only' — per HashingSchemeVersion, V3 is supported from v35 onwards (including dev), not v35 alone.
Review feedback on digital-asset#550 (rst exercise node): convert the exercise encoding to sphinx tabs (V3/V4) like the 3.5 branch, replacing the free-text V4 note. Dropped the V2-only '0x01 || # Node encoding version' line (removed in V3 onwards per the v2 hasher and 3.5's V3 tab) so both tabs are accurate.
… tabs Review feedback on digital-asset#550: replace the inline 'hashing_scheme_version_byte (e.g. 0x03 for V3, 0x04 for V4)' with V3/V4 tabs (0x03/0x04), matching the 3.5 branch.
…in node hashing Review feedback on digital-asset#550 (NodeHashBuilderCommon): key the reject on the node's LF serialization version (external-call results are only valid on dev nodes), mirroring PreparedTransactionDecoder, instead of a hashing-scheme capability hook. Removes the supportsExternalCallResults hook and its V4 override; also catches the invalid 'results on a pre-dev node' case the hook missed. V2/V3 still reject (they only ever hash pre-dev nodes) and V4 is unaffected.
…(foundation) digital-asset#557 refactored ViewParticipantData validation from an in-constructor block into a validated()/checkX structure (incl. checkExternalCallResults). Conflicts resolved by adopting digital-asset#557's structure and re-applying our changes: - ViewParticipantData: keep digital-asset#557's validation refactor; re-apply the externalCallResults ImmArray->Seq migration; keep our supportsExternalCallResults helper (public API consumed by the runtime-integration PRs) and route digital-asset#557's checkExternalCallResults dev-PV gate through it (single source, same behavior). - LegacyTransactionTreeFactory, ExampleTransactionFactory, TransactionViewTest: adopt digital-asset#557's call shape (single arg-list, keyResolution rename) with Seq.empty. - .proto_snapshot_image.bin.gz: regenerated from the merged proto tree.
…' in V2-rejection assertions The prepare/execute V2-rejection assertions expected 'Please using hashing scheme V3 or higher' but the production message says 'Please use' (grammar fixed in the transaction-hash foundation without updating these two integration assertions), so both failed in CI. Align them with the actual message.
This file was only added to force a one-off full recompile in CI; it is not present on the base branch, so removing it keeps the PR clean and returns CI to incremental builds for this branch.
The full-message shouldBe added in c0f3fb5 had the +-continuation string over-indented; align it per scalafmt so the format check passes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This is PR 1 of 8 in the external-call runtime-integration series tracked in digital-asset#513, stacked on digital-asset#537.
The external-call stack (digital-asset#513): digital-asset#506 added the transaction-side representation for recording external-call results; digital-asset#514 added the LF
EXTERNAL_CALLbuiltin surface; digital-asset#518 wired it into Speedy and the LF engine; digital-asset#522 added transaction protobuf encoding/decoding; digital-asset#526 added Canton protocol serialization for recorded results; digital-asset#537 added the participant-side extension-service client. digital-asset#541 implemented the remaining runtime integration as one PR; this series splits digital-asset#541 into 8 independently reviewable PRs (each < 1000 lines) and supersedes it.This PR lays the protocol and transaction-hash foundation the rest of the series builds on: the Canton protocol fields that carry recorded external-call results, and the
HashingSchemeVersionV4 hashing that covers them.Scope
This PR adds:
ViewParticipantData.externalCallResultsand the supporting protocol additions (participant_transaction.proto,SubmitterMetadata,ExternalAuthorization,LocalRejectError), including theImmArray → Seqmigration of the recorded-results collection across the base/common/participant transaction-tree construction sitesHashingSchemeVersionV4 (dev-gated) and the v4 node/transaction hashers that fold recorded external-call result payloads into the transaction hash, with the payloads surfaced in theHashTraceroutputHASHING_SCHEME_VERSION_V4Ledger API enum value and the matchingSubmitRequestValidatorcase (required for-Werrormatch exhaustiveness once the enum exists)transaction.protofield for recorded resultsopenapi.yaml(V4 enum), plus hash tests, generators and docsOut of scope
The prepared-transaction codec (PR 2), command-execution wiring (PR 3), engine replay (PR 4), the extension-service runtime (PR 5+), consistency checking, routing and validation (PR 6–8). No LF semantics change. The feature is
ProtocolVersion.dev-gated, so this PR is dormant on released protocol versions.Hashing Boundary
Recorded external-call result payloads are Canton protocol data: after submission they are carried in
ViewParticipantData.externalCallResultsand protected by the Canton view signature. V4 hashing folds them into the Canton transaction hash on that basis. (Their exclusion from the LF/prepared node hash is covered in PR 2.)Refs digital-asset#513.