Skip to content

Implement CIP-160 protected outputs and Receiving authorization in Dijkstra - #6153

Closed
colll78 wants to merge 13 commits into
IntersectMBO:masterfrom
colll78:codex/cip-160-receiving
Closed

colll78 wants to merge 13 commits into
IntersectMBO:masterfrom
colll78:codex/cip-160-receiving

Conversation

@colll78

@colll78 colll78 commented Oct 7, 2026 •

Copy link
Copy Markdown

Summary

Implement proposed CIP-160 recipient authorization for ordinary protected outputs in Dijkstra, including nested transaction bodies. Each protected Plutus output requires its own Receiving execution, redeemer and budget, even when outputs share a script hash or are byte-identical.

each body's protected ordinary outputs (original indexes)
  payment key     -> signature over that body
  native script   -> existing phase-1 authorization
  Plutus output i -> Receiving(hash, i), redeemer[i], budget[i]
                     context: original i + resolved output[i]

Keys and native scripts require no Plutus redeemer. Pointers use original body-local output indexes; unprotected outputs and protected key/native outputs leave gaps. Parent and child purpose, redeemer, integrity and estimation domains remain separate. Batch fees and execution limits include every invocation. Any failing invocation invalidates ordinary batch effects; an accepted phase-2-invalid transaction applies only top-level collateral effects.

Protection uses payment-header bit 0x08 for base/enterprise addresses and survives identity, compact storage, restored state and stake accounting. Historical eras reject protected outputs; proposed Dijkstra admission starts at protocol major 12. Protected pointers, production initial funds and protected collateral returns are rejected. V4 adds Receiving ScriptHash Integer and ReceivingScript Integer TxOut, both with Data tag 7 and no implicit datum argument. Existing V1–V3 and pre-existing V4 constructor encodings remain unchanged. Legacy contexts reject visible protection they cannot represent. Builders and estimators preserve containing-body identity and original output indexes.

Per-output execution is our implementation decision, supported by CIP-160's rule and lehins's resolved-TxOut comment. Raw indexes, Data formats and activation remain proposals; upstream approval of every detail is not implied. Companions: CIP-160/CIP-19, Plutus V4, and formal specification.

Complete Dijkstra genesis JSON accepts the proposed 369-parameter initial V4 model, preserving strict lengths and historical V1–V3 counts. Conformance recovers committee pool IDs from retained snapshots independently ranked by stake and pool ID, validating weights, honored keys and proof-of-possession with runtime Globals. Companion model fixes preserve hard-fork versions, registered zero-stake pools and unique semantic pool IDs across multiple delegators.

Evidence

  • Before: output creation requires no destination authorization, and Receiving purposes/contexts do not exist.
    After: concrete tests cover duplicate and identical outputs, independent redeemers/budgets, missing or incorrect redeemers, body isolation, validator failure, both validity mismatches, collateral-only effects and Receiving-to-Spending lifecycle behavior.
  • Ledger: reviewed commit 4b06e253 incorporates upstream snapshot/forecasting changes. Its linear rebase preserves the exact validated source tree. The strict eight-target GHC 9.6.7 build and owning conformance test rebuild pass. Scoped runtime checks pass 442 examples, zero failures, two inherited formal properties pending, including Receiving, contexts, protected addresses, NES roundtrip, epoch/SNAP, forecasting, queries and purpose APIs. Three new Foreign regressions check set-versus-mark pool projection, both mark cache refreshes, and live-key genesis committee/cache seeding. Genesis seeding is not full injection or node startup. SQL changes are compile-covered only. Remote CI for this rebased commit remains pending; all five ledger checks passed at the preceding published 6e56634b checkpoint.
  • Plutus/formal: 450 public API and six genuine compiled-plugin tests pass, with all five Plutus remote checks green. Two genuine preprocessor generations agree; all 41 V1–V3 fixture byte strings remain unchanged. Formal source passes complete Agda closure, examples/interfaces, scanner, release extraction and 73 persistent extracted assertions; its pinned artifact matches all 789 generated files. Full ledger conformance passed 1263 examples, zero failures, 28 inherited pending cases at the earlier 77d85ec1d checkpoint. The new scoped checks do not establish a full latest-head conformance pass.
  • Consumer checkpoints, before the upstream merge: API passes 293 unit tests and 125 goldens, with an earlier 171 RPC tests and native WASM golden. CLI passes 81 unit tests and 820 goldens. At the corrected V4 count, affected API 14/0, CLI 8/0 and release admission/capacity 11/0 pass. Both consensus branches pass their remote compiler matrices and required native Hydra jobs. API's 26 checks include Windows, GHC 9.6–9.14 and real WASM builds; CLI's 17 platform/compiler and quality checks pass. Public graphs and assembled Linux/Windows Nix derivation evaluations resolve with default packages/flags retained; these are not full Nix builds. These results require renewed consumer adapters and graph validation against the merged ledger.
  • Node checkpoints, before the upstream merge: 39 unit properties, including default-genesis decoding, pass. A real lifecycle rejects a missing recipient without state change, creates four protected outputs, including two with distinct Plutus redeemers, agrees with API replay and spends all four. Same-database relay restart preserves protected UTxO through fresh queries/replay and permits spending. Generator, supplied-input Conway calibration and real-parser opt-in/protocol-default checks pass. All five ordinary node e6a3b4b matrix jobs pass, including unmodified startup. Separate Hydra DNS Windows, empty-Leios-database fixture and tracer issues remain below. These node results do not validate the merged ledger graph.

