Skip to content
CCPEDIAby Unity Nodes
cip-discuss

CIP-TBD: A ledger record for refused actions

3 messagesstarted 29-10-2026

Also mentionsCIP-0000CIP-0112
  1. O ́rume Dominic#1source ↗ (opens in a new tab)


    An institution on Canton asked "how many attempts did your controls block" has nothing independent to point at today.

    When a Daml check refuses an action the transaction aborts. Nothing is committed, so no update exists and no monitor reading the Update service can see it. The rejection reaches the command completion service, which only the submitting application can read. The party whose conduct is in question is the only party holding the record of it.

    This is not theoretical. The ingestion adapter funded under Dev Fund milestone #302 reads /v2/updates/get-updates-page, /v2/state/active-contracts and /v2/state/ledger-end. It has no reference to completions or rejections. It is a correct adapter. A refused action is simply not in the data it reads.

    The draft proposes writing a refusal as an ordinary contract rather than throwing it as an error, so it travels on the same stream, the same privacy model and the same tooling as everything else, with a counter so the denominator belongs to the ledger rather than to the application.
    It changes no protocol behaviour and needs no participant configuration.

    The usual answer to this is to add the auditor as an observer. That detects a second journal after the fact. It does not prevent one, because an observer's authority is not required to create anything, and a signatory's is.

    That distinction is the whole mechanism.

    I owe the shape of this to two people. Federico Rodriguez replied on 11 September and pointed out that an application's own receipts cannot prove an omission, and that a refusal should be a committed Canton transaction instead.

    The central idea is his. PREDGE replied on 21 October and moved the auditor from the observer line to the signatory line. Both replies are here:

    https://forum.canton.network/t/how-do-you-prove-your-app-didnt-do-something/9114

    Draft:

    https://github.com/dominicrume/cantor8_kya_rails/blob/main/docs/cip/cip-rume-refused-actions.md

    Before writing it I checked what the CIPs already cover, since proposing something that exists would waste everyone's time. Across the 83 CIP bodies in the repository, regulat appears in 26, compliance in 18 and audit in 13. Ten of those 13 are Super Validator admissions where the firm being admitted is an auditor.
    The string refus appears in none of the 83. That note covers all three open RFP 27 proposals including my own, with my interest declared in the first line:

    https://github.com/dominicrume/cantor8_kya_rails/blob/main/docs/rfp-27-overlap.md

    Two questions. Does this belong as a CIP at all, given it changes nothing at the protocol layer? And there is a Dev Fund proposal under RFP 27 covering the same ground, #860, so should the discussion live here or there?

    Once the discussion settles, I am looking for a Super Validator willing to sponsor the CIP and a second to endorse it, per CIP-0000.

    Nothing here has run on DevNet. I hold no credential. This is local Daml script execution, and should be weighed as a specification with a working implementation rather than as deployed software.

  2. Simon Meier#2source ↗ (opens in a new tab)
    Note that creating contracts to store notifications is a storage leak and an anti-pattern. Archiving these contracts costs extra traffic. The better way to signal events is through non-consuming choices.

    As you point out this is an application design pattern that every app provider can decide on independently. So it doesn't require a CIP, as no ecosystem level coordination is needed.

  3. orumedominic#3source ↗ (opens in a new tab)

     

     

    Simon, you are right on both counts about the mechanism, and I had built only the expensive one.

    RefuseSignalled is in now. No contract, and the arguments reach the exercise's informees, the auditor included, because a signatory is an informee of every exercise on a contract. It follows EventLog from CIP-0112.

    What I added is the measurement of what it costs. Pruning never removes an active contract, and a pruned node cannot serve events preceding the prune. So a signaled refusal and a deliberately withheld one leave an identical active contract set, and the participant that can prune belongs to the party the record is about. Twenty refusals each way: twenty contracts against one, with both auditors returning the same count and the same positions. One test per half, and the cheap one was checked by making it create a record.

    So the draft now says, "Signal when somebody is watching now; record when somebody will ask later."

    On whether it needs a CIP, Vacuumlabs, Dev Fund #627, wrote on 18 October: "Since there's no standard pattern out there to commit them on-chain, it didn't make sense to implement it within this proposal." Their refusal logs sit off the ledger, held by the party they describe, because no standard existed. That is the coordination I think is missing, and EventLog is the precedent: a holdings change is application-level too and was standardized so one client can read any issuer.