Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
33c2165
feat: add DatumCache module for memory optimization
awcjack Jan 3, 2026
95dfb61
feat: add datumCache field to OpenState and HasDatumCache instances
awcjack Jan 3, 2026
8fba899
feat: implement datum stripping and restoration in HeadLogic
awcjack Jan 3, 2026
6c8cc46
feat: propagate HasDatumCache constraint to Node layer
awcjack Jan 3, 2026
413372b
test: update tests for datumCache field
awcjack Jan 3, 2026
b749969
chore: update API schema and golden files for datumCache
awcjack Jan 3, 2026
7ff8fea
fix: use newtype instead of data for DatumCache (hlint)
awcjack Jan 3, 2026
be3879b
style: fix formatting per treefmt (import order, comment placement)
awcjack Jan 3, 2026
ffaa7f4
fix: remove unused DatumCache exports to pass weeder check
awcjack Jan 3, 2026
9a7c2bb
ci: add disk cleanup step to prevent space exhaustion
awcjack Jan 3, 2026
9d66287
ci: enable Docker builds for pull requests
awcjack Jan 3, 2026
07d484f
fix: strip datums in SnapshotRequested and LocalStateCleared handlers
awcjack Jan 3, 2026
300a037
fix: restore datums in onOpenNetworkReqSn before applying transactions
awcjack Jan 3, 2026
51bd18c
fix: allow NewTx when node is catching up on chain sync
awcjack Jan 3, 2026
2022a24
Revert "fix: allow NewTx when node is catching up on chain sync"
awcjack Jan 4, 2026
e01ad35
fix: return proper JSON object for transaction submission parse errors
awcjack Jan 4, 2026
c7e6734
fix: check transaction ID when matching RejectedInput in HTTP handler
awcjack Jan 4, 2026
b59260c
test: add test for RejectedInput race condition fix
awcjack Jan 4, 2026
91e89ab
style: fix formatting in HTTPServerSpec test
awcjack Jan 4, 2026
bcd7843
feat: add configurable datum hot cache size limit
awcjack Jan 5, 2026
3cec1ce
fix: address CI failures for datumHotCacheSize
awcjack Jan 5, 2026
21b42b4
fix: address remaining CI failures for datumHotCacheSize
awcjack Jan 5, 2026
7c9bc75
fix: increase network queue capacity and gRPC timeout for high load
awcjack Jan 5, 2026
f512894
feat: add critical logging for network issues even in quiet mode
awcjack Jan 5, 2026
70acb5a
style: fix treefmt formatting for critical logging changes
awcjack Jan 5, 2026
f380e49
feat: add priority queue for protocol messages to prevent signature l…
awcjack Jan 5, 2026
d3ca5bf
fix: remove unused exports to pass weeder check
awcjack Jan 5, 2026
f013ba4
fix: prevent eviction of required datums from cache
awcjack Jan 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .github/actions/nix-cachix-setup/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,21 @@ runs:
using: composite

steps:
- name: 🧹 Free disk space
if: runner.os == 'Linux'
shell: bash
run: |
echo "Disk space before cleanup:"
df -h /
# Remove unnecessary tools to free up disk space
sudo rm -rf /usr/share/dotnet
sudo rm -rf /usr/local/lib/android
sudo rm -rf /opt/ghc
sudo rm -rf /opt/hostedtoolcache/CodeQL
sudo docker image prune --all --force || true
echo "Disk space after cleanup:"
df -h /

- name: ❄ Prepare nix
uses: cachix/install-nix-action@v30
with:
Expand Down
8 changes: 8 additions & 0 deletions .github/workflows/docker.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ on:
push:
branches: [ "master" ]
tags: [ "*.*.*" ]
pull_request:
branches: [ "master" ]
workflow_dispatch:
inputs:
ref_name:
Expand Down Expand Up @@ -73,6 +75,12 @@ jobs:
# And the version as the git commit.
VERSION=${{github.sha}}

# For PRs, tag as pr-<number>
if [[ "${{github.event_name}}" == "pull_request" ]]; then
IMAGE_LABEL=pr-${{github.event.pull_request.number}}
VERSION=${{github.event.pull_request.head.sha}}
fi

# Determine whether we are building a tag and if yes, set the label
# name to be the tag name, and the version to be the tag.
BUILDING_TAG=${{github.ref_type == 'tag'}}
Expand Down
1 change: 1 addition & 0 deletions hydra-cluster/src/HydraNode.hs
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,7 @@ prepareHydraNode chainConfig workDir hydraNodeId hydraSKey hydraVKeys allNodeIds
{ cardanoLedgerProtocolParametersFile
}
, apiTransactionTimeout = 100000
, datumHotCacheSize = 0
}
where
port = fromIntegral $ 5_000 + hydraNodeId
Expand Down
1 change: 1 addition & 0 deletions hydra-node/golden/Greetings/Greetings.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"env": {
"configuredPeers": "",
"contestationPeriod": 43200,
"datumHotCacheSize": 0,
"depositPeriod": 78099,
"otherParties": [],
"participants": [],
Expand Down
42 changes: 23 additions & 19 deletions hydra-node/golden/ReasonablySized (HeadState (Tx ConwayEra)).json

Large diffs are not rendered by default.

9,725 changes: 5,325 additions & 4,400 deletions hydra-node/golden/ReasonablySized (NodeState (Tx ConwayEra)).json

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions hydra-node/golden/RunOptions.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
},
"tag": "CardanoChainConfig"
},
"datumHotCacheSize": 100,
"hydraSigningKey": "b/c.sk",
"hydraVerificationKeys": [
"b/a.vk",
Expand Down Expand Up @@ -93,6 +94,7 @@
"offlineHeadSeed": "605a4786e76db4b28c3668751db34615",
"tag": "OfflineChainConfig"
},
"datumHotCacheSize": 100,
"hydraSigningKey": "a/c.sk",
"hydraVerificationKeys": [
"c.vk",
Expand Down Expand Up @@ -179,6 +181,7 @@
},
"tag": "CardanoChainConfig"
},
"datumHotCacheSize": 100,
"hydraSigningKey": "a.sk",
"hydraVerificationKeys": [
"a/b/c.vk",
Expand Down Expand Up @@ -233,6 +236,7 @@
"offlineHeadSeed": "329e98b0b3a9efc003e42da13950a34f",
"tag": "OfflineChainConfig"
},
"datumHotCacheSize": 100,
"hydraSigningKey": "b/c.sk",
"hydraVerificationKeys": [
"b/a.vk"
Expand Down Expand Up @@ -297,6 +301,7 @@
"startChainFrom": null,
"tag": "CardanoChainConfig"
},
"datumHotCacheSize": 100,
"hydraSigningKey": "b/c/c/b/a/b.sk",
"hydraVerificationKeys": [
"b.vk"
Expand Down
1 change: 1 addition & 0 deletions hydra-node/hydra-node.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ library
Hydra.Chain.Direct.Wallet
Hydra.Chain.Offline
Hydra.Chain.ScriptRegistry
Hydra.DatumCache
Hydra.Events
Hydra.Events.FileBased
Hydra.Events.Rotation
Expand Down
37 changes: 37 additions & 0 deletions hydra-node/json-schemas/api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3113,6 +3113,7 @@ components:
- participants
- contestationPeriod
- depositPeriod
- datumHotCacheSize
- configuredPeers
additionalProperties: false
properties:
Expand All @@ -3132,6 +3133,9 @@ components:
$ref: "api.yaml#/components/schemas/ContestationPeriod"
depositPeriod:
$ref: "api.yaml#/components/schemas/DepositPeriod"
datumHotCacheSize:
type: integer
description: Maximum number of datums to keep in the hot cache (0 = unlimited)
configuredPeers:
type: string

Expand Down Expand Up @@ -3472,6 +3476,7 @@ components:
- chainState
- headId
- headSeed
- datumCache
properties:
parameters:
$ref: "api.yaml#/components/schemas/HeadParameters"
Expand All @@ -3483,6 +3488,38 @@ components:
$ref: "api.yaml#/components/schemas/HeadId"
headSeed:
$ref: "api.yaml#/components/schemas/HeadSeed"
datumCache:
$ref: "api.yaml#/components/schemas/DatumCache"

DatumCache:
type: object
additionalProperties: false
description: |
A cache for inline datums extracted from UTxOs to reduce memory usage.
Contains a list of datum entries, each with a hash and the CBOR-encoded datum.
required:
- entries
properties:
entries:
type: array
description: List of cached datum entries
items:
$ref: "api.yaml#/components/schemas/DatumCacheEntry"

DatumCacheEntry:
type: object
additionalProperties: false
description: A single entry in the datum cache
required:
- hash
- datum
properties:
hash:
type: string
description: The hash of the script data (hex-encoded)
datum:
type: string
description: The CBOR-encoded script data (hex-encoded)

ClosedState:
type: object
Expand Down
7 changes: 4 additions & 3 deletions hydra-node/src/Hydra/API/HTTPServer.hs
Original file line number Diff line number Diff line change
Expand Up @@ -538,7 +538,7 @@ handleSubmitL2Tx ::
handleSubmitL2Tx putClientInput apiTransactionTimeout responseChannel body = do
case Aeson.eitherDecode' @(SubmitL2TxRequest tx) body of
Left err ->
pure $ responseLBS status400 jsonContent (Aeson.encode $ Aeson.String $ pack err)
pure $ responseLBS status400 jsonContent (Aeson.encode $ SubmitTxRejectedResponse $ pack err)
Right SubmitL2TxRequest{submitL2Tx} -> do
-- Duplicate the channel to avoid consuming messages from other consumers.
dupChannel <- atomically $ dupTChan responseChannel
Expand Down Expand Up @@ -581,8 +581,9 @@ handleSubmitL2Tx putClientInput apiTransactionTimeout responseChannel body = do
go = do
event <- atomically $ readTChan dupChannel
case event of
Right (RejectedInput{clientInput = NewTx{}, reason}) -> do
pure $ SubmitTxRejectedResponse reason
Right (RejectedInput{clientInput = NewTx{transaction}, reason})
| txId transaction == txid ->
pure $ SubmitTxRejectedResponse reason
Left (TimedServerOutput{output}) -> case output of
TxValid{transactionId}
| transactionId == txid ->
Expand Down
6 changes: 4 additions & 2 deletions hydra-node/src/Hydra/API/Server.hs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import Hydra.Cardano.Api (LedgerEra)
import Hydra.Chain (Chain (..))
import Hydra.Chain.ChainState (IsChainState)
import Hydra.Chain.Direct.State ()
import Hydra.DatumCache (HasDatumCache)
import Hydra.Events (EventSink (..), EventSource (..))
import Hydra.HeadLogic (
HeadState (..),
Expand Down Expand Up @@ -81,7 +82,7 @@ data APIServerConfig = APIServerConfig

withAPIServer ::
forall tx.
IsChainState tx =>
(IsChainState tx, HasDatumCache (UTxOType tx)) =>
APIServerConfig ->
Environment ->
FilePath ->
Expand All @@ -99,7 +100,8 @@ withAPIServer config env stateFile party eventSource tracer chain pparams server
responseChannel <- newBroadcastTChanIO
-- Initialize our read models from stored events
-- NOTE: we do not keep the stored events around in memory
nodeStateP <- mkProjection "nodeStateP" (initNodeState mkChainState) aggregateNodeState
-- Use 0 (unlimited) for API projections since we're just tracking state for display
nodeStateP <- mkProjection "nodeStateP" (initNodeState mkChainState) (aggregateNodeState 0)
-- XXX: We never subscribe to changes of commitInfoP et al directly so a
-- single read model and normal functions mapping from HeadState ->
-- CommitInfo etc. would suffice and are less fragile
Expand Down
Loading
Loading