Conversation
jasagredo
requested review from
bladyjoker,
dnadales,
geo2a and
nfrisby
as code owners
August 27, 2026 13:17
jasagredo
force-pushed
the
js/tracing-instances
branch
2 times, most recently
from
August 27, 2026 13:32
b003a0e to
7b0838e
Compare
jasagredo
force-pushed
the
js/tracing-instances
branch
from
September 3, 2026 15:21
e9b2bd8 to
8f27e3f
Compare
dnadales
reviewed
Sep 4, 2026
jasagredo
force-pushed
the
js/tracing-instances
branch
2 times, most recently
from
September 9, 2026 12:08
332726c to
b73febc
Compare
8 tasks
jasagredo
force-pushed
the
js/tracing-instances
branch
from
September 16, 2026 10:44
b73febc to
80ae926
Compare
jasagredo
added this pull request to stack #2296
September 16, 2026 10:44
jasagredo
force-pushed
the
js/cardano-config-and-keys
branch
from
September 16, 2026 11:10
40237c4 to
432c368
Compare
jasagredo
force-pushed
the
js/tracing-instances
branch
from
September 16, 2026 11:11
80ae926 to
232e47e
Compare
jasagredo
force-pushed
the
js/cardano-config-and-keys
branch
from
September 16, 2026 11:28
432c368 to
b08c4ae
Compare
jasagredo
force-pushed
the
js/tracing-instances
branch
from
September 16, 2026 11:28
232e47e to
f86d8dc
Compare
jasagredo
force-pushed
the
js/cardano-config-and-keys
branch
from
September 25, 2026 14:54
8a37ec5 to
3e6b1e2
Compare
jasagredo
force-pushed
the
js/tracing-instances
branch
from
September 25, 2026 15:36
680e3a7 to
2a51544
Compare
Introduce a new public sublibrary 'tracing' with instances for Consensus types, moved from cardano-node.
Moving it from cardano-node/cardano-api.
Reimplement, off cardano-api, the Shelley-era JSON rendering helpers that the era tracing instances need: bech32 stake/reward addresses (CIP-19, via the bech32 package), hex script hashes, and an era-generic script-purpose renderer built on cardano-ledger-api's AnyEraScript projections (replacing cardano-api's per-era Alonzo/Conway plutus-purpose rendering and its ShelleyBasedEra/ AlonzoEraOnwards era witnesses). Output matches cardano-api's.
Move Cardano.Node.Tracing.Era.Byron to Ouroboros.Consensus.Tracing.Era.Byron; inline the trivial textShow helper (its only cardano-api use) and drop the imports the old -Wno-unused-imports hack was masking.
Move Cardano.Node.Tracing.Era.Shelley to Ouroboros.Consensus.Tracing.Era.Shelley,
off cardano-api:
- use the new Era.Shelley.Render helpers (bech32 addresses, script hashes,
era-generic plutus purposes) instead of the cardano-api ones
- drop the cardano-api era witnesses (ShelleyLedgerEra/IsShelleyBasedEra/
shelleyBasedEra/forEraInEon/toScriptIndex): the affected instances are now
phrased directly over the ledger era with an AnyEraScript constraint, and
ExtraRedeemers renders redeemer pointers via renderScriptIndex
- render VRF key hashes via the ledger's own hash (fromVRFVerKeyHash was
always a ledger function, only re-exported by cardano-api)
- inline textShow
- re-add the ToJSON orphans for cardano-data's NonEmptySet/NonEmptyMap that
cardano-node previously got transitively from cardano-api
Builds with no warnings.
HotKey.KESInfo and HotKey.KESEvolutionError are Consensus types, but their
LogFormatting/MetaTrace instances (and the ToJSON orphan for KESPeriod they
need) stayed behind in cardano-node's Cardano.Node.Tracing.Tracers.KESInfo,
even though the HasKESInfo/GetKESInfo classes that feed them had already moved
here. A second consumer of :tracing would have had to reimplement those
instances, and would then have clashed with cardano-node's copies.
Move the instances and traceAsKESInfo here, and split the leftover
Ouroboros.Consensus.Tracing.Queries -- a name inherited from
Cardano.Node.Queries that no longer describes its contents -- along the lines
of what the classes are actually for:
- Ouroboros.Consensus.Tracing.KESInfo: HasKESInfo, GetKESInfo,
traceAsKESInfo, and the instances above
- Ouroboros.Consensus.Tracing.ConvertTxId: ConvertTxId
The instance bodies are unchanged, so the rendered messages and the EKG metric
names stay the same.
The LogFormatting/MetaTrace instances are orphans spread over the Ouroboros.Consensus.Tracing.* modules, four of which (Era.Byron, Era.Shelley, Era.HardFork, Formatting) export nothing else and so have to be imported for their instances alone. Which module carries which instance is not something a consumer should have to track: getting it wrong is silently losing an instance, and it already forced cardano-node to sprinkle `import ... ()` lines over five wiring modules. Add an umbrella that re-exports the name-bearing modules and imports the instance-only ones, so a single import brings the whole set into scope and the internal module structure can change without breaking consumers.
renderScriptPurpose and renderScriptIndex both project a PlutusPurpose through cardano-ledger-api's AnyEraScript pattern synonyms. Those synonyms carry no COMPLETE pragma, so the wildcard is needed to keep the match total -- but falling through to Aeson.Null makes a purpose the ledger has added and we do not know about indistinguishable from one that legitimately rendered as null. Fall through to an explicit marker instead, so an unhandled purpose is greppable in the logs and a distinct shape in the trace schemas. Also record that renderScriptIndex does not reproduce the JSON shape cardano-api's toScriptIndex produced for the ExtraRedeemers field.
The instances were phrased over TraceObjectDiffusion{In,Out}bound with both
type parameters free, gated on an ObjectDiffusionMetricsPrefix class that
supplied the EKG metric prefix. That class was not exported, so the fully
general orphan both blocked anyone from writing an instance for their own
instantiation and gave them no way to extend ours.
The object type is a type family (PerasCert / PerasVote) and so cannot appear
in an instance head, which is what forced the generalisation -- but the
object-id type can, and it is what actually distinguishes the two diffusion
pipelines. Match on it directly and drop the class: a further diffusion kind
adds its own pair of instances rather than an instance of a closed class.
The metric prefixes are unchanged.
Consensus.Tracers has carried perasCertInclusionTracer and perasVoteForgingTracer for a while, but TracePerasCertInclusionEvent and TracePerasVoteForgingEvent had no LogFormatting/MetaTrace instances, so cardano-node could only wire both to a no-op: the events were unobservable. Add the instances, with a namespace, a severity and documentation per constructor. The routine "nothing to do this slot/round" cases are Debug, the decisions and their outcomes Info, and the environment read failure Error. The payloads of the decisions and DB outcomes are rendered via Show, as the object diffusion instances alongside them already do. Also export TracePerasVoteForgingEvent (..) from Ouroboros.Consensus.Node.Tracers, which already exported its cert inclusion counterpart, so both trace types reach a consumer from the module that defines the record holding them.
jsonNonEmptySet/jsonNonEmptyMap were introduced with the claim that they match what cardano-node emitted before, which cardano-node got from cardano-api. Neither holds: cardano-api never mentions NonEmptySet, and cardano-data has no ToJSON instance for its non-empty containers to compare against -- putting the container back in place of the helper does not compile. The helpers are still needed and their output is the only shape such an instance could have; just say so rather than claiming a parity that cannot be checked.
Nothing checked these instances: cardano-node's consistency check runs over the assembled node configuration, in the other repo, and ouroboros-network's tracing sublibraries have no tests at all. Writing one by hand -- as the Peras instances just were -- means hand-listing namespaces, severities and documentation, and a typo in any of them is silent. The checks derive everything from allNamespaces and the namespace-indexed methods, so they need no trace values and run over every traced type: 25 of them here, instantiated at CardanoBlock. A namespace must be non-empty and unique, must have a severity (without one the message cannot be configured), a privacy, a detail level and documentation, and the whole namespace tree must satisfy the same check trace-dispatcher applies to a node configuration. The documentation check found 44 namespaces with no documentFor, or with an empty one. Fixed here: ConsensusStartupException, ClientMetrics and the ten object diffusion namespaces. The rest -- ChainDB, ImmutableDB, LedgerDB and the forge tracer, all inherited from cardano-node -- are recorded in knownUndocumented so that new gaps are still rejected, with a second check that fails if an entry there becomes documented, so the list cannot go stale.
These functions were reimplemented off cardano-api when the era tracing
instances moved here, and had already drifted from it twice without anything
noticing. Pin their output as bytes so that changing it takes an explicit,
reviewed change to a golden file.
Writing it found a third divergence: renderScriptPurpose rendered the spending
purpose's TxIn through cardano-ledger's ToJSON, which shows the index newtype
and yields "<txid>#TxIx {unTxIx = 0}". cardano-api rendered "<txid>#0". Add a
renderTxIn that does the latter.
The golden file was checked by hand against cardano-api-11.5.0.0, the version
cardano-node used before the move: the ScriptWitnessIndex kind/value shapes, the
{"item": ...} wrapper on the purposes that keep their AsItem, the CIP-19 bech32
prefixes, and the txid#index form.
The list of traced types was hand-written and had drifted from Consensus.Tracers: six top-level tracers were missing, all of them ones whose type carries a peer or has no block parameter, which is why they were easy to overlook. TraceGDDEvent, Jumping.TraceEventCsj, Jumping.TraceEventDbf, BlockFetch.TraceFetchClientState, TraceDecisionEvent, KESAgentClientTrace They bring 14 more undocumented namespaces into knownUndocumented, 13 of them KESAgentClientTrace's -- an entire tracer whose messages carry no documentation at all, and which nothing was asserting anything about until now. The peer type is a stand-in: no MetaTrace method looks at it, so this uses () rather than pulling in the node's address types.
LedgerDB, ImmutableDB, VolatileDB, PerasCertDB and PerasVoteDB do not have tracers of their own. ChainDbArgs.updateTracer derives each from the ChainDB tracer, and ChainDB.TraceEvent's allNamespaces maps all of their namespaces in under LedgerEvent, ImmDbEvent, VolatileDbEvent and so on -- cardano-node has no tracer for any of them either. Listing them alongside ChainDB.TraceEvent meant every one of their namespaces was checked twice under two different names, and appeared twice in knownUndocumented: once as ChunkValidation.InvalidChunkFile and again as ImmDbEvent.ChunkValidation.InvalidChunkFile, once as Flavor.V2.BackendTrace.LSM.LSMSnap and again as LedgerEvent.Flavor.V2.BackendTrace.LSM.LSMSnap. Keep ChainDB.TraceEvent, which reaches all of them, and drop the 17 duplicated ratchet entries.
'maximumDef' was the only thing taken from it, in two severity computations. 'foldr max' over the same list gives the same answer, and the main library does not depend on cardano-prelude either, so this keeps a public library out of the dependency tree entirely.
cardano-ledger-api does ship a COMPLETE pragma over the seven
AnyEra*Purpose synonyms, so the wildcard was not future-proofing: it was
reachable today, and a Dijkstra guarding redeemer rendered as
{"kind":"UnknownPlutusPurpose"} in the logs.
Match all seven and drop the wildcard, so that the next era is a compile
error here rather than a marker in an operator's logs. Guarding has no
cardano-api rendering to preserve, so its item renders directly (like
spending and rewarding) and its witness index name is ours.
'purposesByItem' only covered three of the six Conway purposes, leaving
certifying, voting and proposing unpinned -- and those are exactly the
{"item": ...}-wrapped ones the comment above warns about, so the ones
most likely to drift. 'renderTxIn' had no entry either.
Add them, plus the guarding purpose, which needs the Dijkstra era and so
also exercises the other AnyEraScript instance rather than only Conway's.
cardano-node removed the instances for [TraceLabelPeer peer (FetchDecision [Point header])] under IntersectMBO/cardano-node#6667: nothing emits that list, and its Accept/Decline/EmptyPeersFetch namespaces were the stale ones the configuration consistency check rejected. The MetaTrace instance for FetchDecision goes with them; its metricsDocFor advertised a connectedPeers metric that no asMetrics ever produced. What remains is LogFormatting (FetchDecision [Point header]), which TraceDecisionEvent's own rendering needs, matching cardano-node master.
The docstring claimed to catch a namespace left out of 'allNamespaces', but every check iterates 'allNamespaces' itself and 'namespaceFor' is never called, so that mistake -- and a typo appearing in both places -- still passes. Catching it needs trace values, which these types have no 'Arbitrary' or 'Enum' to produce, so narrow the wording instead.
'tracing/golden' sits outside the test component's hs-source-dirs, so without an 'extraSrcFiles' entry haskell.nix pruned it out of the component source, and without '--no-create' tasty-golden then created the missing file and reported a pass. The Nix check was green without comparing anything. Key the golden directories by test name so that adding one is a single line and cannot forget either half.
'tracing' is public API -- HasIssuer, ConvertTxId, and every log shape an operator parses -- but it was not in the list the check walks, so a later change to its .hs files would never ask for a fragment. Its path is the directory itself, since that is its hs-source-dirs.
jasagredo
force-pushed
the
js/tracing-instances
branch
from
September 28, 2026 09:16
2a51544 to
cf25039
Compare
jasagredo
removed this pull request from stack #2296
September 28, 2026 09:16
This branch has not been deployed
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.
Move the tracing instances from cardano-node to ouroboros-consensus.