diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d585494326..3888e9c40ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,14 @@ changes. - _DEPRECATED_ the `GetUTxO` client input and `GetUTxOResponse` server output. Use `GET /snapshot/utxo` instead. +## [0.17.0] - UNRELEASED + +- **BREAKING** `hydra-node` `/commit` enpoint now also accepts a _blueprint/draft_ + transaction together with the `UTxO` which is spent in this transaction. `hydra-node` can + still be used like before if the provided `UTxO` is at public key address. In order to spend + from a script `UTxO`, and also unlock more involved use-cases, users need to provide additional + unsigned transaction that correctly specifies required data (like redeemers, validity ranges etc.) + ## [0.16.0] - 2024-04-03 - Tested with `cardano-node 8.9.0`, `cardano-cli 8.20.3.0` and `mithril 2412.0`. diff --git a/docs/docs/blueprint_transaction.md b/docs/docs/blueprint_transaction.md new file mode 100644 index 00000000000..af32a00e943 --- /dev/null +++ b/docs/docs/blueprint_transaction.md @@ -0,0 +1,184 @@ +--- +sidebar_position: 99 +--- + +# Commit using blueprint transaction + + This is a small walk-through on how to use `cardano-cli` to assemble everything needed to commit funds to a `Head` using blueprint transaction. + + Example assumes you have the hydra-node repo at your disposal together with `hydra-node`, `hydra-tui`, `cardano-cli` and `curl` binaries. + + We can use `cardano-cli` to create a _blueprint_ transaction from some `UTxO` we own. + + First we need a running cardano-node so let's spin one on the preprod network: + + + ```shell + ./testnets/cardano-node.sh ~/code/hydra/testnets/preprod + ``` + + Now we need to find the `UTxO` you want to commit to the `Head` + + In this example we will use Alice and her external wallet key so first let's find out the address: + + ```shell + cardano-cli address build \ + --payment-verification-key-file hydra-cluster/config/credentials/alice-funds.vk \ + --testnet-magic 1 + +addr_test1vp5cxztpc6hep9ds7fjgmle3l225tk8ske3rmwr9adu0m6qchmx5z + ``` + +and query to see what `UTxO` Alice has: + +```shell +cardano-cli query utxo \ + --socket-path testnets/preprod/node.socket \ + --address addr_test1vp5cxztpc6hep9ds7fjgmle3l225tk8ske3rmwr9adu0m6qchmx5z \ + --testnet-magic 1 \ + --output-json + +{ + "14ab373afb1112d925b0f6a84518ac26d4a8cfcc99231e1f47e6996182e843a9#0": { + "address": "addr_test1vp5cxztpc6hep9ds7fjgmle3l225tk8ske3rmwr9adu0m6qchmx5z", + "datum": null, + "datumhash": null, + "inlineDatum": null, + "referenceScript": null, + "value": { + "lovelace": 8000000 + } + }, + "14ab373afb1112d925b0f6a84518ac26d4a8cfcc99231e1f47e6996182e843a9#1": { + "address": "addr_test1vp5cxztpc6hep9ds7fjgmle3l225tk8ske3rmwr9adu0m6qchmx5z", + "datum": null, + "datumhash": null, + "inlineDatum": null, + "referenceScript": null, + "value": { + "lovelace": 1828427 + } + }, +} +``` + +Let's pick the first `UTxO` which has total of 8 ADA available. Let's use 5 ADA to commit and rely on `hydra-node` to balance the commit transaction. + +```shell +cardano-cli transaction build-raw \ + --babbage-era \ + --tx-in 14ab373afb1112d925b0f6a84518ac26d4a8cfcc99231e1f47e6996182e843a9#0 \ + --tx-out addr_test1vp5cxztpc6hep9ds7fjgmle3l225tk8ske3rmwr9adu0m6qchmx5z+5000000 \ + --fee 0 \ + --out-file tx.json +``` + +So now we have the _blueprint_ transaction present in the `tx.json` file. + +In order to have `hydra-node` give us a draft commit transaction we need to: + +- Obtain protocol-parameters needed to run the `hydra-node` +- Have the `hydra-node` up and running +- Have the `Head` in the initializing state +- Submit the http request to the `hydra-node` api server using the _blueprint_ transaction we just created and the `UTxO` used for it's input. + + +Query the preview protocol-parameters: + +```shell +cardano-cli query protocol-parameters \ + --testnet-magic 1 \ + --socket-path testnets/preprod/node.socket \ + --out-file pp-preprod.json + +``` + +Start the `hydra-node` in as a _single_ party Head instance. + +Note: The value `6264cee4d5eab3fb58ab67f3899ecbcc0d7e72732a2d9c1c5d638115db6ca711` comes from `hydra-node` release [0.16.0](https://github.com/input-output-hk/hydra/releases/tag/0.16.0) + +```shell +hydra-node \ + --node-id 1 --port 5001 --api-port 4001 \ + --hydra-signing-key demo/alice.sk \ + --hydra-scripts-tx-id 6264cee4d5eab3fb58ab67f3899ecbcc0d7e72732a2d9c1c5d638115db6ca711 \ + --cardano-signing-key hydra-cluster/config/credentials/alice.sk \ + --ledger-protocol-parameters pp-preprod.json \ + --testnet-magic 1 \ + --node-socket testnets/preprod/node.socket \ + --persistence-dir . +``` + +Now we can start `hydra-tui` and initialize the `Head`: + +```shell +hydra-tui \ + --connect 0.0.0.0:4001 \ + --cardano-signing-key hydra-cluster/config/credentials/alice-funds.sk \ + --testnet-magic 1 \ + --node-socket testnets/preprod/node.socket +``` + +Now press `i` to initialize the `Head`. + +Once we see that the head is in the `Initializing` state we are ready to send the HTTP request to the `/commit` API path. + +To assemble the request body we will use the `cborHex` field from the tx-body file `tx.json`. + +To get the json representation of the `UTxO` we used as the input we can just copy/paste the output we got from cardano-cli when we did a `UTxO` query: + +This is the valid json request: + +```shell +{ + "blueprintTx": { + "cborHex": "84a3008182582014ab373afb1112d925b0f6a84518ac26d4a8cfcc99231e1f47e6996182e843a900018182581d6069830961c6af9095b0f2648dff31fa9545d8f0b6623db865eb78fde81a007a12000200a0f5f6", + "description": "", + "type": "Tx BabbageEra" + }, + "utxo": { + "14ab373afb1112d925b0f6a84518ac26d4a8cfcc99231e1f47e6996182e843a9#0": { + "address": "addr_test1vp5cxztpc6hep9ds7fjgmle3l225tk8ske3rmwr9adu0m6qchmx5z", + "datum": null, + "datumhash": null, + "inlineDatum": null, + "referenceScript": null, + "value": { + "lovelace": 8000000 + } + } + } +} +``` + +Let's save this json to commit-request.json file. + +Now, it is time to ask the running `hydra-node` to draft a commit transaction for us: + + +``` +curl -X POST 127.0.0.1:4001/commit \ + --data @commit-request.json + +``` + +This yields a large cbor blob which we can save to `commit-tx.json` file. + +Now we need to sign and submit the draft commit transaction. + +```shell + +cardano-cli transaction sign \ + --tx-file commit-tx.json \ + --signing-key-file hydra-cluster/config/credentials/alice-funds.sk \ + --out-file signed-tx.json + + +cardano-cli transaction submit \ + --tx-file signed-tx.json \ + --socket-path testnets/preprod/node.socket \ + --testnet-magic 1 +``` + +If we start the `hydra-tui` and wait a bit until the transaction we just sent is re-observed by the `hydra-node` we should see that the `Head` is now open. + diff --git a/docs/docs/getting-started/quickstart.md b/docs/docs/getting-started/quickstart.md index 1724c38058e..0307d65a5a8 100644 --- a/docs/docs/getting-started/quickstart.md +++ b/docs/docs/getting-started/quickstart.md @@ -250,7 +250,21 @@ cardano-cli address build --verification-key-file cardano.vk --mainnet ## External commits -While the `hydra-node` holds funds to fuel protocol transactions, any wallet can be used to commit funds into an `initializing` Hydra head. The `hydra-node` provides an HTTP endpoint at `/commit`, which allows to specify multiple UTxO (belonging to public key or script address) and returns a draft transaction. This transaction is already balanced and all fees are paid by the funds held by the `hydra-node`, but is missing witnesses for the public key outputs to commit. Hence, an integrated wallet would need to sign this transaction and submit it to the Cardano network. See the [api documentation](pathname:///api-reference/#operation-publish-/commit) for details. +While the `hydra-node` holds funds to fuel protocol transactions, any wallet can be used to commit funds into an `initializing` Hydra head. The `hydra-node` provides an HTTP endpoint at `/commit`, which allows to specify either: + - a `UTxO` set of outputs to commit (belonging to public keys) or + - a _blueprint_ transaction together with the `UTxO` which resolves it. + +and eventually returns a commit transaction. + +This transaction is already balanced and all fees are paid by the funds held by the `hydra-node`. Hence, an integrated wallet would need to sign this transaction and submit it to the Cardano network. See the [api documentation](pathname:///api-reference/#operation-publish-/commit) for details. + +If the user wants to use some `UTxO` they own and commit it to a `Head` then they need to send the appropriate JSON representation of said `UTxO` to the `/commit` API endpoint. + +Using a _blueprint_ transaction with `/commit` allows for more flexibility since `hydra-node` only adds needed commit transaction data without removing any additional information specified in the _blueprint_ transaction. For example, any present reference inputs, redeemers or validity ranges will be kept. + +> Note: It is important to note that any **outputs** of a blueprint transaction will not be considered, only inputs are used to commit funds to the `Head`. `hydra-node` will also **ignore** any minting or burning specified in the blueprint transaction. + +You can take a look at the small example on how to commit to a `Head` using blueprint transaction [here](/docs/blueprint_transaction.md) ## Generating transactions for the WebSocket API diff --git a/hydra-cardano-api/src/Hydra/Cardano/Api/ScriptData.hs b/hydra-cardano-api/src/Hydra/Cardano/Api/ScriptData.hs index cd0aa507d08..40410d7a9eb 100644 --- a/hydra-cardano-api/src/Hydra/Cardano/Api/ScriptData.hs +++ b/hydra-cardano-api/src/Hydra/Cardano/Api/ScriptData.hs @@ -77,6 +77,8 @@ fromLedgerData = fromAlonzoData -- | Convert a cardano-api script data into a cardano-ledger script 'Data'. +-- XXX: This is a partial function. Ideally it would fall back to the +-- 'Plutus.Data' portion in 'HashableScriptData'. toLedgerData :: Ledger.Era era => HashableScriptData -> Ledger.Data era toLedgerData = toAlonzoData diff --git a/hydra-cardano-api/src/Hydra/Cardano/Api/Tx.hs b/hydra-cardano-api/src/Hydra/Cardano/Api/Tx.hs index c1f43f03ea1..5d23c6984be 100644 --- a/hydra-cardano-api/src/Hydra/Cardano/Api/Tx.hs +++ b/hydra-cardano-api/src/Hydra/Cardano/Api/Tx.hs @@ -67,7 +67,8 @@ import Data.Bifunctor (bimap) import Data.Functor ((<&>)) import Data.Map qualified as Map import Data.Maybe (mapMaybe) -import Hydra.Cardano.Api.TxIn (mkTxIn) +import Data.Set qualified as Set +import Hydra.Cardano.Api.TxIn (mkTxIn, toLedgerTxIn) -- * Extras @@ -174,6 +175,17 @@ signTx signingKey (Tx body wits) = where witness = makeShelleyKeyWitness shelleyBasedEra body (WitnessPaymentKey signingKey) +-- | Create a transaction spending all given `UTxO`. +txSpendingUTxO :: UTxO -> Tx Era +txSpendingUTxO utxo = + fromLedgerTx $ + mkBasicTx + ( mkBasicTxBody + & inputsTxBodyL .~ (toLedgerTxIn `Set.map` inputs) + ) + where + inputs = UTxO.inputSet utxo + -- | Get the UTxO that are produced by some transaction. -- XXX: Defined here to avoid cyclic module dependency utxoProducedByTx :: Tx Era -> UTxO diff --git a/hydra-cluster/src/Hydra/Cluster/Scenarios.hs b/hydra-cluster/src/Hydra/Cluster/Scenarios.hs index cbdaadf7398..654c18956ff 100644 --- a/hydra-cluster/src/Hydra/Cluster/Scenarios.hs +++ b/hydra-cluster/src/Hydra/Cluster/Scenarios.hs @@ -25,16 +25,10 @@ import Data.Aeson.Types (parseMaybe) import Data.ByteString (isInfixOf) import Data.ByteString qualified as B import Data.Set qualified as Set -import Hydra.API.HTTPServer ( - DraftCommitTxRequest (..), - DraftCommitTxResponse (..), - ScriptInfo (..), - TransactionSubmitted (..), - TxOutWithWitness (..), - ) -import Hydra.Cardano.Api (Coin (..), File (File), Key (SigningKey), PaymentKey, PlutusScriptV2, Tx, TxId, UTxO, fromPlutusScript, getVerificationKey, isVkTxOut, lovelaceToValue, makeSignedTransaction, mkScriptAddress, mkTxOutDatumHash, mkTxOutDatumInline, mkVkAddress, selectLovelace, signTx, toScriptData, txOutAddress, txOutValue, writeFileTextEnvelope, pattern ReferenceScriptNone, pattern TxOut, pattern TxOutDatumNone) +import Hydra.API.HTTPServer (DraftCommitTxResponse (..), TransactionSubmitted (..)) +import Hydra.Cardano.Api (Coin (..), File (File), Key (SigningKey), PaymentKey, Tx, TxId, UTxO, getVerificationKey, isVkTxOut, lovelaceToValue, makeSignedTransaction, mkVkAddress, selectLovelace, signTx, txOutAddress, txOutValue, writeFileTextEnvelope, pattern ReferenceScriptNone, pattern TxOut, pattern TxOutDatumNone) import Hydra.Chain.Direct.Tx (verificationKeyToOnChainId) -import Hydra.Cluster.Faucet (FaucetLog, createOutputAtAddress, seedFromFaucet, seedFromFaucet_) +import Hydra.Cluster.Faucet (FaucetLog, seedFromFaucet, seedFromFaucet_) import Hydra.Cluster.Faucet qualified as Faucet import Hydra.Cluster.Fixture (Actor (..), actorName, alice, aliceSk, aliceVk, bob, bobSk, bobVk, carol, carolSk) import Hydra.Cluster.Mithril (MithrilLog) @@ -76,7 +70,6 @@ import Network.HTTP.Req ( runReq, (/:), ) -import PlutusLedgerApi.Test.Examples qualified as Plutus import System.Directory (removeDirectoryRecursive) import System.FilePath (()) import Test.QuickCheck (choose, generate) @@ -217,7 +210,7 @@ singlePartyHeadFullLifeCycle tracer workDir node hydraScriptsTxId = returnFundsToFaucet tracer node AliceFunds ) $ do - refuelIfNeeded tracer node Alice 25_000_000 + refuelIfNeeded tracer node Alice 55_000_000 -- Start hydra-node on chain tip tip <- queryTip networkId nodeSocket contestationPeriod <- fromNominalDiffTime $ 10 * blockTime @@ -302,150 +295,109 @@ singlePartyOpenAHead tracer workDir node hydraScriptsTxId callback = where RunningNode{networkId, nodeSocket, blockTime} = node --- | Exercise committing a script utxo that uses inline datums. -singlePartyCommitsExternalScriptWithInlineDatum :: +-- | Single hydra-node where the commit is done using some wallet UTxO. +singlePartyCommitsFromExternal :: Tracer IO EndToEndLog -> FilePath -> RunningNode -> TxId -> IO () -singlePartyCommitsExternalScriptWithInlineDatum tracer workDir node hydraScriptsTxId = - (`finally` returnFundsToFaucet tracer node Alice) $ do - refuelIfNeeded tracer node Alice 25_000_000 - aliceChainConfig <- chainConfigFor Alice workDir nodeSocket hydraScriptsTxId [] $ UnsafeContestationPeriod 100 - let hydraNodeId = 1 - let hydraTracer = contramap FromHydraNode tracer - withHydraNode hydraTracer aliceChainConfig workDir hydraNodeId aliceSk [] [1] $ \n1 -> do - send n1 $ input "Init" [] - headId <- waitMatch (10 * blockTime) n1 $ headIsInitializingWith (Set.fromList [alice]) +singlePartyCommitsFromExternal tracer workDir node hydraScriptsTxId = + ( `finally` + do + returnFundsToFaucet tracer node Alice + returnFundsToFaucet tracer node AliceFunds + ) + $ do + refuelIfNeeded tracer node Alice 25_000_000 + aliceChainConfig <- chainConfigFor Alice workDir nodeSocket hydraScriptsTxId [] $ UnsafeContestationPeriod 100 + let hydraNodeId = 1 + let hydraTracer = contramap FromHydraNode tracer + withHydraNode hydraTracer aliceChainConfig workDir hydraNodeId aliceSk [] [1] $ \n1 -> do + send n1 $ input "Init" [] + headId <- waitMatch (10 * blockTime) n1 $ headIsInitializingWith (Set.fromList [alice]) - -- Prepare a script output on the network - -- FIXME: spending validators have 3 arguments? does this succeed still? is it not run? - let script = fromPlutusScript @PlutusScriptV2 $ Plutus.alwaysSucceedingNAryFunction 2 - scriptAddress = mkScriptAddress @PlutusScriptV2 networkId script - reedemer = 1 :: Integer - datum = 2 :: Integer - scriptInfo = ScriptInfo (toScriptData reedemer) Nothing script - (scriptTxIn, scriptTxOut) <- createOutputAtAddress node scriptAddress (mkTxOutDatumInline datum) - - -- Commit the script output using known witness - let clientPayload = - DraftCommitTxRequest - { utxoToCommit = - UTxO.singleton - ( scriptTxIn - , TxOutWithWitness - { txOut = scriptTxOut - , witness = Just scriptInfo - } - ) - } - res <- - runReq defaultHttpConfig $ - req - POST - (http "127.0.0.1" /: "commit") - (ReqBodyJson clientPayload) - (Proxy :: Proxy (JsonResponse DraftCommitTxResponse)) - (port $ 4000 + hydraNodeId) - let DraftCommitTxResponse{commitTx} = responseBody res - submitTx node commitTx - - lockedUTxO <- waitMatch (10 * blockTime) n1 $ \v -> do - guard $ v ^? key "headId" == Just (toJSON headId) - guard $ v ^? key "tag" == Just "HeadIsOpen" - pure $ v ^? key "utxo" - lockedUTxO `shouldBe` Just (toJSON $ UTxO.singleton (scriptTxIn, scriptTxOut)) + (walletVk, walletSk) <- keysFor AliceFunds + utxoToCommit <- seedFromFaucet node walletVk 5_000_000 (contramap FromFaucet tracer) + -- Commit the script output + res <- + runReq defaultHttpConfig $ + req + POST + (http "127.0.0.1" /: "commit") + (ReqBodyJson utxoToCommit) + (Proxy :: Proxy (JsonResponse (DraftCommitTxResponse Tx))) + (port $ 4000 + hydraNodeId) + + let DraftCommitTxResponse{commitTx} = responseBody res + submitTx node $ signTx walletSk commitTx + + lockedUTxO <- waitMatch (10 * blockTime) n1 $ \v -> do + guard $ v ^? key "headId" == Just (toJSON headId) + guard $ v ^? key "tag" == Just "HeadIsOpen" + pure $ v ^? key "utxo" + lockedUTxO `shouldBe` Just (toJSON utxoToCommit) where - RunningNode{networkId, nodeSocket, blockTime} = node + RunningNode{nodeSocket, blockTime} = node --- | Single hydra-node where the commit is done from an external UTxO owned by a --- script which requires providing script, datum and redeemer instead of --- signing the transaction. -singlePartyCommitsFromExternalScript :: +-- | Single hydra-node where the commit is done from a raw transaction +-- blueprint. +singlePartyCommitsFromExternalTxBlueprint :: Tracer IO EndToEndLog -> FilePath -> RunningNode -> TxId -> IO () -singlePartyCommitsFromExternalScript tracer workDir node hydraScriptsTxId = +singlePartyCommitsFromExternalTxBlueprint tracer workDir node hydraScriptsTxId = (`finally` returnFundsToFaucet tracer node Alice) $ do - refuelIfNeeded tracer node Alice 25_000_000 + refuelIfNeeded tracer node Alice 20_000_000 aliceChainConfig <- chainConfigFor Alice workDir nodeSocket hydraScriptsTxId [] $ UnsafeContestationPeriod 100 let hydraNodeId = 1 let hydraTracer = contramap FromHydraNode tracer + (someExternalVk, someExternalSk) <- generate genKeyPair withHydraNode hydraTracer aliceChainConfig workDir hydraNodeId aliceSk [] [1] $ \n1 -> do send n1 $ input "Init" [] headId <- waitMatch (10 * blockTime) n1 $ headIsInitializingWith (Set.fromList [alice]) - -- Prepare a script output on the network - let script = fromPlutusScript @PlutusScriptV2 $ Plutus.alwaysSucceedingNAryFunction 2 - scriptAddress = mkScriptAddress @PlutusScriptV2 networkId script - reedemer = 1 :: Integer - datum = 2 :: Integer - scriptInfo = ScriptInfo (toScriptData reedemer) (Just $ toScriptData datum) script - (scriptTxIn, scriptTxOut) <- createOutputAtAddress node scriptAddress (mkTxOutDatumHash datum) - - -- Commit the script output using known witness - let clientPayload = - DraftCommitTxRequest - { utxoToCommit = - UTxO.singleton - ( scriptTxIn - , TxOutWithWitness - { txOut = scriptTxOut - , witness = Just scriptInfo - } - ) - } - res <- - runReq defaultHttpConfig $ - req - POST - (http "127.0.0.1" /: "commit") - (ReqBodyJson clientPayload) - (Proxy :: Proxy (JsonResponse DraftCommitTxResponse)) - (port $ 4000 + hydraNodeId) - - let DraftCommitTxResponse{commitTx} = responseBody res - submitTx node commitTx - - lockedUTxO <- waitMatch (10 * blockTime) n1 $ \v -> do - guard $ v ^? key "headId" == Just (toJSON headId) - guard $ v ^? key "tag" == Just "HeadIsOpen" - pure $ v ^? key "utxo" - lockedUTxO `shouldBe` Just (toJSON $ UTxO.singleton (scriptTxIn, scriptTxOut)) + someUTxO <- seedFromFaucet node someExternalVk 10_000_000 (contramap FromFaucet tracer) + utxoToCommit <- seedFromFaucet node someExternalVk 5_000_000 (contramap FromFaucet tracer) + let someAddress = mkVkAddress networkId someExternalVk + let someOutput = + TxOut + someAddress + (lovelaceToValue $ Coin 2_000_000) + TxOutDatumNone + ReferenceScriptNone + buildTransaction networkId nodeSocket someAddress utxoToCommit (fst <$> UTxO.pairs someUTxO) [someOutput] >>= \case + Left e -> failure $ show e + Right body -> do + let unsignedTx = makeSignedTransaction [] body + let clientPayload = + Aeson.object + [ "blueprintTx" .= unsignedTx + , "utxo" .= utxoToCommit + ] + res <- + runReq defaultHttpConfig $ + req + POST + (http "127.0.0.1" /: "commit") + (ReqBodyJson clientPayload) + (Proxy :: Proxy (JsonResponse Tx)) + (port $ 4000 + hydraNodeId) + + let commitTx = responseBody res + let signedTx = signTx someExternalSk commitTx + submitTx node signedTx + + lockedUTxO <- waitMatch (10 * blockTime) n1 $ \v -> do + guard $ v ^? key "headId" == Just (toJSON headId) + guard $ v ^? key "tag" == Just "HeadIsOpen" + pure $ v ^? key "utxo" + lockedUTxO `shouldBe` Just (toJSON utxoToCommit) where RunningNode{networkId, nodeSocket, blockTime} = node -singlePartyCannotCommitExternallyWalletUtxo :: - Tracer IO EndToEndLog -> - FilePath -> - RunningNode -> - TxId -> - IO () -singlePartyCannotCommitExternallyWalletUtxo tracer workDir node hydraScriptsTxId = - (`finally` returnFundsToFaucet tracer node Alice) $ do - refuelIfNeeded tracer node Alice 25_000_000 - aliceChainConfig <- chainConfigFor Alice workDir nodeSocket hydraScriptsTxId [] $ UnsafeContestationPeriod 100 - let hydraNodeId = 1 - let hydraTracer = contramap FromHydraNode tracer - withHydraNode hydraTracer aliceChainConfig workDir hydraNodeId aliceSk [] [1] $ \n1 -> do - send n1 $ input "Init" [] - _headId <- waitMatch (10 * blockTime) n1 $ headIsInitializingWith (Set.fromList [alice]) - - -- these keys should mimic external wallet keys needed to sign the commit tx - - -- internal wallet uses the actor keys internally so we need to use utxo - -- present at this public key - (userVk, _userSk) <- keysFor Alice - -- submit the tx using our external user key to get a utxo to commit - utxoToCommit <- seedFromFaucet node userVk 2_000_000 (contramap FromFaucet tracer) - -- Request to build a draft commit tx from hydra-node - requestCommitTx n1 utxoToCommit `shouldThrow` expectErrorStatus 400 (Just "SpendingNodeUtxoForbidden") - where - RunningNode{nodeSocket, blockTime} = node - -- | Initialize open and close a head on a real network and ensure contestation -- period longer than the time horizon is possible. For this it is enough that -- we can close a head and not wait for the deadline. diff --git a/hydra-cluster/src/HydraNode.hs b/hydra-cluster/src/HydraNode.hs index a12dd9531cf..0c73f7cb902 100644 --- a/hydra-cluster/src/HydraNode.hs +++ b/hydra-cluster/src/HydraNode.hs @@ -20,11 +20,10 @@ import Data.Aeson.Types (Pair) import Data.List qualified as List import Data.Text (pack) import Data.Text qualified as T -import Hydra.API.HTTPServer (DraftCommitTxRequest (..), DraftCommitTxResponse (..), TxOutWithWitness (..)) +import Hydra.API.HTTPServer (DraftCommitTxRequest (..), DraftCommitTxResponse (..)) import Hydra.Cluster.Util (readConfigFile) import Hydra.ContestationPeriod (ContestationPeriod) import Hydra.Crypto (HydraKey) -import Hydra.Ledger.Cardano () import Hydra.Logging (Tracer, Verbosity (..), traceWith) import Hydra.Network (Host (Host), NodeId (NodeId)) import Hydra.Network qualified as Network @@ -168,24 +167,20 @@ waitForAll tracer delay nodes expected = do _ -> tryNext c msgs stillExpected --- | Create a commit tx using the hydra-node for later submission -requestCommitTx' :: HydraClient -> UTxO' TxOutWithWitness -> IO Tx -requestCommitTx' HydraClient{hydraNodeId} utxos = +-- | Helper to make it easy to obtain a commit tx using some wallet utxo. +-- Create a commit tx using the hydra-node for later submission. +requestCommitTx :: HydraClient -> UTxO -> IO Tx +requestCommitTx HydraClient{hydraNodeId} utxos = runReq defaultHttpConfig request <&> commitTx . responseBody where request = Req.req POST (Req.http "127.0.0.1" /: "commit") - (ReqBodyJson $ DraftCommitTxRequest utxos) - (Proxy :: Proxy (JsonResponse DraftCommitTxResponse)) + (ReqBodyJson $ SimpleCommitRequest @Tx utxos) + (Proxy :: Proxy (JsonResponse (DraftCommitTxResponse Tx))) (Req.port $ 4_000 + hydraNodeId) --- | Helper to make it easy to obtain a commit tx using a wallet utxo -requestCommitTx :: HydraClient -> UTxO -> IO Tx -requestCommitTx client = - requestCommitTx' client . fmap (`TxOutWithWitness` Nothing) - -- | Get the latest snapshot UTxO from the hydra-node. NOTE: While we usually -- avoid parsing responses using the same data types as the system under test, -- this parses the response as a 'UTxO' type as we often need to pick it apart. diff --git a/hydra-cluster/test/Test/DirectChainSpec.hs b/hydra-cluster/test/Test/DirectChainSpec.hs index 274b3bbe26f..54dd1f5bb85 100644 --- a/hydra-cluster/test/Test/DirectChainSpec.hs +++ b/hydra-cluster/test/Test/DirectChainSpec.hs @@ -5,7 +5,6 @@ module Test.DirectChainSpec where import Hydra.Prelude import Test.Hydra.Prelude -import Cardano.Api.UTxO (UTxO' (UTxO, toMap)) import CardanoClient ( QueryPoint (QueryTip), RunningNode (..), @@ -22,20 +21,18 @@ import Hydra.Cardano.Api ( ChainPoint (..), CtxUTxO, Key (SigningKey), - KeyWitnessInCtx (KeyWitnessForSpending), PaymentKey, TxOut, - WitCtxTxIn, - Witness, + UTxO', lovelaceToValue, signTx, txOutValue, unFile, - pattern KeyWitness, ) import Hydra.Chain ( Chain (Chain, draftCommitTx, postTx), ChainEvent (..), + CommitBlueprintTx (..), HeadParameters (..), OnChainTx (..), PostChainTx (..), @@ -449,7 +446,7 @@ data DirectChainTestLog data DirectChainTest tx m = DirectChainTest { postTx :: PostChainTx tx -> m () , waitCallback :: m (ChainEvent tx) - , draftCommitTx :: UTxO' (TxOut CtxUTxO, Witness WitCtxTxIn) -> HeadId -> m tx + , draftCommitTx :: HeadId -> UTxOType tx -> tx -> m tx } -- | Wrapper around 'withDirectChain' that threads a 'ChainStateType tx' through @@ -476,8 +473,8 @@ withDirectChainTest tracer config party action = do DirectChainTest { postTx , waitCallback = atomically $ takeTMVar eventMVar - , draftCommitTx = \utxo headId -> do - eTx <- draftCommitTx headId utxo + , draftCommitTx = \headId utxo blueprintTx -> do + eTx <- draftCommitTx headId $ CommitBlueprintTx{lookupUTxO = utxo, blueprintTx} case eTx of Left e -> throwIO e Right tx -> pure tx @@ -528,10 +525,9 @@ externalCommit :: HeadId -> UTxO' (TxOut CtxUTxO) -> IO () -externalCommit node hydraClient externalSk headId utxoToCommit' = do - let utxoToCommit = - UTxO $ (,KeyWitness KeyWitnessForSpending) <$> toMap utxoToCommit' - commitTx <- draftCommitTx utxoToCommit headId +externalCommit node hydraClient externalSk headId utxoToCommit = do + let blueprintTx = txSpendingUTxO utxoToCommit + commitTx <- draftCommitTx headId utxoToCommit blueprintTx let signedTx = signTx externalSk commitTx submitTx node signedTx where diff --git a/hydra-cluster/test/Test/EndToEndSpec.hs b/hydra-cluster/test/Test/EndToEndSpec.hs index fadbf01147b..0e72c82a289 100644 --- a/hydra-cluster/test/Test/EndToEndSpec.hs +++ b/hydra-cluster/test/Test/EndToEndSpec.hs @@ -67,9 +67,8 @@ import Hydra.Cluster.Scenarios ( refuelIfNeeded, restartedNodeCanAbort, restartedNodeCanObserveCommitTx, - singlePartyCannotCommitExternallyWalletUtxo, - singlePartyCommitsExternalScriptWithInlineDatum, - singlePartyCommitsFromExternalScript, + singlePartyCommitsFromExternal, + singlePartyCommitsFromExternalTxBlueprint, singlePartyHeadFullLifeCycle, testPreventResumeReconfiguredPeer, threeNodesNoErrorsOnOpen, @@ -178,26 +177,21 @@ spec = around (showLogsOnFailure "EndToEndSpec") $ do withCardanoNodeDevnet (contramap FromCardanoNode tracer) tmpDir $ \node -> publishHydraScriptsAs node Faucet >>= timedTx tmpDir tracer node - it "commits from external with script utxo" $ \tracer -> do + it "commits from external with utxo" $ \tracer -> do withClusterTempDir $ \tmpDir -> do withCardanoNodeDevnet (contramap FromCardanoNode tracer) tmpDir $ \node -> publishHydraScriptsAs node Faucet - >>= singlePartyCommitsFromExternalScript tracer tmpDir node - it "commit external wallet utxo with inline datum in the script" $ \tracer -> do - withClusterTempDir $ \tmpDir -> do - withCardanoNodeDevnet (contramap FromCardanoNode tracer) tmpDir $ \node -> - publishHydraScriptsAs node Faucet - >>= singlePartyCommitsExternalScriptWithInlineDatum tracer tmpDir node - it "can't commit externally with internal wallet utxo" $ \tracer -> do + >>= singlePartyCommitsFromExternal tracer tmpDir node + it "can submit a signed user transaction" $ \tracer -> do withClusterTempDir $ \tmpDir -> do withCardanoNodeDevnet (contramap FromCardanoNode tracer) tmpDir $ \node -> publishHydraScriptsAs node Faucet - >>= singlePartyCannotCommitExternallyWalletUtxo tracer tmpDir node - it "can submit a signed user transaction" $ \tracer -> do + >>= canSubmitTransactionThroughAPI tracer tmpDir node + it "commits from external with tx blueprint" $ \tracer -> do withClusterTempDir $ \tmpDir -> do withCardanoNodeDevnet (contramap FromCardanoNode tracer) tmpDir $ \node -> publishHydraScriptsAs node Faucet - >>= canSubmitTransactionThroughAPI tracer tmpDir node + >>= singlePartyCommitsFromExternalTxBlueprint tracer tmpDir node describe "three hydra nodes scenario" $ do it "does not error when all nodes open the head concurrently" $ \tracer -> diff --git a/hydra-node/golden/ReasonablySized (DraftCommitTxRequest (Tx BabbageEra)).json b/hydra-node/golden/ReasonablySized (DraftCommitTxRequest (Tx BabbageEra)).json new file mode 100644 index 00000000000..f97639a17be --- /dev/null +++ b/hydra-node/golden/ReasonablySized (DraftCommitTxRequest (Tx BabbageEra)).json @@ -0,0 +1,851 @@ +{ + "samples": [ + { + "0103030708040808080206010506010105010404030406080205060402060406#98": { + "address": "addr1q8va4hat34z4y84tklmljt7fz2njt23yep83s480de4rn0juvaeegyzeru7dv450906vj0z8rp7xek3mzqtgdf070ywqcdd84s", + "datum": null, + "inlineDatum": { + "constructor": 2, + "fields": [ + { + "constructor": 2, + "fields": [ + { + "constructor": 3, + "fields": [ + { + "bytes": "e52a" + } + ] + }, + { + "bytes": "" + }, + { + "constructor": 2, + "fields": [ + { + "bytes": "5b" + } + ] + }, + { + "bytes": "77cda6" + }, + { + "bytes": "e87fb8" + } + ] + }, + { + "map": [ + { + "k": { + "constructor": 1, + "fields": [] + }, + "v": { + "bytes": "" + } + }, + { + "k": { + "list": [ + { + "int": 0 + }, + { + "bytes": "6d" + }, + { + "bytes": "6e" + }, + { + "bytes": "" + }, + { + "bytes": "b4" + } + ] + }, + "v": { + "int": -3 + } + } + ] + } + ] + }, + "inlineDatumhash": "3d066e89ad6cbe7019184e588a734a47b322ebf6c2e4a43a284481812c8d87c9", + "referenceScript": null, + "value": { + "700ccc9d5ee36e47fd6e2a2b13831aee1f4c6b836b81f463ddf880ec": { + "35": 1 + } + } + }, + "0205000502080304030202040705000006070604080807050808050705000104#35": { + "address": "addr1zxfwh7ehakjnu2tsfgufq2tlsj9fg820thg49yp2x26fkv7ju08fslkje4xvjq8advpexjp7t20y2cfcvh079nezudmqr22nx6", + "datum": null, + "inlineDatum": { + "map": [ + { + "k": { + "int": 0 + }, + "v": { + "list": [] + } + }, + { + "k": { + "constructor": 1, + "fields": [ + { + "bytes": "cf9c1f71" + }, + { + "int": 2 + }, + { + "int": 0 + }, + { + "map": [ + { + "k": { + "bytes": "" + }, + "v": { + "int": -2 + } + }, + { + "k": { + "bytes": "5f2c" + }, + "v": { + "int": -3 + } + }, + { + "k": { + "bytes": "4cb8" + }, + "v": { + "int": -5 + } + } + ] + } + ] + }, + "v": { + "map": [ + { + "k": { + "constructor": 3, + "fields": [ + { + "int": -1 + }, + { + "int": 0 + }, + { + "bytes": "8bfac2f6" + }, + { + "bytes": "c366" + } + ] + }, + "v": { + "int": 4 + } + }, + { + "k": { + "bytes": "34cf1e" + }, + "v": { + "map": [ + { + "k": { + "bytes": "2e72f6" + }, + "v": { + "int": -1 + } + } + ] + } + }, + { + "k": { + "map": [ + { + "k": { + "bytes": "db" + }, + "v": { + "int": -5 + } + } + ] + }, + "v": { + "constructor": 5, + "fields": [ + { + "bytes": "d36e4695" + }, + { + "bytes": "80a7d9" + }, + { + "bytes": "e49f" + }, + { + "bytes": "71d79f" + }, + { + "bytes": "2bd1c9f0" + } + ] + } + } + ] + } + }, + { + "k": { + "map": [] + }, + "v": { + "bytes": "1c75c177" + } + }, + { + "k": { + "bytes": "17be43" + }, + "v": { + "bytes": "51" + } + } + ] + }, + "inlineDatumhash": "77ed7ed47a123918ddfdead03503899007e3d48b7c7f07b5b0eb70668f5adb60", + "referenceScript": null, + "value": { + "89ef4ec2f32af5703bd4f2be331b1f06466ebd76e18a41d3b0bcf3e5": { + "5ae592846df35902aa": 5675497201616615523 + }, + "lovelace": 3601972019525104427 + } + }, + "0300000206060204060707050205010802070406060506020508030207040208#42": { + "address": "addr_test1zp7kxsagqslyltx6p9kdx3lhlqfasy4frntzhdqv2e9f6uzkvk0a7f0vl5jqgczmj9kn0rmj8f2sguzyp97se6a9fc7qv0j9zw", + "datum": null, + "datumhash": null, + "inlineDatum": null, + "referenceScript": { + "script": { + "cborHex": "46450100002261", + "description": "", + "type": "PlutusScriptV1" + }, + "scriptLanguage": "PlutusScriptLanguage PlutusScriptV1" + }, + "value": { + "d6eaf905ce0cb03d6c24aa5664b6da8d451bdf49b367cdeb12a05d3c": { + "37bd": 1 + }, + "lovelace": 5247759364583205505 + } + }, + "0403060306000304040004030808030807000805020103040800020501040608#78": { + "address": "addr_test12p37gt4nja3spwggdw7k26y4ace3fdpsttm77hedgkrfwscxqczs9nvwwz", + "datum": null, + "datumhash": null, + "inlineDatum": null, + "referenceScript": { + "script": { + "cborHex": "82018482050b820284830302828200581c65fc709a5e019b8aba76f6977c1c8770e4b36fa76f434efc588747b78200581c76e607db2a31c9a2c32761d2431a186a550cc321f79cd8d6a82b29b88201828200581c76e607db2a31c9a2c32761d2431a186a550cc321f79cd8d6a82b29b88200581cb5ae663aaea8e500157bdf4baafd6f5ba0ce5759f7cd4101fc132f548202838200581cbd039f956f4b302f3ab6fc7c4bac3350a540f44af81a8492194dd2c28200581c65fc709a5e019b8aba76f6977c1c8770e4b36fa76f434efc588747b78200581c58e1b65718531b42494610c506cef10ff031fa817a8ff75c0ab180e7830304858200581c4acf2773917c7b547c576a7ff110d2ba5733c1f1ca9cdc659aea3a568200581c58e1b65718531b42494610c506cef10ff031fa817a8ff75c0ab180e78200581c4acf2773917c7b547c576a7ff110d2ba5733c1f1ca9cdc659aea3a568200581c3542acb3a64d80c29302260d62c3b87a742ad14abf855ebc6733081e8200581cb16b56f5ec064be6ac3cab6035efae86b366cc3dc4a0d571603d70e58204038201828204108201838200581c76e607db2a31c9a2c32761d2431a186a550cc321f79cd8d6a82b29b88200581cb5ae663aaea8e500157bdf4baafd6f5ba0ce5759f7cd4101fc132f548200581ce0a714319812c3f773ba04ec5d6b3ffcd5aad85006805b047b082541", + "description": "", + "type": "SimpleScript" + }, + "scriptLanguage": "SimpleScriptLanguage" + }, + "value": { + "9e24f8a2a18a108390b9a0ecfb6aca1ff4e66867b995c11ba9d96bc7": { + "37": 1 + }, + "lovelace": 2119842977817854865 + } + }, + "0605060103000503080006050306050703060000050105020808080806000300#69": { + "address": "addr1x8c7mf57utayw8vnhmd5zvd9wqd57aqglra5c0kjh8gfgs6mygehcql5mahdskqhg2t4qds7s4le3vm4n94v35dcz32qthjzeh", + "datum": null, + "datumhash": "7afd04806608632ceaa2384c668e99bd2895acc1c24c8632ae92d072e63e3c3a", + "inlineDatum": null, + "referenceScript": null, + "value": { + "fef91098d6feeaf11a3c301de39e00cf653d37f49db690f422e39937": { + "c4b08bf247496acb57b47f9679fbea": 2222597395007839854 + } + } + } + }, + { + "0108010806040708030808030604040005030301040603070700050803020602#6": { + "address": "addr1zyzte92v2s4u2z0avzg9t8hn0hugh4w803wpds42lwkc6k764uwdxl0wmumqyjr2lt993w3gr2nmsl89y55vusr3huks8e4s09", + "datum": null, + "datumhash": "3aa954ab240423867ba8426fb9cf7031d552998628e1fbd1bf2cd044d7373d9f", + "inlineDatum": null, + "referenceScript": { + "script": { + "cborHex": "8200581cbd039f956f4b302f3ab6fc7c4bac3350a540f44af81a8492194dd2c2", + "description": "", + "type": "SimpleScript" + }, + "scriptLanguage": "SimpleScriptLanguage" + }, + "value": { + "c978e3be0d01b37fde57640fa7e047dcaf12f40d2c21c1a3f04d2d67": { + "33": 5039428953979917821 + } + } + }, + "0400070105070805080801000107000007010708050304080300040400050102#86": { + "address": "addr1z9lvz9lg0wxw8l4jaljcptd03ap3kq4ftc8y7ts6pzhcle6d5c5mrqsry7ywkamrpttmzwwhj0qjygu9s5qpz0xrzudsc6g9ed", + "datum": null, + "datumhash": "46d21152941afe6bbb85319745aa72a76af1a721f653076c09049b56feb54521", + "inlineDatum": null, + "referenceScript": null, + "value": { + "bfcddec5bb6d3bbabebf06639ffd3a8a49228b4442fc0416ccbf8814": { + "218e396ccbf2d0ca04150b0d538b504c70bd9384": 1 + }, + "lovelace": 1612728224243880708 + } + }, + "0601010303060403000300000208070700010808040503070705070106040808#16": { + "address": "addr1zxu26at4xsvc4ut4shp4hne6wnkhh2sk06p8w864qjjzru9rnf0qjmh78h7e5ugmwcprchrwxxcdxywem9z0tewhvdesc9m7yn", + "datum": null, + "datumhash": null, + "inlineDatum": null, + "referenceScript": { + "script": { + "cborHex": "82050d", + "description": "", + "type": "SimpleScript" + }, + "scriptLanguage": "SimpleScriptLanguage" + }, + "value": { + "ac8d5150293afecfe5f39741e7b64e96b580d3b5a82bb29c77ca52f5": { + "2f6cc7e50ee0d249ec2975602e87ad88ddafb64f2dbf": 8368921626681574220 + }, + "lovelace": 5372186911364879546 + } + }, + "0603030800050201000108010208020507010705080106000200000806040506#91": { + "address": "2RhQhCGqYPDmimLy4p9dC9jawhiPzKMxpLw3Pybzz1RcK9Fz7geeKk2fEHoGsmNk3xfrBdLWUmjzapmc35GzHMDVvYAyU2w2V9q3F5qDefRf7V", + "datum": null, + "inlineDatum": { + "bytes": "b0" + }, + "inlineDatumhash": "5deac6e1ed5e764dffe204d608cb9d43483c752730a71eb197cb356edefb04fe", + "referenceScript": null, + "value": { + "4a1c412d8e2b3015a7fb7d382808fb7cb721bf93a56e8bb6661cdebe": { + "cfa8d2af4f7a2ed11b4d44a4ce2894788235da": 2 + } + } + }, + "0604010208000602030504000603060501040106050006050303060707060805#18": { + "address": "addr1z9n2f6rd82xtsm67w3z4kjwtk02jm2kmd9nefafvd8mx0tttsynyp4kpum4wpqzruk59wl6p4djx6w6cgp0kykk2rdjqghmn2x", + "datum": null, + "inlineDatum": { + "map": [ + { + "k": { + "bytes": "" + }, + "v": { + "int": -3 + } + }, + { + "k": { + "map": [ + { + "k": { + "constructor": 1, + "fields": [ + { + "int": -5 + }, + { + "int": -4 + } + ] + }, + "v": { + "bytes": "f9be" + } + }, + { + "k": { + "int": -4 + }, + "v": { + "map": [] + } + } + ] + }, + "v": { + "constructor": 0, + "fields": [ + { + "constructor": 2, + "fields": [ + { + "int": 0 + }, + { + "bytes": "67bb037d" + }, + { + "int": -2 + }, + { + "int": -1 + }, + { + "int": 0 + } + ] + }, + { + "map": [ + { + "k": { + "int": 5 + }, + "v": { + "bytes": "66f98e" + } + }, + { + "k": { + "bytes": "1f2d95c2" + }, + "v": { + "int": -3 + } + }, + { + "k": { + "int": -1 + }, + "v": { + "int": -1 + } + } + ] + }, + { + "bytes": "" + }, + { + "constructor": 5, + "fields": [ + { + "bytes": "" + } + ] + }, + { + "constructor": 3, + "fields": [] + } + ] + } + }, + { + "k": { + "constructor": 5, + "fields": [ + { + "bytes": "011a" + }, + { + "list": [ + { + "int": 0 + } + ] + } + ] + }, + "v": { + "bytes": "8037" + } + }, + { + "k": { + "bytes": "65024a" + }, + "v": { + "bytes": "67" + } + }, + { + "k": { + "list": [ + { + "constructor": 5, + "fields": [] + }, + { + "bytes": "656ab9" + }, + { + "constructor": 1, + "fields": [ + { + "int": 1 + }, + { + "int": 3 + }, + { + "int": 0 + }, + { + "bytes": "811e" + }, + { + "int": -5 + } + ] + }, + { + "constructor": 3, + "fields": [ + { + "bytes": "52e6" + }, + { + "bytes": "db1e" + }, + { + "int": -2 + }, + { + "bytes": "" + }, + { + "bytes": "" + } + ] + } + ] + }, + "v": { + "map": [ + { + "k": { + "int": -2 + }, + "v": { + "bytes": "3c" + } + }, + { + "k": { + "map": [ + { + "k": { + "int": 1 + }, + "v": { + "int": 3 + } + } + ] + }, + "v": { + "list": [ + { + "int": -1 + }, + { + "bytes": "" + }, + { + "bytes": "26ed8e83" + }, + { + "int": 2 + }, + { + "int": 5 + } + ] + } + } + ] + } + } + ] + }, + "inlineDatumhash": "f4e57802c7368970e194d42fb7298160aeb8ceb74545c3f2fcd0a806faa38284", + "referenceScript": null, + "value": { + "105a8f1bb56444cacc86378c95421aceeb326b0fb7743e493eb82fd5": { + "02c7cf174a3a08fd55db4b4ad835": 2 + }, + "lovelace": 5591405365557491808 + } + }, + "0604010704050001000606000503060003060700000300070006030502030701#80": { + "address": "EqGAuA8vHnNjywupMK5tiTd8GDJJFpuqcHXptRb3r9USxyyUDry8iD76yzNo1MiBqqJZSGsc6By9YKRRGKQ4g2dpVeYKPCHdkeB6qn3BUXK9fBmM6SBVdoS", + "datum": null, + "inlineDatum": { + "constructor": 2, + "fields": [ + { + "bytes": "bf" + }, + { + "map": [ + { + "k": { + "int": 3 + }, + "v": { + "int": -4 + } + } + ] + }, + { + "int": -2 + }, + { + "list": [ + { + "map": [ + { + "k": { + "int": -1 + }, + "v": { + "bytes": "e7" + } + }, + { + "k": { + "bytes": "7de4" + }, + "v": { + "int": 0 + } + }, + { + "k": { + "bytes": "a87f5d" + }, + "v": { + "bytes": "0f0513" + } + }, + { + "k": { + "int": -4 + }, + "v": { + "int": -5 + } + } + ] + }, + { + "list": [ + { + "int": 2 + }, + { + "bytes": "8a4128" + }, + { + "int": -2 + } + ] + }, + { + "bytes": "7e68ad4a" + }, + { + "constructor": 3, + "fields": [ + { + "int": -2 + }, + { + "bytes": "bbdea19c" + }, + { + "bytes": "30a17e" + } + ] + }, + { + "bytes": "53" + } + ] + }, + { + "int": 3 + } + ] + }, + "inlineDatumhash": "4e6fe1b0d0a73c5b818d054f91fe9985d76f7ad492e7bc66cf24706e36c0ff01", + "referenceScript": { + "script": { + "cborHex": "8200581cb5ae663aaea8e500157bdf4baafd6f5ba0ce5759f7cd4101fc132f54", + "description": "", + "type": "SimpleScript" + }, + "scriptLanguage": "SimpleScriptLanguage" + }, + "value": { + "4db2d10d7a192810c07a414aa07718d49ed17d1a27df10cf98cc15d2": { + "fcba6c84dcc17b1608bac24c6941c90954053720a68ce1234de5cafa7ffde1": 2 + }, + "lovelace": 3155843221276811965 + } + } + }, + { + "0107000206060500050101060206020305080302060602050608060105010207#49": { + "address": "addr1q8fw9k3t5xwmh8888mmvw4m8fa36sue5fud4hqk3vjvdpkg8grs7frxah5zp0fsfzguy9up8lfczl4u97tyd3mc52d0s9mg54l", + "datum": null, + "inlineDatum": { + "int": 0 + }, + "inlineDatumhash": "03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314", + "referenceScript": { + "script": { + "cborHex": "820409", + "description": "", + "type": "SimpleScript" + }, + "scriptLanguage": "SimpleScriptLanguage" + }, + "value": { + "2db8410d969b6ad6b6969703c77ebf6c44061aa51c5d6ceba46557e2": { + "4c3ac4b8ae22d78574a471": 3252627476648027334 + }, + "lovelace": 802727441781211751 + } + }, + "0306060606010602050804040600000008010406000606010502020405000003#64": { + "address": "addr_test1qzp0uwngkq6ev9y2rah94p6gch3c9xetg2fhqzqf9jszth96fxrhc2xswvnfghtey0rkp2dr7gdmv8qar5tz4u6zt58qjp0cgu", + "datum": null, + "datumhash": "c7eb1e39e64aa0fff288fb086350cdc1582999140a0827373a016882b4ebe7ff", + "inlineDatum": null, + "referenceScript": { + "script": { + "cborHex": "4746010000220011", + "description": "", + "type": "PlutusScriptV1" + }, + "scriptLanguage": "PlutusScriptLanguage PlutusScriptV1" + }, + "value": { + "467f58932b54910584a0e8ea25a225e06a14530b2e96e938c53a3f22": { + "33": 8171274763688114280 + } + } + }, + "0403050008070704010007010004040705000200030604040601070002060404#3": { + "address": "addr_test1xqlght27whxk6xslcljvcnm9c29l8y4mqqlgak8w5pak4yqs6czlyn43g26cvtw7d30p0u02e73aawh4wwx7mx56j90qkd2r4v", + "datum": null, + "datumhash": "69e754d808d5050231024b3a85fb17cd625f6daa0d3089e525362444b8b375f3", + "inlineDatum": null, + "referenceScript": { + "script": { + "cborHex": "8201858201828200581ca646474b8f5431261506b6c273d307c7569a4eb6c96b42dd4a29520a8201838200581cb16b56f5ec064be6ac3cab6035efae86b366cc3dc4a0d571603d70e58200581cb16b56f5ec064be6ac3cab6035efae86b366cc3dc4a0d571603d70e58200581c65fc709a5e019b8aba76f6977c1c8770e4b36fa76f434efc588747b782018282040983030080830302828202858200581ca646474b8f5431261506b6c273d307c7569a4eb6c96b42dd4a29520a8200581ca646474b8f5431261506b6c273d307c7569a4eb6c96b42dd4a29520a8200581c58e1b65718531b42494610c506cef10ff031fa817a8ff75c0ab180e78200581cb16b56f5ec064be6ac3cab6035efae86b366cc3dc4a0d571603d70e58200581cbd039f956f4b302f3ab6fc7c4bac3350a540f44af81a8492194dd2c28200581cbd039f956f4b302f3ab6fc7c4bac3350a540f44af81a8492194dd2c28202858205058201808201858200581cb5ae663aaea8e500157bdf4baafd6f5ba0ce5759f7cd4101fc132f548200581c76e607db2a31c9a2c32761d2431a186a550cc321f79cd8d6a82b29b88200581c4acf2773917c7b547c576a7ff110d2ba5733c1f1ca9cdc659aea3a568200581c3542acb3a64d80c29302260d62c3b87a742ad14abf855ebc6733081e8200581ca646474b8f5431261506b6c273d307c7569a4eb6c96b42dd4a29520a8205048201818200581cb16b56f5ec064be6ac3cab6035efae86b366cc3dc4a0d571603d70e58200581c0d94e174732ef9aae73f395ab44507bfa983d65023c11a951f0c32e4", + "description": "", + "type": "SimpleScript" + }, + "scriptLanguage": "SimpleScriptLanguage" + }, + "value": { + "2db8410d969b6ad6b6969703c77ebf6c44061aa51c5d6ceba46557e2": { + "39": 1 + } + } + }, + "0502020106030505000006060405020501040304010304010002020308050206#9": { + "address": "addr_test1wrf760yv690hr6gy7x5z7xldlv7ctxvmu9h4sc6hk6yp02clxnzg9", + "datum": null, + "inlineDatum": { + "bytes": "e7" + }, + "inlineDatumhash": "366b5af863f9330c1e697af71560b3cb4ae2a72f89ea60091d141d4226ca2ded", + "referenceScript": { + "script": { + "cborHex": "82040d", + "description": "", + "type": "SimpleScript" + }, + "scriptLanguage": "SimpleScriptLanguage" + }, + "value": { + "2db8410d969b6ad6b6969703c77ebf6c44061aa51c5d6ceba46557e2": { + "38": 1 + } + } + } + }, + {}, + { + "blueprintTx": { + "cborHex": "84ab00818258206a680b5268d5d4fa35646cbe8b950fc8ff893200ed911d3ef0202ac20a1b6e240b0181a400583921723fc52e62468988ed24670cf10c0b319981b754b77c1ede4cd98bda7c7c8014b8978a16c6b2425914d36e34792bc0de4930019382e6c2cb018200a1581c2db8410d969b6ad6b6969703c77ebf6c44061aa51c5d6ceba46557e2a149a6a500dd40b089074d1b639a5d1448c22110028201d8184d9fd87c9fd87e9f4040ffff04ff03d8184a8202474601000022001110a4005839003d23fb802eeea2069ce33d2c127d5ca0e9b2be22d1960a18065abfc22cc43e009329859bb0996c199d41da3d8ce30af071610a7fd1390bb4018200a1581c3b54651d1d57e502b5866a52158cc5a23c900324e1dfea032b1158d3a141341b5403644dc827fb3902820058208c1559be875555a6b2a4986a4978f9cb80c2ab69788fbd34bf79f66d1118cbc103d818458200820506021a0001255e04868304581c255148304ff826ddb0abbc5e8f43eb641e0f28d8caf5f194b22cabee028304581c8b877632ed521cae938f804a0afcc834edec774e1ed1a79deb38528b0a82018201581c00cab54aa82b180cd99c689cc8cd70e9004c61b8b4b107806a7eb7a782068201a38200581c7aaf21cc6418e43a45c39f30feeddfcf38ebee7065335b96f05717901a000f1f128200581c7ef8775f41538241aba7d4cd2601907b7640dfd3e67a4468272b00f83a0001dd408200581ca628bab394852154ace133cbf55ce1577463db6d2d1387aba20506803a000142158304581c05bad8a483b209b70f1e6ed7e8a4eb1bd6e5f71891981d0b6e1596dc0e82018201581cef078d2ac33fec7ce07f791f47f6c9060c0146d9cf45f4d865eb8be405a6581df044c060a5600a561e527e92aebb486f48851c9101e7764be81c9b20be1a000497e5581de0459c9f8a1427dfe228bb07cec9f8b5e5918405aea5566afe66c9e8791a000a45e4581df1b03a1003c2f7d117122a481b02b949d681fb5f54878060ddd9bf0bf919a961581df1f5375108450776b8cd3a33676efd23985fcb27a0fa74c6c10238c2ef1a0006f9df581de1bd91c1569c64927f23f6a6e6fcb174b26ae1ac0d2366ac57f20a59261a00033947581de1f8b470d74ea631da45fc3d1119f0e24785ae8acf5919a13e5b0c78111a0005059d08040e85581c2cab970ed95ebeb110c286c13982f834b43ed447fd0ea3549a0c287a581c2ccffaf7565317e858debbd6fc19e4c651c6580877a1de1dd5129590581c33d7f48cd19e3a2111206565b2d32bcf12409635d6a5960594375aa7581c626c7dbee79548091358454ae45abfedbd62a5614c55eda6db8ad611581c73b984c3055f3f551583324bddcf5d563bac9c97b2d9ef4d8dfc4d6809a1581c2d32344cff305cd943ae9661114a968667836ef26387bc1be22c24a6a141391b635c9db406047b64075820326b0350ca3a7c0d1678c7a6bcc480635bc301ce84793778863bd8de9090cdae0f00a30084825820425858d4c9b3fbf4eaf373657ff48b102eb60184819d1b66cc75b4828158b8c8584086f38b7f3b454145555435c889cc9c44ae1e0d480d688b6cda1644268b01d0c2b076304437e4e91d2b611928fff4f3c1e7dc821ca79675210b6a33d2e986f3d7825820da2ae99063b6b980c1fe1a525279e2c8be9d0e53a50a0e4a54e70db7408756b35840602d33fa28b0fdb9f157bac577888ac6961e50602b797f2644d69ce48bc9a6b2f2de6d6257e0325fe9c67572c0e782fd72a868cde13d67af02cd569c03e8c5488258206bd7f6e7065f5065e08dd482c6d0941f76224450e2f12726d14a3e1f33f7931b58406df1961a2126138a08980c6b6e2b3191cb57dbd8cc6bee1213602507e272fa96172bc74759800eca8ee666e05429f4ef596ce8462ef68cbbf1828e5df600d7c58258203e718bb6ca2d784d6b44e0c7c5c96dd0d190bd7614326697152e614fd1d9e6e8584066a4afd983bd4dbc084debf4aa4e252b944fab892cb75a6184a5a7e5a0abdbdc569229e0b64bed04d9f617ba05f489f85f177d05d3e9db69b22d0dc5210986f504819fa120a14042a088d87e9fa44454e2bf8d05054040034358dfed20d87c9f04ffff24427cec43f8062bff0581840107a30243b54d97d87b9fd8799f20040242e270ff431a98ead87b80ff208005821b6bb75a9f798019371b5cb0725442de00c9f5f6", + "description": "", + "txId": "1b624e3638fecc7a4f547e4e0e1b71bc46c02bfe0a02bc0eef38ef79be964a96", + "type": "Tx BabbageEra" + }, + "utxo": { + "0707080105000302030305010005080505070402080205010001010101050400#41": { + "address": "addr1qyxdjakrzzjezr24awcpxgczr0zvvnw6x8nuph4ng02zzxx9twytg8xx5pxg64x25n7qged96txm6vksdzkm28t7rahq6kg3t9", + "datum": null, + "datumhash": null, + "inlineDatum": null, + "referenceScript": { + "script": { + "cborHex": "8200581c0d94e174732ef9aae73f395ab44507bfa983d65023c11a951f0c32e4", + "description": "", + "type": "SimpleScript" + }, + "scriptLanguage": "SimpleScriptLanguage" + }, + "value": { + "4a1c412d8e2b3015a7fb7d382808fb7cb721bf93a56e8bb6661cdebe": { + "b55c5fbef99a09cff2f553": 2525071571567660025 + }, + "lovelace": 823353035918019402 + } + } + } + } + ], + "seed": -1235188385 +} \ No newline at end of file diff --git a/hydra-node/golden/ReasonablySized (DraftCommitTxResponse (Tx BabbageEra)).json b/hydra-node/golden/ReasonablySized (DraftCommitTxResponse (Tx BabbageEra)).json new file mode 100644 index 00000000000..10539ffcc6f --- /dev/null +++ b/hydra-node/golden/ReasonablySized (DraftCommitTxResponse (Tx BabbageEra)).json @@ -0,0 +1,35 @@ +{ + "samples": [ + { + "cborHex": "84b000848258200487146667ebe2d8cac1603bcd769cd6e37ebbdd8147163f01ae2692c47398c00e82582028e095c4104f8188d096209d7de2faabaf0d4d9c8c172cb416bdb4bce128a6a90d8258206895b4df2924123102dd27c5931328df47ab368ef4eb080f6361c0621fbe3f1a0b8258209520e761ec08f5d3413bd5d5b7c050a00ec8ab33225925d07e3d2c82cf3b432d020d858258201209ed00ec1be8322759a519fa85ad8658362e5b93e56ddb2f5c9ba1a048ffd3088258204381dc6c897993790580901c528e885e4cd97ded9cd264f519b5b638e99df476068258204bf7966d1e17b89cd43889197a65b378bc68de22319551df63760653a4997ddb0e82582052259bc4ca71926fa322e3e188a57dc2649e0ee6e284bb027fab800a5899b02c06825820b7936b4fcfc982541b3e432f3868a0038056ffb04f6af8e78a6934ead4813c2b06128482582027242c4d7766d5e9f826704b4fec6fb03c97e61f9f1cc6010dbe8ce03e136d300e825820427085d7809b4ea6e71278a36c0e6cc0590590ad889d78f4e40d6e40236042760282582046b34374f5086b79168838757fd265f52606666ca5bf57bdfc4cdb0ddc7f83bf0882582085599d8fb6479404fed3de1545a649c1a22b9fd46f8fd10da01d31fe228700000f0184a400581d60d03b55b8df43818f7be0e0e2c5123e6bb0fda3ebd73f894c714af5be018200a1581c30bf5574e73e2b25f79fde171e0073f60fb5b349c6f6d7192176d1e3a141331b2a44db2ea6372085028201d818412003d81858738200820182830302828201838200581c4acf2773917c7b547c576a7ff110d2ba5733c1f1ca9cdc659aea3a568200581c58e1b65718531b42494610c506cef10ff031fa817a8ff75c0ab180e78200581cb16b56f5ec064be6ac3cab6035efae86b366cc3dc4a0d571603d70e582050d83030080a4005839014dcac9da1bce500a066289642496e229af1392e6c8f8a118a75853b612873dbc61fbbe908761a6c2a9c1e339b0c719101abc6e8e436d18cc01821b7d2ad2f4b4c22a39a1581cd4ff6b7afa7d865e021bf15800619a9f04eb7a5c50946c6a188ccfefa141381b758617e34cdc629c0282005820f3805b3cefeff3cf983e0ed9dc29a94e4e421c600033d66dd3621eb681e5874703d81846820082041819a4005820403d0d81f2506397884da7a3b4cccaa1eae7a53eaf578a8ac9943eb43d05080001821b5deabb85a2ee5145a1581c245d5a7a06fe18358242e81281cd5ba9e6abe4efc54e7b659f25abaea1413501028201d818581b9fa1d87c9f446b63407c429a5203ff0502a280a02443b82d5d23ff03d8185901a682008303058582050e830303838201808204018200581c76e607db2a31c9a2c32761d2431a186a550cc321f79cd8d6a82b29b88202818204038200581c3542acb3a64d80c29302260d62c3b87a742ad14abf855ebc6733081e820283830300858200581cb16b56f5ec064be6ac3cab6035efae86b366cc3dc4a0d571603d70e58200581cb5ae663aaea8e500157bdf4baafd6f5ba0ce5759f7cd4101fc132f548200581cb5ae663aaea8e500157bdf4baafd6f5ba0ce5759f7cd4101fc132f548200581c4acf2773917c7b547c576a7ff110d2ba5733c1f1ca9cdc659aea3a568200581c4acf2773917c7b547c576a7ff110d2ba5733c1f1ca9cdc659aea3a568201848200581c3542acb3a64d80c29302260d62c3b87a742ad14abf855ebc6733081e8200581c58e1b65718531b42494610c506cef10ff031fa817a8ff75c0ab180e78200581c76e607db2a31c9a2c32761d2431a186a550cc321f79cd8d6a82b29b88200581c65fc709a5e019b8aba76f6977c1c8770e4b36fa76f434efc588747b78201818200581c65fc709a5e019b8aba76f6977c1c8770e4b36fa76f434efc588747b7a300585082d818584683581c3c623f45b94d97d063f7a67255ac6b6fe91f9214df83747cea50e0a5a10158225820737968627471656e7569656a63716d6e7967786a7176736867776a656b686a63001ac73995fd018200a1581c2dc02db1e4e92307f287d395956c563ff777914b96387b97ec288f13a14a84546a46fb66b1d9f9191b413e4deea5f034be03d81845820082050210a4005839109e5777688a5a87a77fcd301f29e4fccbf9865a2fb0bb546d1941d27ed2080281784edebfc1bccf958349ff3e99cee969cee5cf7cfacae5df01821b6a3722f427a5e4c0a1581c105a8f1bb56444cacc86378c95421aceeb326b0fb7743e493eb82fd5a158200af5328540124624de19c63c2955dc81a92560dc6233660ef039e2965f02100a1b01a458410d63d52402820058209a73bd9e6a210253047b26baaa8f53f6584048ad79f051866572439fcb11521a03d818458200820410111a00037ffd021a0007d7fd031004848304581cd823d1b1957869a7c0dfbb6ea59aee58081a95872106d6d6b1813c280c8304581c6ad7d8e3d95b5efe8f9505035d51684fb8c463c1e2a77e8449d949cd0c8a03581c57c587434d36ada1abc7740ab8dff57c636492b262bd1d54cd10ff315820c90eae77f5226f51a805bf4571ff74098bc69cee946fd204f2b9cb985050adf91a00065fd81a000bd0cad81e82030a581df094cae75671cf417de0ae0248aaa31dd55e31c308be13c63f167eee1284581c786293d60dd25d13206576e00e204407f66c6494b3e12b0eeda315cf581c7ef87f73d405bd051174719693c07c4623fa1dec1689e3a7f6da266e581c9e65016b69db68eaffb816c6e10c82f60973792dfa3a78d66aeb4631581cc40208ac215a6ac037489598edb2c41f317709a7746e3d18cf70a5148583010078344a49784a3546456452477051444257336f446f3738684e4a657230417252752e49304e7134672e5357686f425a74556c2e636f6d840001440000000650030000000800000002000000070000008400064400000006f682027838563258726544545053696b6d31396147634e6c4c486c394a41384f37337730595a787550344b4331657a7a6874784168684e6c542e636f6d8202783e5576566c6d63366d7579616d3747316962507872344e71464a4b5868314271355261324a55586b5150723638677267576f6532416432463966682e636f6d827368747470733a2f2f454f376636564a2e636f6d444860f9fd8405581c7bdef9f73b8d92a5e87758ecf7b25f8c3ca8dfe5a64b57c0a44a7dfc581c4b7df24d9936e2d19c9e7972a3364079850a445766b01adbab0d231558203524b280e1e21faa8be67ec53e73b7f7e8d9257507dfda393428c5b9f7d8da7805a4581de02466c9052bd876471650e6dd602a835ef739dd37366cac40ae101ba11a0005843d581df1dfea930eba1be0487c47cfacc4ce0b4b0809a4ce7012146a32f6292a1a0001362b581de17a9b2c160d6d7cda1bf2203a64e43cd99c9f6339b3100fd5f38ce67a1a000a1508581de1cad5375232489c9f9b8cd94e20ea4033beb798b3cfc68992a6cf60451a0002dd07080f0e81581c66a1727baa9be0463a813e963e8362181c8504f30fb6979076441a5209a1581c467f58932b54910584a0e8ea25a225e06a14530b2e96e938c53a3f22a15820ee66d82a836f80e2d4b3f9d6d9e88c278e31c01059dbd2c3037cb7484efbf89d1b761a5668ca5c985f0b582089d1f3f9d122758aeaf9975736ab8f8e0bc37fe2a12dd111bfeb4705e3fa8f220758204366493aa0a13603225f7259fc9d13c83107b3c665b9d14521a110bccdebf15c0f00a40086825820b8bc70a16e06ced2098cd05f31fd79d013d27b638b963da6a58cd6d0883de6e55840aad7ad7d8e87f581c71c13b72c28121a08c8ff4013df07260c69a1e7aee3c04fb569a1844708db12f5152e40f9eed60beef80a90e82c6b797a50a6591fca03e182582007aa8262366cfa1052232665a388521e63ed8336f83cde951d8efbcd4fd24b2e584088203d3b57c18ff89bbe20781a5f96c5cdb69a5bedc296f2f056f0a3935215cff7f86820fd5f43c21beae983417b98bfac29ffa33f915cbf9e38d36de54ed20e825820aca9d471fb15ec6c659fadab5604f3c55623b16cb9ac30840e5544c7122b4cc35840fcdc44f8559ad581c36f3a48c2df04e0426d5c6d943565dd574176eee3f3e8ef173db68267be086d8d787c98d04aed348563b2fcd1bf6b09898f07258c12ff708258202b99e90af7e925d36b9082872682a5c004414bba20c6c849d7461f6be8b4a8595840aea6cd9a0f4986e94c3deb74ab7a8adb48a148a7c850bdea64d318ed61a5f70c384599bce2f87de4423359741ec03d2776433cceeaf20e3a39ced5ae49bf584f8258203bab62275483e829fec288b89ace239a262477cb7c12235317808f0fdbea7687584089e3ec14124eb3ac55ffc6c0a4bfc8ebbe9fcd61e6ab848d75c775e636909ad0b4f14ce3a4966232da309ff61999169f4c7380aa295c528e03d769dd81e8435982582046366fa2dc2e3bf1020d5b65d7d25cb5b71503b1fddb0adc41a9d9a570dcf8e75840de61876c197e3f3cab61490330092578bae8e87fecab0fe906b87cbe0e016f78934a1884a17025d0e76c4ab4aa78b470687c1039caed64f3a4311f2e24fd7a540281845820eec7e0df3757518756a7e89da71650af931bd46e4afeb82a9220d1373a8258795840d584697b17a8dbe11cc29cad9e8a6c8be97e78dd740dd121f1569b203c1defe2395ca78e8f4e4eeb5ce907bb2bc09ad53fa903bb50143534cb9bf3015cc4e05241ed4450333f460182820283830301818205018202858202818200581cbd039f956f4b302f3ab6fc7c4bac3350a540f44af81a8492194dd2c28204018202848200581c76e607db2a31c9a2c32761d2431a186a550cc321f79cd8d6a82b29b88200581cb16b56f5ec064be6ac3cab6035efae86b366cc3dc4a0d571603d70e58200581c4acf2773917c7b547c576a7ff110d2ba5733c1f1ca9cdc659aea3a568200581c58e1b65718531b42494610c506cef10ff031fa817a8ff75c0ab180e78201808201838200581c0d94e174732ef9aae73f395ab44507bfa983d65023c11a951f0c32e48200581c65fc709a5e019b8aba76f6977c1c8770e4b36fa76f434efc588747b78200581cbd039f956f4b302f3ab6fc7c4bac3350a540f44af81a8492194dd2c2830300818201828200581c76e607db2a31c9a2c32761d2431a186a550cc321f79cd8d6a82b29b88200581cbd039f956f4b302f3ab6fc7c4bac3350a540f44af81a8492194dd2c282028004844004444f380964a39fa1224001219f445e28d98bff9f428d530442316640ffffd8799f04ff9fd87d9f4041a8ff8004ff43aca134a022f4d90103a200a10b020181820409", + "description": "", + "txId": "747960e654a7ff934e8ad28edaccc8c57c949648b540da82668b8b94db2df722", + "type": "Tx BabbageEra" + }, + { + "cborHex": "84ae0081825820ae1bfb38225f59ffcbfa265dda41901770bf028904001e5066fe3db972cb061e0f0d838258204ec8d782035b1c8ff77fee3c8b68df6b71e3a362d5fb24080f2617fc323130510d825820d7522692d3ebf3e345b78129a25b0c7cbc21effd6f81b6c2282884e4fdee0a4b10825820fcd9855ff32221517b926606633d777b07668a5eff8eb60c9c0119a37146ca2e0f128282582087008d83f360f11cc99ea2684ac9d35693df22132c595e5ca64839c6a78b4b430382582094b4e9533314f2fd39423b8f4d477902778695fe67ddf3fdd791576aea548a56090182a4005839100f341375219b04b6b3419625aaf7e85ab32d6ac528fc8d5e1323d4e7da8b4fbdde00d19b9acb49675b7c824bf631e02df61daa776787569b01821b5daeff2cf4f793fea1581c9e660d935fcde6a5b69f8a0a936693aa53815cdd8c05c3f36d3eddd4a141381b15c405d4ef1ed6870282005820cf41847858cedaa02838598346274428dc51ff1e3e228d2f9467751131fc4eca03d818458200820410a3005839213913478a87aad2efc6670de370ec19230dc6130870167beca23cdcfc2ea475852b630e8307778210c9b8a7e2530b68fe76a15b667e62896801821b6b2b550f03354949a1581cc08f3a4324fa8dd578b47c1a0df700d858a46eb1562b5d4c591116c1a141361b0814e115bc816463028201d818549fd8799fd87e80ffa19f2140ff441d35407223ff10a4005839301b3b09ff5096ea4b5604d02840b0ebff45dbb61e88d14ecdfacd62f0e0981dd2a32267663d81c411560a3d93d0fdcdf59ae496c6c3996903018200a1581c2db8410d969b6ad6b6969703c77ebf6c44061aa51c5d6ceba46557e2a1581df68f1aa8afaaf40d32934ff479a002fadbabc3f30d156fdaea1b9fd88701028201d818449f41e4ff03d81845820082050c111a000b13bf021a00085447030c04868405581ce377dbc45642857656c5e9cbb0f47d5ad7082d4a7682990639485b71581c0cc6b7a6205c9dc1ee8cc4a6b5699296560d26ba1a03acbcac167b225820c47af88c62fb67a24cc15fde629f5dfed507b9d7f4fabd9997981bff72e054a18304581c198d2e7cca897b2da0ad7f3f7a81d65eba1ca197b2eb1c476cb5e94e0a82018200581ca610229a679b106a84f0877d9fa5b0375dbcf006faa19b824dfd87b683028200581cfdb76e9780e13390e7e7f56f70157b70dedb29c4f18b7aed484f7b0f581cd44d72e0390cf75e98d8bd26911328952d5c4990b0d1d108f9c91b28820682001a000258b68a03581c753d58fccdb250ac84a2729108f03929825995c72d865d29d4346acc58201c8cd57315322b92ff20a2dceabb20fe0057a392f038eb519d7bb48e32866da01a000bbe5d1a000df25fd81e8218491864581df1635fc9e944b5eaf6c12c21dd21781f131e102ccfffe893af934902ea85581c02809870ce1a31e7ed28840cb3c3f41c489d6a91337fb1d7ce62c61c581c65350cc5c53ced45814c78330416cde1489e5403ad9809697126e632581c6fd4adaf9679ab0c88d15f41839fd478af2fff5a02f00b7398fdc6b7581caa1b1ed12e886dae238a82b163fe2adaa7ae55b20b49285348e5fd08581cde34b17e737862cc0249ea49d38746b8172fe280a046450244797ab58182027833337a5645594c5471686e52642e72774b73654a46355134793376713937567750776749753135477a7461735237454b2e636f6d827468747470733a2f2f77754a4e543342382e636f6d42bda705a4581de02c6e76d135a09c68864969870a14e7df27501717d63400fda251cfff1a00027587581de08969a906f695c1e5a1135b9f71ddeb36f0aa6ee2cc7c30dbec199ef21a000e9160581de19575bcaa1d8f8a56b7c2e572451202c664f02ca9906fe4e2f92bab121a00061346581de19c9a4b16efc4849ddf2dade3ea80a8948b9ea8052ec20046e9df67851a0008744c080c0e85581c5c4933e38862e6e10d17c0d2e352b2dadce93f2f227a9adb36ad1227581c7145d238d2f712ba3ecc6e7d74b3e05c494fe0ce2bfcac7c41ba72af581caaf5bd2aed2e94376ec5f4ac9903b0e11c50ad69d2cc27b8ce8576b0581cbc62055ddf26d7849022c78b60ee98fbe5ac930dbe2d857203262404581cc28414d0fdb8af8ab2d8edec1a5c14b9cc5950b45a4d1b92d464c8d409a1581c2e12c5e499e0521b13837391beed1248a2e36117370662ee75918b56a141343b4ffa7a1e889104c80b5820abe9ed019691a29a908270ea9eb4e71a060c51418442cd9aef61c5c0b79830aca300828258200ded6dbc68fa0eba7a143029ea00876244a068233ae02d3acfe87ca0a0fb866958406818fe8384b6b944d67f191dd2ca614091f50c070492a96e2da2af2ad22111eb305e91daad054a74acc880177e9856f31bc8b6cfdb3b9b3b4b4f092e08bd28c58258203b3853c80a322cf2335a4a7836a22aa1377273119795ecbe525faed9a26f13595840af97751e37da8ad4d6935cf8a20908b0af8e7b833949adead79255be26a4b51529d61055fd1a07f7f28763bdedc741ab1edbab88e2bb4838d539cbc0347910940186820508830300808204028205158202838205098202808202838204108205058205098202848200581c4acf2773917c7b547c576a7ff110d2ba5733c1f1ca9cdc659aea3a56830300808202838200581cb16b56f5ec064be6ac3cab6035efae86b366cc3dc4a0d571603d70e58205088200581c0d94e174732ef9aae73f395ab44507bfa983d65023c11a951f0c32e482050c058284030604821b4eb0f367bc019b041b6b34af95ac67b51184030805821b6a318acf848b02ae1b681ce177073874c3f4d90103a200a6004291200168707ef48d8ab77605040508400b83653d7d22521da12266f489a09d2f308242e1af425dfa0ea001818200581ceccbfb5c619673f0648a42cc2f822c81cbc34aee41274638e89a7af5", + "description": "", + "txId": "fb8e41e74275c7b76d21b4969b5c61b3ac07dd6d62d23bcc5817350661faa19e", + "type": "Tx BabbageEra" + }, + { + "cborHex": "84b0008582582008a04e4b4ec67dafe61005e93032dd78d517e075a0df4abcc9ea23ac53fa734e0b8258201e382643919177c0715a703c4e374cd7fb0291df2df7c986d94e31cbc4e053a40d82582088933876633f9ade0375390a14b749f3ebd149ea7636ae32f2f33c06373f599a0b825820a27ed8aa68c53e2daf318fcab02f6a639759683bf29726cf1303d9780e3dea6906825820e05bdf4097722d63a0b4a604b05781fb481e0cd3fcedc3fb2f170818ef1f72d4060d82825820b12e8d624e0efc82b96ec77f6b93639169749527827aaf7a54357e7939adc6fd08825820cbba44aa20e433d76daf1f8a8feedabc99337aa21e784a43b7d03641a28e67001012838258200a6efd01cdbac95eba4f7d0ae928a957af34870570206cec585d8d9abcf34e3b0f8258204d3d2dc024a126983314a42820dd75ca786d7f63025a4980ab43f00e347a150906825820c96f6ec199e964854b78d5f4f17f56e0ad7e12d6475c92bd59638ea4c48fb4c90d0183a300583931171f555ee44034d6d8a3ab972e2804cfa0c184d47e0642eaaa36fb5c4e0d87413c3ed4a27e8b4ebd28da51ca90f08694d2e4e36260aa5c4201821b03f06412ce30b389a1581c350e8f03a5de8824f6240a505afa949bbad5d62b7ee767d47ab90deda14a3ec26784960b98244aa201028201d8184342eb0ca4005839213878102087a3d8d232c196c57707c751384730676e917f9d85b8950bc57797fad04308bb0c7b8af0a5dccd228bb938a2509061d328ef4935018200a1581c105a8f1bb56444cacc86378c95421aceeb326b0fb7743e493eb82fd5a14b8076e7cd11ab76c145d4ab01028201d818414003d818587782008201858205048204038204018205088201818201838200581c3542acb3a64d80c29302260d62c3b87a742ad14abf855ebc6733081e8200581c0d94e174732ef9aae73f395ab44507bfa983d65023c11a951f0c32e48200581cbd039f956f4b302f3ab6fc7c4bac3350a540f44af81a8492194dd2c2a400583931dccf0587ddd0be9615048582ee635a54593862a6008eed3494a131c82d17e13dd0448e6c7c12d85d0b25e1c92a82f155c6ee4fc98d46511f018200a1581c864e0c5586316b73e4e36751f6f63993d5555e4f751faa7a82426b9fa15523137d7b8e7774b3dd283f1da3a5148578c8ee5d3f0202820058202c94aa4c9a972b9ab208969e2fc79e0d9ea44b5ba0e019650aa4956ad23a2a2103d81845820082028010a400582b82d818582183581c2f90441ce8d3123a67593076667c7f4c2df48cbcdcd6523e325abccba0021a89e749d9018200a1581c105a8f1bb56444cacc86378c95421aceeb326b0fb7743e493eb82fd5a143226e8d01028201d818582b9f059f44820567b59f240405ffa440242122402144fbab2d7242daa1d87d9f4044884c62860302ffff80ff03d818458200820409111a00060cdb021a000c9dab0303048682068200a68201581c723396e2540518edd00a681ebe0ea5f3e5faaaeea4a28553528701c139ac808201581cb2a4cfed087cb242009be5b97fb859cb0a00aaa04f015099c92b91703a000f091b8200581c2b3a8d31c9b29c0fd9dce14311fb072d177db45d8092465554ba3f713a000289c48200581c2e20208316480e7b12922e4ae179d7cfe872fa06eae9a89fb36908793a0001e9918200581c2f8b9f7afaf0c6373a4a270ba7eb889434a4e6b47c2250e68e35ad433a000aa30d8200581c56b5964fe568742fc548eb6686f7c4ee77c90aa21777d32760b3d601196a8c820682011a000c31e28a03581c6d2b65ddc3c3923b5a17265fbc7e49bb94d2d7fd35ab2eeb8a6a4aa758200c92c96ce28663657cdd73ae608f2cec0fc6435eed81cb653c299fe86776c0801a000dcc8f1a000cf837d81e8219233b192710581de08608db8c3df0a6b03bae3e23a3c19747d868696d760b906f60e9b06984581c43aba2fd364956e18f8626bd460f32286d399825297d0824a58cc45c581c4ab2ab6d7dc4af5c3612ecf1610bc44c35dd292c3d9396b308413641581c7cce60b57156c94effe01a104f15c421fb69c63ff9119e7f0014b67a581cd52dbbba1928c802bbfd0ef555e6434f28e05c49468e59a7a85ae38480f68405581c3a87c79e5f7061816b7a3bd1fe2db227fa93a66fe826b31644623220581cff6a5ba025ae194a01a10849e79181dad78e18122b4d1b8c83749e98582055e13be2261f94e562085f243d3ee42afb58e4f63439f5df6bb24629fd294af482068200a08405581c18324f603833476cc4c47bfd7e4320692e3fefbf7f55a7b9b1e23848581cb52aa4001b45160e183a89394810c7100189be9333d4cf14e213321f5820322c75d9058984b308b689d9a44cfcbe595615878d7f25d4e5639527aeda9f5605a1581de059ff10604b78182e261daac1163dc6da32f3818d6141816395d21ac91a00097e52080a0e84581c41715c766ab978749ec153b9db838da8f5a5b45b8f0b365dbd6ecebe581c9d28d0617a9f817ff349c6fdc8b9b8ec4c0b9a06eefbe9b56cb158bd581cc5b6b6023c64a57b17ae3b7c6a218a911d718ec1f30e660d26b8adec581cfa671e7c5ba9e1d54f0e1ab9d735642c483ce490afa49d64a637c5e109a1581c90d25420669bd1a051520f8196dafe3a1a24d58f9d76c899a044d2d9a141303b0821ce5feec956710b58206b16cdfac1ffd9c8f3a4c0d19a4018b286ce8b92a872067148f98e1ba16433cd0758207f568f4dc1626b37f824a2b042a40001407363d202dbff0e1d546c771b8f1e4d0f00a5008282582076bcdf509f869adfb6665966bebab8a762f0b1832f8b69ddd75c3d84ca3a545c5840a44228fe2a97930aa52152353946019aeed0a4d2409906eeb36b3510eb48efdb3917d242202f21b12d1b76dc1102dedf4560f5283fda566deb4a7724fed26e238258207ba6c6b28f4ab796b8507b07cbf85c49d356853e9ae23df41fcdad825a45f38b5840e3a524048da74420b74db3eb44b612381a93ab153a5627c75335fbd19007113b380ad473d1d444730744946e7efaeb9c4c82b4b650499247833225d7667d6e70028284582003b84c509b365a0cb4c8ffa37555fbf122de84a11c9b8cbcd7d766c9a7ae8313584054b6d89416e1746f953f3d8578967ee214d175ec70d021c9841cc45a201db4e1e30906b9d3dbcef6aa86e80d00a10c9cb7491c7dca8cd5daad733a351b49bd0142dee441e28458204f52be1972a0a914eab6b5b73cbd9e3529110df6f09931d23f912d023edee44a584028c8c04906c36d2f7bb52f83764e01e6a88c92380887ebf015c80e3dcdd35b0d4aad70b235267784bfb78a5fd41a3109ccae5240a28a4b0de1529983b176dbdf44bba095e7430612830181820280048442218d0201d87b800586840003d87a9fd87e9f9f42b07705ffff2104a5d8799f422756ffd87d9f404024ff8043095b35d87e9f20400000ff01435a9ccda42144aac5c52d431a3744404233e50144271685fd00d87d80439d573dff821b753b23ec10673d611b4b6ff54534a4affe8402009fa0d87a9f0142778744fef66a26ff40ff821b3d7a4d21fa4ca7621b4887bec6ae0306968402029f40ff821b2009f65cd7f50cd91b43c7da2e7b7d48a8840303a5a2a24472f7972402432787c5019f43452c9341b7234210e440ffd87d9f415140ffa20144edf731052000a3a42220052141194484a91d78425f180420a2412a0244528a29ed43b2b86cd87b9f438bea600443549a0a420035ffa5212142f1770305426307030301249f22ff9f0440a1224335516820ffa541c041589f0540ffd87a9f222041b44220e202ffa3034042a26643ef7777402124d87b9f204451f223860041924130ffa4034161447560bb544334533c004042d3880240d87d9f446752cf79014212a2ff0423d8799fd87e9f21ff20ff059f40ff22821b53738ddd94e3bfbf1b37333116d0e58be984030602821b3ff56eac7c8e63261b056d96ab4c6022a984030702821b6e9ba3a98d7a25f71b3cb3981d4e67e2caf5d90103a100a60525062007636c7c210c240e44c10948bf0f82421e0240", + "description": "", + "txId": "86ef39251bae9783e93e110fe841a57b6b29a532a18493b5a4ce973f97358745", + "type": "Tx BabbageEra" + }, + { + "cborHex": "84ad0086825820100065f66cd7868145ed3960c20cec21ce774cb6ca60b06d8a836a12e988ea3f0c8258204d35a213421e7165ec0bec47f2d5ce99db00b35acd6b03cbe35af91551d4ff3606825820ba6a1f04f3a2c1dfb21857ef5c2527232ceb9f6bb4b445875e9a9b534feeceac05825820bd73a4810d336a0914d66c719d9bc1be85103de78e5b8a5a4ef5229c30ff14b80a825820e39fb781ce13da32b81f577529b8f5130a9fcf47a41c8d90d89dd04483e3092c06825820e738084fd76e47790be75baf06776858ed658552f2ce61c1c69ef7ae816d36c1000d81825820a3af5b6809a2c7aec7120ce0cef76b7beecf0b19e62819f3398d5375335f82400612838258202b28e6e7be8c268e084622cfbc3cb54fe09f5628b796f0bb18f5031553aab686008258203cea390f392f166f779ddbce5e6f4caeb545cf06a84c79eecc98a0b283b0dfd20d825820951a9ef4d01fd52bd6e75c75caca515d29458a9b2d88951980581bdc00c13b090b0186a40058391006df88659b3d0783c8df59b41f9eea2ad3840b5013a75d415c94690c5b999dce280883d48fd9f3f029e8d2871832d9b96ffcb6241d048fa3018200a1581c2db8410d969b6ad6b6969703c77ebf6c44061aa51c5d6ceba46557e2a1413402028200582091036961992bb6191d7cca564c19280989692065fd392e11c59a5adb7de1eff103d81845820082040ca4005839201b24aa7e82da40466c9f4a5afa910b23efd6ab64d22d5d86ac0aade3975611fd46e14ae9c7f9249b6c0597185eae8ff9044ca080f39fb7bf018200a1581c245d5a7a06fe18358242e81281cd5ba9e6abe4efc54e7b659f25abaea14aff6c18067d8f335d1a04010282005820f08150b7fbe5530307cc163578c65a84930198e11c3b4dc4647182bb1528010803d818584882008201838204018200581cb16b56f5ec064be6ac3cab6035efae86b366cc3dc4a0d571603d70e58200581ce0a714319812c3f773ba04ec5d6b3ffcd5aad85006805b047b082541a400583282d818582883581caa99a1ab7af359e0d74445ab9d761d557d47c8c25bacaa91c15be674a102451a175d95e1001a503b1547018200a1581c9d939fe6d1735d3ce21cb5b256182629be12301f36888ff48c7979f8a141311b33d9a124ea19364b028201d8185819a122d87e9fa0a503044358791901050020442b816f1b2102ff03d818458200820509a300583900a2a428057f85bdd437c11d44a1b6e38ce9c2ff0330d8c190dca332aaf139af3107e9fb9e6a3ec366156a53c3090a7953bba7f781a977f87a01821b23faa1b02c2e0fb0a1581c31438c85161eb8bfa620893d5a5e7612d04f136a95c48e444d0975eaa1581ce7c9427f5ca79b4bc6b03ff97df5e64b32408deb492ba50070cc48960103d818582f8200830303848202808204108204108200581ce0a714319812c3f773ba04ec5d6b3ffcd5aad85006805b047b082541a400583911012cc3c6de9058581b2e2f6934cbd3f0c7844858a5dbb4f36ddb67d7631044f673fa96f34bafe6de5f0b03719a17bc5b19a7d42717539f95018200a1581c118383f4b2cac6cb2729f9ed37343da873d0e7e4f69e3495ec18f9b7a1413201028201d818583c9fd87d9f41daa44493fcdd88444b9e2096423c344403334fac430fd7b742eb940301ffd8799f9f22404004ff41cb2042a0bdff9f80ff44204b6d88ff03d81848820082028182050883585082d818584683581c4029e24126599502351abce28438733cdd93254cbc832dfb5d904cc7a10158225820686a797974757770706e69796878756c636f6671687a786b6b7a737a74676b79001ad32fc14a821b3f33540564de8bd4a1581c245d5a7a06fe18358242e81281cd5ba9e6abe4efc54e7b659f25abaea143f816cd1b290064b534fc9e10582046edb059d4038c8f328a793d6dc01b189c1ad1043721e950a9143ecb126938a310a40058392031c5dbaebf447cd79240b9c131d40d0b703e62f13e297bb7b50d7a82157656bf9fba90590be33fd443a6d37fe2521ae3d299f5491cb41ccf01821b14e4a53394676722a1581ca1ef258f8a6faa1ac047898b223e496356fd8f9f5a585af441dda490a142ee871b3a9a508d2f73e50d028201d818549f9f049f2342942bffd87b9f4440f3fa96ffffff03d81859013c8200830302828202838201838200581ce0a714319812c3f773ba04ec5d6b3ffcd5aad85006805b047b0825418200581ce0a714319812c3f773ba04ec5d6b3ffcd5aad85006805b047b0825418200581c0d94e174732ef9aae73f395ab44507bfa983d65023c11a951f0c32e48200581cb16b56f5ec064be6ac3cab6035efae86b366cc3dc4a0d571603d70e5820180820283830300818200581c76e607db2a31c9a2c32761d2431a186a550cc321f79cd8d6a82b29b88202848200581c0d94e174732ef9aae73f395ab44507bfa983d65023c11a951f0c32e48200581c65fc709a5e019b8aba76f6977c1c8770e4b36fa76f434efc588747b78200581c4acf2773917c7b547c576a7ff110d2ba5733c1f1ca9cdc659aea3a568200581c0d94e174732ef9aae73f395ab44507bfa983d65023c11a951f0c32e482040a111a00010686021a0001104904858405581c9ec5f28067edbfe5e6b2aca6f498f2281c5f035467251f6bd02c4940581ccd29a5e52714c0078bf77cba5025f90be5394a704845724f40c26ce05820a6550bca5b0c9cf93a890a2dbd3e742f70203a77bf52f4f61f68bc83213f85a68405581c08281dc59dc5fee2d928c35409d4cd5fc0216d6f159a89c29c1d4cbb581ceda1b8e0c8870ce8315effbe0b845bd4abf7d3521a80dd29b114416e582050cec21c964b6037295658278589ce58bf2f8a1e684ef2ebc6ba307140644bf2820682001a00044e568a03581c09bd11dbbc9bd35cab9ac7384a0c049b9662231e70c66290bfe8679b58204394b11363e0dc1bc8986f42c29c5566c499531157b33bd17907a548ffd95b211a000a5e591a000d9e2cd81e821b00082a35ae8f3d071b002386f26fc10000581de0b211dca28b4ea9856acf0163a0663ddd54854533b32fdf755df1687a83581c3cf4291ac5cafc87ab7bdf3630d82c587ee883caece1e305a04aa679581caaeb637cc1b25b66643145d455bd0a6e1cf0b4a4d819fe331e56d0fe581ccd93965e0c31a5546523861f70c0b689c2e87ebd6a4900dcf0476637818202783a54755648744130594243684b3274526162336a2d727036584a3148373644476f462e417771717a6b475137346f556834336a68774b692e636f6d827668747470733a2f2f595471424f786333424d2e636f6d4235cc82008201581c12a288ea389bebcf8af52bfde4014dbc36e66bf5c9f816872e93ef520e82581c21402cdac6c241eed19538deedccc3f252ea8198af0967aea55938e2581c78c41f988c751b2686b31f75f6a87c908910e9a76c06ceb7eaa003c209a1581cf2771ad88995646f9e403976307be5f8cc50241f432b2162bf0e1c34a1581831b5e481e4f71df1a0a6026690c128194fc55c567194c8453b60a5eb85d801ad090b58202daec8838fa0aaf5ac4e913075cab54d1359394182348556d02b2535364d320c07582004f55adba4587ef5eec1ddb5caeaa3b80241a86deae8ac7fc23a6a93f3cc396c0f01a50081825820509bce915bf191ff26dcf1bb252f8701fa02d9ff06a008d50804c0f235abbf115840e39fa84538d7586ec287d0e7b84a7352a50cfc9f635ee5e2c2158acdd6317dc6f5ccaa36795838ed1c910e06f146a3a3d777e10ed9f491ec63e0cefb60164ef20281845820f01041bf86fee0b1f737b1ddc5f07bfbbff64dc3ee6a3ad9b0a9071beab4dc0a584080169ad1997457752e33f828fec9ac63b94e8db8e832876aa61126697c5e11b863f1044094f756352013a26644be5fdecf133166336a792c3cb3e52a0f0d36ef404001828200581cbd039f956f4b302f3ab6fc7c4bac3350a540f44af81a8492194dd2c2820281820401048541bbd87c8043bf3b55d87a9fa5d87b9f24ff9f0021ff219f4002ffa34432fc1dad4159002242bd9b22230543afbe719f2443514a1240ff02ff03058184020240821b7952d27b2e9e66b01b09cce49e334bff3ef5d90103a200a305400c858167355233f3bca88281626a616152a4417264f48387ad406a68f3b2b5b91814ecb2be616c6818f096a190016c30406501f3b4978683406a5ff3b996adf0a1bfb67b230e010184820505820284820405820504820285830301828200581c0d94e174732ef9aae73f395ab44507bfa983d65023c11a951f0c32e48200581c76e607db2a31c9a2c32761d2431a186a550cc321f79cd8d6a82b29b88201818200581c3542acb3a64d80c29302260d62c3b87a742ad14abf855ebc6733081e82050d8202818200581cb16b56f5ec064be6ac3cab6035efae86b366cc3dc4a0d571603d70e58201818200581cbd039f956f4b302f3ab6fc7c4bac3350a540f44af81a8492194dd2c28201848201848200581ce0a714319812c3f773ba04ec5d6b3ffcd5aad85006805b047b0825418200581c76e607db2a31c9a2c32761d2431a186a550cc321f79cd8d6a82b29b88200581cb5ae663aaea8e500157bdf4baafd6f5ba0ce5759f7cd4101fc132f548200581c0d94e174732ef9aae73f395ab44507bfa983d65023c11a951f0c32e48201828200581c76e607db2a31c9a2c32761d2431a186a550cc321f79cd8d6a82b29b88200581c4acf2773917c7b547c576a7ff110d2ba5733c1f1ca9cdc659aea3a568200581c3542acb3a64d80c29302260d62c3b87a742ad14abf855ebc6733081e820509820504820280", + "description": "", + "txId": "66fa7f2044f49163a9d855c47b2e038ba30388443ff09198636ccb197304f797", + "type": "Tx BabbageEra" + }, + { + "cborHex": "84ad0082825820273351706e6ef46dbc539c15992a0184ed757d5d36136240c1f2bb9cd118b51f02825820cff4afb91911f78ca5404757cd9d9d71925a3237b0985af2f92b177be2199ecc090d868258205583072da36ed50061e5aa01fe159df24d1a9a5d4358a864222ca74079ae96800982582066ffc0ab3a8e2d831a595b6bbfab04fc8bdd8036aabaeeb6bf70fbbaee912d8e0a8258206aa9015bb788e6ad4fb808984b2d17b3c5bb46efa6f8d07956ae680ee46fde290b8258207ae72cacc4cf604a6e16b779cbc11152e186b30c1b8dbdc0ed03e62115374d340182582092a6f5871b0b224cdcac7cf417568a5a006882890eda6c7ae687f8a42c925ba204825820943ddd20c9b79ca1c3a8339c626eb8912217860ea3a45657e6a887db33acae0207128482582026517940a10df05ee170f02d208702a204b953a3e6a103561371da44d3b95249048258208448f4d4d2fb770c96af1ef11d3c1e1aadef86dff5596f2b4ac1ef3bfbbd79230a825820c4888f3d01cdd056e6279853ed9efdefa1591e4dc01cca3f7bd3ea1c70d772bb04825820fe424d4a3e9127d530e5c19dc20550c22741c73f806ce2255de3341354ab825b04018583583920da20a7af1db4f096a7414c7773af4470b97d4e04b0ac30fc728513d2aa41641eb701a8af7dbee014543e411a3887dabfd8206d1ccd9e610b8200a1581c2db8410d969b6ad6b6969703c77ebf6c44061aa51c5d6ceba46557e2a141340158203016d52c2885790084912c738c71fc03fab866766f5daed43457006feaf7e0d8a40058392103736a8f84e90ed929ae3a008be1300a3ae95a74b6a5c58807e05b535885216cdfde611867730d8c0df307a1b094ab012c59205cc3f2ad9501821b7b2f1ef3121497ffa1581c8f461954fe2f18fee1dca233f358907e643ff839ed1f995e4bf325e3a141381b5ae872156dad60ab028201d818410003d818458200820401a400581d607115f5ad63eb875c746301a2815f307aae8fa8b3bac71ecef9394d3a01821b188626ea23dfc060a1581cb23cce0e9eebd26f541db8b243d7c6566f79e02fe91f19f89d1a3fc1a15011cdcebd92c116f8c2f156f8fb62df7c1b294d89d252cb64870282005820e859d305a355c1850f899a79aa94e5face56448aeaf49df4ec51cf376342f13303d818582282008200581c0d94e174732ef9aae73f395ab44507bfa983d65023c11a951f0c32e4a300581d604fd4c71a1ceefccc7d50e19071cf95b11de8173a951db1eb27e4caa4018200a1581cac775536faaf39252148ecc6385b6cf4345c9b49ff9605cb90a64241a14c979194b3ae66519745eaabf81b554d6c9d594afbcb028201d818410482582b82d818582183581ccbbcf5e081952f05e75a5c9f484fab3dd70195e2241369a4142b443aa0021a428f503f8200a1581c2e12c5e499e0521b13837391beed1248a2e36117370662ee75918b56a1561658cd82a06f412cc0bc812e5f6fe6c6fa3e23b10ec101111a0005c512021a000cfdd103070481820682011a0004a00a05a1581de00c28003a7eea01474d84e7d132a3fc7b02a149f16646b5c00c5d5fe11a000ddb1908030e86581c2351fa8ce7d3554c867667a20196957f7c7c63b5fb073b5c6c70f5ea581c557e55d60888c8548f7445e123c65fba8c17a779b42832ce55ed429e581c5aac1b5ddb21ccc7093410a6c3354bbe97f62fc58487e7f50375d0e5581c5c7b3bd946c9ddf88a9857b151d4843f883094b240dd99e7df4a78b8581c9e882b906b1bc259a471cd0a72b303e58adaa11fdb70f04b0276f41b581cc6658c2111bfb66c9a4bd91505bfb85f8c69aaa3d48143f3a4367ce809a1581c467f58932b54910584a0e8ea25a225e06a14530b2e96e938c53a3f22a1581b049af8e0a7eb7f5d8157ef2b20a16a1e464acf9ce98f1c4857045d3b267f1d203b8796d50b5820c2a6848f5bd326d90b7ba2df7691c7654d88acb03e671edc942e4c57e494c260a50085825820c787f93f963e2fef6e24bb6124b59c284562ad2afa92f452a278bede501e6acf584095750ea610d09c3e3a9ba3e4ae47717ac5131209ef71fe62f29836ecaef7cd26799d83c5335fd2308339ac5b194b04801d5ecdd35f760d2363040615506e8e8982582009d43d9803648aa50874f748d43421cc72a515a576fd42a13bd9019cfb4b4efc5840505bdf7ef7057fbf1ee9ce580fad2dbb72848526bce366c50a7d4a0f62bd84bc4aed38b0bb9b8b0cc31d8bfa9417006e2a6418ab5ecbebdca4b3ce6bf6a3a8a082582031ac883a697127305790c525311b4eb444ca3113d09021f0b792efa032576bcc584086d2e41cd88e9489c430f7390c8375cbf3b95f63ba4d630ea03dc27b57bd7cf45aa9d7de1857147cdd378192eebcdbc037870d590951f64c202095df2964acea8258206839cd42ed02a7fd1e4ac3990b9bd86da6514df1daab83df1fbd15b3648535575840b16da1967c865e747c534205aae93d39091e5953198b372e7c164be688cffc5b4979a0b70bad2656d87080a0b7bf5f986450ff734f8ad7b54e770b72a71924fe825820dc01e56289eebb536a5e020d24a1b667afd684e1c9187b22cd01c36690eec70d584016cb94c2ed3863d50f387ef2550679237bc0c81990f49c21b59f726775d67171dc649e600080e36bf22bb1e8eb2c422845867f1eb2b3333346738a4966a4c638028684582031b156094d4d7770ad3ea4259312e1061a1de67307651813bc0de594bcab457158407023a4e1dfd1f64b096f3c41a7441111b93e6068f6158b35867add9d8df4a981f5ef173fc1d03ef78852cc51bb42907dcfaf0811104e24ea4bfd57f48c11a0f94043b39ac7845820b1a7e85144cec7c8374e94f8d86f359d25807c4836a9c8f9f0b84e1adfc7c63e58409aaf4fa88649ab41142d919f1772bc384737e3be1bf548b80dfacc9770ea39e85c5de746c3cb26393e240617f60d62307e669df8d94fb8a124a13a8aa5ad078a419e41ff845820d85101b0d97d981697f0033b1a8c80680b53c1ca6b17e5f0502550847c76cc0e584013f0153596e3663554a60f5311977466b24a72bcd1c6d5f73888afc872decf72d3b615a23c96457285d302ff258281684bb9aaf1e737f4835b193aa556b5bfff444abad7d642d6a2845820311e216ad7f1a27d48849518d8d3bb8aa1aef31279e8ac30b964cc1c5f77cecb5840612bdb213fa18b88e6324286fa4aeef3069518691fbc70b1a7af32128f589ea934513a7611bb5604521f62c0bc7a801b05815f71e78e6c5d41b58867b4dd18c340408458200f0ca2c35f2ab5fe5701efc0a508a426dfc99b3297675ea860a9c0185421dfe95840d8f79837f1a36bc0671336385c219c286e1ac583bf818244814b1018a1e3d6d7bd267ac0a0748d3d679abcf3b6abd91bca88be428d6b40d0067c2058b98a4a0842aebc43984b20845820b71e136f512db6a9dd67be4655ab09d39b82c657f61e40f651ec9da870424d52584023ede34c1c86f1b88c228b17f2631c4a3b5e2a5f04ba71bc02f3f42414592689de823e56d066a64ccb14ab6532c2cebc904f291a4240ba5223e1104d429a72ac42665541fd018482051082050c82040d820184820501820182830300828200581c0d94e174732ef9aae73f395ab44507bfa983d65023c11a951f0c32e48200581c3542acb3a64d80c29302260d62c3b87a742ad14abf855ebc6733081e8202838200581c58e1b65718531b42494610c506cef10ff031fa817a8ff75c0ab180e78200581ca646474b8f5431261506b6c273d307c7569a4eb6c96b42dd4a29520a8200581c58e1b65718531b42494610c506cef10ff031fa817a8ff75c0ab180e7820180830300828202808200581c65fc709a5e019b8aba76f6977c1c8770e4b36fa76f434efc588747b70486d87e9f21ff42bbfe41f7d87d9f800440ffd87c9f8021a39f21ff2343ba6755a201004022809f202023ffffd87c9f80a18041caff058484000541df821b04c2d622ef1cb90d1b7d77ecedd526d9ac8401079fd87d9f446e45939941be05d87d9f420a2a01ffa4054469c5ef0e44867a9b9a04419240446d8275f0426ef8ffff821b487aca54793ad2171b59fb1d14ebb2293a84020101821b7ff4092d71a940c31b3d02764a364fc9b3840306434efc0d821b56f369b8392b179a1b001070d3446980b2f5f6", + "description": "", + "txId": "0fbb99085b92165b1b32e01232b39798eacf0093614d77eaf6fb517a7fb85baa", + "type": "Tx BabbageEra" + } + ], + "seed": 1986993722 +} \ No newline at end of file diff --git a/hydra-node/golden/ReasonablySized (ServerOutput SimpleTx).json b/hydra-node/golden/ReasonablySized (ServerOutput SimpleTx).json index c4d98de5116..d5586e8b4bd 100644 --- a/hydra-node/golden/ReasonablySized (ServerOutput SimpleTx).json +++ b/hydra-node/golden/ReasonablySized (ServerOutput SimpleTx).json @@ -304,7 +304,7 @@ ] }, "postTxError": { - "tag": "FailedToDraftTxNotInitializing" + "tag": "SpendingNodeUtxoForbidden" }, "tag": "PostTxOnChainFailed" }, @@ -568,23 +568,8 @@ ] }, "postTxError": { - "headUTxO": [ - -3, - 0, - 6 - ], - "reason": "", - "tag": "InternalWalletError", - "tx": { - "id": 1, - "inputs": [ - 4, - 5 - ], - "outputs": [ - 0 - ] - } + "failureReason": "\n႕", + "tag": "FailedToPostTx" }, "tag": "PostTxOnChainFailed" }, @@ -857,9 +842,33 @@ ] }, "postTxError": { - "failureReason": "􄣽i!\u0004", - "redeemerPtr": "\"+)󸍻M0", - "tag": "ScriptFailedInWallet" + "headUTxO": [ + -6, + -4, + 2, + 3, + 5 + ], + "reason": "\u001a\u0004f", + "tag": "InternalWalletError", + "tx": { + "id": 4, + "inputs": [ + -5, + -3, + -2, + 0, + 1, + 2 + ], + "outputs": [ + -6, + -5, + -2, + 3, + 4 + ] + } }, "tag": "PostTxOnChainFailed" }, @@ -1149,7 +1158,7 @@ "tag": "ContestTx" }, "postTxError": { - "tag": "FailedToConstructCollectTx" + "tag": "FailedToConstructFanoutTx" }, "tag": "PostTxOnChainFailed" }, @@ -1320,25 +1329,8 @@ "tag": "ContestTx" }, "postTxError": { - "headUTxO": [ - -3, - 0, - 4 - ], - "reason": "\u0010焨䤠b􈅙􊨍", - "tag": "InternalWalletError", - "tx": { - "id": 3, - "inputs": [ - 3, - 4 - ], - "outputs": [ - -1, - 2, - 5 - ] - } + "failureReason": "J􉷾kP", + "tag": "FailedToPostTx" }, "tag": "PostTxOnChainFailed" }, @@ -1738,7 +1730,7 @@ ] }, "postTxError": { - "tag": "NotEnoughFuel" + "tag": "NoFuelUTXOFound" }, "tag": "PostTxOnChainFailed" }, @@ -1783,7 +1775,19 @@ ] }, "postTxError": { - "tag": "CannotCommitReferenceScript" + "chainState": { + "slot": 1 + }, + "tag": "InvalidStateToPost", + "txTried": { + "headSeed": "04060507080501070206000402030407", + "tag": "AbortTx", + "utxo": [ + -4, + 2, + 4 + ] + } }, "tag": "PostTxOnChainFailed" }, @@ -1830,7 +1834,54 @@ "tag": "CloseTx" }, "postTxError": { - "tag": "CannotCommitReferenceScript" + "chainState": { + "slot": 0 + }, + "tag": "InvalidStateToPost", + "txTried": { + "confirmedSnapshot": { + "signatures": { + "multiSignature": [ + "ebddeecc3bc01790c4f058affbda9299aafe0da6c3385c9ae5e7b1b54054fadd4c90e5b573384a9263a631c6489d75b864204fdeabbc49d1b9cafbd610a3600a", + "c7953eab0f83edc97375df45b36442136a0487adb9cfb3a696c70629ad66c51f5ff7f5193c4b2d0fc2492b2e3d8ca096b8048822a57782ac5a9e2c1764539909", + "0fc684f87e20b0fffb8bd3b76f4572c3500cc25d8a4dfd6da27f0c7137948c919a041fd520c83f646aa2167411ce2bce624f1953f3c2a950ac263bdc10d0560c", + "b9d52dd477e7e51f8263bce7a1c4162eef80e15c468f106f9e02fbabe6155e9e9c193234322cd3cbf7b1a876e5bd56c0301d4917635450912cfe8948fb255008", + "a533f10e6335db5561018d88a57295dc91fa7f4da66806b35e74713016c21b710099efa419716a06704ded9da617a058479c01a410342946f82811e6022db90e" + ] + }, + "snapshot": { + "confirmedTransactions": [], + "headId": "02040306000707000502050804020700", + "snapshotNumber": 4, + "utxo": [ + -4 + ] + }, + "tag": "ConfirmedSnapshot" + }, + "headId": "05050405040602040202060108060103", + "headParameters": { + "contestationPeriod": 43200, + "parties": [ + { + "vkey": "0b0e2630b85586f73774081f3c3448142dc6f9eaa0793effec7473b86db37b96" + }, + { + "vkey": "281019832a4203c4d6946fe22cb8fe93a7edfee50c8adf6f629ec23ea5de5b6e" + }, + { + "vkey": "3d81d50a18583d4b16161e33c6c4755af84827c9374301d8a5b5ab09cddcfed8" + }, + { + "vkey": "14daab812bee410dea4ff5cf6e5a63a05f57aaf6351b2a5505ed319835d4c570" + }, + { + "vkey": "7c357785a5ace8921baa5ad2297337d985dbc647259f0c9c2799cfb00cb500ec" + } + ] + }, + "tag": "ContestTx" + } }, "tag": "PostTxOnChainFailed" }, @@ -2152,7 +2203,7 @@ "tag": "ContestTx" }, "postTxError": { - "tag": "SpendingNodeUtxoForbidden" + "tag": "FailedToConstructAbortTx" }, "tag": "PostTxOnChainFailed" }, @@ -2280,7 +2331,7 @@ "tag": "CloseTx" }, "postTxError": { - "tag": "FailedToConstructContestTx" + "tag": "FailedToConstructCollectTx" }, "tag": "PostTxOnChainFailed" }, diff --git a/hydra-node/golden/ReasonablySized DraftCommitTxRequest.json b/hydra-node/golden/ReasonablySized DraftCommitTxRequest.json deleted file mode 100644 index d8fe0a3ae00..00000000000 --- a/hydra-node/golden/ReasonablySized DraftCommitTxRequest.json +++ /dev/null @@ -1,553 +0,0 @@ -{ - "samples": [ - { - "0408040001060501000701050003050605070508080601030304040806070707#77": { - "address": "addr_test1wzgzpjplkmcsh6hkx0hjggk9frpggazkkr6jgg0gvwfjftserq3sm", - "datum": null, - "datumhash": "bb2672ab68ca309f3e92994d15bc8da2e50a11040d088c3a7001998ff81870f0", - "inlineDatum": null, - "referenceScript": null, - "value": { - "lovelace": 161777137293141776 - }, - "witness": { - "datum": "9f40ff", - "plutusV2Script": { - "cborHex": "46010200050605", - "description": "", - "type": "PlutusScriptV2" - }, - "redeemer": "80" - } - }, - "0507030007000000070303080502080308040404030500030307080602000305#99": { - "address": "addr_test1xpfv6fqykty6r3tpuqza2tj3z43jhmcp6ugpyqp3sldda4h06k7j25gsy62ua8tzukancxeavptjp4kezcplqfxdtgeqpd0ttu", - "datum": null, - "inlineDatum": { - "constructor": 5, - "fields": [ - { - "bytes": "23556c" - }, - { - "list": [] - }, - { - "constructor": 0, - "fields": [ - { - "bytes": "f46d3468" - }, - { - "map": [ - { - "k": { - "bytes": "e799" - }, - "v": { - "bytes": "2b" - } - }, - { - "k": { - "bytes": "" - }, - "v": { - "bytes": "649b4054" - } - }, - { - "k": { - "int": 2 - }, - "v": { - "int": 1 - } - } - ] - } - ] - }, - { - "list": [ - { - "constructor": 0, - "fields": [] - }, - { - "int": 5 - }, - { - "int": 3 - } - ] - }, - { - "int": 3 - } - ] - }, - "inlineDatumhash": "bf7cc85eb167b06fb321d1f3d58bebd57a838c2b902a9456997b9518346fa01e", - "referenceScript": null, - "value": { - "lovelace": 7168756688860419297 - }, - "witness": { - "datum": null, - "plutusV2Script": { - "cborHex": "46060607040502", - "description": "", - "type": "PlutusScriptV2" - }, - "redeemer": "40" - } - }, - "0701040700070402020801010105080408030608060500030301010305080506#10": { - "address": "addr_test1zpnm8ttw586n40evcjjjdhvhj4dhztmrapluakh4n6ct06adfgfnkme3pwzutvnzh3h93475qhr8tspnuw6v692shycqcjdzm7", - "datum": null, - "datumhash": "3f42377d71c7d0f3063ebb958f6be3f51cdcf395deac1b510e280dee52d76122", - "inlineDatum": null, - "referenceScript": null, - "value": { - "lovelace": 5204095253784175078 - }, - "witness": { - "datum": null, - "plutusV2Script": { - "cborHex": "46020308040308", - "description": "", - "type": "PlutusScriptV2" - }, - "redeemer": "4100" - } - }, - "0704080306050104040506070706040408050007000200060806040508050105#51": { - "address": "addr_test1zrk2nux9elchu3rvy9vw5t6j6n7kfd3v7lws38tru83mhng3xtn0299atcfytflk79l0n2sl4le83mtqx8xy92gqcngs8ceqmk", - "datum": null, - "datumhash": "4053094762ac8103a634f1c1ac6a802797284fd60277b666b6ef0aadf8e79b18", - "inlineDatum": null, - "referenceScript": null, - "value": { - "lovelace": 8635212330638838499 - }, - "witness": { - "datum": "4100", - "plutusV2Script": { - "cborHex": "4103", - "description": "", - "type": "PlutusScriptV2" - }, - "redeemer": "420101" - } - }, - "0804070704030601080506040406010608040003050403010704040504020603#73": { - "address": "addr_test1yzfju8t0achc8qhyxz7nkvkrkzu2p6vg7f9yvt672nvyhsgyxqq6nh4nmupeywvjkuee4gqxs6y5ydma39j38x28ymms3n8p8j", - "datum": null, - "inlineDatum": { - "map": [] - }, - "inlineDatumhash": "d36a2619a672494604e11bb447cbcf5231e9f2ba25c2169177edc941bd50ad6c", - "referenceScript": null, - "value": { - "97c123a1e55c30c5a8ad7ba5eeee92f9a6685ad5883d30f1cbb87e75": { - "1f38f38498864eb230850a09b213a592": 6925299155115781699 - }, - "lovelace": 1345124535162132722 - }, - "witness": { - "datum": null, - "plutusV2Script": { - "cborHex": "43080802", - "description": "", - "type": "PlutusScriptV2" - }, - "redeemer": "43000100" - } - } - }, - { - "0102060100070708010507030404040200010404050806050704060704070407#36": { - "address": "addr_test1qqwppdma6z05gtt8dlme0gu3h7g6dp7ltu02hmd9rfam7ar5lduvk5gqg3d73plfvd52fhszg7ew5qmsp7hdleqjgrxszygu6g", - "datum": null, - "datumhash": null, - "inlineDatum": null, - "referenceScript": null, - "value": { - "072a4796db5469ee7b3824bc7314bbc978aaf168d7d5c561ff1bfd0e": { - "5aa154a37ccb63803f3d65160a27d9777094fb75c15117b9888b62dbb11c": 7082452847606764205 - }, - "lovelace": 7002024969193393855 - }, - "witness": { - "datum": "9f00d87a80ff", - "plutusV2Script": { - "cborHex": "40", - "description": "", - "type": "PlutusScriptV2" - }, - "redeemer": "420001" - } - }, - "0104060605020407040607000405080606070206010304080407000207020608#7": { - "address": "addr_test1zpd85v5jpjwvrldfnq56n04c5rh75wq9rst6pmq0j6n9h6c8k8tl86lg2plkq86n90aq88spp78sh902zv590s9njwkqztpk4j", - "datum": null, - "inlineDatum": { - "int": 3 - }, - "inlineDatumhash": "e88bd757ad5b9bedf372d8d3f0cf6c962a469db61a265f6418e1ffed86da29ec", - "referenceScript": null, - "value": { - "8f461954fe2f18fee1dca233f358907e643ff839ed1f995e4bf325e3": { - "fec3fd5636189def39": 7526447698726176993 - }, - "lovelace": 4471064148471550567 - }, - "witness": { - "datum": "420002", - "plutusV2Script": { - "cborHex": "4103", - "description": "", - "type": "PlutusScriptV2" - }, - "redeemer": "d8799f4100a1d8798040a18080ff" - } - }, - "0505040505000806000602070304080305070304050006040403080104050001#23": { - "address": "addr_test1ypm8kr8cqddxvettp8jey0uxneq2gzy2uaulx9j7ctdrywwfepu0za733y9kv0tny5t9e6leua6wkskupl9cgghtqf3suufpws", - "datum": null, - "datumhash": null, - "inlineDatum": null, - "referenceScript": null, - "value": { - "lovelace": 5584395409911584208 - } - }, - "0707050508050104030004060203020603020503000605070204030605050606#64": { - "address": "addr_test1qr9xzyf3kpprk3y8p64vt3cg6ycm4xyhcuh40nhncjutmnhwcfkrd38pqpsrhq5hm67an9atet6dq0nmu4xyp6aev5zs8d9cr6", - "datum": null, - "datumhash": "97330eaf6f895efce34ef3dafda9eacc37723941d6b5df625f5bc0bcc2f2c659", - "inlineDatum": null, - "referenceScript": null, - "value": { - "3adfb8ec617bef5de5bcf0025c5224126a5bf748ea5e4e9016d881e7": { - "c406604d83d1a1f80ae5ed5b65f3353ea09b18bc5f": 7747395311619844201 - }, - "lovelace": 693276334491171264 - }, - "witness": { - "datum": "d87a9fd879800101ff", - "plutusV2Script": { - "cborHex": "46060808010707", - "description": "", - "type": "PlutusScriptV2" - }, - "redeemer": "9fa10000a0ff" - } - }, - "0800010106010200000500070405000305030806060704080200080100080407#18": { - "address": "addr_test1wp9mjm90smyx8792gxwqgmctlpc6gl5xn3c0rkysnspdvzszh5rt0", - "datum": null, - "datumhash": "849e7aa93b023c29308ee0c91fdc4d6c0a1393599672ee64b3f232d080e25265", - "inlineDatum": null, - "referenceScript": null, - "value": { - "2db8410d969b6ad6b6969703c77ebf6c44061aa51c5d6ceba46557e2": { - "b57db5802d6cc234bc527ff94a": 3598652961404124270 - }, - "lovelace": 6633079461205696672 - }, - "witness": { - "datum": "43010101", - "plutusV2Script": { - "cborHex": "43060702", - "description": "", - "type": "PlutusScriptV2" - }, - "redeemer": "420000" - } - }, - "0802010302080306010802050405030705070401040208060406080707070300#11": { - "address": "addr_test1vp4wvv3rkxdqn9jf6sfg78alq5kx76uszsa78ych9dnsraqwe6fwe", - "datum": null, - "datumhash": "cf23e4ce7db809e363df5abdc2e90fb741b2beeb40b3423bb51b5e9148adcce6", - "inlineDatum": null, - "referenceScript": null, - "value": { - "lovelace": 8468718031792502556 - }, - "witness": { - "datum": "d87b9f20ff", - "plutusV2Script": { - "cborHex": "46080506000406", - "description": "", - "type": "PlutusScriptV2" - }, - "redeemer": "22" - } - } - }, - { - "0101010000040005050106030704000302010003000506040301010703020203#15": { - "address": "addr_test1xzuhpfwz4h59q2z0drujl2tvyg5ra9zrypd9ku2js8zfj7cfz62qqgm0d67kxx4htyj27ndt7esk9c8845nnwksx4d6s2gh3v5", - "datum": null, - "datumhash": "05012bb0448cddbc55f4f0e947fd69f330264d32d10d088446d6de596ba881d7", - "inlineDatum": null, - "referenceScript": null, - "value": { - "lovelace": 641966023422547031 - }, - "witness": { - "datum": "d87a9fd87a809f40ffd87a80ff", - "plutusV2Script": { - "cborHex": "450607020701", - "description": "", - "type": "PlutusScriptV2" - }, - "redeemer": "d87a9fa0d87a9fa0ff4100ff" - } - }, - "0104070104080305010600020008080201070700040302030004000101070301#59": { - "address": "addr_test1zzzfkqsnu30rwasyx4mfmquc745tpd36cgtn9ylc97rrnvkke45maz4uyuxx4wmz3a7ea2j2m0ml22nn3sr4c2e3rc6qzzfyu4", - "datum": null, - "datumhash": "9067fef4cb1093f77135baf15a7d0f14a145645c8890403eb044a8f616c65cb8", - "inlineDatum": null, - "referenceScript": null, - "value": { - "lovelace": 2581030569813074538 - } - }, - "0803000506030604030205040306060102020204030807050107080708010401#33": { - "address": "addr_test1xz4luu8qnj2kfkzxmk82g4wqahffavn4qt4quj7fg08xs0qk7d07w2jxt9vmu9t0avsm6a90jpeex3u2q4ygxjl6ye5sqhaggr", - "datum": null, - "datumhash": "f5a7894a7793bebee491a02c3106b1f940db41afda884dc29b389cfdda92e741", - "inlineDatum": null, - "referenceScript": null, - "value": { - "lovelace": 1599957305510962495 - }, - "witness": { - "datum": null, - "plutusV2Script": { - "cborHex": "420201", - "description": "", - "type": "PlutusScriptV2" - }, - "redeemer": "9fa180d8798000ff" - } - } - }, - { - "0003030502050406010303010200030404060605050802080104070207010704#65": { - "address": "addr_test1wzjnt7paw6qzh4c5u555lmmh99cju0z36dq3g4cjvupjh8gpu5gxe", - "datum": null, - "inlineDatum": { - "list": [ - { - "int": 3 - }, - { - "list": [ - { - "map": [] - }, - { - "map": [ - { - "k": { - "int": 5 - }, - "v": { - "bytes": "a6" - } - }, - { - "k": { - "bytes": "124f" - }, - "v": { - "int": 4 - } - }, - { - "k": { - "bytes": "9084" - }, - "v": { - "int": 3 - } - } - ] - }, - { - "bytes": "a3" - }, - { - "int": 4 - } - ] - }, - { - "constructor": 0, - "fields": [ - { - "map": [ - { - "k": { - "int": -5 - }, - "v": { - "bytes": "f0c0ec" - } - } - ] - }, - { - "constructor": 4, - "fields": [ - { - "int": -4 - }, - { - "int": -2 - }, - { - "int": -2 - } - ] - }, - { - "int": 1 - } - ] - }, - { - "int": -4 - }, - { - "int": -2 - } - ] - }, - "inlineDatumhash": "75cc9e6003afbc7d76f95ddbb4c5b30010d1232aff711e205747c63aa4b2d54a", - "referenceScript": null, - "value": { - "lovelace": 2322041380280110763 - }, - "witness": { - "datum": "43020202", - "plutusV2Script": { - "cborHex": "450100050007", - "description": "", - "type": "PlutusScriptV2" - }, - "redeemer": "40" - } - }, - "0103070101010104060808010502030207060604030608000703020203070700#43": { - "address": "addr_test1qpzljpzpt2t2k8ccjvn0t2v5079vx0u2p2wslxsvgz3aqd9cf85at2c50lxmj826aumj4fc460p3s87ykz630nkwwnkslla2jk", - "datum": null, - "datumhash": "5a13137b39952fd037885f8178f628688d76c45acb9c8fc422dba834f8e73abe", - "inlineDatum": null, - "referenceScript": null, - "value": { - "lovelace": 1119537756963686208 - } - }, - "0205030703050607070803000806070408070104010005040002010307000006#17": { - "address": "addr_test1zrwkjg9m56hkxxegjf2vtypqjfleqnrj9838mk95tax2gvdnfkhcz6u8eme02ws5akpfl5lxgkf3ga0ummpu3nynf9dq25eqsf", - "datum": null, - "datumhash": null, - "inlineDatum": null, - "referenceScript": null, - "value": { - "lovelace": 722504041032752508 - } - }, - "0800030305050608030104040707010602080505070704000701070405030000#20": { - "address": "addr_test1yrauceg9jy0ju25w5vrds4yvy8fvkfqc44ukrpmfpfdpkx6xhn6dwxm0qsvqxg4sw0xtedl38s00hku7rygqaxcxqqsqnrtadr", - "datum": null, - "datumhash": null, - "inlineDatum": null, - "referenceScript": null, - "value": { - "lovelace": 2220537541968540510 - }, - "witness": { - "datum": null, - "plutusV2Script": { - "cborHex": "46040602020805", - "description": "", - "type": "PlutusScriptV2" - }, - "redeemer": "d87a9fd87a80d87a8040ff" - } - }, - "0808050604030501080705040804050003080703010100020105060704070600#66": { - "address": "addr_test1yraq6t6spcj6gue2ewvw83s4ukwnmt9axdzc86y49p6sv07rl7v0ky89t2lsy4avk3x5fv7ccdm2p7zy5nu984wmyl7sk6wmen", - "datum": null, - "datumhash": "2b1bfcafc5478d0dad2e23883b159b9a4c0a4f593b9b765496b72241cbf03dff", - "inlineDatum": null, - "referenceScript": null, - "value": { - "4b23d8bbbaacb30fa91270d19043d014b7cb6483c72a15c7bebc4126": { - "8942db600767f1f0c32dcea69c9535694e8d23f3b8129562071933ec": 3341256643509928663 - }, - "lovelace": 518482064320134531 - } - } - }, - { - "0001070703030307070407040308000203080302040704040300020705040601#87": { - "address": "addr_test1zr5zk27jqw48emqufjdq4nwkqhz06j2yl5daxfpgtg5d9vmgs3w7clgxq5u6p09ma9qctkfl7ynmrtw48fkfru54c0sqfzwyd5", - "datum": null, - "datumhash": "952e2c99ffca66dc4f34bee5c02545c29f943e14cce879ba6e56aabd17fa78e6", - "inlineDatum": null, - "referenceScript": null, - "value": { - "lovelace": 1552573957901903928 - } - }, - "0008080100010700070601060704000708000203080304080106070407020808#58": { - "address": "addr_test1zrk8h05e05sy6j3hwspwxyk2gdsfnly0qgz77spc2w4j4xw7rqxts4msfgy37rtzgxqkaegsxur6qme3xde7qcl544mqq2m0mz", - "datum": null, - "datumhash": null, - "inlineDatum": null, - "referenceScript": null, - "value": { - "lovelace": 8353507006040297895 - }, - "witness": { - "datum": null, - "plutusV2Script": { - "cborHex": "43070101", - "description": "", - "type": "PlutusScriptV2" - }, - "redeemer": "d8799fa0ff" - } - }, - "0301070400050605040504060802040007080605060400050302080808050306#20": { - "address": "addr_test1qqjxma6670x23w4nk35c2vm3yjy5c59qwt4uhs45r2d5nzlau9ujnzwp9elm82ux24mpw2xu4r00tp4je2qn9956rcfqy93czv", - "datum": null, - "inlineDatum": { - "bytes": "2b" - }, - "inlineDatumhash": "93731cbd30b156243d4c623d96df8fb4f47c672467e6e35e3354141c6c250706", - "referenceScript": null, - "value": { - "lovelace": 161489348527668654 - }, - "witness": { - "datum": "9f4040d87a9f00ffff", - "plutusV2Script": { - "cborHex": "43020800", - "description": "", - "type": "PlutusScriptV2" - }, - "redeemer": "a38000d87980019f00ff4100" - } - } - } - ], - "seed": -1235188385 -} \ No newline at end of file diff --git a/hydra-node/golden/ReasonablySized DraftCommitTxResponse.json b/hydra-node/golden/ReasonablySized DraftCommitTxResponse.json deleted file mode 100644 index 2b22ac618e8..00000000000 --- a/hydra-node/golden/ReasonablySized DraftCommitTxResponse.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "samples": [ - { - "cborHex": "84ad00848258200268be9dbd0446eaa217e1dec8f399249305e551d7fc1437dd84521f74aa621c06825820642206314f534b29ad297d82440a5f9f210e30ca5ced805a587ca402de9273420282582095c3003a78585e0db8c9496f6deef4de0ff000994b8534cd66d4fe96bb21ddd308825820bfa726c3c149165b108e6ff550cb1a1c4f0fdc2e9f26a9a16f48babe73b600ce040d85825820642206314f534b29ad297d82440a5f9f210e30ca5ced805a587ca402de92734203825820bb30a42c1e62f0afda5f0a4e8a562f7a13a24cea00ee81917b86b89e801314aa06825820e88bd757ad5b9bedf372d8d3f0cf6c962a469db61a265f6418e1ffed86da29ec07825820e88bd757ad5b9bedf372d8d3f0cf6c962a469db61a265f6418e1ffed86da29ec08825820fb3d635c7cb573d1b9e9bff4a64ab4f25190d29b6fd8db94c605a218a23fa9ad061284825820642206314f534b29ad297d82440a5f9f210e30ca5ced805a587ca402de92734208825820ae85d245a3d00bfde01f59f3c4fe0b4bfae1cb37e9cf91929eadcea4985711de01825820bfa726c3c149165b108e6ff550cb1a1c4f0fdc2e9f26a9a16f48babe73b600ce08825820e88bd757ad5b9bedf372d8d3f0cf6c962a469db61a265f6418e1ffed86da29ec030184a400585782d818584d83581c0ab8d95ece6f8c5ec22ca9b6bd6ead48c29b28ad293851c9666931eaa201582258206671626c77717874666a6e73636c72727864786b786367757a74696e7478637402451a87ab04c8021a6cf0b0f701820ea5581c0d94e174732ef9aae73f395ab44507bfa983d65023c11a951f0c32e4a1460003030501020d581c1920e782f048e9ef52acd89c4341a89c3908c6e046ad87c474fffb48a2401042000408581c4acf2773917c7b547c576a7ff110d2ba5733c1f1ca9cdc659aea3a56a145020107000701581c76e607db2a31c9a2c32761d2431a186a550cc321f79cd8d6a82b29b8a142070401581ceccbfb5c619673f0648a42cc2f822c81cbc34aee41274638e89a7af5a1440605010304028201d818412003d818582282008200581c0d94e174732ef9aae73f395ab44507bfa983d65023c11a951f0c32e4a400585782d818584d83581cc457b0349a5742814ecf9b6ecde00c9f7e17e1c23ae2c75527939fa4a2015822582062626a766a6a6f636276617463717476756563776365766e75676b646f656f6502451a2296ed0a021a4118ef6a01820ea5581c3542acb3a64d80c29302260d62c3b87a742ad14abf855ebc6733081ea14206080c581c4acf2773917c7b547c576a7ff110d2ba5733c1f1ca9cdc659aea3a56a1460806000105000f581c58e1b65718531b42494610c506cef10ff031fa817a8ff75c0ab180e7a1440707040803581cbd039f956f4b302f3ab6fc7c4bac3350a540f44af81a8492194dd2c2a14304040306581ce0a714319812c3f773ba04ec5d6b3ffcd5aad85006805b047b082541a2460001010004020d41030f0282005820f63498b4ae65be466e4a71878971b9c524458996450b0ff8262cddf3f0d9922903d818478200820419db52a400581d60b5ae663aaea8e500157bdf4baafd6f5ba0ce5759f7cd4101fc132f54018206a2581c1920e782f048e9ef52acd89c4341a89c3908c6e046ad87c474fffb48a1460500040208080d581ce0a714319812c3f773ba04ec5d6b3ffcd5aad85006805b047b082541a3460502050607020d42060206460705000601060f028201d818581b9fa1d87a9f446b63407c429a5203ff0502a280a02443b82d5d23ff03d818478200820519f74da300581d6165fc709a5e019b8aba76f6977c1c8770e4b36fa76f434efc588747b7010703d8185833820082018382041a0001853a830300818200581c58e1b65718531b42494610c506cef10ff031fa817a8ff75c0ab180e78202800219031b03199c0d04848a03581c1920e782f048e9ef52acd89c4341a89c3908c6e046ad87c474fffb485820bb30a42c1e62f0afda5f0a4e8a562f7a13a24cea00ee81917b86b89e801314aa1901991852d81e820508581de1a646474b8f5431261506b6c273d307c7569a4eb6c96b42dd4a29520a85581c3542acb3a64d80c29302260d62c3b87a742ad14abf855ebc6733081e581c4acf2773917c7b547c576a7ff110d2ba5733c1f1ca9cdc659aea3a56581c65fc709a5e019b8aba76f6977c1c8770e4b36fa76f434efc588747b7581cb16b56f5ec064be6ac3cab6035efae86b366cc3dc4a0d571603d70e5581cbd039f956f4b302f3ab6fc7c4bac3350a540f44af81a8492194dd2c28384000344c000020150b80d012000000000000000000100000082026f666f6f2e6578616d706c652e636f6d8301f66f666f6f2e6578616d706c652e636f6d8264746578744a62797465737472696e678a03581c1920e782f048e9ef52acd89c4341a89c3908c6e046ad87c474fffb485820642206314f534b29ad297d82440a5f9f210e30ca5ced805a587ca402de927342185a190327d81e820405581de158e1b65718531b42494610c506cef10ff031fa817a8ff75c0ab180e784581c1920e782f048e9ef52acd89c4341a89c3908c6e046ad87c474fffb48581c58e1b65718531b42494610c506cef10ff031fa817a8ff75c0ab180e7581c65fc709a5e019b8aba76f6977c1c8770e4b36fa76f434efc588747b7581cb16b56f5ec064be6ac3cab6035efae86b366cc3dc4a0d571603d70e5818301f66f666f6f2e6578616d706c652e636f6d8264746578744a62797465737472696e678a03581c4acf2773917c7b547c576a7ff110d2ba5733c1f1ca9cdc659aea3a565820ae85d245a3d00bfde01f59f3c4fe0b4bfae1cb37e9cf91929eadcea4985711de1903d818cad81e820102581df04acf2773917c7b547c576a7ff110d2ba5733c1f1ca9cdc659aea3a5684581c0d94e174732ef9aae73f395ab44507bfa983d65023c11a951f0c32e4581c58e1b65718531b42494610c506cef10ff031fa817a8ff75c0ab180e7581cb5ae663aaea8e500157bdf4baafd6f5ba0ce5759f7cd4101fc132f54581cbd039f956f4b302f3ab6fc7c4bac3350a540f44af81a8492194dd2c2858301f66f666f6f2e6578616d706c652e636f6d8400f644c000020150b80d01200000000000000000010000008400f644c000020150b80d012000000000000000000100000082026f666f6f2e6578616d706c652e636f6d82026f666f6f2e6578616d706c652e636f6d8264746578744a62797465737472696e678405581cbd039f956f4b302f3ab6fc7c4bac3350a540f44af81a8492194dd2c2581c58e1b65718531b42494610c506cef10ff031fa817a8ff75c0ab180e75820fb3d635c7cb573d1b9e9bff4a64ab4f25190d29b6fd8db94c605a218a23fa9ad05a4581de0eccbfb5c619673f0648a42cc2f822c81cbc34aee41274638e89a7af5183d581df1e0a714319812c3f773ba04ec5d6b3ffcd5aad85006805b047b08254119022b581de165fc709a5e019b8aba76f6977c1c8770e4b36fa76f434efc588747b7190108581de1e0a714319812c3f773ba04ec5d6b3ffcd5aad85006805b047b0825411901070819c8d80e81581c58e1b65718531b42494610c506cef10ff031fa817a8ff75c0ab180e709a3581c1920e782f048e9ef52acd89c4341a89c3908c6e046ad87c474fffb48a145000803000726581c3542acb3a64d80c29302260d62c3b87a742ad14abf855ebc6733081ea1430203070f581c58e1b65718531b42494610c506cef10ff031fa817a8ff75c0ab180e7a14102020b5820fb3d635c7cb573d1b9e9bff4a64ab4f25190d29b6fd8db94c605a218a23fa9ad0f00a400868258209ca80d378e4ed84e4496d73136c36ad9a4b5c37b6a0bb74c85f2a5110bafdb945840bb1e017acf3e0d221f9f2082164cab8604ab8e389bffd4a934e50b3302f7266ba00c560796c47f311e8df2ef566e227981a2021692b121279b89dfd3a2d48556825820d7106abab021f9e7846960c4f4b43db7828524706418240c48f742e53d3042f958400f9b872a54ccb9ad33473e7211ce2c4ab0211a296fcdfb967a6f9644b5ee3ba51d59054dcba3def756b10e1394c0da8323c6848546a0a6b7b7cad1d44ad020a4825820dc9337a7bfeea633775356ad61abbd920a407f4369ab219130d1391a155801c25840a8add343aa764cb0f00697545405582e0517cf76884db5b5b86d38df2148a1e7f0d1127eee9ed9aed7abc4830a55416924b6739fc0c21bded6762814979b64ea82582050aa9b8534b3a40237842ba4ed162dce740b14f04b50fe31125b739bccfd939e584092dc1ab142d91d347b5a8975fc30afe1af29a0778d2c66148e6d4839050036c45fee7081d1be46b93a49ae5c6c88eb0095dddfd232190d1ded60020ba986134d825820f0b43efd50f79e5cd1fc150fa9ce2e8b0390d73bbc0a2a3f64ee1267dc4c0a1b5840fd7ebd27c48432e9834e19978ac12f5c679bb6a4500e77a6b411fb0457b2237b6bc526601cf3455f66ae91023332f1ac36bd4093a8d7790ce8f0d51a9777866182582098cc2e85f00340f1bd89eda1caf7a332afc7f7406045ae3182185e9bb77b50eb58408be6dcf30b93822e7d133e9e39225c567024cf5ddca176f50798b7615efe21cdbb85b5d0eaefe94900eec8c55f3b31c9aacad79e0a9fef67e655c7f7cd683b8c028184582017c9cf0481cfe5613bbcff1897ffbda410c3c240fc2585561610eb23fd5832e55840e32c149647fc74c85ff4c59a40a8252876bae654093d987626ed4abf9bb99ded58e2bc44397dfa3d4de4a4aa40fdfb7938018f1485f24ad25bedb99bbb61c35841ed4450333f46018282028383030181820519e8828202858202818200581cbd039f956f4b302f3ab6fc7c4bac3350a540f44af81a8492194dd2c2820419ecd08202848200581c76e607db2a31c9a2c32761d2431a186a550cc321f79cd8d6a82b29b88200581cb16b56f5ec064be6ac3cab6035efae86b366cc3dc4a0d571603d70e58200581c4acf2773917c7b547c576a7ff110d2ba5733c1f1ca9cdc659aea3a568200581c58e1b65718531b42494610c506cef10ff031fa817a8ff75c0ab180e78201808201838200581c0d94e174732ef9aae73f395ab44507bfa983d65023c11a951f0c32e48200581c65fc709a5e019b8aba76f6977c1c8770e4b36fa76f434efc588747b78200581cbd039f956f4b302f3ab6fc7c4bac3350a540f44af81a8492194dd2c2830300818201828200581c76e607db2a31c9a2c32761d2431a186a550cc321f79cd8d6a82b29b88200581cbd039f956f4b302f3ab6fc7c4bac3350a540f44af81a8492194dd2c282028004844004444f380964a39fa1224001219f445e28d98bff9f428d530442316640ffffd8668219020d9f04ff9fd866821901f79f4041a8ff8004ff43aca134a022f4f6", - "description": "Hydra commit transaction", - "type": "Tx BabbageEra" - }, - { - "cborHex": "84ae0081825820ee155ace9c40292074cb6aff8c9ccdd273c81648ff1149ef36bcea6ebb8a3e25030d8382582003170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314068258204f539156bfbefc070a3b61cad3d1cedab3050e2b2a62f0ffe16a43eb0edc1ce802825820ae85d245a3d00bfde01f59f3c4fe0b4bfae1cb37e9cf91929eadcea4985711de0112828258202208e439244a1d0ef238352e3693098aba9de9dd0154f9056551636c8ed15dc104825820fb3d635c7cb573d1b9e9bff4a64ab4f25190d29b6fd8db94c605a218a23fa9ad030182a300585782d818584d83581c44e53c8740a4098e03d7f53b538cfc2e45ff47ac9da198411812e780a201582258207277716c7574776479707374716a726378726665686e6d6b796c72716f627a6c02451a2567f6c7001ad1dc1ea7018202a5581c3542acb3a64d80c29302260d62c3b87a742ad14abf855ebc6733081ea1440305010201581c65fc709a5e019b8aba76f6977c1c8770e4b36fa76f434efc588747b7a14602050403070802581c76e607db2a31c9a2c32761d2431a186a550cc321f79cd8d6a82b29b8a1430504010b581cbd039f956f4b302f3ab6fc7c4bac3350a540f44af81a8492194dd2c2a142020410581ce0a714319812c3f773ba04ec5d6b3ffcd5aad85006805b047b082541a143050106040282005820bfa726c3c149165b108e6ff550cb1a1c4f0fdc2e9f26a9a16f48babe73b600cea400582b82d818582183581c8ba1028c40cfac46d0617ce80996c471fc93d98caba666b248fa7b78a0021a22df3dfc010c028201d818581c9fd866821901939fd8668219013380ffa19f2140ff441d35407223ff03d81858b7820083030284820419da8c8205196d4e820281830300848200581c76e607db2a31c9a2c32761d2431a186a550cc321f79cd8d6a82b29b88200581cb16b56f5ec064be6ac3cab6035efae86b366cc3dc4a0d571603d70e58200581cbd039f956f4b302f3ab6fc7c4bac3350a540f44af81a8492194dd2c28200581c65fc709a5e019b8aba76f6977c1c8770e4b36fa76f434efc588747b78200581ca646474b8f5431261506b6c273d307c7569a4eb6c96b42dd4a29520a111902830218470319a1b804868405581c4acf2773917c7b547c576a7ff110d2ba5733c1f1ca9cdc659aea3a56581c76e607db2a31c9a2c32761d2431a186a550cc321f79cd8d6a82b29b85820bfa726c3c149165b108e6ff550cb1a1c4f0fdc2e9f26a9a16f48babe73b600ce8304581c4acf2773917c7b547c576a7ff110d2ba5733c1f1ca9cdc659aea3a56196ea682018200581ce0a714319812c3f773ba04ec5d6b3ffcd5aad85006805b047b08254183028200581c58e1b65718531b42494610c506cef10ff031fa817a8ff75c0ab180e7581c4acf2773917c7b547c576a7ff110d2ba5733c1f1ca9cdc659aea3a568206820018b68a03581c3542acb3a64d80c29302260d62c3b87a742ad14abf855ebc6733081e5820bb30a42c1e62f0afda5f0a4e8a562f7a13a24cea00ee81917b86b89e801314aa19025d19025fd81e820105581df1e0a714319812c3f773ba04ec5d6b3ffcd5aad85006805b047b08254184581c1920e782f048e9ef52acd89c4341a89c3908c6e046ad87c474fffb48581c58e1b65718531b42494610c506cef10ff031fa817a8ff75c0ab180e7581cb5ae663aaea8e500157bdf4baafd6f5ba0ce5759f7cd4101fc132f54581ce0a714319812c3f773ba04ec5d6b3ffcd5aad85006805b047b0825418182026f666f6f2e6578616d706c652e636f6d8264746578744a62797465737472696e6705a4581de01920e782f048e9ef52acd89c4341a89c3908c6e046ad87c474fffb48190160581de0b5ae663aaea8e500157bdf4baafd6f5ba0ce5759f7cd4101fc132f54190187581de176e607db2a31c9a2c32761d2431a186a550cc321f79cd8d6a82b29b8190346581de1b5ae663aaea8e500157bdf4baafd6f5ba0ce5759f7cd4101fc132f54184c08190ec00e84581c76e607db2a31c9a2c32761d2431a186a550cc321f79cd8d6a82b29b8581ca646474b8f5431261506b6c273d307c7569a4eb6c96b42dd4a29520a581cbd039f956f4b302f3ab6fc7c4bac3350a540f44af81a8492194dd2c2581ce0a714319812c3f773ba04ec5d6b3ffcd5aad85006805b047b0825410b5820ae85d245a3d00bfde01f59f3c4fe0b4bfae1cb37e9cf91929eadcea4985711de07582003170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c1113140f00a30082825820f0ba28be376edbf78c07a98fc67c1a1a600fc789eec9e534e3d37ce33adfb4625840dfb67ba391d77fc0ba75a7b1802c98b0c689331f149a7795c31b8acaede26729bf5e1d46586aec4eedd377a4203bf09e35cc5c0e1615e234e52723366f3274068258206810b5b01c9cc19de7d9fb65f6c0adef005baffc4d851b3129ac226b0ba7dafb5840cf060fd1f4872176819ca07f9e58425851b74ce70c18da3429fb835b3b444b1b7a25158baa41da2f49965de0ea8b338dc695397f4f058640aa0d8b8df997dfae01868204199cb5820519274e8202848200581c4acf2773917c7b547c576a7ff110d2ba5733c1f1ca9cdc659aea3a56830300808202838200581cb16b56f5ec064be6ac3cab6035efae86b366cc3dc4a0d571603d70e582051a000160308200581c0d94e174732ef9aae73f395ab44507bfa983d65023c11a951f0c32e48205195feb8303008082028382051a000147df82028082028382041a000125cf82051a00013d4f82051a00016f708205194c3a058284000b05821b6a318acf848b02ae1b681ce177073874c384020504821b4eb0f367bc019b041b6b34af95ac67b511f4d90103a200a401a340614b8041a5a08241c46de782913bf09899a4f0a99d922d02822242c2cb096577f0a6898110426b0a0181820183820284820419a1af8202838200581c4acf2773917c7b547c576a7ff110d2ba5733c1f1ca9cdc659aea3a568200581ca646474b8f5431261506b6c273d307c7569a4eb6c96b42dd4a29520a8200581cbd039f956f4b302f3ab6fc7c4bac3350a540f44af81a8492194dd2c28200581cbd039f956f4b302f3ab6fc7c4bac3350a540f44af81a8492194dd2c282051a00011c6282041a000129038200581cb16b56f5ec064be6ac3cab6035efae86b366cc3dc4a0d571603d70e5", - "description": "Hydra commit transaction", - "type": "Tx BabbageEra" - }, - { - "cborHex": "84ad008582582003170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c11131406825820ae85d245a3d00bfde01f59f3c4fe0b4bfae1cb37e9cf91929eadcea4985711de02825820bb30a42c1e62f0afda5f0a4e8a562f7a13a24cea00ee81917b86b89e801314aa04825820f63498b4ae65be466e4a71878971b9c524458996450b0ff8262cddf3f0d9922908825820fb3d635c7cb573d1b9e9bff4a64ab4f25190d29b6fd8db94c605a218a23fa9ad080d8282582003170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c1113140882582095c3003a78585e0db8c9496f6deef4de0ff000994b8534cd66d4fe96bb21ddd30412838258204f539156bfbefc070a3b61cad3d1cedab3050e2b2a62f0ffe16a43eb0edc1ce802825820642206314f534b29ad297d82440a5f9f210e30ca5ced805a587ca402de92734201825820f63498b4ae65be466e4a71878971b9c524458996450b0ff8262cddf3f0d99229060183a300585082d818584683581c67fa44aa283b77ce90d10c786d6b2bc7292ad356c134a51a58732571a101582258200d075343c1a27de6d91a79fe415c76daaecb84340406109890e569708190c731001adfd41146018209a3581c0d94e174732ef9aae73f395ab44507bfa983d65023c11a951f0c32e4a243040704094605070600000010581c58e1b65718531b42494610c506cef10ff031fa817a8ff75c0ab180e7a2460004060300010e41040c581c76e607db2a31c9a2c32761d2431a186a550cc321f79cd8d6a82b29b8a1460402060505080e028201d8184342eb0ca400581d61b5ae663aaea8e500157bdf4baafd6f5ba0ce5759f7cd4101fc132f54018201a3581c58e1b65718531b42494610c506cef10ff031fa817a8ff75c0ab180e7a14205040f581ca646474b8f5431261506b6c273d307c7569a4eb6c96b42dd4a29520aa142040007581cb16b56f5ec064be6ac3cab6035efae86b366cc3dc4a0d571603d70e5a243020001024606010105060807028201d818414003d81849820082051a00012743a300585082d818584683581c011ae11c0b732270a8a04ddcc6ac78d138924f17c40b77067b8aa25ea101582258206165626d73687169706b716c7666687a756473797177787871646c6a64687677001a344f03ba018202a5581c3542acb3a64d80c29302260d62c3b87a742ad14abf855ebc6733081ea145030307080602581c58e1b65718531b42494610c506cef10ff031fa817a8ff75c0ab180e7a142010405581c65fc709a5e019b8aba76f6977c1c8770e4b36fa76f434efc588747b7a1440703000201581ca646474b8f5431261506b6c273d307c7569a4eb6c96b42dd4a29520aa144000206000c581ce0a714319812c3f773ba04ec5d6b3ffcd5aad85006805b047b082541a14200070802820058202208e439244a1d0ef238352e3693098aba9de9dd0154f9056551636c8ed15dc110a400585782d818584d83581c692d925c024075156343e6b6f0032af3a780e4d450b5510786567530a20158225820787a7079756f79787a70627962646c7971756766636a676f797a746c7779776702451a960a2aec001a5c5637ae018206a2581c76e607db2a31c9a2c32761d2431a186a550cc321f79cd8d6a82b29b8a1430305050e581cb16b56f5ec064be6ac3cab6035efae86b366cc3dc4a0d571603d70e5a1430602020a028201d818434245a303d818582282008200581cbd039f956f4b302f3ab6fc7c4bac3350a540f44af81a8492194dd2c2111901e9021901ab048682068200a58201581c1920e782f048e9ef52acd89c4341a89c3908c6e046ad87c474fffb481901d78201581cb16b56f5ec064be6ac3cab6035efae86b366cc3dc4a0d571603d70e53902c38200581c65fc709a5e019b8aba76f6977c1c8770e4b36fa76f434efc588747b718e48200581cbd039f956f4b302f3ab6fc7c4bac3350a540f44af81a8492194dd2c219034a8200581ce0a714319812c3f773ba04ec5d6b3ffcd5aad85006805b047b082541390339820682011901e28a03581cb5ae663aaea8e500157bdf4baafd6f5ba0ce5759f7cd4101fc132f545820ee155ace9c40292074cb6aff8c9ccdd273c81648ff1149ef36bcea6ebb8a3e2518871837d81e820203581de0e0a714319812c3f773ba04ec5d6b3ffcd5aad85006805b047b08254183581c76e607db2a31c9a2c32761d2431a186a550cc321f79cd8d6a82b29b8581cb5ae663aaea8e500157bdf4baafd6f5ba0ce5759f7cd4101fc132f54581ce0a714319812c3f773ba04ec5d6b3ffcd5aad85006805b047b082541808264746578744a62797465737472696e678405581cbd039f956f4b302f3ab6fc7c4bac3350a540f44af81a8492194dd2c2581c3542acb3a64d80c29302260d62c3b87a742ad14abf855ebc6733081e5820bfa726c3c149165b108e6ff550cb1a1c4f0fdc2e9f26a9a16f48babe73b600ce82068200a08405581ce0a714319812c3f773ba04ec5d6b3ffcd5aad85006805b047b082541581cbd039f956f4b302f3ab6fc7c4bac3350a540f44af81a8492194dd2c25820fb3d635c7cb573d1b9e9bff4a64ab4f25190d29b6fd8db94c605a218a23fa9ad05a1581de0eccbfb5c619673f0648a42cc2f822c81cbc34aee41274638e89a7af5190252081a00012d260e84581c0d94e174732ef9aae73f395ab44507bfa983d65023c11a951f0c32e4581ca646474b8f5431261506b6c273d307c7569a4eb6c96b42dd4a29520a581ce0a714319812c3f773ba04ec5d6b3ffcd5aad85006805b047b082541581ceccbfb5c619673f0648a42cc2f822c81cbc34aee41274638e89a7af509a3581c3542acb3a64d80c29302260d62c3b87a742ad14abf855ebc6733081ea1410601581c58e1b65718531b42494610c506cef10ff031fa817a8ff75c0ab180e7a14010581ca646474b8f5431261506b6c273d307c7569a4eb6c96b42dd4a29520aa14408000001030b58200268be9dbd0446eaa217e1dec8f399249305e551d7fc1437dd84521f74aa621ca50082825820c46fc8fc5c4b3db3c102c24155619bed7427b6abb35e238908f38dd6b4200e4d5840ac6f9e17b7b4af4900c3f49e7bce30d079783ced94342e1780f8e7c27988511f4bf46d819b1add78c382f211ddccc09d62cde3c9581fe6acfe2ebfb4b4d10fca825820a0c4e1d10d6085eff5f6d5c97d470b8d2d876eccbe50b736f4df26e11c17dfb658406f278d02303a0e09c52ac17832ec1fc6370afb3c526c77062847fdf337a689156f01219ec302c779e330590bc1415b547ad3c022ffbc6e8eb4918076c076cc740282845820ba835577a585d835a2252d44fc12061d16cc2e6c13d923d67ec39c36e7b24ff65840a5858812bd926e53dd5f4a5a83afef780b461228302eb8b439a8af88e55e6421e928bf83f24e94b95db8d5aa060373a273c277b38cc10ae57b99b05a2f75460c42dee441e2845820cd472123feb72c46b1df581c53c68b27e33659f3ed5fef945df8456c96d12f595840fe7eda80e45c0e5c3e2f871cd0588593f9976e325cb5099b1b0b1c059fa57427c613b8251952b7eedbe7c76ba73238cf9289ded3749a39d08040decb3dee5c4844bba095e74306128301818202800484d866821901e48042218d020105868400019fa0d9055e9f0142778744fef66a26ff40ff821b3d7a4d21fa4ca7621b4887bec6ae030696840003d87f9fd866821901639f9f42b07705ffff2104a5d866821902e19f422756ffd905499f404024ff8043095b35d866821902309f20400000ff01435a9ccda42144aac5c52d431a3744404233e50144271685fd00d866821901a480439d573dff821b753b23ec10673d611b4b6ff54534a4affe84010d9f40ff821b2009f65cd7f50cd91b43c7da2e7b7d48a884020a02821b6e9ba3a98d7a25f71b3cb3981d4e67e2ca84020f02821b3ff56eac7c8e63261b056d96ab4c6022a9840301a5a2a24472f7972402432787c5019f43452c9341b7234210e440ffd8668219035f9f415140ffa20144edf731052000a3a42220052141194484a91d78425f180420a2412a0244528a29ed43b2b86cd866821901db9f438bea600443549a0a420035ffa5212142f1770305426307030301249f22ff9f0440a1224335516820ffa541c041589f0540ffd866821903e79f222041b44220e202ffa3034042a26643ef7777402124d866821903bc9f204451f223860041924130ffa4034161447560bb544334533c004042d3880240d905379f446752cf79014212a2ff0423d8668218bf9fd866821901129f21ff20ff059f40ff22821b53738ddd94e3bfbf1b37333116d0e58be9f5d90103a200a403a303a460450750ffb73541c2054113614a60434f6021020522452e2cdfe5c009a00f0010650a32280864018382041a00016a918200581c76e607db2a31c9a2c32761d2431a186a550cc321f79cd8d6a82b29b8830304848303048482041930ec8201848200581ce0a714319812c3f773ba04ec5d6b3ffcd5aad85006805b047b0825418200581c76e607db2a31c9a2c32761d2431a186a550cc321f79cd8d6a82b29b88200581c58e1b65718531b42494610c506cef10ff031fa817a8ff75c0ab180e78200581c4acf2773917c7b547c576a7ff110d2ba5733c1f1ca9cdc659aea3a56830300808200581c3542acb3a64d80c29302260d62c3b87a742ad14abf855ebc6733081e8200581c58e1b65718531b42494610c506cef10ff031fa817a8ff75c0ab180e7820419d15e8205198d05", - "description": "Hydra commit transaction", - "type": "Tx BabbageEra" - }, - { - "cborHex": "84aa00868258204f539156bfbefc070a3b61cad3d1cedab3050e2b2a62f0ffe16a43eb0edc1ce806825820642206314f534b29ad297d82440a5f9f210e30ca5ced805a587ca402de92734208825820ae85d245a3d00bfde01f59f3c4fe0b4bfae1cb37e9cf91929eadcea4985711de06825820f63498b4ae65be466e4a71878971b9c524458996450b0ff8262cddf3f0d9922906825820fb3d635c7cb573d1b9e9bff4a64ab4f25190d29b6fd8db94c605a218a23fa9ad00825820fb3d635c7cb573d1b9e9bff4a64ab4f25190d29b6fd8db94c605a218a23fa9ad010d818258204f539156bfbefc070a3b61cad3d1cedab3050e2b2a62f0ffe16a43eb0edc1ce80712838258204f539156bfbefc070a3b61cad3d1cedab3050e2b2a62f0ffe16a43eb0edc1ce8018258204f539156bfbefc070a3b61cad3d1cedab3050e2b2a62f0ffe16a43eb0edc1ce807825820ee155ace9c40292074cb6aff8c9ccdd273c81648ff1149ef36bcea6ebb8a3e25020186a400583910a646474b8f5431261506b6c273d307c7569a4eb6c96b42dd4a29520a4acf2773917c7b547c576a7ff110d2ba5733c1f1ca9cdc659aea3a56018209a2581c0d94e174732ef9aae73f395ab44507bfa983d65023c11a951f0c32e4a142040808581c4acf2773917c7b547c576a7ff110d2ba5733c1f1ca9cdc659aea3a56a14506010305000802820058202208e439244a1d0ef238352e3693098aba9de9dd0154f9056551636c8ed15dc103d81849820082051a00010be0a400581d604acf2773917c7b547c576a7ff110d2ba5733c1f1ca9cdc659aea3a5601820ba2581c0d94e174732ef9aae73f395ab44507bfa983d65023c11a951f0c32e4a14307000410581cb5ae663aaea8e500157bdf4baafd6f5ba0ce5759f7cd4101fc132f54a241030b44060204040b0282005820e88bd757ad5b9bedf372d8d3f0cf6c962a469db61a265f6418e1ffed86da29ec03d818582d8200830301828200581c58e1b65718531b42494610c506cef10ff031fa817a8ff75c0ab180e782041a0001132ca4005821514acf2773917c7b547c576a7ff110d2ba5733c1f1ca9cdc659aea3a56a1190606018209a3581c4acf2773917c7b547c576a7ff110d2ba5733c1f1ca9cdc659aea3a56a1400d581cb16b56f5ec064be6ac3cab6035efae86b366cc3dc4a0d571603d70e5a1430402070e581ceccbfb5c619673f0648a42cc2f822c81cbc34aee41274638e89a7af5a14005028201d818581da122d866821902909fa0a503044358791901050020442b816f1b2102ff03d818582d82008201838200581c58e1b65718531b42494610c506cef10ff031fa817a8ff75c0ab180e7820419f489820180a300583900eccbfb5c619673f0648a42cc2f822c81cbc34aee41274638e89a7af53542acb3a64d80c29302260d62c3b87a742ad14abf855ebc6733081e018210a2581cbd039f956f4b302f3ab6fc7c4bac3350a540f44af81a8492194dd2c2a14207040e581ceccbfb5c619673f0648a42cc2f822c81cbc34aee41274638e89a7af5a14205050c03d818582282008200581c1920e782f048e9ef52acd89c4341a89c3908c6e046ad87c474fffb48a300582b82d818582183581c3cdc4c2d3204691824263c5d96765e9adeb1c08a7994efbcb16f7c68a0001a54d1f65f018206a4581c3542acb3a64d80c29302260d62c3b87a742ad14abf855ebc6733081ea1410207581c65fc709a5e019b8aba76f6977c1c8770e4b36fa76f434efc588747b7a1410107581cb5ae663aaea8e500157bdf4baafd6f5ba0ce5759f7cd4101fc132f54a145030607060009581ce0a714319812c3f773ba04ec5d6b3ffcd5aad85006805b047b082541a14301080601028201d81858449fd866821903669f41daa44493fcdd88444b9e2096423c344403334fac430fd7b742eb940301ffd866821901d49f9f22404004ff41cb2042a0bdff9f80ff44204b6d88ffa300585082d818584683581c4029e24126599502351abce28438733cdd93254cbc832dfb5d904cc7a10158225820686a797974757770706e69796878756c636f6671687a786b6b7a737a74676b79001ad32fc14a01820ca1581c65fc709a5e019b8aba76f6977c1c8770e4b36fa76f434efc588747b7a146060000030302100282005820e88bd757ad5b9bedf372d8d3f0cf6c962a469db61a265f6418e1ffed86da29ec021849031a0001444604858405581c3542acb3a64d80c29302260d62c3b87a742ad14abf855ebc6733081e581c3542acb3a64d80c29302260d62c3b87a742ad14abf855ebc6733081e5820fb3d635c7cb573d1b9e9bff4a64ab4f25190d29b6fd8db94c605a218a23fa9ad8405581cb5ae663aaea8e500157bdf4baafd6f5ba0ce5759f7cd4101fc132f54581c4acf2773917c7b547c576a7ff110d2ba5733c1f1ca9cdc659aea3a565820f63498b4ae65be466e4a71878971b9c524458996450b0ff8262cddf3f0d99229820682001902568a03581c1920e782f048e9ef52acd89c4341a89c3908c6e046ad87c474fffb4858200268be9dbd0446eaa217e1dec8f399249305e551d7fc1437dd84521f74aa621c19025919022cd81e820710581de0eccbfb5c619673f0648a42cc2f822c81cbc34aee41274638e89a7af583581ca646474b8f5431261506b6c273d307c7569a4eb6c96b42dd4a29520a581cb16b56f5ec064be6ac3cab6035efae86b366cc3dc4a0d571603d70e5581cbd039f956f4b302f3ab6fc7c4bac3350a540f44af81a8492194dd2c28182026f666f6f2e6578616d706c652e636f6df682008201581cbd039f956f4b302f3ab6fc7c4bac3350a540f44af81a8492194dd2c20819d8df0e82581cb16b56f5ec064be6ac3cab6035efae86b366cc3dc4a0d571603d70e5581cbd039f956f4b302f3ab6fc7c4bac3350a540f44af81a8492194dd2c2075820ae85d245a3d00bfde01f59f3c4fe0b4bfae1cb37e9cf91929eadcea4985711dea50081825820a5abb33b8f5f273c388a954792b3144d183be1c083ec6e34b3b9d92d1138815e5840325fb0a1dfcb2fcac089dc9d9a09f0ee0677b4d810487bffb76cae3ee2bf5e4f2164149053d28ed310e6f13d47792456a0cf48c2f958c2de40c1358794b2c7330281845820422ef2b0cc9e9bae019b724d315b735763fad676411211b9e685a18136cdf00158407768666b68766378727977636d6d7864626878797a7a7a6b6a7262776e68726e76706461676d696a667764776765647068796c76766a6c6d767079686c787964404001828200581cbd039f956f4b302f3ab6fc7c4bac3350a540f44af81a8492194dd2c282028182041a00016d240485d8668219029e9fa5d866821901649f24ff9f0021ff219f4002ffa34432fc1dad4159002242bd9b22230543afbe719f2443514a1240ff02ff41bb43bf3b55d866821901108003058284020040821b7952d27b2e9e66b01b09cce49e334bff3e840201a544bdef464b9f249f40000122ff9f43d56ac3ffa5230343fea95e429deb43ae589e0541580044e3677df842211c9f04044233daffff9fd866821901739f439563cdffff43d5eb57d866821902c29f0022ff009fa4438de277200142593f02212044913adeb6a52041aa402141c121242244966fb14042ec4e42cf99ff9f40ff8040821b2f07fc56af176c4e1b11c17e9edfff1375f5d90103a20183820519762e82041a00016bbc82041972170382464501000026014746010000220011", - "description": "Hydra commit transaction", - "type": "Tx BabbageEra" - }, - { - "cborHex": "84ac008282582003170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c11131402825820bfa726c3c149165b108e6ff550cb1a1c4f0fdc2e9f26a9a16f48babe73b600ce050d858258200268be9dbd0446eaa217e1dec8f399249305e551d7fc1437dd84521f74aa621c0782582003170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c11131401825820bb30a42c1e62f0afda5f0a4e8a562f7a13a24cea00ee81917b86b89e801314aa05825820ee155ace9c40292074cb6aff8c9ccdd273c81648ff1149ef36bcea6ebb8a3e2508825820fb3d635c7cb573d1b9e9bff4a64ab4f25190d29b6fd8db94c605a218a23fa9ad02128482582003170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314028258202208e439244a1d0ef238352e3693098aba9de9dd0154f9056551636c8ed15dc104825820bb30a42c1e62f0afda5f0a4e8a562f7a13a24cea00ee81917b86b89e801314aa04825820ee155ace9c40292074cb6aff8c9ccdd273c81648ff1149ef36bcea6ebb8a3e25020185a30058392058e1b65718531b42494610c506cef10ff031fa817a8ff75c0ab180e70d94e174732ef9aae73f395ab44507bfa983d65023c11a951f0c32e4018202a4581c3542acb3a64d80c29302260d62c3b87a742ad14abf855ebc6733081ea244000304010845050604070509581c58e1b65718531b42494610c506cef10ff031fa817a8ff75c0ab180e7a1410301581cb16b56f5ec064be6ac3cab6035efae86b366cc3dc4a0d571603d70e5a14306050007581ceccbfb5c619673f0648a42cc2f822c81cbc34aee41274638e89a7af5a14103080282005820bb30a42c1e62f0afda5f0a4e8a562f7a13a24cea00ee81917b86b89e801314aaa400585782d818584d83581cf4362c1db60604ff86e13f5c9a2cbeb8dd886d0acb7bb0eb72500b75a2015822582075727971656f646f797a756d78766a727173656f77627165726771666576667202451a67e48ceb021a7a5ae89b018202a2581c4acf2773917c7b547c576a7ff110d2ba5733c1f1ca9cdc659aea3a56a14605010404070009581ceccbfb5c619673f0648a42cc2f822c81cbc34aee41274638e89a7af5a1460404020603000e028201d818410003d8185901c6820082018382018282051a0001326282051a00014e4c8200581c65fc709a5e019b8aba76f6977c1c8770e4b36fa76f434efc588747b78202848201858200581c3542acb3a64d80c29302260d62c3b87a742ad14abf855ebc6733081e8200581c76e607db2a31c9a2c32761d2431a186a550cc321f79cd8d6a82b29b88200581c3542acb3a64d80c29302260d62c3b87a742ad14abf855ebc6733081e8200581c4acf2773917c7b547c576a7ff110d2ba5733c1f1ca9cdc659aea3a568200581ca646474b8f5431261506b6c273d307c7569a4eb6c96b42dd4a29520a8201828200581cb5ae663aaea8e500157bdf4baafd6f5ba0ce5759f7cd4101fc132f548200581cb5ae663aaea8e500157bdf4baafd6f5ba0ce5759f7cd4101fc132f54830303848200581c4acf2773917c7b547c576a7ff110d2ba5733c1f1ca9cdc659aea3a568200581c65fc709a5e019b8aba76f6977c1c8770e4b36fa76f434efc588747b78200581c65fc709a5e019b8aba76f6977c1c8770e4b36fa76f434efc588747b78200581c58e1b65718531b42494610c506cef10ff031fa817a8ff75c0ab180e78201818200581ca646474b8f5431261506b6c273d307c7569a4eb6c96b42dd4a29520aa400585082d818584683581cbfeb771b4bb042887009ccd1420a6a63c18e443adf658fde6e8788eea1015822582074636675797171726e6864627a787371776374666a71736f6e786b756676736e001a02f9417a01820ea2581c4acf2773917c7b547c576a7ff110d2ba5733c1f1ca9cdc659aea3a56a1430506030a581ceccbfb5c619673f0648a42cc2f822c81cbc34aee41274638e89a7af5a146010403080108090282005820f63498b4ae65be466e4a71878971b9c524458996450b0ff8262cddf3f0d9922903d8185902af82008303008582028482051986a482051a000142868201858200581c58e1b65718531b42494610c506cef10ff031fa817a8ff75c0ab180e78200581c0d94e174732ef9aae73f395ab44507bfa983d65023c11a951f0c32e48200581cbd039f956f4b302f3ab6fc7c4bac3350a540f44af81a8492194dd2c28200581ce0a714319812c3f773ba04ec5d6b3ffcd5aad85006805b047b0825418200581cb16b56f5ec064be6ac3cab6035efae86b366cc3dc4a0d571603d70e58202838200581ce0a714319812c3f773ba04ec5d6b3ffcd5aad85006805b047b0825418200581cbd039f956f4b302f3ab6fc7c4bac3350a540f44af81a8492194dd2c28200581c58e1b65718531b42494610c506cef10ff031fa817a8ff75c0ab180e782028082051980b48201848202838200581c0d94e174732ef9aae73f395ab44507bfa983d65023c11a951f0c32e48200581c65fc709a5e019b8aba76f6977c1c8770e4b36fa76f434efc588747b78200581cb5ae663aaea8e500157bdf4baafd6f5ba0ce5759f7cd4101fc132f548200581c3542acb3a64d80c29302260d62c3b87a742ad14abf855ebc6733081e8201828200581ce0a714319812c3f773ba04ec5d6b3ffcd5aad85006805b047b0825418200581cbd039f956f4b302f3ab6fc7c4bac3350a540f44af81a8492194dd2c28202858200581cbd039f956f4b302f3ab6fc7c4bac3350a540f44af81a8492194dd2c28200581c3542acb3a64d80c29302260d62c3b87a742ad14abf855ebc6733081e8200581cb5ae663aaea8e500157bdf4baafd6f5ba0ce5759f7cd4101fc132f548200581cb5ae663aaea8e500157bdf4baafd6f5ba0ce5759f7cd4101fc132f548200581c4acf2773917c7b547c576a7ff110d2ba5733c1f1ca9cdc659aea3a568200581ce0a714319812c3f773ba04ec5d6b3ffcd5aad85006805b047b082541a3005822401920e782f048e9ef52acd89c4341a89c3908c6e046ad87c474fffb488295680005018206a4581c65fc709a5e019b8aba76f6977c1c8770e4b36fa76f434efc588747b7a1400c581c76e607db2a31c9a2c32761d2431a186a550cc321f79cd8d6a82b29b8a14006581cb16b56f5ec064be6ac3cab6035efae86b366cc3dc4a0d571603d70e5a1460500050404030e581ceccbfb5c619673f0648a42cc2f822c81cbc34aee41274638e89a7af5a142000409028201d8184104a300582b82d818582183581ccbbcf5e081952f05e75a5c9f484fab3dd70195e2241369a4142b443aa0021a428f503f01820fa1581c3542acb3a64d80c29302260d62c3b87a742ad14abf855ebc6733081ea1430801031003d818582282008200581cbd039f956f4b302f3ab6fc7c4bac3350a540f44af81a8492194dd2c210a20058393065fc709a5e019b8aba76f6977c1c8770e4b36fa76f434efc588747b74acf2773917c7b547c576a7ff110d2ba5733c1f1ca9cdc659aea3a5601820aa4581c0d94e174732ef9aae73f395ab44507bfa983d65023c11a951f0c32e4a1440604020801581c4acf2773917c7b547c576a7ff110d2ba5733c1f1ca9cdc659aea3a56a145060707010302581cb16b56f5ec064be6ac3cab6035efae86b366cc3dc4a0d571603d70e5a24102074205020f581ceccbfb5c619673f0648a42cc2f822c81cbc34aee41274638e89a7af5a1440408080607021901d10319a3b70481820682010a05a1581de0a646474b8f5431261506b6c273d307c7569a4eb6c96b42dd4a29520a1903190e84581c58e1b65718531b42494610c506cef10ff031fa817a8ff75c0ab180e7581c65fc709a5e019b8aba76f6977c1c8770e4b36fa76f434efc588747b7581cb16b56f5ec064be6ac3cab6035efae86b366cc3dc4a0d571603d70e5581ceccbfb5c619673f0648a42cc2f822c81cbc34aee41274638e89a7af509a1581c1920e782f048e9ef52acd89c4341a89c3908c6e046ad87c474fffb48a14204002a0f00a500858258206af2f57e0027505e3f6b08d6abe5336fde3891e2ced65dbb255d4d354f4a3a365840d5e0211042075e8f2471379ecc2cfb5e80eaa9a2ae5f2182670dd2d4392bdcac9da4347a5883fcfd109b4ff0ccf55fbd78dafc0748cb92648e247be288142ba58258208aa6b76cdcbd9635cc4a48a791f7738f56071274fd35820b74b0646d2922188e5840f51bc9f8f4646eda8b244708d0a298b8c783d1e25bd753dd3caaaf729a345376bd4ee8ff4477494f996d599d845f4a6c0a083aff8d0e464cf84245a9124753bf825820a0573d850bb9a408164ccb4522d09a61537187b745dc2135fb16ab9e5a9289345840319878be9ae6e2d57c4b86faf9a13f43a53aa087b7f195cc74a1eb8676f21f06134e9b150f28b2a4cdd5272acc1c17f45fefc6bcab7c858f85044ac4862da1c6825820fced95dd37c88c9031329cddc3357a3d8ebb6e4661cae658f7e6a69b5af771555840e1b869106866c8e882bc5b27e17c4bdcf4c6fe13aebeeb6c45d266b3f9ab851ce355dd9c25f0a160d12bc1064ac001c04d88ead2a53cf6de4c02dc53f222d12f825820669b10b77f4ac754d19cc48b06ddd1b4355e9ef968c145f952a3c74e84065d675840b8b08ef0bc3bfe10bfb875e57cd46679bf36d957f5ed16acb6f69d12b7670fe5344f0089f54efc36d957ac01abac75ed7ed2e9f7c996a7ef1bfd2f462b5c3ac60286845820b7780a8d1488809d35b6424e0bc1810268a9ae26455965d37f9da2372493031a58405b26c7e936df958adf31ea83963c866ae9b3d5c1a2ddeb7bd3b1ffab7592a9e1bf748ed0893a414c83117c87ef9432697c838b87c4435eb277f33735ffdf455242665541fd84582095c3f864a26175545c87464d4095317c8b72803a82a0d1f6e7db718ef3749aa35840796c6e64736274796a656e79686e707464646e737673627066646e616f6a61726a677173636a6e686d656a6266626372636c79766b62797065757376636e6b654043b39ac78458205174a34bbfd0cf1b66cfdd7cccfc9753e8f615ca2dd019a104595de54b81d1845840b428e5412a13aa34c5da73effd3058822d8246b62b26e977c48ff1f5f0137486954cd8844df08b1d2970db0c5546cb2402ef5976bf93cae3d3b3176a87ac6d6042aebc43984b208458200776905a8510e12617f24c059316cdd39e342eaa0d08814f952e69276c0c0b6558408937f2b104653eb655a257ed3477a87aa5507c8b14e60cc572ad8e54fe891b063592a96e1fd87392f555a0ce4bdac5b559a6d73fc3bf5dc0e14a8d9e1632ffbf444abad7d642d6a2845820f707819b3141e650dad70ac385e9ab8ba11b3aeba980b7275521c7fd0b3bc3ff58406d73716a747a74776d67696a696d647464736d656e646f716e636b7362697177796b6166706b696b6b676a6564796e78677a737a76696868686e6566766173644040845820f964ffa949c9c5a5dc8e7183a14f27a2aa60e329fda7157bd5838ae9667d2b8a584091ca4fb091e281e008ee0f7d59f8062ec35c01314b210dd45eb724f0e93af1557cbca9f11fc16015a330f048a2289e28fadb8a6470cd287d288dde7b885e7923419e41ff0184820419fbf782051a00010290820184820519689c820182830300828200581c0d94e174732ef9aae73f395ab44507bfa983d65023c11a951f0c32e48200581c3542acb3a64d80c29302260d62c3b87a742ad14abf855ebc6733081e8202838200581c58e1b65718531b42494610c506cef10ff031fa817a8ff75c0ab180e78200581ca646474b8f5431261506b6c273d307c7569a4eb6c96b42dd4a29520a8200581c58e1b65718531b42494610c506cef10ff031fa817a8ff75c0ab180e7820180830300828202808200581c65fc709a5e019b8aba76f6977c1c8770e4b36fa76f434efc588747b782051a0001347d0486d866821901f59f8021a39f21ff2343ba6755a201004022809f202023ffffd8668218ef9f80a18041caff42bbfe41f7d8668218ce9f21ffd86682188d9f800440ff05848400079fd866821903b89f446e45939941be05d9054c9f420a2a01ffa4054469c5ef0e44867a9b9a04419240446d8275f0426ef8ffff821b487aca54793ad2171b59fb1d14ebb2293a84010741df821b04c2d622ef1cb90d1b7d77ecedd526d9ac84020d434efc0d821b56f369b8392b179a1b001070d3446980b284030ca3a1d866821903099f43784536ffa3050201440718f87142496f430e0619a3a3052302446e5d54300001408042722fd866821903229f242123415eff004041264279d7412e821b41f72cc9684ae1951b0b054f83eceea2a1f5f6", - "description": "Hydra commit transaction", - "type": "Tx BabbageEra" - } - ], - "seed": 1986993722 -} \ No newline at end of file diff --git a/hydra-node/json-schemas/api.yaml b/hydra-node/json-schemas/api.yaml index 20a841942c0..56703f3ed3c 100644 --- a/hydra-node/json-schemas/api.yaml +++ b/hydra-node/json-schemas/api.yaml @@ -12,7 +12,7 @@ info: They can interact with their node by pushing events to it, some are local, and some will have consequences on the rest of the head. See [the documentation](https://hydra.family/head-protocol/core-concepts/behavior/) for more details on the overall API behavior. - Users can also use the HTTP endpoint to draft a commit tx using their own utxo. + Users can also use the HTTP endpoint to draft a commit tx using their own utxo, potentially including a blueprint tx as part of the draft. > By default, a Hydra node listens for TCP WebSocket connections on port `tcp/4001` . This can be changed using `--port`. @@ -122,7 +122,6 @@ channels: description: | Possible responses of this endpoint are: * DraftCommitTxResponse - 200 ok - * CannotCommitReferenceScript - 400 bad request * CommittedTooMuchADAForMainnet - 400 bad request * UnsupportedLegacyOutput - 400 bad request * SpendingNodeUtxoForbidden - 400 bad request @@ -469,56 +468,7 @@ components: Provide utxos that will be used to draft a commit transaction that will be sent back to the user. Script utxos must provide a witness, regulars can omit this. payload: - $ref: "api.yaml#/components/schemas/UTxOWithWitness" - example: - { - "0406060506030602040508060506060306050406020207000508040704040203#89": { - "address": "addr_test1vz66ue36465w2qq40005h2hadad6pnjht8mu6sgplsfj74q9pm4f4", - "value": { - "lovelace": 7620669 - } - }, - "6f066e0f6ba373c0ea7d8b47aefd7e14d1a781698cd052d0254afe65e039b083#0": { - "address": "addr_test1wqv4z4hc0u5e2c3sppfdu8ckn82hfegpkjagsm4t8ttvlycg9mkca", - "datum": null, - "datumhash": "bb30a42c1e62f0afda5f0a4e8a562f7a13a24cea00ee81917b86b89e801314aa", - "inlineDatum": null, - "referenceScript": null, - "value": { - "lovelace": 1034400 - }, - "witness": { - "datum": "02", - "plutusV2Script": { - "cborHex": "484701000022200101", - "description": "", - "type": "PlutusScriptV2" - }, - "redeemer": "01" - } - }, - "87a0c1e14be2cd8c385b6fe5a40b024b7201da9df375542029d91ccaba01ac82#0": { - "address": "addr_test1wqv4z4hc0u5e2c3sppfdu8ckn82hfegpkjagsm4t8ttvlycg9mkca", - "datum": null, - "inlineDatum": { - "int": 2 - }, - "inlineDatumhash": "bb30a42c1e62f0afda5f0a4e8a562f7a13a24cea00ee81917b86b89e801314aa", - "referenceScript": null, - "value": { - "lovelace": 905100 - }, - "witness": { - "datum": null, - "plutusV2Script": { - "cborHex": "484701000022200101", - "description": "", - "type": "PlutusScriptV2" - }, - "redeemer": "01" - } - } - } + $ref: "api.yaml#/components/schemas/DraftCommitTxRequest" DraftCommitTxResponse: title: DraftCommitTxResponse @@ -1508,17 +1458,6 @@ components: enum: ["UnsupportedLegacyOutput"] byronAddress: $ref: "api.yaml#/components/schemas/ByronAddress" - - title: CannotCommitReferenceScript - type: object - additionalProperties: false - required: - - tag - description: >- - The UTxO provided to commit contains a reference script, which is currently not supported. - properties: - tag: - type: string - enum: ["CannotCommitReferenceScript"] - title: NoSeedInput type: object additionalProperties: false @@ -1845,66 +1784,6 @@ components: contentEncoding: base16 - type: "null" - TxOutWithWitness: - type: object - description: | - A single transaction output with optional witness to spend it. - Some notes related to witness field: - - When it is present we are treating the output as a script output. - - When `inlineDatum` is present we ignore the `witness.datum` field. - required: - - address - - value - additionalProperties: false - properties: - address: - $ref: "api.yaml#/components/schemas/Address" - value: - $ref: "api.yaml#/components/schemas/Value" - referenceScript: - oneOf: - - $ref: "api.yaml#/components/schemas/Script" - - type: "null" - datumhash: - oneOf: - - type: string - contentEncoding: base16 - - type: "null" - inlineDatum: - oneOf: - - type: object - - type: "null" - inlineDatumhash: - oneOf: - - type: string - contentEncoding: base16 - - type: "null" - datum: - oneOf: - - type: string - contentEncoding: base16 - - type: "null" - witness: - oneOf: - - $ref: "api.yaml#/components/schemas/Witness" - - type: "null" - - Witness: - type: object - description: | - A script witness - required: - - datum - - plutusV2Script - - redeemer - additionalProperties: false - properties: - datum: - type: string - plutusV2Script: - $ref: "api.yaml#/components/schemas/PlutusV2Script" - redeemer: - type: string HydraNodeVersion: type: string description: | @@ -1945,50 +1824,55 @@ components: } } - UTxOWithWitness: + DraftCommitTxRequest: type: object - propertyNames: - pattern: "^[0-9a-f]{64}#[0-9]+$" items: - $ref: "api.yaml#/components/schemas/TxOutWithWitness" + oneof: + - $ref: "api.yaml#/components/schemas/UTxO" + - $ref: "api.yaml#/components/schemas/FullCommitRequest" + + FullCommitRequest: + type: object + required: + - blueprintTx + - utxo + properties: + blueptintTx: + $ref: "api.yaml#/components/schemas/Transaction" + utxo: + $ref: "api.yaml#/components/schemas/UTxO" example: { - "09d34606abdcd0b10ebc89307cbfa0b469f9144194137b45b7a04b273961add8#687": { - "address": "addr1w9htvds89a78ex2uls5y969ttry9s3k9etww0staxzndwlgmzuul5", - "value": { - "lovelace": 7620669 + "blueprintTx": { + "cborHex": "...", + "type": "Tx BabbageEra" + }, + "utxo": { + "e44bdebd6bd7f54f081b5945a5e30521833fd3944f4f4d13de309d36ac5f9615#80": { + "address": "addr1zyhxu2ejxercjqwz3yzv3nx5qjup37n5x2eskf4kna2rpdcqdjxnpvxsxr0plavuw385mqg2ts0zlqkm9r879kgn5vysfkfu4t", + "datum": null, + "datumhash": "aa218e748e45df83c4fe14759280170edcce8f1c45d52d555b8038b50d6cd29e", + "inlineDatum": null, + "referenceScript": { + "script": { + "cborHex": "...", + "description": "", + "type": "SimpleScript" }, - "witness": { - "datum": "02", - "plutusV2Script": { - "cborHex": "420606", - "description": "", - "type": "PlutusScriptV2" - }, - "redeemer": "21" - } + "scriptLanguage": "SimpleScriptLanguage" + }, + "value": { + "2d725128406dc832eb74c4709aca0512499b3c7b17e00d7cb2e6d1b1": { + "32": 2 + }, + "lovelace": 1 + } } + } } # END OF SERVER OUTPUT SCHEMAS - ScriptInfo: - description: | - Script data needed to spend user provided utxo. - If datum field is ommitted we expect inline datum to be present. - required: - - redeemer - - plutusV2Script - payload: - type: object - properties: - redeemer: - $ref: "api.yaml#/components/schemas/Cbor" - datum: - $ref: "api.yaml#/components/schemas/Cbor" - plutusV2Script: - type: object - $ref: "api.yaml#/components/schemas/PlutusV2Script" PlutusV2Script: type: object diff --git a/hydra-node/src/Hydra/API/HTTPServer.hs b/hydra-node/src/Hydra/API/HTTPServer.hs index 30489793175..0253f611bd9 100644 --- a/hydra-node/src/Hydra/API/HTTPServer.hs +++ b/hydra-node/src/Hydra/API/HTTPServer.hs @@ -4,36 +4,20 @@ module Hydra.API.HTTPServer where import Hydra.Prelude -import Cardano.Api.UTxO qualified as UTxO import Cardano.Ledger.Core (PParams) -import Data.Aeson (KeyValue ((.=)), Value (Object), object, withObject, (.:), (.:?)) +import Data.Aeson (KeyValue ((.=)), object, withObject, (.:)) import Data.Aeson qualified as Aeson -import Data.Aeson.KeyMap qualified as KeyMap import Data.ByteString.Lazy qualified as LBS import Data.ByteString.Short () import Data.Text (pack) import Hydra.API.APIServerLog (APIServerLog (..), Method (..), PathInfo (..)) import Hydra.Cardano.Api ( - CtxUTxO, - HashableScriptData, - KeyWitnessInCtx (..), LedgerEra, - PlutusScript, - ScriptDatum (InlineScriptDatum, ScriptDatumForTxIn), - ScriptWitnessInCtx (ScriptWitnessForSpending), Tx, - TxOut, - UTxO', - deserialiseFromTextEnvelope, fromLedgerPParams, - mkScriptWitness, - proxyToAsType, - serialiseToTextEnvelope, shelleyBasedEra, - pattern KeyWitness, - pattern ScriptWitness, ) -import Hydra.Chain (Chain (..), IsChainState, PostTxError (..), draftCommitTx) +import Hydra.Chain (Chain (..), CommitBlueprintTx (..), IsChainState, PostTxError (..), draftCommitTx) import Hydra.Chain.Direct.State () import Hydra.HeadId (HeadId) import Hydra.Ledger (IsTx (..)) @@ -48,79 +32,64 @@ import Network.Wai ( responseLBS, ) -newtype DraftCommitTxResponse = DraftCommitTxResponse - { commitTx :: Tx +newtype DraftCommitTxResponse tx = DraftCommitTxResponse + { commitTx :: tx } - deriving stock (Show, Generic) + deriving stock (Generic) -instance ToJSON DraftCommitTxResponse where - toJSON (DraftCommitTxResponse tx) = - toJSON $ serialiseToTextEnvelope (Just "Hydra commit transaction") tx +deriving stock instance Show tx => Show (DraftCommitTxResponse tx) -instance FromJSON DraftCommitTxResponse where - parseJSON v = do - env <- parseJSON v - case deserialiseFromTextEnvelope (proxyToAsType Proxy) env of - Left e -> fail $ show e - Right tx -> pure $ DraftCommitTxResponse tx +instance IsTx tx => ToJSON (DraftCommitTxResponse tx) where + toJSON (DraftCommitTxResponse tx) = toJSON tx -instance Arbitrary DraftCommitTxResponse where +instance IsTx tx => FromJSON (DraftCommitTxResponse tx) where + parseJSON v = DraftCommitTxResponse <$> parseJSON v + +instance Arbitrary tx => Arbitrary (DraftCommitTxResponse tx) where arbitrary = genericArbitrary shrink = \case DraftCommitTxResponse xs -> DraftCommitTxResponse <$> shrink xs --- TODO: This should actually be isomorphic to ScriptWitness of cardano-api, --- i.e. we should support also native scripts, other versions of plutus and --- witnessing via reference inputs -data ScriptInfo = ScriptInfo - { redeemer :: HashableScriptData - , datum :: Maybe HashableScriptData - , plutusV2Script :: PlutusScript - } - deriving stock (Show, Eq, Generic) - deriving anyclass (ToJSON, FromJSON) - -instance Arbitrary ScriptInfo where - arbitrary = genericArbitrary - -data TxOutWithWitness = TxOutWithWitness - { txOut :: TxOut CtxUTxO - , witness :: Maybe ScriptInfo - } - deriving stock (Show, Eq, Generic) - -instance ToJSON TxOutWithWitness where - toJSON TxOutWithWitness{txOut, witness} = - case toJSON txOut of - Object km - | isJust witness -> - Object $ km & "witness" `KeyMap.insert` toJSON witness - x -> x - -instance FromJSON TxOutWithWitness where - parseJSON v = do - txOut <- parseJSON v - flip (withObject "TxOutWithWitness") v $ \o -> do - witness <- o .:? "witness" - pure $ TxOutWithWitness{txOut, witness} - -instance Arbitrary TxOutWithWitness where - arbitrary = genericArbitrary - -deriving newtype instance Arbitrary (UTxO' TxOutWithWitness) +data DraftCommitTxRequest tx + = SimpleCommitRequest + { utxoToCommit :: UTxOType tx + } + | FullCommitRequest + { blueprintTx :: tx + , utxo :: UTxOType tx + } + deriving stock (Generic) + +deriving stock instance (Eq tx, Eq (UTxOType tx)) => Eq (DraftCommitTxRequest tx) +deriving stock instance (Show tx, Show (UTxOType tx)) => Show (DraftCommitTxRequest tx) + +instance (ToJSON tx, ToJSON (UTxOType tx)) => ToJSON (DraftCommitTxRequest tx) where + toJSON = \case + FullCommitRequest{blueprintTx, utxo} -> + object + [ "blueprintTx" .= toJSON blueprintTx + , "utxo" .= toJSON utxo + ] + SimpleCommitRequest{utxoToCommit} -> + toJSON utxoToCommit + +instance (FromJSON tx, FromJSON (UTxOType tx)) => FromJSON (DraftCommitTxRequest tx) where + parseJSON v = fullVariant v <|> simpleVariant v + where + fullVariant = withObject "FullCommitRequest" $ \o -> do + blueprintTx :: tx <- o .: "blueprintTx" + utxo <- o .: "utxo" + pure FullCommitRequest{blueprintTx, utxo} -newtype DraftCommitTxRequest = DraftCommitTxRequest - { utxoToCommit :: UTxO' TxOutWithWitness - } - deriving stock (Eq, Show, Generic) - deriving newtype (ToJSON, FromJSON) + simpleVariant val = SimpleCommitRequest <$> parseJSON val -instance Arbitrary DraftCommitTxRequest where +instance (Arbitrary tx, Arbitrary (UTxOType tx)) => Arbitrary (DraftCommitTxRequest tx) where arbitrary = genericArbitrary shrink = \case - DraftCommitTxRequest u -> DraftCommitTxRequest <$> shrink u + SimpleCommitRequest u -> SimpleCommitRequest <$> shrink u + FullCommitRequest a b -> FullCommitRequest <$> shrink a <*> shrink b newtype SubmitTxRequest tx = SubmitTxRequest { txToSubmit :: tx @@ -150,7 +119,8 @@ instance Arbitrary TransactionSubmitted where -- | Hydra HTTP server httpApp :: - IsTx tx => + forall tx. + IsChainState tx => Tracer IO APIServerLog -> Chain tx IO -> PParams LedgerEra -> @@ -190,80 +160,9 @@ httpApp tracer directChain pparams getInitializingHeadId getConfirmedUTxO reques -- * Handlers -- | Handle request to obtain a draft commit tx. --- --- Users can decide to commit a public key as well as script outputs. --- --- ==== __Request body examples:__ --- --- @ --- --- // Committing public key output --- --- { --- "0406060506030602040508060506060306050406020207000508040704040203#89": { --- "address": "addr_test1vz66ue36465w2qq40005h2hadad6pnjht8mu6sgplsfj74q9pm4f4", --- "value": { --- "lovelace": 7620669 --- } --- } --- --- @ --- --- @ --- --- // Committing a script output --- --- { --- "6f066e0f6ba373c0ea7d8b47aefd7e14d1a781698cd052d0254afe65e039b083#0": { --- "address": "addr_test1wqv4z4hc0u5e2c3sppfdu8ckn82hfegpkjagsm4t8ttvlycg9mkca", --- "datum": null, --- "datumhash": "bb30a42c1e62f0afda5f0a4e8a562f7a13a24cea00ee81917b86b89e801314aa", --- "inlineDatum": null, --- "referenceScript": null, --- "value": { --- "lovelace": 1034400 --- }, --- "witness": { --- "datum": "02", --- "plutusV2Script": { --- "cborHex": "484701000022200101", --- "description": "", --- "type": "PlutusScriptV2" --- }, --- "redeemer": "01" --- } --- } --- --- @ --- --- @ --- // Committing a script output using inline datum --- --- { --- --- "87a0c1e14be2cd8c385b6fe5a40b024b7201da9df375542029d91ccaba01ac82#0": { --- "address": "addr_test1wqv4z4hc0u5e2c3sppfdu8ckn82hfegpkjagsm4t8ttvlycg9mkca", --- "datum": null, --- "inlineDatum": { --- "int": 2 --- }, --- "inlineDatumhash": "bb30a42c1e62f0afda5f0a4e8a562f7a13a24cea00ee81917b86b89e801314aa", --- "referenceScript": null, --- "value": { --- "lovelace": 905100 --- }, --- "witness": { --- "datum": null, --- "plutusV2Script": { --- "cborHex": "484701000022200101", --- "description": "", --- "type": "PlutusScriptV2" --- }, --- "redeemer": "01" --- } --- } --- @ handleDraftCommitUtxo :: + forall tx. + IsChainState tx => Chain tx IO -> -- | A means to get the 'HeadId' if initializing the Head. IO (Maybe HeadId) -> @@ -271,53 +170,43 @@ handleDraftCommitUtxo :: LBS.ByteString -> IO Response handleDraftCommitUtxo directChain getInitializingHeadId body = do - case Aeson.eitherDecode' body :: Either String DraftCommitTxRequest of - Left err -> - pure $ responseLBS status400 [] (Aeson.encode $ Aeson.String $ pack err) - Right DraftCommitTxRequest{utxoToCommit} -> do - getInitializingHeadId >>= \case - Just headId -> do - draftCommitTx headId (fromTxOutWithWitness <$> utxoToCommit) <&> \case - Left e -> - -- Distinguish between errors users can actually benefit from and - -- other errors that are turned into 500 responses. - case e of - CannotCommitReferenceScript -> badRequest e - CommittedTooMuchADAForMainnet _ _ -> badRequest e - UnsupportedLegacyOutput _ -> badRequest e - walletUtxoErr@SpendingNodeUtxoForbidden -> badRequest walletUtxoErr - _ -> responseLBS status500 [] (Aeson.encode $ toJSON e) - Right commitTx -> - responseLBS status200 [] (Aeson.encode $ DraftCommitTxResponse commitTx) - -- XXX: This is not really an internal server error - Nothing -> pure $ responseLBS status500 [] (Aeson.encode $ FailedToDraftTxNotInitializing @Tx) + getInitializingHeadId >>= \case + Just headId -> do + case Aeson.eitherDecode' body :: Either String (DraftCommitTxRequest tx) of + Left err -> + pure $ responseLBS status400 [] (Aeson.encode $ Aeson.String $ pack err) + Right FullCommitRequest{blueprintTx, utxo} -> do + draftCommit headId utxo blueprintTx + Right SimpleCommitRequest{utxoToCommit} -> do + let blueprintTx = txSpendingUTxO utxoToCommit + draftCommit headId utxoToCommit blueprintTx + -- XXX: This is not really an internal server error + Nothing -> pure $ responseLBS status500 [] (Aeson.encode (FailedToDraftTxNotInitializing :: PostTxError tx)) where + draftCommit headId lookupUTxO blueprintTx = + draftCommitTx headId CommitBlueprintTx{lookupUTxO, blueprintTx} <&> \case + Left e -> + -- Distinguish between errors users can actually benefit from and + -- other errors that are turned into 500 responses. + case e of + CommittedTooMuchADAForMainnet _ _ -> badRequest e + UnsupportedLegacyOutput _ -> badRequest e + walletUtxoErr@SpendingNodeUtxoForbidden -> badRequest walletUtxoErr + _ -> responseLBS status500 [] (Aeson.encode $ toJSON e) + Right commitTx -> + okJSON $ DraftCommitTxResponse commitTx Chain{draftCommitTx} = directChain - fromTxOutWithWitness TxOutWithWitness{txOut, witness} = - (txOut, toScriptWitness witness) - where - toScriptWitness = \case - Nothing -> - KeyWitness KeyWitnessForSpending - Just ScriptInfo{redeemer, datum, plutusV2Script} -> - ScriptWitness ScriptWitnessForSpending $ - case datum of - Nothing -> - -- In case the datum field is not present we are assumming the datum - -- is inlined. - mkScriptWitness plutusV2Script InlineScriptDatum redeemer - Just d -> - mkScriptWitness plutusV2Script (ScriptDatumForTxIn d) redeemer - -- | Handle request to submit a cardano transaction. handleSubmitUserTx :: + forall tx. + FromJSON tx => Chain tx IO -> -- | Request body. LBS.ByteString -> IO Response handleSubmitUserTx directChain body = do - case Aeson.eitherDecode' body :: Either String Tx of + case Aeson.eitherDecode' body of Left err -> pure $ responseLBS status400 [] (Aeson.encode $ Aeson.String $ pack err) Right txToSubmit -> do diff --git a/hydra-node/src/Hydra/API/Server.hs b/hydra-node/src/Hydra/API/Server.hs index 98722823e5a..96e02f7dc1e 100644 --- a/hydra-node/src/Hydra/API/Server.hs +++ b/hydra-node/src/Hydra/API/Server.hs @@ -23,21 +23,21 @@ import Hydra.API.ServerOutput ( ) import Hydra.API.WSServer (nextSequenceNumber, wsApp) import Hydra.Cardano.Api (LedgerEra) -import Hydra.Chain ( - Chain (..), - IsChainState, - ) +import Hydra.Chain (Chain (..), IsChainState) import Hydra.Chain.Direct.State () import Hydra.Logging (Tracer, traceWith) import Hydra.Network (IP, PortNumber) import Hydra.Party (Party) import Hydra.Persistence (PersistenceIncremental (..)) +import Network.HTTP.Types (status500) +import Network.Wai (responseLBS) import Network.Wai.Handler.Warp ( defaultSettings, runSettings, setBeforeMainLoop, setHost, setOnException, + setOnExceptionResponse, setPort, ) import Network.Wai.Handler.WebSockets (websocketsOr) @@ -88,6 +88,7 @@ withAPIServer host port party PersistenceIncremental{loadAll, append} tracer cha & setHost (fromString $ show host) & setPort (fromIntegral port) & setOnException (\_ e -> traceWith tracer $ APIConnectionError{reason = show e}) + & setOnExceptionResponse (responseLBS status500 [] . show) & setBeforeMainLoop notifyServerRunning race_ ( do diff --git a/hydra-node/src/Hydra/Chain.hs b/hydra-node/src/Hydra/Chain.hs index 5bfaf07f3ed..f6983e98b94 100644 --- a/hydra-node/src/Hydra/Chain.hs +++ b/hydra-node/src/Hydra/Chain.hs @@ -19,12 +19,6 @@ import Hydra.Cardano.Api ( Address, ByronAddr, Coin (..), - CtxUTxO, - Tx, - TxOut, - UTxO', - WitCtxTxIn, - Witness, ) import Hydra.ContestationPeriod (ContestationPeriod) import Hydra.Environment (Environment (..)) @@ -137,8 +131,6 @@ data PostTxError tx | CannotFindOwnInitial {knownUTxO :: UTxOType tx} | -- | Comitting byron addresses is not supported. UnsupportedLegacyOutput {byronAddress :: Address ByronAddr} - | -- | Comitting reference scripts is not supported right now. - CannotCommitReferenceScript | InvalidStateToPost {txTried :: PostChainTx tx, chainState :: ChainStateType tx} | NotEnoughFuel | NoFuelUTXOFound @@ -234,6 +226,11 @@ class -- encountered, we assume monotonically increasing slots. chainStateSlot :: ChainStateType tx -> ChainSlot +-- | _Blueprint/Draft_ transaction paired with the 'UTxO' which resolves it's inputs. +-- The transaction inputs are committed to a `Head` and the 'lookupUTxO' is expected +-- to contain these inputs. +data CommitBlueprintTx tx = CommitBlueprintTx {lookupUTxO :: UTxOType tx, blueprintTx :: tx} + -- | Handle to interface with the main chain network data Chain tx m = Chain { postTx :: MonadThrow m => PostChainTx tx -> m () @@ -247,11 +244,12 @@ data Chain tx m = Chain , draftCommitTx :: MonadThrow m => HeadId -> - UTxO' (TxOut CtxUTxO, Witness WitCtxTxIn) -> - m (Either (PostTxError Tx) Tx) + CommitBlueprintTx tx -> + m (Either (PostTxError tx) tx) -- ^ Create a commit transaction using user provided utxos (zero or many) and - -- information to spend from a script. Errors are handled at the call site. - , submitTx :: MonadThrow m => Tx -> m () + -- a _blueprint_ transaction which spends these outputs. + -- Errors are handled at the call site. + , submitTx :: MonadThrow m => tx -> m () -- ^ Submit a cardano transaction. -- -- Throws at least 'PostTxError'. diff --git a/hydra-node/src/Hydra/Chain/Direct/Handlers.hs b/hydra-node/src/Hydra/Chain/Direct/Handlers.hs index 13962ba0dcf..67a8fe1dd58 100644 --- a/hydra-node/src/Hydra/Chain/Direct/Handlers.hs +++ b/hydra-node/src/Hydra/Chain/Direct/Handlers.hs @@ -14,7 +14,6 @@ import Cardano.Slotting.Slot (SlotNo (..)) import Control.Concurrent.Class.MonadSTM (modifyTVar, newTVarIO, writeTVar) import Control.Monad.Class.MonadSTM (throwSTM) import Data.Map.Strict qualified as Map -import Data.Set qualified as Set import Hydra.Cardano.Api ( BlockHeader, ChainPoint (..), @@ -25,6 +24,7 @@ import Hydra.Cardano.Api ( getChainPoint, getTxBody, getTxId, + txIns', ) import Hydra.Chain ( Chain (..), @@ -32,6 +32,7 @@ import Hydra.Chain ( ChainEvent (..), ChainStateHistory, ChainStateType, + CommitBlueprintTx (..), HeadParameters (..), IsChainState, OnChainTx (..), @@ -157,19 +158,20 @@ mkChain tracer queryTimeHandle wallet@TinyWallet{getUTxO} ctx LocalChainState{ge atomically (prepareTxToPost timeHandle wallet ctx spendableUTxO tx) >>= finalizeTx wallet ctx spendableUTxO mempty submitTx vtx - , -- Handle that creates a draft commit tx using the user utxo. + , -- Handle that creates a draft commit tx using the user utxo and a _blueprint_ transaction. -- Possible errors are handled at the api server level. - draftCommitTx = \headId utxoToCommit -> do + draftCommitTx = \headId commitBlueprintTx -> do ChainStateAt{spendableUTxO} <- atomically getLatest walletUtxos <- atomically getUTxO let walletTxIns = fromLedgerTxIn <$> Map.keys walletUtxos - let userTxIns = Set.toList $ UTxO.inputSet utxoToCommit + let CommitBlueprintTx{lookupUTxO, blueprintTx} = commitBlueprintTx + let userTxIns = txIns' blueprintTx let matchedWalletUtxo = filter (`elem` walletTxIns) userTxIns -- prevent trying to spend internal wallet's utxo if null matchedWalletUtxo then - traverse (finalizeTx wallet ctx spendableUTxO (fst <$> utxoToCommit)) $ - commit' ctx headId spendableUTxO utxoToCommit + traverse (finalizeTx wallet ctx spendableUTxO lookupUTxO) $ + commit' ctx headId spendableUTxO commitBlueprintTx else pure $ Left SpendingNodeUtxoForbidden , -- Submit a cardano transaction to the cardano-node using the -- LocalTxSubmission protocol. @@ -200,7 +202,7 @@ finalizeTx TinyWallet{sign, coverFee} ctx utxo userUTxO partialTx = do } :: PostTxError Tx ) - Left e -> do + Left e -> throwIO ( InternalWalletError { headUTxO diff --git a/hydra-node/src/Hydra/Chain/Direct/State.hs b/hydra-node/src/Hydra/Chain/Direct/State.hs index adb8e4ec275..8eaab18335d 100644 --- a/hydra-node/src/Hydra/Chain/Direct/State.hs +++ b/hydra-node/src/Hydra/Chain/Direct/State.hs @@ -18,7 +18,6 @@ import Hydra.Cardano.Api ( ChainPoint (..), CtxUTxO, Key (SigningKey, VerificationKey, verificationKeyHash), - KeyWitnessInCtx (..), NetworkId (Mainnet, Testnet), NetworkMagic (NetworkMagic), PaymentKey, @@ -32,8 +31,6 @@ import Hydra.Cardano.Api ( TxOut, UTxO, UTxO' (UTxO), - WitCtxTxIn, - Witness, chainPointToSlotNo, fromPlutusScript, fromScriptData, @@ -44,20 +41,18 @@ import Hydra.Cardano.Api ( selectLovelace, toTxContext, txIns', - txOutReferenceScript, txOutScriptData, txOutValue, + txSpendingUTxO, valueFromList, valueToList, pattern ByronAddressInEra, - pattern KeyWitness, - pattern ReferenceScript, - pattern ReferenceScriptNone, pattern ShelleyAddressInEra, pattern TxOut, ) import Hydra.Chain ( ChainStateType, + CommitBlueprintTx (..), HeadParameters (..), IsChainState (..), OnChainTx (..), @@ -226,7 +221,7 @@ instance Arbitrary ChainContext where arbitrary = do networkId <- Testnet . NetworkMagic <$> arbitrary ownVerificationKey <- genVerificationKey - otherParties <- arbitrary + otherParties <- choose (1, maximumNumberOfParties) >>= \n -> replicateM n arbitrary ownParty <- elements otherParties scriptRegistry <- genScriptRegistry pure @@ -343,14 +338,15 @@ commit :: HeadId -> -- | Spendable 'UTxO' UTxO -> - -- | 'UTxO' to commit. All outputs are assumed to be owned by public keys. + -- | 'UTxO' to commit. All outputs are assumed to be owned by public keys UTxO -> Either (PostTxError Tx) Tx -commit ctx headId spendableUTxO utxoToCommit = - commit' ctx headId spendableUTxO $ utxoToCommit <&> (,KeyWitness KeyWitnessForSpending) +commit ctx headId spendableUTxO lookupUTxO = + let blueprintTx = txSpendingUTxO lookupUTxO + in commit' ctx headId spendableUTxO CommitBlueprintTx{lookupUTxO, blueprintTx} -- | Construct a commit transaction based on known, spendable UTxO and some --- arbitrary UTxOs to commit. This does look for "our initial output" to spend +-- user UTxO inputs to commit. This does look for "our initial output" to spend -- and check the given 'UTxO' to be compatible. Hence, this function does fail -- if already committed or if the head is not initializing. -- @@ -360,18 +356,17 @@ commit' :: HeadId -> -- | Spendable 'UTxO' UTxO -> - -- | 'UTxO' to commit, along with witnesses to spend them. - UTxO' (TxOut CtxUTxO, Witness WitCtxTxIn) -> + CommitBlueprintTx Tx -> Either (PostTxError Tx) Tx -commit' ctx headId spendableUTxO utxoToCommit = do +commit' ctx headId spendableUTxO commitBlueprintTx = do pid <- headIdToPolicyId headId ?> InvalidHeadId{headId} (i, o) <- ownInitial pid ?> CannotFindOwnInitial{knownUTxO = spendableUTxO} - let utxo = fst <$> utxoToCommit - rejectByronAddress utxo - rejectReferenceScripts utxo - rejectMoreThanMainnetLimit networkId utxo - pure $ commitTx networkId scriptRegistry headId ownParty utxoToCommit (i, o, vkh) + rejectByronAddress lookupUTxO + rejectMoreThanMainnetLimit networkId lookupUTxO + pure $ commitTx networkId scriptRegistry headId ownParty commitBlueprintTx (i, o, vkh) where + CommitBlueprintTx{lookupUTxO} = commitBlueprintTx + ChainContext{networkId, ownParty, scriptRegistry, ownVerificationKey} = ctx vkh = verificationKeyHash ownVerificationKey @@ -390,16 +385,6 @@ rejectByronAddress u = do (TxOut ShelleyAddressInEra{} _ _ _) -> Right () -rejectReferenceScripts :: UTxO -> Either (PostTxError Tx) () -rejectReferenceScripts u = - when (any hasReferenceScript u) $ - Left CannotCommitReferenceScript - where - hasReferenceScript out = - case txOutReferenceScript out of - ReferenceScript{} -> True - ReferenceScriptNone -> False - -- Rejects outputs with more than 'maxMainnetLovelace' lovelace on mainnet -- NOTE: Remove this limit once we have more experiments on mainnet. rejectMoreThanMainnetLimit :: NetworkId -> UTxO -> Either (PostTxError Tx) () diff --git a/hydra-node/src/Hydra/Chain/Direct/Tx.hs b/hydra-node/src/Hydra/Chain/Direct/Tx.hs index 59e073a05fb..dbdb3de0ace 100644 --- a/hydra-node/src/Hydra/Chain/Direct/Tx.hs +++ b/hydra-node/src/Hydra/Chain/Direct/Tx.hs @@ -13,12 +13,36 @@ import Hydra.Cardano.Api import Hydra.Prelude import Cardano.Api.UTxO qualified as UTxO +import Cardano.Ledger.Alonzo.Scripts (ExUnits (..)) +import Cardano.Ledger.Alonzo.TxAuxData (AlonzoTxAuxData (..), hashAlonzoTxAuxData) +import Cardano.Ledger.Api ( + AlonzoPlutusPurpose (..), + AsIndex (..), + Redeemers (..), + auxDataHashTxBodyL, + auxDataTxL, + bodyTxL, + inputsTxBodyL, + mintTxBodyL, + mkAlonzoTxAuxData, + outputsTxBodyL, + rdmrsTxWitsL, + referenceInputsTxBodyL, + reqSignerHashesTxBodyL, + unRedeemers, + witsTxL, + ) +import Cardano.Ledger.BaseTypes (StrictMaybe (..)) +import Control.Lens ((.~), (<>~), (^.)) import Data.Aeson qualified as Aeson import Data.ByteString qualified as BS import Data.ByteString.Base16 qualified as Base16 import Data.Map qualified as Map +import Data.Sequence.Strict qualified as StrictSeq +import Data.Set qualified as Set import Hydra.Cardano.Api.Network (networkIdToNetwork) -import Hydra.Chain (HeadParameters (..)) +import Hydra.Cardano.Api.Prelude (toShelleyMetadata) +import Hydra.Chain (CommitBlueprintTx (..), HeadParameters (..)) import Hydra.Chain.Direct.ScriptRegistry (ScriptRegistry (..)) import Hydra.Chain.Direct.TimeHandle (PointInTime) import Hydra.ContestationPeriod (ContestationPeriod, fromChain, toChain) @@ -217,39 +241,80 @@ commitTx :: ScriptRegistry -> HeadId -> Party -> - -- | The UTxO to commit to the Head along with witnesses. - UTxO' (TxOut CtxUTxO, Witness WitCtxTxIn) -> + CommitBlueprintTx Tx -> -- | The initial output (sent to each party) which should contain the PT and is -- locked by initial script (TxIn, TxOut CtxUTxO, Hash PaymentKey) -> Tx -commitTx networkId scriptRegistry headId party utxoToCommitWitnessed (initialInput, out, vkh) = - unsafeBuildTransaction $ - emptyTxBody - & addInputs [(initialInput, initialWitness)] - & addReferenceInputs [initialScriptRef] - & addInputs committedTxIns - & addExtraRequiredSigners [vkh] - & addOutputs [commitOutput] - & setTxMetadata (TxMetadataInEra $ mkHydraHeadV1TxName "CommitTx") +commitTx networkId scriptRegistry headId party commitBlueprintTx (initialInput, out, vkh) = + let + ledgerBlueprintTx = + toLedgerTx blueprintTx + & bodyTxL . inputsTxBodyL <>~ Set.singleton (toLedgerTxIn initialInput) + & bodyTxL . referenceInputsTxBodyL <>~ Set.fromList [toLedgerTxIn initialScriptRef] + & bodyTxL . outputsTxBodyL .~ StrictSeq.singleton (toLedgerTxOut commitOutput) + & bodyTxL . reqSignerHashesTxBodyL <>~ Set.singleton (toLedgerKeyHash vkh) + & bodyTxL . auxDataHashTxBodyL .~ SJust (hashAlonzoTxAuxData txAuxMetadata) + & bodyTxL . mintTxBodyL .~ mempty + & auxDataTxL .~ addMetadata txAuxMetadata + existingWits = toLedgerTx blueprintTx ^. witsTxL + allInputs = ledgerBlueprintTx ^. bodyTxL . inputsTxBodyL + blueprintRedeemers = unRedeemers $ toLedgerTx blueprintTx ^. witsTxL . rdmrsTxWitsL + resolved = resolveRedeemers blueprintRedeemers committedTxIns + wits = + witsTxL + .~ ( existingWits + & rdmrsTxWitsL .~ Redeemers (Map.fromList $ reassociate resolved allInputs) + ) + in + fromLedgerTx $ ledgerBlueprintTx & wits where - initialWitness = - BuildTxWith $ - ScriptWitness scriptWitnessInCtx $ - mkScriptReference initialScriptRef initialScript InlineScriptDatum initialRedeemer + addMetadata newMetadata@(AlonzoTxAuxData metadata' _ _) = + case toLedgerTx blueprintTx ^. auxDataTxL of + SNothing -> SJust newMetadata + SJust (AlonzoTxAuxData metadata timeLocks languageMap) -> + SJust $ + AlonzoTxAuxData + (Map.union metadata metadata') + timeLocks + languageMap + + -- re-associates final commit tx inputs with the redeemer data from blueprint tx + reassociate resolved allInputs = + foldl' + ( \newRedeemerData txin -> + let key = mkSpendingKey $ Set.findIndex txin allInputs + in case find (\(txin', _) -> txin == txin') resolved of + Nothing -> newRedeemerData + Just (_, d) -> + (key, d) : newRedeemerData + ) + [] + allInputs + + -- Creates a list of 'TxIn' paired with redeemer data and also adds the initial txIn and it's redeemer. + resolveRedeemers existingRedeemerMap blueprintInputs = + (toLedgerTxIn initialInput, (toLedgerData @LedgerEra initialRedeemer, ExUnits 0 0)) + : foldl' + ( \pairs txin -> + let key = mkSpendingKey $ Set.findIndex txin blueprintInputs + in case Map.lookup key existingRedeemerMap of + Nothing -> pairs + Just d -> (txin, d) : pairs + ) + [] + committedTxIns - initialScript = - fromPlutusScript @PlutusScriptV2 Initial.validatorScript + mkSpendingKey i = AlonzoSpending (AsIndex $ fromIntegral i) initialScriptRef = fst (initialReference scriptRegistry) initialRedeemer = toScriptData . Initial.redeemer $ - Initial.ViaCommit (toPlutusTxOutRef . fst <$> committedTxIns) + Initial.ViaCommit (toPlutusTxOutRef . fromLedgerTxIn <$> Set.toList committedTxIns) - committedTxIns = - map (\(i, (_, w)) -> (i, BuildTxWith w)) $ UTxO.pairs utxoToCommitWitnessed + committedTxIns = toLedgerTx blueprintTx ^. bodyTxL . inputsTxBodyL commitOutput = TxOut commitAddress commitValue commitDatum ReferenceScriptNone @@ -260,13 +325,19 @@ commitTx networkId scriptRegistry headId party utxoToCommitWitnessed (initialInp commitAddress = mkScriptAddress @PlutusScriptV2 networkId commitScript + utxoToCommit = + UTxO.fromPairs $ mapMaybe (\txin -> (txin,) <$> UTxO.resolve txin lookupUTxO) (txIns' blueprintTx) + commitValue = txOutValue out <> foldMap txOutValue utxoToCommit commitDatum = mkTxOutDatumInline $ mkCommitDatum party utxoToCommit (headIdToCurrencySymbol headId) - utxoToCommit = fst <$> utxoToCommitWitnessed + TxMetadata metadataMap = mkHydraHeadV1TxName "CommitTx" + + txAuxMetadata = mkAlonzoTxAuxData @[] @LedgerEra (toShelleyMetadata metadataMap) [] + CommitBlueprintTx{lookupUTxO, blueprintTx} = commitBlueprintTx mkCommitDatum :: Party -> UTxO -> CurrencySymbol -> Plutus.Datum mkCommitDatum party utxo headId = diff --git a/hydra-node/src/Hydra/Ledger.hs b/hydra-node/src/Hydra/Ledger.hs index 9aca27ad15a..82549c154d6 100644 --- a/hydra-node/src/Hydra/Ledger.hs +++ b/hydra-node/src/Hydra/Ledger.hs @@ -52,6 +52,8 @@ class -- | Hash a utxo set to be able to sign (off-chain) and verify it (on-chain). hashUTxO :: UTxOType tx -> ByteString + txSpendingUTxO :: UTxOType tx -> tx + -- | A generic description for a chain slot all implementions need to use. newtype ChainSlot = ChainSlot Natural deriving stock (Ord, Eq, Show, Generic) diff --git a/hydra-node/src/Hydra/Ledger/Cardano.hs b/hydra-node/src/Hydra/Ledger/Cardano.hs index fe9600895da..2f72883b481 100644 --- a/hydra-node/src/Hydra/Ledger/Cardano.hs +++ b/hydra-node/src/Hydra/Ledger/Cardano.hs @@ -15,7 +15,9 @@ import Hydra.Ledger.Cardano.Builder import Cardano.Api.UTxO (fromPairs, pairs) import Cardano.Api.UTxO qualified as UTxO import Cardano.Crypto.DSIGN qualified as CC -import Cardano.Ledger.Api (updateTxBodyL) +import Cardano.Ledger.Api ( + updateTxBodyL, + ) import Cardano.Ledger.Babbage.Tx qualified as Ledger import Cardano.Ledger.BaseTypes (StrictMaybe (..)) import Cardano.Ledger.BaseTypes qualified as Ledger @@ -115,6 +117,8 @@ instance IsTx Tx where -- NOTE: See note from `Head.hashTxOuts`. hashUTxO = fromBuiltin . Head.hashTxOuts . mapMaybe toPlutusTxOut . toList + txSpendingUTxO = Hydra.Cardano.Api.txSpendingUTxO + instance ToCBOR Tx where toCBOR = CBOR.encodeBytes . serialize' ledgerEraVersion . toLedgerTx @@ -365,7 +369,6 @@ genTxOut = [ fromLedgerTxOut <$> arbitrary , notMultiAsset . fromLedgerTxOut <$> arbitrary ] - notMultiAsset = modifyTxOutValue (lovelaceToValue . selectLovelace) diff --git a/hydra-node/src/Hydra/Ledger/Cardano/Evaluate.hs b/hydra-node/src/Hydra/Ledger/Cardano/Evaluate.hs index bdda104630f..486e6e19bdb 100644 --- a/hydra-node/src/Hydra/Ledger/Cardano/Evaluate.hs +++ b/hydra-node/src/Hydra/Ledger/Cardano/Evaluate.hs @@ -59,6 +59,7 @@ import Hydra.Cardano.Api ( toLedgerTx, toLedgerUTxO, ) +import Hydra.Cardano.Api.Pretty (renderTxWithUTxO) import Hydra.ContestationPeriod (ContestationPeriod (UnsafeContestationPeriod)) import Hydra.Ledger.Cardano.Time (slotNoFromUTCTime, slotNoToUTCTime) import Ouroboros.Consensus.Cardano.Block (CardanoEras) @@ -75,7 +76,7 @@ import Ouroboros.Consensus.HardFork.History ( import PlutusCore qualified as PLC import PlutusLedgerApi.Common (mkTermToEvaluate) import PlutusLedgerApi.Common qualified as Plutus -import Test.QuickCheck (choose) +import Test.QuickCheck (Property, choose, counterexample, property) import Test.QuickCheck.Gen (chooseWord64) import UntypedPlutusCore (UnrestrictedProgram (..)) import UntypedPlutusCore qualified as UPLC @@ -351,6 +352,35 @@ slotLength = mkSlotLength 1 systemStart :: SystemStart systemStart = SystemStart $ posixSecondsToUTCTime 0 +-- * Properties + +-- | Expect a given 'Tx' and 'UTxO' to pass evaluation. +propTransactionEvaluates :: (Tx, UTxO) -> Property +propTransactionEvaluates (tx, lookupUTxO) = + case evaluateTx tx lookupUTxO of + Left err -> + property False + & counterexample ("Transaction: " <> renderTxWithUTxO lookupUTxO tx) + & counterexample ("Phase-1 validation failed: " <> show err) + Right redeemerReport -> + all isRight (Map.elems redeemerReport) + & counterexample ("Transaction: " <> renderTxWithUTxO lookupUTxO tx) + & counterexample ("Redeemer report: " <> show redeemerReport) + & counterexample "Phase-2 validation failed" + +-- | Expect a given 'Tx' and 'UTxO' to fail phase 1 or phase 2 evaluation. +propTransactionFailsEvaluation :: (Tx, UTxO) -> Property +propTransactionFailsEvaluation (tx, lookupUTxO) = + case evaluateTx tx lookupUTxO of + Left _ -> property True + Right redeemerReport -> + any isLeft redeemerReport + & counterexample ("Transaction: " <> renderTxWithUTxO lookupUTxO tx) + & counterexample ("Redeemer report: " <> show redeemerReport) + & counterexample "Phase-2 validation should have failed" + +-- * Generators + genPointInTime :: Gen (SlotNo, UTCTime) genPointInTime = do slot <- SlotNo <$> arbitrary diff --git a/hydra-node/src/Hydra/Ledger/Simple.hs b/hydra-node/src/Hydra/Ledger/Simple.hs index dd7eef8c52d..853e5c3ff61 100644 --- a/hydra-node/src/Hydra/Ledger/Simple.hs +++ b/hydra-node/src/Hydra/Ledger/Simple.hs @@ -53,6 +53,13 @@ instance IsTx SimpleTx where balance = Set.size hashUTxO = toStrict . foldMap (serialise . unSimpleTxIn) + txSpendingUTxO utxo = + SimpleTx + { txSimpleId = 0 + , txInputs = utxo + , txOutputs = mempty + } + instance Arbitrary SimpleTx where shrink = genericShrink arbitrary = genericArbitrary diff --git a/hydra-node/test/Hydra/API/HTTPServerSpec.hs b/hydra-node/test/Hydra/API/HTTPServerSpec.hs index 3dd41a8f27d..95be609ad9b 100644 --- a/hydra-node/test/Hydra/API/HTTPServerSpec.hs +++ b/hydra-node/test/Hydra/API/HTTPServerSpec.hs @@ -4,10 +4,16 @@ import Hydra.Prelude hiding (get) import Test.Hydra.Prelude import Data.Aeson (Result (Error, Success), eitherDecode, encode, fromJSON) +import Data.Aeson qualified as Aeson import Data.Aeson.Lens (key, nth) -import Hydra.API.HTTPServer (DraftCommitTxRequest, DraftCommitTxResponse, SubmitTxRequest (..), TransactionSubmitted, httpApp) +import Hydra.API.HTTPServer (DraftCommitTxRequest (..), DraftCommitTxResponse (..), SubmitTxRequest (..), TransactionSubmitted, httpApp) import Hydra.API.ServerSpec (dummyChainHandle) -import Hydra.Cardano.Api (fromLedgerPParams, serialiseToTextEnvelope, shelleyBasedEra) +import Hydra.Cardano.Api ( + fromLedgerPParams, + serialiseToTextEnvelope, + shelleyBasedEra, + ) +import Hydra.Chain (Chain (draftCommitTx), PostTxError (..)) import Hydra.Chain.Direct.Fixture (defaultPParams) import Hydra.JSONSchema (SchemaSelector, prop_validateJSONSchema, validateJSON, withJsonSpecifications) import Hydra.Ledger (UTxOType) @@ -17,24 +23,32 @@ import Hydra.Logging (nullTracer) import System.FilePath (()) import System.IO.Unsafe (unsafePerformIO) import Test.Aeson.GenericSpecs (roundtripAndGoldenSpecs) -import Test.Hspec.Wai (MatchBody (..), ResponseMatcher (matchBody), get, shouldRespondWith, with) +import Test.Hspec.Wai (MatchBody (..), ResponseMatcher (matchBody), get, post, shouldRespondWith, with) import Test.Hspec.Wai.Internal (withApplication) -import Test.QuickCheck.Property (counterexample, cover, forAll, property, withMaxSuccess) +import Test.QuickCheck ( + checkCoverage, + counterexample, + cover, + forAll, + generate, + property, + withMaxSuccess, + ) spec :: Spec spec = do parallel $ do - roundtripAndGoldenSpecs (Proxy @(ReasonablySized DraftCommitTxResponse)) - roundtripAndGoldenSpecs (Proxy @(ReasonablySized DraftCommitTxRequest)) + roundtripAndGoldenSpecs (Proxy @(ReasonablySized (DraftCommitTxResponse Tx))) + roundtripAndGoldenSpecs (Proxy @(ReasonablySized (DraftCommitTxRequest Tx))) roundtripAndGoldenSpecs (Proxy @(ReasonablySized (SubmitTxRequest Tx))) roundtripAndGoldenSpecs (Proxy @(ReasonablySized TransactionSubmitted)) prop "Validate /commit publish api schema" $ - prop_validateJSONSchema @DraftCommitTxRequest "api.json" $ + prop_validateJSONSchema @(DraftCommitTxRequest Tx) "api.json" $ key "components" . key "messages" . key "DraftCommitTxRequest" . key "payload" prop "Validate /commit subscribe api schema" $ - prop_validateJSONSchema @DraftCommitTxResponse "api.json" $ + prop_validateJSONSchema @(DraftCommitTxResponse Tx) "api.json" $ key "components" . key "messages" . key "DraftCommitTxResponse" . key "payload" prop "Validate /cardano-transaction publish api schema" $ @@ -70,7 +84,6 @@ spec = do Success{} -> property True Error e -> counterexample (toString $ toText e) $ property False --- TODO: we should add more tests for other routes here (eg. /commit) apiServerSpec :: Spec apiServerSpec = do describe "API should respond correctly" $ do @@ -87,7 +100,6 @@ apiServerSpec = do (schemaDir "api.json") (key "components" . key "messages" . key "ProtocolParameters" . key "payload") } - it "responds given parameters" $ get "/protocol-parameters" `shouldRespondWith` 200 @@ -119,6 +131,43 @@ apiServerSpec = do (key "channels" . key "/snapshot/utxo" . key "subscribe" . key "message" . key "payload") } + describe "POST /commit" $ do + let getHeadId = pure $ Just (generateWith arbitrary 42) + let workingChainHandle = + dummyChainHandle + { draftCommitTx = \_ _ -> do + tx <- generate $ arbitrary @Tx + pure $ Right tx + } + prop "responds on valid requests" $ \(request :: DraftCommitTxRequest Tx) -> + withApplication (httpApp nullTracer workingChainHandle defaultPParams getHeadId getNothing) $ do + post "/commit" (Aeson.encode request) + `shouldRespondWith` 200 + + let failingChainHandle postTxError = + dummyChainHandle + { draftCommitTx = \_ _ -> pure $ Left postTxError + } + prop "handles PostTxErrors accordingly" $ \request postTxError -> do + let expectedResponse = + case postTxError of + SpendingNodeUtxoForbidden -> 400 + CommittedTooMuchADAForMainnet{} -> 400 + UnsupportedLegacyOutput{} -> 400 + _ -> 500 + let coverage = case postTxError of + SpendingNodeUtxoForbidden -> cover 1 True "SpendingNodeUtxoForbidden" + CommittedTooMuchADAForMainnet{} -> cover 1 True "CommittedTooMuchADAForMainnet" + UnsupportedLegacyOutput{} -> cover 1 True "UnsupportedLegacyOutput" + InvalidHeadId{} -> cover 1 True "InvalidHeadId" + CannotFindOwnInitial{} -> cover 1 True "CannotFindOwnInitial" + _ -> property + checkCoverage $ + coverage $ + withApplication (httpApp @Tx nullTracer (failingChainHandle postTxError) defaultPParams getHeadId getNothing) $ do + post "/commit" (Aeson.encode (request :: DraftCommitTxRequest Tx)) + `shouldRespondWith` expectedResponse + -- * Helpers -- | Create a 'ResponseMatcher' or 'MatchBody' from a JSON serializable value diff --git a/hydra-node/test/Hydra/API/ServerSpec.hs b/hydra-node/test/Hydra/API/ServerSpec.hs index d7ae7d4962e..ee46145c658 100644 --- a/hydra-node/test/Hydra/API/ServerSpec.hs +++ b/hydra-node/test/Hydra/API/ServerSpec.hs @@ -33,7 +33,7 @@ import Hydra.Chain ( submitTx, ) import Hydra.Chain.Direct.Fixture (defaultPParams) -import Hydra.Ledger.Simple (SimpleTx (..)) +import Hydra.Ledger.Simple (SimpleTx) import Hydra.Logging (Tracer, showLogsOnFailure) import Hydra.Network (PortNumber) import Hydra.Options qualified as Options @@ -157,7 +157,7 @@ spec = withTestAPIServer port alice mockPersistence tracer $ \Server{sendOutput} -> do mapM_ sendOutput outputs withClient port "/" $ \conn -> do - received <- failAfter 5 $ replicateM (length outputs + 1) (receiveData conn) + received <- failAfter 10 $ replicateM (length outputs + 1) (receiveData conn) case traverse Aeson.eitherDecode received of Left{} -> failure $ "Failed to decode messages:\n" <> show received Right timedOutputs -> do diff --git a/hydra-node/test/Hydra/Chain/Direct/Contract/Commit.hs b/hydra-node/test/Hydra/Chain/Direct/Contract/Commit.hs index 27d241bf290..c4680a4fda9 100644 --- a/hydra-node/test/Hydra/Chain/Direct/Contract/Commit.hs +++ b/hydra-node/test/Hydra/Chain/Direct/Contract/Commit.hs @@ -5,15 +5,13 @@ module Hydra.Chain.Direct.Contract.Commit where import Hydra.Cardano.Api import Hydra.Prelude --- Arbitrary VerificationKey instance -import Hydra.Chain.Direct.TxSpec () - import Cardano.Api.UTxO qualified as UTxO import Cardano.Ledger.Api (bodyTxL) import Cardano.Ledger.Api.Tx.Body (EraTxBody (outputsTxBodyL), setMinCoinTxOut) import Control.Lens (mapped, (%~)) import Data.List qualified as List import Data.Maybe (fromJust) +import Hydra.Chain (CommitBlueprintTx (..)) import Hydra.Chain.Direct.Contract.Gen (genMintedOrBurnedValue) import Hydra.Chain.Direct.Contract.Mutation ( Mutation (..), @@ -32,6 +30,7 @@ import Hydra.Contract.Initial qualified as Initial import Hydra.Contract.InitialError (InitialError (..)) import Hydra.Ledger.Cardano ( genAddressInEra, + genSigningKey, genUTxOAdaOnlyOfSize, genValue, genVerificationKey, @@ -48,7 +47,7 @@ healthyCommitTx = (tx', lookupUTxO) where lookupUTxO = - UTxO.singleton (healthyIntialTxIn, toUTxOContext healthyInitialTxOut) + UTxO.singleton (healthyInitialTxIn, toUTxOContext healthyInitialTxOut) <> healthyCommittedUTxO <> registryUTxO scriptRegistry @@ -57,14 +56,16 @@ healthyCommitTx = setOutputsMinValue = bodyTxL . outputsTxBodyL . mapped %~ setMinCoinTxOut Fixture.pparams + blueprintTx = txSpendingUTxO healthyCommittedUTxO + tx = commitTx Fixture.testNetworkId scriptRegistry (mkHeadId Fixture.testPolicyId) commitParty - (healthyCommittedUTxO <&> (,KeyWitness KeyWitnessForSpending)) - (healthyIntialTxIn, toUTxOContext healthyInitialTxOut, initialPubKeyHash) + CommitBlueprintTx{lookupUTxO = healthyCommittedUTxO, blueprintTx} + (healthyInitialTxIn, toUTxOContext healthyInitialTxOut, initialPubKeyHash) scriptRegistry = genScriptRegistry `generateWith` 42 @@ -73,11 +74,14 @@ healthyCommitTx = commitParty :: Party commitParty = generateWith arbitrary 42 +commitSigningKey :: SigningKey PaymentKey +commitSigningKey = genSigningKey `generateWith` 42 + commitVerificationKey :: VerificationKey PaymentKey -commitVerificationKey = generateWith arbitrary 42 +commitVerificationKey = getVerificationKey commitSigningKey -healthyIntialTxIn :: TxIn -healthyIntialTxIn = generateWith arbitrary 42 +healthyInitialTxIn :: TxIn +healthyInitialTxIn = generateWith arbitrary 42 healthyInitialTxOut :: TxOut CtxTx healthyInitialTxOut = @@ -122,7 +126,7 @@ genCommitMutation :: (Tx, UTxO) -> Gen SomeMutation genCommitMutation (tx, _utxo) = oneof [ SomeMutation (Just $ toErrorCode WrongHeadIdInCommitDatum) NonContinuousHeadId <$> do - otherHeadId <- fmap headPolicyId (arbitrary `suchThat` (/= healthyIntialTxIn)) + otherHeadId <- fmap headPolicyId (arbitrary `suchThat` (/= healthyInitialTxIn)) let mutateHeadId = modifyInlineDatum $ \((party, mCommit, _headId) :: Commit.DatumType) -> @@ -148,7 +152,7 @@ genCommitMutation (tx, _utxo) = [ RemoveInput removedTxIn , ChangeOutput 0 mutatedCommitTxOut , ChangeInput - healthyIntialTxIn + healthyInitialTxIn (toUTxOContext healthyInitialTxOut) (Just $ toScriptData $ Initial.ViaCommit (removedTxIn `List.delete` allComittedTxIn <&> toPlutusTxOutRef)) ] @@ -158,12 +162,12 @@ genCommitMutation (tx, _utxo) = , -- XXX: This is a bit confusing and not giving much value. Maybe we can remove this. -- This also seems to be covered by MutateRequiredSigner SomeMutation (Just $ toErrorCode CouldNotFindTheCorrectCurrencySymbolInTokens) UsePTFromDifferentHead <$> do - otherHeadId <- fmap headPolicyId (arbitrary `suchThat` (/= healthyIntialTxIn)) + otherHeadId <- fmap headPolicyId (arbitrary `suchThat` (/= healthyInitialTxIn)) pure $ Changes [ ChangeOutput 0 (replacePolicyIdWith Fixture.testPolicyId otherHeadId commitTxOut) , ChangeInput - healthyIntialTxIn + healthyInitialTxIn (toUTxOContext $ replacePolicyIdWith Fixture.testPolicyId otherHeadId healthyInitialTxOut) (Just $ toScriptData $ Initial.ViaCommit (allComittedTxIn <&> toPlutusTxOutRef)) ] diff --git a/hydra-node/test/Hydra/Chain/Direct/Contract/Mutation.hs b/hydra-node/test/Hydra/Chain/Direct/Contract/Mutation.hs index 91351ff5b15..f00ec309a73 100644 --- a/hydra-node/test/Hydra/Chain/Direct/Contract/Mutation.hs +++ b/hydra-node/test/Hydra/Chain/Direct/Contract/Mutation.hs @@ -213,31 +213,6 @@ propTransactionFailsPhase2 mExpectedError (tx, lookupUTxO) = ScriptErrorEvaluationFailed _ errList -> errMsg `elem` errList _otherScriptExecutionError -> False --- | Expect a given 'Tx' and 'UTxO' to pass evaluation. -propTransactionEvaluates :: (Tx, UTxO) -> Property -propTransactionEvaluates (tx, lookupUTxO) = - case evaluateTx tx lookupUTxO of - Left err -> - property False - & counterexample ("Transaction: " <> renderTxWithUTxO lookupUTxO tx) - & counterexample ("Phase-1 validation failed: " <> show err) - Right redeemerReport -> - all isRight (Map.elems redeemerReport) - & counterexample ("Transaction: " <> renderTxWithUTxO lookupUTxO tx) - & counterexample ("Redeemer report: " <> show redeemerReport) - & counterexample "Phase-2 validation failed" - --- | Expect a given 'Tx' and 'UTxO' to fail phase 1 or phase 2 evaluation. -propTransactionFailsEvaluation :: (Tx, UTxO) -> Property -propTransactionFailsEvaluation (tx, lookupUTxO) = - case evaluateTx tx lookupUTxO of - Left _ -> property True - Right redeemerReport -> - any isLeft redeemerReport - & counterexample ("Transaction: " <> renderTxWithUTxO lookupUTxO tx) - & counterexample ("Redeemer report: " <> show redeemerReport) - & counterexample "Phase-2 validation should have failed" - -- * Mutations -- | Existential wrapper 'SomeMutation' and some label type. diff --git a/hydra-node/test/Hydra/Chain/Direct/ContractSpec.hs b/hydra-node/test/Hydra/Chain/Direct/ContractSpec.hs index e6a169a3af7..3a1fae508a3 100644 --- a/hydra-node/test/Hydra/Chain/Direct/ContractSpec.hs +++ b/hydra-node/test/Hydra/Chain/Direct/ContractSpec.hs @@ -26,7 +26,7 @@ import Hydra.Chain.Direct.Contract.Commit (genCommitMutation, healthyCommitTx) import Hydra.Chain.Direct.Contract.Contest (genContestMutation, healthyContestTx) import Hydra.Chain.Direct.Contract.FanOut (genFanoutMutation, healthyFanoutTx) import Hydra.Chain.Direct.Contract.Init (genInitMutation, healthyInitTx) -import Hydra.Chain.Direct.Contract.Mutation (propMutation, propTransactionEvaluates) +import Hydra.Chain.Direct.Contract.Mutation (propMutation) import Hydra.Chain.Direct.Fixture (testNetworkId) import Hydra.Chain.Direct.Tx (headIdToCurrencySymbol) import Hydra.Contract.Commit qualified as Commit @@ -44,6 +44,7 @@ import Hydra.Ledger.Cardano ( genUTxOWithSimplifiedAddresses, shrinkUTxO, ) +import Hydra.Ledger.Cardano.Evaluate (propTransactionEvaluates) import Hydra.Ledger.Simple (SimpleTx) import Hydra.Party (deriveParty, partyToChain) import Hydra.Plutus.Orphans () diff --git a/hydra-node/test/Hydra/Chain/Direct/StateSpec.hs b/hydra-node/test/Hydra/Chain/Direct/StateSpec.hs index fe9025cfaa3..98d0cdd860b 100644 --- a/hydra-node/test/Hydra/Chain/Direct/StateSpec.hs +++ b/hydra-node/test/Hydra/Chain/Direct/StateSpec.hs @@ -43,8 +43,6 @@ import Hydra.Chain.Direct.Contract.Mutation ( Mutation (..), applyMutation, modifyInlineDatum, - propTransactionEvaluates, - propTransactionFailsEvaluation, replaceHeadId, replacePolicyIdWith, ) @@ -111,7 +109,6 @@ import Hydra.Ledger.Cardano ( genTxOut, genTxOutAdaOnly, genTxOutByron, - genTxOutWithReferenceScript, genUTxO1, genUTxOSized, ) @@ -119,6 +116,8 @@ import Hydra.Ledger.Cardano.Evaluate ( evaluateTx, genValidityBoundsFromContestationPeriod, maxTxSize, + propTransactionEvaluates, + propTransactionFailsEvaluation, ) import Hydra.Ledger.Cardano.Time (slotNoFromUTCTime) import Hydra.Snapshot (ConfirmedSnapshot (InitialSnapshot, initialUTxO)) @@ -274,16 +273,6 @@ spec = parallel $ do Left UnsupportedLegacyOutput{} -> property True _ -> property False - prop "reject committing outputs with reference scripts" $ - monadicST $ do - hctx <- pickBlind $ genHydraContext maximumNumberOfParties - (ctx, stInitial@InitialState{headId}) <- pickBlind $ genStInitial hctx - utxo <- pick $ genUTxO1 genTxOutWithReferenceScript - pure $ - case commit ctx headId (getKnownUTxO stInitial) utxo of - Left CannotCommitReferenceScript{} -> property True - _ -> property False - prop "reject Commits with more than maxMainnetLovelace Lovelace" $ monadicST $ do hctx <- pickBlind $ genHydraContext maximumNumberOfParties diff --git a/hydra-node/test/Hydra/Chain/Direct/TxSpec.hs b/hydra-node/test/Hydra/Chain/Direct/TxSpec.hs index 2c70d793b50..ccbfcec45ec 100644 --- a/hydra-node/test/Hydra/Chain/Direct/TxSpec.hs +++ b/hydra-node/test/Hydra/Chain/Direct/TxSpec.hs @@ -1,22 +1,40 @@ {-# LANGUAGE DuplicateRecordFields #-} -{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-} {-# OPTIONS_GHC -Wno-orphans #-} -- | Unit tests for our "hand-rolled" transactions as they are used in the -- "direct" chain component. module Hydra.Chain.Direct.TxSpec where -import Hydra.Cardano.Api -import Hydra.Chain.Direct.Tx import Hydra.Prelude hiding (label) -import Test.Hydra.Prelude import Cardano.Api.UTxO qualified as UTxO +import Cardano.Ledger.Alonzo.TxAuxData (AlonzoTxAuxData (..)) +import Cardano.Ledger.Api ( + AlonzoPlutusPurpose (AlonzoSpending), + Metadatum, + auxDataTxL, + bodyTxL, + inputsTxBodyL, + outputsTxBodyL, + rdmrsTxWitsL, + referenceInputsTxBodyL, + reqSignerHashesTxBodyL, + unRedeemers, + vldtTxBodyL, + witsTxL, + ) import Cardano.Ledger.Core (EraTx (getMinFeeTx)) +import Cardano.Ledger.Credential (Credential (..)) +import Control.Lens ((^.)) import Data.Map qualified as Map +import Data.Maybe.Strict (fromSMaybe) +import Data.Set qualified as Set import Data.Text qualified as T -import Hydra.Cardano.Api.Pretty (renderTx) -import Hydra.Chain (HeadParameters (..)) +import Data.Text qualified as Text +import Hydra.Cardano.Api +import Hydra.Cardano.Api.Pretty (renderTx, renderTxWithUTxO) +import Hydra.Chain (CommitBlueprintTx (..), HeadParameters (..)) +import Hydra.Chain.Direct.Contract.Commit (commitSigningKey, healthyInitialTxIn, healthyInitialTxOut) import Hydra.Chain.Direct.Fixture ( epochInfo, pparams, @@ -25,25 +43,47 @@ import Hydra.Chain.Direct.Fixture ( testPolicyId, testSeedInput, ) +import Hydra.Chain.Direct.Fixture qualified as Fixture import Hydra.Chain.Direct.ScriptRegistry (genScriptRegistry, registryUTxO) -import Hydra.Chain.Direct.State (HasKnownUTxO (getKnownUTxO), genChainStateWithTx) +import Hydra.Chain.Direct.State (ChainContext (..), HasKnownUTxO (getKnownUTxO), genChainStateWithTx) import Hydra.Chain.Direct.State qualified as Transition +import Hydra.Chain.Direct.Tx import Hydra.Chain.Direct.Wallet (ErrCoverFee (..), coverFee_) import Hydra.Contract.Commit qualified as Commit import Hydra.Contract.HeadTokens (headPolicyId, mkHeadTokenScript) import Hydra.Contract.Initial qualified as Initial -import Hydra.Ledger.Cardano (adaOnly, genOneUTxOFor, genVerificationKey) -import Hydra.Ledger.Cardano.Evaluate (EvaluationReport, maxTxExecutionUnits) +import Hydra.Ledger.Cardano ( + adaOnly, + addInputs, + addReferenceInputs, + addVkInputs, + emptyTxBody, + genOneUTxOFor, + genTxOutWithReferenceScript, + genUTxO1, + genUTxOAdaOnlyOfSize, + genValue, + genVerificationKey, + unsafeBuildTransaction, + ) +import Hydra.Ledger.Cardano.Evaluate (EvaluationReport, maxTxExecutionUnits, propTransactionEvaluates) import Hydra.Party (Party) +import Hydra.PersistenceSpec (genSomeText) +import PlutusLedgerApi.Test.Examples qualified as Plutus import Test.Hydra.Fixture (genForParty) +import Test.Hydra.Prelude import Test.QuickCheck ( + Positive (..), Property, choose, + conjoin, counterexample, + cover, elements, forAll, forAllBlind, label, + oneof, property, vectorOf, withMaxSuccess, @@ -141,6 +181,194 @@ spec = & counterexample (renderTx tx) & counterexample (show e) + describe "commitTx" $ do + prop "genBlueprintTx generates interesting txs" prop_interestingBlueprintTx + + prop "Validate blueprint and commit transactions" $ do + forAllBlind arbitrary $ \chainContext -> do + let ChainContext{networkId, ownVerificationKey, ownParty, scriptRegistry} = + chainContext{ownVerificationKey = getVerificationKey commitSigningKey, networkId = testNetworkId} + forAll genBlueprintTxWithUTxO $ \(lookupUTxO, blueprintTx') -> do + let commitTx' = + commitTx + networkId + scriptRegistry + (mkHeadId Fixture.testPolicyId) + ownParty + CommitBlueprintTx{lookupUTxO, blueprintTx = blueprintTx'} + (healthyInitialTxIn, toUTxOContext healthyInitialTxOut, verificationKeyHash ownVerificationKey) + let blueprintTx = toLedgerTx blueprintTx' + let blueprintBody = blueprintTx ^. bodyTxL + let tx = toLedgerTx commitTx' + let commitTxBody = tx ^. bodyTxL + + let spendableUTxO = + UTxO.singleton (healthyInitialTxIn, toUTxOContext healthyInitialTxOut) + <> lookupUTxO + <> registryUTxO scriptRegistry + + conjoin + [ propTransactionEvaluates (blueprintTx', lookupUTxO) + & counterexample ("Blueprint transaction failed to evaluate: " <> renderTxWithUTxO lookupUTxO blueprintTx') + , propTransactionEvaluates (commitTx', spendableUTxO) + & counterexample ("Commit transaction failed to evaluate: " <> renderTxWithUTxO spendableUTxO commitTx') + , let blueprintMetadata = fromSMaybe mempty $ getAuxMetadata <$> blueprintTx ^. auxDataTxL + commitMetadata = fromSMaybe mempty $ getAuxMetadata <$> tx ^. auxDataTxL + in blueprintMetadata `Map.isSubmapOf` commitMetadata + & counterexample ("blueprint metadata: " <> show blueprintMetadata) + & counterexample ("commit metadata: " <> show commitMetadata) + , let blueprintValidity = blueprintBody ^. vldtTxBodyL + commitValidity = commitTxBody ^. vldtTxBodyL + in blueprintValidity === commitValidity + & counterexample ("blueprint validity: " <> show blueprintValidity) + & counterexample ("commit validity: " <> show commitValidity) + , let blueprintInputs = blueprintBody ^. inputsTxBodyL + commitInputs = commitTxBody ^. inputsTxBodyL + in property (blueprintInputs `Set.isSubsetOf` commitInputs) + & counterexample ("blueprint inputs: " <> show blueprintInputs) + & counterexample ("commit inputs: " <> show commitInputs) + , let blueprintOutputs = toList $ blueprintBody ^. outputsTxBodyL + commitOutputs = toList $ commitTxBody ^. outputsTxBodyL + in property + ( all + (`notElem` blueprintOutputs) + commitOutputs + ) + & counterexample ("blueprint outputs: " <> show blueprintOutputs) + & counterexample ("commit outputs: " <> show commitOutputs) + , let blueprintSigs = blueprintBody ^. reqSignerHashesTxBodyL + commitSigs = commitTxBody ^. reqSignerHashesTxBodyL + in property (blueprintSigs `Set.isSubsetOf` commitSigs) + & counterexample ("blueprint signatures: " <> show blueprintSigs) + & counterexample ("commit signatures: " <> show commitSigs) + , let blueprintRefInputs = blueprintBody ^. referenceInputsTxBodyL + commitRefInputs = commitTxBody ^. referenceInputsTxBodyL + in property (blueprintRefInputs `Set.isSubsetOf` commitRefInputs) + & counterexample ("blueprint reference inputs: " <> show blueprintRefInputs) + & counterexample ("commit reference inputs: " <> show commitRefInputs) + ] + +getAuxMetadata :: AlonzoTxAuxData LedgerEra -> Map Word64 Metadatum +getAuxMetadata (AlonzoTxAuxData metadata _ _) = metadata + +genBlueprintTxWithUTxO :: Gen (UTxO, Tx) +genBlueprintTxWithUTxO = + fmap (second unsafeBuildTransaction) $ + spendingPubKeyOutput (mempty, emptyTxBody) + >>= spendSomeScriptInputs + >>= addSomeReferenceInputs + >>= addValidityRange + >>= addRandomMetadata + >>= removeRandomInputs + >>= addCollateralInput + where + spendingPubKeyOutput (utxo, txbody) = do + utxoToSpend <- (genUTxOAdaOnlyOfSize . getPositive) . Positive =<< choose (0, 50) + pure + ( utxo <> utxoToSpend + , txbody & addVkInputs (toList $ UTxO.inputSet utxoToSpend) + ) + + spendSomeScriptInputs (utxo, txbody) = do + let alwaysSucceedingScript = PlutusScriptSerialised $ Plutus.alwaysSucceedingNAryFunction 3 + datum <- unsafeHashableScriptData . fromPlutusData <$> arbitrary + redeemer <- + unsafeHashableScriptData . fromPlutusData <$> arbitrary -- . B . BS.pack <$> vector n + let genTxOut = do + value <- genValue + let scriptAddress = mkScriptAddress testNetworkId alwaysSucceedingScript + pure $ TxOut scriptAddress value (TxOutDatumInline datum) ReferenceScriptNone + utxoToSpend <- genUTxO1 genTxOut + pure + ( utxo <> utxoToSpend + , txbody + & addInputs + ( UTxO.pairs $ + ( \_ -> + BuildTxWith $ + ScriptWitness ScriptWitnessForSpending $ + mkScriptWitness alwaysSucceedingScript (ScriptDatumForTxIn datum) redeemer + ) + <$> utxoToSpend + ) + ) + + addSomeReferenceInputs (utxo, txbody) = do + txout <- genTxOutWithReferenceScript + txin <- arbitrary + pure (utxo <> UTxO.singleton (txin, txout), txbody & addReferenceInputs [txin]) + + addValidityRange (utxo, txbody) = do + (start, end) <- arbitrary + pure + ( utxo + , txbody{txValidityLowerBound = start, txValidityUpperBound = end} + ) + + addRandomMetadata (utxo, txbody) = do + mtdt <- oneof [randomMetadata, pure TxMetadataNone] + pure (utxo, txbody{txMetadata = mtdt}) + where + randomMetadata = do + n <- choose (2, 50) + metadata <- Text.take n <$> genSomeText + l <- arbitrary + pure $ + TxMetadataInEra $ + TxMetadata $ + Map.fromList [(l, TxMetaText metadata)] + + removeRandomInputs (utxo, txbody) = do + someInput <- elements $ txIns txbody + pure (utxo, txbody{txIns = [someInput]}) + + addCollateralInput (utxo, txbody) = do + utxoToSpend <- genUTxOAdaOnlyOfSize 1 + pure + ( utxo <> utxoToSpend + , txbody{txInsCollateral = TxInsCollateral $ toList (UTxO.inputSet utxoToSpend)} + ) + +prop_interestingBlueprintTx :: Property +prop_interestingBlueprintTx = do + forAll genBlueprintTxWithUTxO $ \(utxo, tx) -> + checkCoverage + True + & cover 1 (spendsFromScript (utxo, tx)) "blueprint spends script UTxO" + & cover 1 (spendsFromPubKey (utxo, tx)) "blueprint spends pub key UTxO" + & cover 1 (hasReferenceInputs tx) "blueprint has reference input" + where + hasReferenceInputs tx = + not . null $ toLedgerTx tx ^. bodyTxL . referenceInputsTxBodyL + + spendsFromPubKey (utxo, tx) = + any + ( \txIn -> case UTxO.resolve (fromLedgerTxIn txIn) utxo of + Just (TxOut (ShelleyAddressInEra (ShelleyAddress _ (KeyHashObj _) _)) _ _ _) -> True + _ -> False + ) + $ toLedgerTx tx ^. bodyTxL . inputsTxBodyL + + -- XXX: We do check both, the utxo and redeemers, because we + -- don't do phase 1 validation of the resulting transactions + -- and would not detect if redeemers are missing. + spendsFromScript (utxo, tx) = + any + ( \txIn -> case UTxO.resolve (fromLedgerTxIn txIn) utxo of + Just (TxOut (ShelleyAddressInEra (ShelleyAddress _ (ScriptHashObj _) _)) _ _ _) -> True + _ -> False + ) + (toLedgerTx tx ^. bodyTxL . inputsTxBodyL) + && any + ( \case + AlonzoSpending _ -> True + _ -> False + ) + ( Map.keysSet + . unRedeemers + $ toLedgerTx @Era tx ^. witsTxL . rdmrsTxWitsL + ) + withinTxExecutionBudget :: EvaluationReport -> Property withinTxExecutionBudget report = (totalMem <= maxMem && totalCpu <= maxCpu) diff --git a/hydra-node/test/Hydra/Model/MockChain.hs b/hydra-node/test/Hydra/Model/MockChain.hs index 74a409b0154..afe711cf0a0 100644 --- a/hydra-node/test/Hydra/Model/MockChain.hs +++ b/hydra-node/test/Hydra/Model/MockChain.hs @@ -31,11 +31,7 @@ import GHC.IO.Exception (userError) import Hydra.API.Server (Server (..)) import Hydra.BehaviorSpec (SimulatedChainNetwork (..)) import Hydra.Cardano.Api.Pretty (renderTxWithUTxO) -import Hydra.Chain ( - Chain (..), - PostChainTx (CloseTx, confirmedSnapshot, headId, headParameters), - initHistory, - ) +import Hydra.Chain (Chain (..), CommitBlueprintTx (..), PostChainTx (CloseTx, confirmedSnapshot, headId, headParameters), initHistory) import Hydra.Chain.Direct.Fixture (testNetworkId) import Hydra.Chain.Direct.Handlers ( ChainSyncHandler (..), @@ -191,7 +187,7 @@ mockChainAndNetwork tr seedKeys commits = do atomically $ modifyTVar nodes (mockNode :) pure node' - simulateCommit nodes (party, utxoToCommit) = do + simulateCommit nodes (party, lookupUTxO) = do hydraNodes <- readTVarIO nodes case find (matchingParty party) hydraNodes of Nothing -> error "simulateCommit: Could not find matching HydraNode" @@ -205,9 +201,10 @@ mockChainAndNetwork tr seedKeys commits = do Initial InitialState{headId} -> headId Open OpenState{headId} -> headId Closed ClosedState{headId} -> headId + blueprintTx = txSpendingUTxO lookupUTxO -- NOTE: We don't need to sign a tx here since the MockChain -- doesn't actually validate transactions using a real ledger. - eTx <- draftCommitTx hId $ (,KeyWitness KeyWitnessForSpending) <$> utxoToCommit + eTx <- draftCommitTx hId CommitBlueprintTx{lookupUTxO, blueprintTx} case eTx of Left e -> throwIO e Right tx -> submitTx tx diff --git a/hydra-tui/src/Hydra/Client.hs b/hydra-tui/src/Hydra/Client.hs index 0b019ce706c..66256d4f849 100644 --- a/hydra-tui/src/Hydra/Client.hs +++ b/hydra-tui/src/Hydra/Client.hs @@ -10,16 +10,17 @@ import Control.Concurrent.Class.MonadSTM (newTBQueueIO, readTBQueue, writeTBQueu import Control.Exception (Handler (Handler), IOException, catches) import Data.Aeson (eitherDecodeStrict, encode) import Hydra.API.ClientInput (ClientInput) -import Hydra.API.HTTPServer (DraftCommitTxRequest (DraftCommitTxRequest), DraftCommitTxResponse (..), TxOutWithWitness (TxOutWithWitness)) +import Hydra.API.HTTPServer (DraftCommitTxRequest (..), DraftCommitTxResponse (..)) import Hydra.API.ServerOutput (TimedServerOutput) -import Hydra.Cardano.Api ( +import Hydra.Cardano.Api.Prelude ( AsType (AsPaymentKey, AsSigningKey), PaymentKey, SigningKey, - signTx, ) +import Hydra.Cardano.Api.Tx (signTx) import Hydra.Chain.CardanoClient (submitTransaction) import Hydra.Chain.Direct.Util (readFileTextEnvelopeThrow) +import Hydra.Ledger.Cardano (Tx) import Hydra.Network (Host (Host, hostname, port)) import Hydra.TUI.Options (Options (..)) import Network.HTTP.Req (defaultHttpConfig, responseBody, runReq) @@ -105,7 +106,7 @@ withClient Options{hydraNodeHost = Host{hostname, port}, cardanoSigningKey, card Req.req Req.POST (Req.http hostname Req./: "commit") - (Req.ReqBodyJson . DraftCommitTxRequest $ (`TxOutWithWitness` Nothing) <$> payload) + (Req.ReqBodyJson $ SimpleCommitRequest @Tx payload) Req.jsonResponse (Req.port $ fromIntegral port)