Conformance compares translated state and acceptance/rejection, not exact failure payloads or concrete UPLC execution. Foreign contexts/evaluator, Coin-only values, fees/integrity and size callbacks retain documented abstractions.

Performance measurements are also pre-merge checkpoints. Four synthetic ordinary Shelley–Alonzo transactions produce byte-identical states against their baseline; the paired whole-process envelope measures +0.222% median CPU and +19,200 bytes allocation, not replay or pure throughput. Isolated enterprise decoding costs +8.66–10.21% CPU and +152 B/address; instance decoding adds 40 B/address. API extraction measures 29.146–129.120 µs for 101–401 Plutus outputs including preparation, without paired baseline, allocation or end-to-end claims. Benchmark smoke success does not establish performance neutrality.

Checklist

  • Meaningful commits, tests, changelogs, versions and dependency bounds.
  • Recorded Haskell/Cabal/changelog formatting, generated CDDL and hie.yaml checks.
  • Standards and semantic self-review, including the upstream merge resolution.
  • Latest-head CI, consumer graph validation and external merge gates resolved.

Merge Danger

Door: one-way after activation

The address bit, purpose tag and V4 Data shapes become protocol formats. This PR does not authorize activation or changes to a deployed language.

Blast Radius: ledger

The reviewed upstream merge changes forecasting and snapshot caches: NES removes stored pool distribution and changes CBOR arity 7→6; Mark adds the key-age parameter and changes arity 3→4, reconstructing its caches on decode. Old on-disk NES/Mark formats require replay. Consumer adapters must replace removed state interfaces and handle the new snapshot API before fresh graph/runtime validation. Earlier consumer proofs do not cover this state-format boundary.

CLI/node ancestry gates remain enabled and fail on proposal fork pins; the matching formal artifact must become an upstream master-artifacts ancestor. DNS workflow approval remains external. Public DNS df28303 repairs the Windows partial-function failures, but consumers still pin the older source; exact Windows Hydra validation after pin refresh remains pending. The empty-Leios-database fixture passes a real historical-tools red/green check (55 immutable blocks reduced to exactly two); current NixOS validation remains pending. A test-only tracer change preserves the delivery deadline and moves cumulative log validation outside it; fresh-graph and remote validation remain pending.

A recorded-seed CSJ download-bound counterexample still reproduces locally with an identical trace: accepted-prefix loss during new-dynamo reset after catch-up. Baseline dependency-graph reproduction and the intended cumulative-bound guarantee remain unresolved; random CI success does not dispose of it. No protocol/property was weakened. The musl loader diagnostic is independently nonfatal, but full current musl compilation remains pending.

Broader scheduled activation, snapshot restoration, rollback, Leios and Receiving-specific binding runtime coverage remain incomplete. This is not a final merge-readiness claim.

@colll78
colll78 force-pushed the codex/cip-160-receiving branch from 22860e4 to 4b06e25 Compare October 7, 2026 13:50
@lehins

lehins commented Oct 7, 2026

Copy link
Copy Markdown
Collaborator

I am closing this PR for two reasons:

  • Dijkstra scope has been frozen in august and no new features or CIPs will be accepted for Dijkstra era.
  • We do not accept AI slop into the repo. This is our policy for contributors:

Usage of AI tools for adding contributions to the repository is reserved for maintainers and core contributors only. Any pull request that was generated by AI or with use of AI will be immediately rejected.

That being said, if you want to implement this CIP for Euler era next year, then we can talk about creating a plan of how this feature can be added to ledger in small reviewable PRs. Note that BlockPQR and Anastasia Labs will need to have a discussion on who is going to pay for reviewing this work as well, but that will be a problem for Leonard Hegarty and yourself to resolve.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants