cardano-rpc: Add timestamp to fetchBlock#1242
Conversation
4cc7e51 to
3ef4994
Compare
There was a problem hiding this comment.
Pull request overview
This PR extends the cardano-rpc FetchBlock SyncService implementation to populate Block.timestamp, by deriving a slot timestamp using SystemStart plus an EraHistory computed from the node’s ledger state. To support this from cardano-rpc, it also expands Cardano.Api.Consensus re-exports for node-kernel access.
Changes:
- Extend
NodeKernelAccessto carrySystemStartand an IO-backedreadEraHistoryaction, enabling slot-to-UTC conversion when servingFetchBlock. - Populate
Block.timestamp(milliseconds since epoch) in the FetchBlock handler and update docs to reflect the feature. - Add additional consensus re-exports (and changelog fragments) to support the new node-kernel/ledger-era-history functionality.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| cardano-rpc/src/Cardano/Rpc/Server/NodeKernelAccess/Type.hs | Extend the node-kernel handle with systemStart and readEraHistory (and rename the ChainDB field). |
| cardano-rpc/src/Cardano/Rpc/Server/NodeKernelAccess.hs | Build the extended NodeKernelAccess from TopLevelConfig + NodeKernel; adjust block fetch helper to use renamed field. |
| cardano-rpc/src/Cardano/Rpc/Server/Internal/UtxoRpc/Sync.hs | Compute and populate Block.timestamp during FetchBlock responses. |
| cardano-rpc/README.md | Mark FetchBlock as no longer missing Block.timestamp. |
| cardano-api/src/Cardano/Api/Consensus/Internal/Reexport.hs | Expand internal consensus re-exports used by Cardano.Api.Consensus. |
| cardano-api/src/Cardano/Api/Consensus.hs | Re-export additional consensus/node-kernel symbols from the public Cardano.Api.Consensus module. |
| .changes/20260602_cardano_rpc_fetchblock.yml | Update changelog fragment text for the FetchBlock timestamp work. |
| .changes/20260602_cardano_api_consensus_reexports.yml | Update changelog fragment text for additional consensus re-exports. |
| - compatible | ||
| description: | | ||
| Re-export consensus types from Cardano.Api.Consensus for node kernel access: NodeKernel, ChainDB, BlockComponent, RealPoint, OneEraHash, HeaderHash, HasHeader, BlockType, StandardCrypto, CardanoBlock, blockNo. | ||
| Re-export consensus types from Cardano.Api.Consensus for node kernel access: NodeKernel, ChainDB, BlockComponent, RealPoint, OneEraHash, HeaderHash, HasHeader, BlockType, StandardCrypto, CardanoBlock, blockNo, getCurrentLedger, TopLevelConfig, configLedger, configBlock, ledgerState, HasHardForkHistory(..), ConfigSupportsNode, nodeSystemStart, mkInterpreter. |
| throwPastHorizon = | ||
| throwGrpcErrorWithMessage GrpcInternal $ | ||
| "past horizon converting slot " <> tshow (unSlotNo slot) <> " to timestamp" | ||
| headerHash <- | ||
| deserialiseFromRawBytes (proxyToAsType (Proxy @(Hash BlockHeader))) hashBytes | ||
| & either (const throwInvalidHash) pure | ||
| (rawBytes, BlockNo height) <- | ||
| fetchBlock nodeKernelAccess slot headerHash >>= maybe throwNotFound pure | ||
| eraHistory <- readEraHistory | ||
| timestampMs <- | ||
| slotToUTCTime systemStart eraHistory slot | ||
| & either (const throwPastHorizon) (pure . round . (* 1000) . utcTimeToPOSIXSeconds) |
There was a problem hiding this comment.
we don't gain any extra info from it, and the showed exception is quite verbose
| eraHistory <- readEraHistory | ||
| timestampMs <- | ||
| slotToUTCTime systemStart eraHistory slot | ||
| & either (const throwPastHorizon) (pure . round . (* 1000) . utcTimeToPOSIXSeconds) |
| - breaking | ||
| description: | | ||
| Implement FetchBlock SyncService method via node kernel access. Fetches blocks from ChainDB with raw CBOR bytes and cardano block header (slot, hash, height). Breaking: `runRpcServer` signature now takes `IORef (Maybe NodeKernelAccess)` for node kernel access. | ||
| Implement FetchBlock SyncService method via node kernel access. Fetches blocks from ChainDB with raw CBOR bytes, cardano block header (slot, hash, height), and timestamp (slot-to-UTC conversion via EraHistory). Breaking: `runRpcServer` signature now takes `IORef (Maybe NodeKernelAccess)` for node kernel access. |
| , getOpCertCounters | ||
| , interpreterToEpochInfo | ||
| , mkInterpreter | ||
| , unsafeExtendSafeZone | ||
| , txId |
3ef4994 to
73e1a16
Compare
| import Ouroboros.Consensus.Util.Condense (condense) | ||
|
|
||
| -- | Extract the network system start time from the node's top-level configuration. | ||
| nodeSystemStart :: ConfigSupportsNode blk => TopLevelConfig blk -> SystemStart |
There was a problem hiding this comment.
This would be better suited in Cardano.Api.Consensus or some other adjacent module as it's not strictly a re-export.
| "block not found at slot " <> tshow (unSlotNo slot) | ||
| throwPastHorizon = | ||
| throwGrpcErrorWithMessage GrpcInternal $ | ||
| "past horizon converting slot " <> tshow (unSlotNo slot) <> " to timestamp" |
There was a problem hiding this comment.
Can you add a hint as to how a user would correct this error in the error message?
| { nkaChainDB :: Consensus.ChainDB IO (Consensus.CardanoBlock Consensus.StandardCrypto) | ||
| { chainDb :: Consensus.ChainDB IO (Consensus.CardanoBlock Consensus.StandardCrypto) | ||
| -- ^ Handle to the consensus chain database | ||
| , systemStart :: SystemStart |
There was a problem hiding this comment.
Something like:
- ^ Network system start time, extracted from genesis config.
-- Used together with 'readEraHistory' to convert slots to wall-clock
-- time
Would be useful.
73e1a16 to
534dce1
Compare
534dce1 to
15431b7
Compare
Context
Additional context for the PR goes here. If the PR fixes a particular issue please provide a link to the issue.
How to trust this PR
Highlight important bits of the PR that will make the review faster. If there are commands the reviewer can run to observe the new behavior, describe them.
Checklist
.changes/