diff --git a/.github/actions/nix-cachix-setup/action.yml b/.github/actions/nix-cachix-setup/action.yml index fcf19333bb5..6c24c24a284 100644 --- a/.github/actions/nix-cachix-setup/action.yml +++ b/.github/actions/nix-cachix-setup/action.yml @@ -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: diff --git a/.github/workflows/ci-nix.yaml b/.github/workflows/ci-nix.yaml index 8477afbd02d..d3843fa4815 100644 --- a/.github/workflows/ci-nix.yaml +++ b/.github/workflows/ci-nix.yaml @@ -11,7 +11,11 @@ on: branches: - master - release + - v1.2.0-base pull_request: + branches: + - master + - v1.2.0-base schedule: # Everyday at 4:00 AM - cron: "0 4 * * *" diff --git a/.github/workflows/docker.yaml b/.github/workflows/docker.yaml index e0021638606..f9262c0609f 100644 --- a/.github/workflows/docker.yaml +++ b/.github/workflows/docker.yaml @@ -11,8 +11,10 @@ concurrency: on: push: - branches: [ "master" ] + branches: [ "master", "v1.2.0-base" ] tags: [ "*.*.*" ] + pull_request: + branches: [ "master", "v1.2.0-base" ] workflow_dispatch: inputs: ref_name: @@ -73,6 +75,12 @@ jobs: # And the version as the git commit. VERSION=${{github.sha}} + # For PRs, tag as pr- + 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'}} diff --git a/README.md b/README.md index 4938dadd46f..4d33dc3fe7e 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,6 @@ Please follow our [Contributing Guidelines](./CONTRIBUTING.md) and [Code of Cond ## ๐Ÿ™ Credits - Logo created by Alexander Wende - ---

diff --git a/hydra-node/hydra-node.cabal b/hydra-node/hydra-node.cabal index 90205b097b8..2ff54fa1451 100644 --- a/hydra-node/hydra-node.cabal +++ b/hydra-node/hydra-node.cabal @@ -36,6 +36,7 @@ common project-config OverloadedStrings PartialTypeSignatures PatternSynonyms + StrictData TypeFamilies ViewPatterns diff --git a/hydra-node/src/Hydra/Chain.hs b/hydra-node/src/Hydra/Chain.hs index 21f63c9e792..7b79cffc7f5 100644 --- a/hydra-node/src/Hydra/Chain.hs +++ b/hydra-node/src/Hydra/Chain.hs @@ -47,7 +47,7 @@ import Test.QuickCheck.Instances.Time () -- | Hardcoded limit for commit tx on mainnet maxMainnetLovelace :: Coin -maxMainnetLovelace = Coin 100_000_000 +maxMainnetLovelace = Coin 1_000_000_000 -- | Hardcoded limit for maximum number of parties in a head protocol The value -- is obtained from calculating the costs of running the scripts and on-chan diff --git a/hydra-node/src/Hydra/HeadLogic.hs b/hydra-node/src/Hydra/HeadLogic.hs index ab4c088c702..b879d438501 100644 --- a/hydra-node/src/Hydra/HeadLogic.hs +++ b/hydra-node/src/Hydra/HeadLogic.hs @@ -461,8 +461,16 @@ onOpenNetworkReqSn env ledger pendingDeposits currentSlot st otherParty sv sn re , newCurrentDepositTxId = mDepositTxId } where + -- Allow version-1 only if ReqSn has no IC/ID content (safe stale request) + -- This handles the race condition where ReqSn is sent before L1 tx confirms + -- but processed after the version bump. + allowStaleVersion = + sv == version - 1 + && isNothing mDecommitTx + && isNothing mDepositTxId + requireReqSn continue - | sv /= version = + | sv /= version && not allowStaleVersion = Error $ RequireFailed $ ReqSvNumberInvalid{requestedSv = sv, lastSeenSv = version} | sn /= seenSn + 1 = Error $ RequireFailed $ ReqSnNumberInvalid{requestedSn = sn, lastSeenSn = seenSn} @@ -480,6 +488,8 @@ onOpenNetworkReqSn env ledger pendingDeposits currentSlot st otherParty sv sn re waitOnSnapshotVersion continue | version == sv = continue + | allowStaleVersion = + continue | otherwise = wait $ WaitOnSnapshotVersion sv @@ -688,13 +698,32 @@ onOpenNetworkAckSn Environment{party} pendingDeposits openState otherParty snaps RequireFailed $ InvalidMultisignature{multisig = show multisig, vkeys} - maybeRequestNextSnapshot previous outcome = do + maybeRequestNextSnapshot (previous :: Snapshot tx) outcome = do let nextSn = previous.number + 1 - if isLeader parameters party nextSn && not (null localTxs) + -- Clear if just processed (prevents stale reference after IC/ID) + nextDepositTxId = + if isJust (previous.utxoToCommit :: Maybe (UTxOType tx)) + then Nothing + else currentDepositTxId + nextDecommitTx = + if isJust (previous.utxoToDecommit :: Maybe (UTxOType tx)) + then Nothing + else decommitTx + -- Pick active deposit if available + depositToInclude = + if isNothing nextDepositTxId && isNothing nextDecommitTx + then getNextActiveDeposit pendingDeposits + else nextDepositTxId + -- Trigger on ANY pending work (fixes P1, P2) + hasPendingWork = + not (null localTxs) + || isJust nextDecommitTx + || isJust depositToInclude + if isLeader parameters party nextSn && hasPendingWork then outcome <> newState SnapshotRequestDecided{snapshotNumber = nextSn} - <> cause (NetworkEffect $ ReqSn version nextSn (txId <$> localTxs) decommitTx currentDepositTxId) + <> cause (NetworkEffect $ ReqSn version nextSn (txId <$> localTxs) nextDecommitTx depositToInclude) else outcome maybePostIncrementTx snapshot@Snapshot{utxoToCommit} signatures outcome = @@ -1080,6 +1109,15 @@ isLeader HeadParameters{parties} p sn = Just i -> ((fromIntegral sn - 1) `mod` length parties) == i _ -> False +-- | Get the next active deposit to include in a snapshot request. +-- Deposits are selected in arrival order (FIFO) based on creation time. +getNextActiveDeposit :: (Eq (UTxOType tx), Monoid (UTxOType tx), Ord (TxIdType tx)) => PendingDeposits tx -> Maybe (TxIdType tx) +getNextActiveDeposit deposits = + let isActive (_, Deposit{deposited, status}) = deposited /= mempty && status == Active + in case filter isActive (Map.toList deposits) of + [] -> Nothing + xs -> Just $ fst $ minimumBy (comparing (\(_, Deposit{created}) -> created)) xs + -- ** Closing the Head -- | Client request to close the head. This leads to a close transaction on