Skip to content

Commit

Permalink
Merge pull request #1414 from SundaeSwap-finance/document-offline-mode
Browse files Browse the repository at this point in the history
Document offline mode
  • Loading branch information
ch1bo committed May 17, 2024
2 parents 84b641a + 3a7b50f commit 433c5dc
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 2 deletions.
9 changes: 9 additions & 0 deletions docs/docs/getting-started/offline-mode.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Hydra supports an offline mode, which allows for disabling the Layer 1 interface (that is, the underlying Cardano blockchain which Hydra heads use to seed funds and ultimately funds are withdrawn to). Disabling Layer 1 interactions allows use-cases which would otherwise require running and configuring an entire Layer 1 private devnet. For example, the offline mode can be used to quickly validate a series of transactions against a UTxO, without having to spin up an entire Layer 1 Cardano node.

In this offline mode, only the Layer 2 ledger is run, along with the Hydra API and persistence, to support interacting with the offline Hydra. Therefore, ledger genesis parameters that normally influence things like time-based transaction validation, may be set to defaults that aren't reflective of mainnet. To set this, set --ledger-protocol-parameters to a non-zero file, as described [here](https://hydra.family/head-protocol/unstable/docs/configuration/#ledger-parameters).

To initialize the Layer 2 ledger's UTXO state, offline mode takes an obligatory --initial-utxo parameter, which points to a JSON encoded UTXO file. This UTXO is independent of Event Source loaded events, and the latter are validated against this UTXO. The UTXO follows the following schema `{ txout : {address, value : {asset : quantity}, datum, datumhash, inlinedatum, referenceScript }`

An example UTXO:
```json
{"1541287c2598ffc682742c961a96343ac64e9b9030e6b03a476bb18c8c50134d#0":{"address":"addr_test1vqg9ywrpx6e50uam03nlu0ewunh3yrscxmjayurmkp52lfskgkq5k","datum":null,"datumhash":null,"inlineDatum":null,"referenceScript":null,"value":{"lovelace":100000000}},"39786f186d94d8dd0b4fcf05d1458b18cd5fd8c6823364612f4a3c11b77e7cc7#0":{"address":"addr_test1vru2drx33ev6dt8gfq245r5k0tmy7ngqe79va69de9dxkrg09c7d3","datum":null,"datumhash":null,"inlineDatum":null,"referenceScript":null,"value":{"lovelace":100000000}}}```
20 changes: 18 additions & 2 deletions hydra-node/src/Hydra/Chain/Offline.hs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import Cardano.Api.GenesisParameters (fromShelleyGenesis)
import Cardano.Ledger.Slot (unSlotNo)
import Cardano.Slotting.Time (SystemStart (SystemStart), mkSlotLength)
import Control.Monad.Class.MonadAsync (link)
import Data.Aeson qualified as Aeson
import Data.Aeson.Types qualified as Aeson
import Hydra.Cardano.Api (GenesisParameters (..), ShelleyEra, ShelleyGenesis (..), StandardCrypto, Tx)
import Hydra.Chain (
Chain (..),
Expand Down Expand Up @@ -36,7 +38,18 @@ offlineHeadId = UnsafeHeadId "offline"
offlineHeadSeed :: HeadSeed
offlineHeadSeed = UnsafeHeadSeed "offline"

newtype InitialUTxOParseException = InitialUTxOParseException String
deriving stock (Show)

instance Exception InitialUTxOParseException where
displayException (InitialUTxOParseException err) =
"Failed to parse initial UTXO: "
<> err
<> ". Example UTXO: "
<> "{\"1541287c2598ffc682742c961a96343ac64e9b9030e6b03a476bb18c8c50134d#0\":{\"address\":\"addr_test1vqg9ywrpx6e50uam03nlu0ewunh3yrscxmjayurmkp52lfskgkq5k\",\"datum\":null,\"datumhash\":null,\"inlineDatum \":null,\"referenceScript\":null,\"value\":{\"lovelace\":100000000}},\"39786f186d94d8dd0b4fcf05d1458b18cd5fd8c6823364612f4a3c11b77e7cc7#0\":{\"address\":\"addr_test1vru2drx33ev6dt8gfq245r5k0tmy7ngqe79va69de9dxkrg09c7d3\",\"datum\":null,\"datumhash\":null,\"inlineDatum\":null,\"referenceScript\":null,\"value\":{\"lovelace\":100000000}}}"

-- | Load the given genesis file or use defaults specific to the offline mode.
-- Throws: 'InitialUTxOParseException' if the initial UTXO file could not be parsed.
loadGenesisFile :: Maybe FilePath -> IO (GenesisParameters ShelleyEra)
loadGenesisFile ledgerGenesisFile =
-- TODO: uses internal cardano-api lib
Expand All @@ -46,8 +59,11 @@ loadGenesisFile ledgerGenesisFile =
now <- getCurrentTime
-- TODO: uses internal cardano-api lib
pure shelleyGenesisDefaults{sgSystemStart = now}
Just fp ->
readJsonFileThrow (parseJSON @(ShelleyGenesis StandardCrypto)) fp
Just fp -> do
jsonVal <- Aeson.eitherDecodeFileStrict fp >>= either fail pure -- just crash if we can't read the file
case Aeson.parseEither (parseJSON @(ShelleyGenesis StandardCrypto)) jsonVal of
Right a -> pure a
Left e -> throwIO $ InitialUTxOParseException e

withOfflineChain ::
OfflineChainConfig ->
Expand Down

0 comments on commit 433c5dc

Please sign in to comment.