commit c76e19b502eb694ce740082540683271cb74b3f4 Author: Adriaan Leijnse Date: Thu Oct 20 21:45:15 2022 +0100 Initial commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..9afb5f1 --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ +#

Hydra Head Demo, Reflex-DOM edition

+ +This is an extended, graphical re-implementation of the original [Hydra Heads demo](https://github.com/input-output-hk/hydra-poc/tree/master/demo) implemented with [Reflex FRP](https://reflex-frp.org/). +It allows starting and closing a head with an arbitrary number of nodes, each with some initial amount of Ada to perform transactions within the head. + +# Running + +To run the demo enter a Nix shell and run it with `cabal`: + +``` + $ nix-shell -A shells.ghc default.nix + $ cabal run +``` + +The demo can then be viewed in Chrome at `http://localhost:3003/`. diff --git a/default.nix b/default.nix new file mode 100644 index 0000000..0864555 --- /dev/null +++ b/default.nix @@ -0,0 +1,37 @@ +# default.nix +{ system ? builtins.currentSystem }: +let + nix-thunk = import ./dep/nix-thunk { }; + sources = nix-thunk.mapSubdirectories nix-thunk.thunkSource ./dep; + reflex-platform = import sources.reflex-platform { inherit system; }; + hydra-poc = import sources.hydra-poc { }; +in reflex-platform.project ({ pkgs, ... }: + let haskellLib = pkgs.haskell.lib; + in { + packages = { hydra-head-demo = ./.; }; + + shellToolOverrides = ghc: super: { + }; + + overrides = self: super: { + hydra-head-demo = haskellLib.overrideCabal super.hydra-head-demo (drv: { + librarySystemDepends = (drv.librarySystemDepends or [ ]) ++ [ + hydra-poc.cardano-node.cardano-node + hydra-poc.cardano-node.cardano-cli + hydra-poc.hsPkgs.hydra-node.components.exes.hydra-node + hydra-poc.hsPkgs.hydra-node.components.exes.hydra-tools + pkgs.jq + pkgs.coreutils + ]; + }); + }; + + useWarp = true; + + withHoogle = true; + + shells = { + ghc = [ "hydra-head-demo" ]; + ghcjs = [ ]; + }; + }) diff --git a/demo/LICENSE b/demo/LICENSE new file mode 100644 index 0000000..a23c02e --- /dev/null +++ b/demo/LICENSE @@ -0,0 +1,203 @@ +[Original license of https://github.com/input-output-hk/hydra-poc below.] + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [2021-2022] [IOG] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/demo/credentials/faucet.sk b/demo/credentials/faucet.sk new file mode 100644 index 0000000..cb6f8c5 --- /dev/null +++ b/demo/credentials/faucet.sk @@ -0,0 +1,5 @@ +{ + "type": "PaymentSigningKeyShelley_ed25519", + "description": "Payment Signing Key", + "cborHex": "5820a5e4238b67ebb1108c52a01ac850bbce82c915d77bad94331892f3edf612883c" +} diff --git a/demo/credentials/faucet.vk b/demo/credentials/faucet.vk new file mode 100644 index 0000000..db53a30 --- /dev/null +++ b/demo/credentials/faucet.vk @@ -0,0 +1,5 @@ +{ + "type": "PaymentVerificationKeyShelley_ed25519", + "description": "Payment Verification Key", + "cborHex": "5820ce13cd433cdcb3dfb00c04e216956aeb622dcd7f282b03304d9fc9de804723b2" +} diff --git a/demo/devnet/byron-delegate.key b/demo/devnet/byron-delegate.key new file mode 100644 index 0000000..6693ec7 Binary files /dev/null and b/demo/devnet/byron-delegate.key differ diff --git a/demo/devnet/byron-delegation.cert b/demo/devnet/byron-delegation.cert new file mode 100644 index 0000000..f29f3e5 --- /dev/null +++ b/demo/devnet/byron-delegation.cert @@ -0,0 +1,8 @@ +{ "omega": 0 +, "issuerPk": + "NclXQiNNEpaaLdSxP3VFeOPIfSuFqBcNtmv8/7fftBKtgW1Aig7UqHJ/czsywkWFFVmBYPRnGjXspUl3wEMvuQ==" +, "delegatePk": + "24ejRK+kCDs1g4f3PcodFEUFVgNFWtfmuoEtVQf8/Ii2j2ruXHebJmZZPrwtAdbJYwDiSEvsHr95+BAF1ifGsA==" +, "cert": + "498c72e35ef30cd4657b48bfcc0a84a555a67981e3b6104a0d1708ab84510367d81e1ba3f47619565b1ee1098e31dcb8eb648d8030e061b568de113fdf3d6a09" +} \ No newline at end of file diff --git a/demo/devnet/cardano-node.json b/demo/devnet/cardano-node.json new file mode 100644 index 0000000..ceee0d6 --- /dev/null +++ b/demo/devnet/cardano-node.json @@ -0,0 +1,79 @@ +{ + "Protocol": "Cardano", + + "ByronGenesisFile": "genesis-byron.json", + "ShelleyGenesisFile": "genesis-shelley.json", + "AlonzoGenesisFile": "genesis-alonzo.json", + + "ApplicationName": "cardano-sl", + "ApplicationVersion": 1, + "MaxKnownMajorProtocolVersion": 2, + "LastKnownBlockVersion-Alt": 0, + "LastKnownBlockVersion-Major": 6, + "LastKnownBlockVersion-Minor": 0, + + "TestShelleyHardForkAtEpoch": 0, + "TestAllegraHardForkAtEpoch": 0, + "TestMaryHardForkAtEpoch": 0, + "TestAlonzoHardForkAtEpoch": 0, + "TestBabbageHardForkAtEpoch": 0, + + "RequiresNetworkMagic": "RequiresNoMagic", + + "minSeverity": "Info", + "defaultBackends": ["KatipBK"], + "defaultScribes": [[ "StdoutSK", "stdout" ]], + "setupBackends": ["KatipBK"], + "setupScribes": [ + { + "scFormat": "ScJson", + "scKind": "StdoutSK", + "scName": "stdout", + "scRotation": null + } + ], + + "TurnOnLogMetrics": true, + "TurnOnLogging": true, + + "TracingVerbosity": "NormalVerbosity", + "TraceBlockFetchClient": false, + "TraceBlockFetchDecisions": false, + "TraceBlockFetchProtocol": false, + "TraceBlockFetchProtocolSerialised": false, + "TraceBlockFetchServer": false, + "TraceChainDb": true, + "TraceChainSyncBlockServer": false, + "TraceChainSyncClient": false, + "TraceChainSyncHeaderServer": false, + "TraceChainSyncProtocol": false, + "TraceDNSResolver": false, + "TraceDNSSubscription": false, + "TraceErrorPolicy": false, + "TraceForge": true, + "TraceHandshake": false, + "TraceIpSubscription": false, + "TraceLocalChainSyncProtocol": true, + "TraceLocalErrorPolicy": false, + "TraceLocalHandshake": false, + "TraceLocalTxSubmissionProtocol": true, + "TraceLocalTxSubmissionServer": true, + "TraceMempool": true, + "TraceMux": false, + "TraceTxInbound": false, + "TraceTxOutbound": false, + "TraceTxSubmissionProtocol": false, + + "options": { + "mapBackends": { + "cardano.node.metrics": [ "EKGViewBK" ], + "cardano.node.resources": [ "EKGViewBK" ] + }, + "mapSubtrace": { + "cardano.node.metrics": { "subtrace": "Neutral" } + } + }, + + "TestEnableDevelopmentHardForkEras": true, + "TestEnableDevelopmentNetworkProtocols": true +} diff --git a/demo/devnet/genesis-alonzo.json b/demo/devnet/genesis-alonzo.json new file mode 100644 index 0000000..edd0406 --- /dev/null +++ b/demo/devnet/genesis-alonzo.json @@ -0,0 +1,365 @@ +{ + "collateralPercentage": 150, + "costModels": { + "PlutusV1": { + "addInteger-cpu-arguments-intercept": 197209, + "addInteger-cpu-arguments-slope": 0, + "addInteger-memory-arguments-intercept": 1, + "addInteger-memory-arguments-slope": 1, + "appendByteString-cpu-arguments-intercept": 396231, + "appendByteString-cpu-arguments-slope": 621, + "appendByteString-memory-arguments-intercept": 0, + "appendByteString-memory-arguments-slope": 1, + "appendString-cpu-arguments-intercept": 150000, + "appendString-cpu-arguments-slope": 1000, + "appendString-memory-arguments-intercept": 0, + "appendString-memory-arguments-slope": 1, + "bData-cpu-arguments": 150000, + "bData-memory-arguments": 32, + "blake2b_256-cpu-arguments-intercept": 2477736, + "blake2b_256-cpu-arguments-slope": 29175, + "blake2b_256-memory-arguments": 4, + "cekApplyCost-exBudgetCPU": 29773, + "cekApplyCost-exBudgetMemory": 100, + "cekBuiltinCost-exBudgetCPU": 29773, + "cekBuiltinCost-exBudgetMemory": 100, + "cekConstCost-exBudgetCPU": 29773, + "cekConstCost-exBudgetMemory": 100, + "cekDelayCost-exBudgetCPU": 29773, + "cekDelayCost-exBudgetMemory": 100, + "cekForceCost-exBudgetCPU": 29773, + "cekForceCost-exBudgetMemory": 100, + "cekLamCost-exBudgetCPU": 29773, + "cekLamCost-exBudgetMemory": 100, + "cekStartupCost-exBudgetCPU": 100, + "cekStartupCost-exBudgetMemory": 100, + "cekVarCost-exBudgetCPU": 29773, + "cekVarCost-exBudgetMemory": 100, + "chooseData-cpu-arguments": 150000, + "chooseData-memory-arguments": 32, + "chooseList-cpu-arguments": 150000, + "chooseList-memory-arguments": 32, + "chooseUnit-cpu-arguments": 150000, + "chooseUnit-memory-arguments": 32, + "consByteString-cpu-arguments-intercept": 150000, + "consByteString-cpu-arguments-slope": 1000, + "consByteString-memory-arguments-intercept": 0, + "consByteString-memory-arguments-slope": 1, + "constrData-cpu-arguments": 150000, + "constrData-memory-arguments": 32, + "decodeUtf8-cpu-arguments-intercept": 150000, + "decodeUtf8-cpu-arguments-slope": 1000, + "decodeUtf8-memory-arguments-intercept": 0, + "decodeUtf8-memory-arguments-slope": 8, + "divideInteger-cpu-arguments-constant": 148000, + "divideInteger-cpu-arguments-model-arguments-intercept": 425507, + "divideInteger-cpu-arguments-model-arguments-slope": 118, + "divideInteger-memory-arguments-intercept": 0, + "divideInteger-memory-arguments-minimum": 1, + "divideInteger-memory-arguments-slope": 1, + "encodeUtf8-cpu-arguments-intercept": 150000, + "encodeUtf8-cpu-arguments-slope": 1000, + "encodeUtf8-memory-arguments-intercept": 0, + "encodeUtf8-memory-arguments-slope": 8, + "equalsByteString-cpu-arguments-constant": 150000, + "equalsByteString-cpu-arguments-intercept": 112536, + "equalsByteString-cpu-arguments-slope": 247, + "equalsByteString-memory-arguments": 1, + "equalsData-cpu-arguments-intercept": 150000, + "equalsData-cpu-arguments-slope": 10000, + "equalsData-memory-arguments": 1, + "equalsInteger-cpu-arguments-intercept": 136542, + "equalsInteger-cpu-arguments-slope": 1326, + "equalsInteger-memory-arguments": 1, + "equalsString-cpu-arguments-constant": 1000, + "equalsString-cpu-arguments-intercept": 150000, + "equalsString-cpu-arguments-slope": 1000, + "equalsString-memory-arguments": 1, + "fstPair-cpu-arguments": 150000, + "fstPair-memory-arguments": 32, + "headList-cpu-arguments": 150000, + "headList-memory-arguments": 32, + "iData-cpu-arguments": 150000, + "iData-memory-arguments": 32, + "ifThenElse-cpu-arguments": 1, + "ifThenElse-memory-arguments": 1, + "indexByteString-cpu-arguments": 150000, + "indexByteString-memory-arguments": 1, + "lengthOfByteString-cpu-arguments": 150000, + "lengthOfByteString-memory-arguments": 4, + "lessThanByteString-cpu-arguments-intercept": 103599, + "lessThanByteString-cpu-arguments-slope": 248, + "lessThanByteString-memory-arguments": 1, + "lessThanEqualsByteString-cpu-arguments-intercept": 103599, + "lessThanEqualsByteString-cpu-arguments-slope": 248, + "lessThanEqualsByteString-memory-arguments": 1, + "lessThanEqualsInteger-cpu-arguments-intercept": 145276, + "lessThanEqualsInteger-cpu-arguments-slope": 1366, + "lessThanEqualsInteger-memory-arguments": 1, + "lessThanInteger-cpu-arguments-intercept": 179690, + "lessThanInteger-cpu-arguments-slope": 497, + "lessThanInteger-memory-arguments": 1, + "listData-cpu-arguments": 150000, + "listData-memory-arguments": 32, + "mapData-cpu-arguments": 150000, + "mapData-memory-arguments": 32, + "mkCons-cpu-arguments": 150000, + "mkCons-memory-arguments": 32, + "mkNilData-cpu-arguments": 150000, + "mkNilData-memory-arguments": 32, + "mkNilPairData-cpu-arguments": 150000, + "mkNilPairData-memory-arguments": 32, + "mkPairData-cpu-arguments": 150000, + "mkPairData-memory-arguments": 32, + "modInteger-cpu-arguments-constant": 148000, + "modInteger-cpu-arguments-model-arguments-intercept": 425507, + "modInteger-cpu-arguments-model-arguments-slope": 118, + "modInteger-memory-arguments-intercept": 0, + "modInteger-memory-arguments-minimum": 1, + "modInteger-memory-arguments-slope": 1, + "multiplyInteger-cpu-arguments-intercept": 61516, + "multiplyInteger-cpu-arguments-slope": 11218, + "multiplyInteger-memory-arguments-intercept": 0, + "multiplyInteger-memory-arguments-slope": 1, + "nullList-cpu-arguments": 150000, + "nullList-memory-arguments": 32, + "quotientInteger-cpu-arguments-constant": 148000, + "quotientInteger-cpu-arguments-model-arguments-intercept": 425507, + "quotientInteger-cpu-arguments-model-arguments-slope": 118, + "quotientInteger-memory-arguments-intercept": 0, + "quotientInteger-memory-arguments-minimum": 1, + "quotientInteger-memory-arguments-slope": 1, + "remainderInteger-cpu-arguments-constant": 148000, + "remainderInteger-cpu-arguments-model-arguments-intercept": 425507, + "remainderInteger-cpu-arguments-model-arguments-slope": 118, + "remainderInteger-memory-arguments-intercept": 0, + "remainderInteger-memory-arguments-minimum": 1, + "remainderInteger-memory-arguments-slope": 1, + "sha2_256-cpu-arguments-intercept": 2477736, + "sha2_256-cpu-arguments-slope": 29175, + "sha2_256-memory-arguments": 4, + "sha3_256-cpu-arguments-intercept": 0, + "sha3_256-cpu-arguments-slope": 82363, + "sha3_256-memory-arguments": 4, + "sliceByteString-cpu-arguments-intercept": 150000, + "sliceByteString-cpu-arguments-slope": 5000, + "sliceByteString-memory-arguments-intercept": 0, + "sliceByteString-memory-arguments-slope": 1, + "sndPair-cpu-arguments": 150000, + "sndPair-memory-arguments": 32, + "subtractInteger-cpu-arguments-intercept": 197209, + "subtractInteger-cpu-arguments-slope": 0, + "subtractInteger-memory-arguments-intercept": 1, + "subtractInteger-memory-arguments-slope": 1, + "tailList-cpu-arguments": 150000, + "tailList-memory-arguments": 32, + "trace-cpu-arguments": 150000, + "trace-memory-arguments": 32, + "unBData-cpu-arguments": 150000, + "unBData-memory-arguments": 32, + "unConstrData-cpu-arguments": 150000, + "unConstrData-memory-arguments": 32, + "unIData-cpu-arguments": 150000, + "unIData-memory-arguments": 32, + "unListData-cpu-arguments": 150000, + "unListData-memory-arguments": 32, + "unMapData-cpu-arguments": 150000, + "unMapData-memory-arguments": 32, + "verifyEd25519Signature-cpu-arguments-intercept": 3345831, + "verifyEd25519Signature-cpu-arguments-slope": 1, + "verifyEd25519Signature-memory-arguments": 1 + }, + "PlutusV2": { + "addInteger-cpu-arguments-intercept": 205665, + "addInteger-cpu-arguments-slope": 812, + "addInteger-memory-arguments-intercept": 1, + "addInteger-memory-arguments-slope": 1, + "appendByteString-cpu-arguments-intercept": 1000, + "appendByteString-cpu-arguments-slope": 571, + "appendByteString-memory-arguments-intercept": 0, + "appendByteString-memory-arguments-slope": 1, + "appendString-cpu-arguments-intercept": 1000, + "appendString-cpu-arguments-slope": 24177, + "appendString-memory-arguments-intercept": 4, + "appendString-memory-arguments-slope": 1, + "bData-cpu-arguments": 1000, + "bData-memory-arguments": 32, + "blake2b_256-cpu-arguments-intercept": 117366, + "blake2b_256-cpu-arguments-slope": 10475, + "blake2b_256-memory-arguments": 4, + "cekApplyCost-exBudgetCPU": 23000, + "cekApplyCost-exBudgetMemory": 100, + "cekBuiltinCost-exBudgetCPU": 23000, + "cekBuiltinCost-exBudgetMemory": 100, + "cekConstCost-exBudgetCPU": 23000, + "cekConstCost-exBudgetMemory": 100, + "cekDelayCost-exBudgetCPU": 23000, + "cekDelayCost-exBudgetMemory": 100, + "cekForceCost-exBudgetCPU": 23000, + "cekForceCost-exBudgetMemory": 100, + "cekLamCost-exBudgetCPU": 23000, + "cekLamCost-exBudgetMemory": 100, + "cekStartupCost-exBudgetCPU": 100, + "cekStartupCost-exBudgetMemory": 100, + "cekVarCost-exBudgetCPU": 23000, + "cekVarCost-exBudgetMemory": 100, + "chooseData-cpu-arguments": 19537, + "chooseData-memory-arguments": 32, + "chooseList-cpu-arguments": 175354, + "chooseList-memory-arguments": 32, + "chooseUnit-cpu-arguments": 46417, + "chooseUnit-memory-arguments": 4, + "consByteString-cpu-arguments-intercept": 221973, + "consByteString-cpu-arguments-slope": 511, + "consByteString-memory-arguments-intercept": 0, + "consByteString-memory-arguments-slope": 1, + "constrData-cpu-arguments": 89141, + "constrData-memory-arguments": 32, + "decodeUtf8-cpu-arguments-intercept": 497525, + "decodeUtf8-cpu-arguments-slope": 14068, + "decodeUtf8-memory-arguments-intercept": 4, + "decodeUtf8-memory-arguments-slope": 2, + "divideInteger-cpu-arguments-constant": 196500, + "divideInteger-cpu-arguments-model-arguments-intercept": 453240, + "divideInteger-cpu-arguments-model-arguments-slope": 220, + "divideInteger-memory-arguments-intercept": 0, + "divideInteger-memory-arguments-minimum": 1, + "divideInteger-memory-arguments-slope": 1, + "encodeUtf8-cpu-arguments-intercept": 1000, + "encodeUtf8-cpu-arguments-slope": 28662, + "encodeUtf8-memory-arguments-intercept": 4, + "encodeUtf8-memory-arguments-slope": 2, + "equalsByteString-cpu-arguments-constant": 245000, + "equalsByteString-cpu-arguments-intercept": 216773, + "equalsByteString-cpu-arguments-slope": 62, + "equalsByteString-memory-arguments": 1, + "equalsData-cpu-arguments-intercept": 1060367, + "equalsData-cpu-arguments-slope": 12586, + "equalsData-memory-arguments": 1, + "equalsInteger-cpu-arguments-intercept": 208512, + "equalsInteger-cpu-arguments-slope": 421, + "equalsInteger-memory-arguments": 1, + "equalsString-cpu-arguments-constant": 187000, + "equalsString-cpu-arguments-intercept": 1000, + "equalsString-cpu-arguments-slope": 52998, + "equalsString-memory-arguments": 1, + "fstPair-cpu-arguments": 80436, + "fstPair-memory-arguments": 32, + "headList-cpu-arguments": 43249, + "headList-memory-arguments": 32, + "iData-cpu-arguments": 1000, + "iData-memory-arguments": 32, + "ifThenElse-cpu-arguments": 80556, + "ifThenElse-memory-arguments": 1, + "indexByteString-cpu-arguments": 57667, + "indexByteString-memory-arguments": 4, + "lengthOfByteString-cpu-arguments": 1000, + "lengthOfByteString-memory-arguments": 10, + "lessThanByteString-cpu-arguments-intercept": 197145, + "lessThanByteString-cpu-arguments-slope": 156, + "lessThanByteString-memory-arguments": 1, + "lessThanEqualsByteString-cpu-arguments-intercept": 197145, + "lessThanEqualsByteString-cpu-arguments-slope": 156, + "lessThanEqualsByteString-memory-arguments": 1, + "lessThanEqualsInteger-cpu-arguments-intercept": 204924, + "lessThanEqualsInteger-cpu-arguments-slope": 473, + "lessThanEqualsInteger-memory-arguments": 1, + "lessThanInteger-cpu-arguments-intercept": 208896, + "lessThanInteger-cpu-arguments-slope": 511, + "lessThanInteger-memory-arguments": 1, + "listData-cpu-arguments": 52467, + "listData-memory-arguments": 32, + "mapData-cpu-arguments": 64832, + "mapData-memory-arguments": 32, + "mkCons-cpu-arguments": 65493, + "mkCons-memory-arguments": 32, + "mkNilData-cpu-arguments": 22558, + "mkNilData-memory-arguments": 32, + "mkNilPairData-cpu-arguments": 16563, + "mkNilPairData-memory-arguments": 32, + "mkPairData-cpu-arguments": 76511, + "mkPairData-memory-arguments": 32, + "modInteger-cpu-arguments-constant": 196500, + "modInteger-cpu-arguments-model-arguments-intercept": 453240, + "modInteger-cpu-arguments-model-arguments-slope": 220, + "modInteger-memory-arguments-intercept": 0, + "modInteger-memory-arguments-minimum": 1, + "modInteger-memory-arguments-slope": 1, + "multiplyInteger-cpu-arguments-intercept": 69522, + "multiplyInteger-cpu-arguments-slope": 11687, + "multiplyInteger-memory-arguments-intercept": 0, + "multiplyInteger-memory-arguments-slope": 1, + "nullList-cpu-arguments": 60091, + "nullList-memory-arguments": 32, + "quotientInteger-cpu-arguments-constant": 196500, + "quotientInteger-cpu-arguments-model-arguments-intercept": 453240, + "quotientInteger-cpu-arguments-model-arguments-slope": 220, + "quotientInteger-memory-arguments-intercept": 0, + "quotientInteger-memory-arguments-minimum": 1, + "quotientInteger-memory-arguments-slope": 1, + "remainderInteger-cpu-arguments-constant": 196500, + "remainderInteger-cpu-arguments-model-arguments-intercept": 453240, + "remainderInteger-cpu-arguments-model-arguments-slope": 220, + "remainderInteger-memory-arguments-intercept": 0, + "remainderInteger-memory-arguments-minimum": 1, + "remainderInteger-memory-arguments-slope": 1, + "serialiseData-cpu-arguments-intercept": 1159724, + "serialiseData-cpu-arguments-slope": 392670, + "serialiseData-memory-arguments-intercept": 0, + "serialiseData-memory-arguments-slope": 2, + "sha2_256-cpu-arguments-intercept": 806990, + "sha2_256-cpu-arguments-slope": 30482, + "sha2_256-memory-arguments": 4, + "sha3_256-cpu-arguments-intercept": 1927926, + "sha3_256-cpu-arguments-slope": 82523, + "sha3_256-memory-arguments": 4, + "sliceByteString-cpu-arguments-intercept": 265318, + "sliceByteString-cpu-arguments-slope": 0, + "sliceByteString-memory-arguments-intercept": 4, + "sliceByteString-memory-arguments-slope": 0, + "sndPair-cpu-arguments": 85931, + "sndPair-memory-arguments": 32, + "subtractInteger-cpu-arguments-intercept": 205665, + "subtractInteger-cpu-arguments-slope": 812, + "subtractInteger-memory-arguments-intercept": 1, + "subtractInteger-memory-arguments-slope": 1, + "tailList-cpu-arguments": 41182, + "tailList-memory-arguments": 32, + "trace-cpu-arguments": 212342, + "trace-memory-arguments": 32, + "unBData-cpu-arguments": 31220, + "unBData-memory-arguments": 32, + "unConstrData-cpu-arguments": 32696, + "unConstrData-memory-arguments": 32, + "unIData-cpu-arguments": 43357, + "unIData-memory-arguments": 32, + "unListData-cpu-arguments": 32247, + "unListData-memory-arguments": 32, + "unMapData-cpu-arguments": 38314, + "unMapData-memory-arguments": 32, + "verifyEcdsaSecp256k1Signature-cpu-arguments": 35892428, + "verifyEcdsaSecp256k1Signature-memory-arguments": 10, + "verifyEd25519Signature-cpu-arguments-intercept": 9462713, + "verifyEd25519Signature-cpu-arguments-slope": 1021, + "verifyEd25519Signature-memory-arguments": 10, + "verifySchnorrSecp256k1Signature-cpu-arguments-intercept": 38887044, + "verifySchnorrSecp256k1Signature-cpu-arguments-slope": 32947, + "verifySchnorrSecp256k1Signature-memory-arguments": 10 + } + }, + "executionPrices": { + "prMem": 5.77e-2, + "prSteps": 7.21e-5 + }, + "lovelacePerUTxOWord": 34482, + "maxBlockExUnits": { + "exUnitsMem": 80000000, + "exUnitsSteps": 40000000000 + }, + "maxCollateralInputs": 3, + "maxTxExUnits": { + "exUnitsMem": 16000000, + "exUnitsSteps": 10000000000 + }, + "maxValueSize": 5000 +} diff --git a/demo/devnet/genesis-byron.json b/demo/devnet/genesis-byron.json new file mode 100644 index 0000000..0965391 --- /dev/null +++ b/demo/devnet/genesis-byron.json @@ -0,0 +1,36 @@ +{ + "protocolConsts": { + "k": 2160, + "protocolMagic": 42 + }, + "startTime": 1657186415, + "blockVersionData": { + "scriptVersion": 0, + "slotDuration": "250", + "maxBlockSize": "2000000", + "maxHeaderSize": "2000000", + "maxTxSize": "4096", + "maxProposalSize": "700", + "mpcThd": "20000000000000", + "heavyDelThd": "300000000000", + "updateVoteThd": "1000000000000", + "updateProposalThd": "100000000000000", + "updateImplicit": "10000", + "softforkRule": { + "initThd": "900000000000000", + "minThd": "600000000000000", + "thdDecrement": "50000000000000" + }, + "txFeePolicy": { + "summand": "155381000000000", + "multiplier": "43000000000" + }, + "unlockStakeEpoch": "18446744073709551615" + }, + "bootStakeholders": { + "7a4519c93d7be4577dd85bd524c644e6b809e44eae0457b43128c1c7": 1 + }, + "heavyDelegation": {}, + "nonAvvmBalances": {}, + "avvmDistr": {} +} diff --git a/demo/devnet/genesis-shelley.json b/demo/devnet/genesis-shelley.json new file mode 100644 index 0000000..555a4f9 --- /dev/null +++ b/demo/devnet/genesis-shelley.json @@ -0,0 +1,65 @@ +{ + "epochLength": 432000, + "activeSlotsCoeff": 1.0, + "slotLength": 0.1, + "securityParam": 2160, + "genDelegs": {}, + "initialFunds": { + "00813c32c92aad21770ff8001de0918f598df8c06775f77f8e8839d2a0074a515f7f32bf31a4f41c7417a8136e8152bfb42f06d71b389a6896": 900000000000, + "609783be7d3c54f11377966dfabc9284cd6c32fca1cd42ef0a4f1cc45b": 900000000000 + }, + "maxKESEvolutions": 60, + "maxLovelaceSupply": 2000000000000, + "networkId": "Testnet", + "networkMagic": 42, + "protocolParams": { + "a0": 0.0, + "decentralisationParam": 0, + "eMax": 18, + "extraEntropy": { + "tag": "NeutralNonce" + }, + "keyDeposit": 0, + "maxBlockBodySize": 65536, + "maxBlockHeaderSize": 1100, + "maxTxSize": 16384, + "minFeeA": 44, + "minFeeB": 155381, + "minPoolCost": 0, + "minUTxOValue": 0, + "nOpt": 100, + "poolDeposit": 0, + "protocolVersion": { + "major": 7, + "minor": 0 + }, + "rho": 0.1, + "tau": 0.1 + }, + "slotsPerKESPeriod": 129600, + "staking": { + "pools": { + "8a219b698d3b6e034391ae84cee62f1d76b6fbc45ddfe4e31e0d4b60": { + "cost": 0, + "margin": 0.0, + "metadata": null, + "owners": [], + "pledge": 0, + "publicKey": "8a219b698d3b6e034391ae84cee62f1d76b6fbc45ddfe4e31e0d4b60", + "relays": [], + "rewardAccount": { + "credential": { + "key hash": "b6ffb20cf821f9286802235841d4348a2c2bafd4f73092b7de6655ea" + }, + "network": "Testnet" + }, + "vrf": "fec17ed60cbf2ec5be3f061fb4de0b6ef1f20947cfbfce5fb2783d12f3f69ff5" + } + }, + "stake": { + "074a515f7f32bf31a4f41c7417a8136e8152bfb42f06d71b389a6896": "8a219b698d3b6e034391ae84cee62f1d76b6fbc45ddfe4e31e0d4b60" + } + }, + "systemStart": "2022-07-07T09:33:35Z", + "updateQuorum": 2 +} diff --git a/demo/devnet/kes.skey b/demo/devnet/kes.skey new file mode 100644 index 0000000..8711a55 --- /dev/null +++ b/demo/devnet/kes.skey @@ -0,0 +1,5 @@ +{ + "type": "KesSigningKey_ed25519_kes_2^6", + "description": "KES Signing Key", + "cborHex": "590260a199f16b11da6c7f5c1e0f1eb0b9bbe278d3d8f35bfd50d0951c2ff94d0344cd57df5f64c9bac1dd60b4482f9c636168f40737d526625a2ec82f22ec0c72de0013f86ef743a7bba0286db6ddf3d85bf8e49ddbf14d9d3b7ee22f4857c77b740948f84f2e72f6bcf91f405e34ea50a2c53fa4876b43cfce2bcfe87c06a903de8bb33d968ca7930b67d0c23f5cb2d74e422d773ba80e388de384691000d6ba8a9b4dc7d3187f76048fbef9a52b72d80d835bb76eced7c0e0cdc5b58869b73c095dffa01db4ff51765afcead565395a5ed1cf74e5f2134d61076fece21aacd080bbbfaab94125401d7bbc74eafc7e7e3a2235f59dc03d6e332e53d558493a1e22213b92c77b1328ff1b83855da704fc366bf4415490602481d1939136eeaf252c65184912a779d9d94a90e32b72c1877ef60b6d79e707ce5a762acb4bed46436efe4fe62aae50b39068cc508a09427c92791cbcbea44318529cc68d297ca24e1b73b2394c385ec63fcd85ed56eec3de48860a1ec950aad4f91cbf741dbd7bf1d3c278875bd20e31ff5372339f6aa5280ad9b8bf3514889ac44600fe57ca0b535d6dc6b0b981e079595aad186ee0be9b07e837391ab165e4ca406601c876a86e246a3f53311e21199cccc0b080f28d18f4dc6987731e10e4ade00df7c6921c5ef3022b6f49a29ba307a2c8f4bd2ba42fcfa0aad68a2f0ad31fff69a99d3471f9036d3f5817a3edfeff7fc3c14e1151d767aaa043481cfd1a6ee55e8e5d7853ecdaf9da2bb36c716beae8d706bc648a790d4697e1d044a11a49f305ab8bc64a094bd81bda7395fe6f77dd5557c39919dd9bb9cf22a87fe47408ae3ec2247007d015a5" +} diff --git a/demo/devnet/opcert.cert b/demo/devnet/opcert.cert new file mode 100644 index 0000000..2ae24e0 --- /dev/null +++ b/demo/devnet/opcert.cert @@ -0,0 +1,5 @@ +{ + "type": "NodeOperationalCertificate", + "description": "", + "cborHex": "828458204cd49bb05e9885142fe7af1481107995298771fd1a24e72b506a4d600ee2b3120000584089fc9e9f551b2ea873bf31643659d049152d5c8e8de86be4056370bccc5fa62dd12e3f152f1664e614763e46eaa7a17ed366b5cef19958773d1ab96941442e0b58205a3d778e76741a009e29d23093cfe046131808d34d7c864967b515e98dfc3583" +} diff --git a/demo/devnet/vrf.skey b/demo/devnet/vrf.skey new file mode 100644 index 0000000..5133967 --- /dev/null +++ b/demo/devnet/vrf.skey @@ -0,0 +1,5 @@ +{ + "type": "VrfSigningKey_PraosVRF", + "description": "VRF Signing Key", + "cborHex": "5840899795b70e9f34b737159fe21a6170568d6031e187f0cc84555c712b7c29b45cb882007593ef70f86e5c0948561a3b8e8851529a4f98975f2b24e768dda38ce2" +} diff --git a/demo/prepare-devnet.sh b/demo/prepare-devnet.sh new file mode 100755 index 0000000..ceeaed6 --- /dev/null +++ b/demo/prepare-devnet.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +# Prepare a "devnet" directory holding credentials, a dummy topology and +# "up-to-date" genesis files. If the directory exists, it is wiped out. +set -e + +BASEDIR=$(dirname $(realpath $0)) +TARGETDIR="${BASEDIR}/../devnet" + +[ -d "$TARGETDIR" ] && { echo "Cleaning up directory $TARGETDIR" ; rm -r $TARGETDIR ; } + +cp -af "$BASEDIR/devnet/" "$TARGETDIR" +cp -af "$BASEDIR/credentials" "$TARGETDIR" +cp -af "$BASEDIR/protocol-parameters.json" "$TARGETDIR" +echo '{"Producers": []}' > "$TARGETDIR/topology.json" +sed -i "s/\"startTime\": [0-9]*/\"startTime\": $(date +%s)/" "$TARGETDIR/genesis-byron.json" && \ +sed -i "s/\"systemStart\": \".*\"/\"systemStart\": \"$(date -u +%FT%TZ)\"/" "$TARGETDIR/genesis-shelley.json" + +find $TARGETDIR -type f -exec chmod 0400 {} \; +mkdir "$TARGETDIR/ipc" +echo "Prepared devnet, you can start the cluster now" diff --git a/demo/protocol-parameters.json b/demo/protocol-parameters.json new file mode 100644 index 0000000..1c16011 --- /dev/null +++ b/demo/protocol-parameters.json @@ -0,0 +1,386 @@ +{ + "collateralPercentage": 150, + "costModels": { + "PlutusScriptV1": { + "addInteger-cpu-arguments-intercept": 197209, + "addInteger-cpu-arguments-slope": 0, + "addInteger-memory-arguments-intercept": 1, + "addInteger-memory-arguments-slope": 1, + "appendByteString-cpu-arguments-intercept": 396231, + "appendByteString-cpu-arguments-slope": 621, + "appendByteString-memory-arguments-intercept": 0, + "appendByteString-memory-arguments-slope": 1, + "appendString-cpu-arguments-intercept": 150000, + "appendString-cpu-arguments-slope": 1000, + "appendString-memory-arguments-intercept": 0, + "appendString-memory-arguments-slope": 1, + "bData-cpu-arguments": 150000, + "bData-memory-arguments": 32, + "blake2b_256-cpu-arguments-intercept": 2477736, + "blake2b_256-cpu-arguments-slope": 29175, + "blake2b_256-memory-arguments": 4, + "cekApplyCost-exBudgetCPU": 29773, + "cekApplyCost-exBudgetMemory": 100, + "cekBuiltinCost-exBudgetCPU": 29773, + "cekBuiltinCost-exBudgetMemory": 100, + "cekConstCost-exBudgetCPU": 29773, + "cekConstCost-exBudgetMemory": 100, + "cekDelayCost-exBudgetCPU": 29773, + "cekDelayCost-exBudgetMemory": 100, + "cekForceCost-exBudgetCPU": 29773, + "cekForceCost-exBudgetMemory": 100, + "cekLamCost-exBudgetCPU": 29773, + "cekLamCost-exBudgetMemory": 100, + "cekStartupCost-exBudgetCPU": 100, + "cekStartupCost-exBudgetMemory": 100, + "cekVarCost-exBudgetCPU": 29773, + "cekVarCost-exBudgetMemory": 100, + "chooseData-cpu-arguments": 150000, + "chooseData-memory-arguments": 32, + "chooseList-cpu-arguments": 150000, + "chooseList-memory-arguments": 32, + "chooseUnit-cpu-arguments": 150000, + "chooseUnit-memory-arguments": 32, + "consByteString-cpu-arguments-intercept": 150000, + "consByteString-cpu-arguments-slope": 1000, + "consByteString-memory-arguments-intercept": 0, + "consByteString-memory-arguments-slope": 1, + "constrData-cpu-arguments": 150000, + "constrData-memory-arguments": 32, + "decodeUtf8-cpu-arguments-intercept": 150000, + "decodeUtf8-cpu-arguments-slope": 1000, + "decodeUtf8-memory-arguments-intercept": 0, + "decodeUtf8-memory-arguments-slope": 8, + "divideInteger-cpu-arguments-constant": 148000, + "divideInteger-cpu-arguments-model-arguments-intercept": 425507, + "divideInteger-cpu-arguments-model-arguments-slope": 118, + "divideInteger-memory-arguments-intercept": 0, + "divideInteger-memory-arguments-minimum": 1, + "divideInteger-memory-arguments-slope": 1, + "encodeUtf8-cpu-arguments-intercept": 150000, + "encodeUtf8-cpu-arguments-slope": 1000, + "encodeUtf8-memory-arguments-intercept": 0, + "encodeUtf8-memory-arguments-slope": 8, + "equalsByteString-cpu-arguments-constant": 150000, + "equalsByteString-cpu-arguments-intercept": 112536, + "equalsByteString-cpu-arguments-slope": 247, + "equalsByteString-memory-arguments": 1, + "equalsData-cpu-arguments-intercept": 150000, + "equalsData-cpu-arguments-slope": 10000, + "equalsData-memory-arguments": 1, + "equalsInteger-cpu-arguments-intercept": 136542, + "equalsInteger-cpu-arguments-slope": 1326, + "equalsInteger-memory-arguments": 1, + "equalsString-cpu-arguments-constant": 1000, + "equalsString-cpu-arguments-intercept": 150000, + "equalsString-cpu-arguments-slope": 1000, + "equalsString-memory-arguments": 1, + "fstPair-cpu-arguments": 150000, + "fstPair-memory-arguments": 32, + "headList-cpu-arguments": 150000, + "headList-memory-arguments": 32, + "iData-cpu-arguments": 150000, + "iData-memory-arguments": 32, + "ifThenElse-cpu-arguments": 1, + "ifThenElse-memory-arguments": 1, + "indexByteString-cpu-arguments": 150000, + "indexByteString-memory-arguments": 1, + "lengthOfByteString-cpu-arguments": 150000, + "lengthOfByteString-memory-arguments": 4, + "lessThanByteString-cpu-arguments-intercept": 103599, + "lessThanByteString-cpu-arguments-slope": 248, + "lessThanByteString-memory-arguments": 1, + "lessThanEqualsByteString-cpu-arguments-intercept": 103599, + "lessThanEqualsByteString-cpu-arguments-slope": 248, + "lessThanEqualsByteString-memory-arguments": 1, + "lessThanEqualsInteger-cpu-arguments-intercept": 145276, + "lessThanEqualsInteger-cpu-arguments-slope": 1366, + "lessThanEqualsInteger-memory-arguments": 1, + "lessThanInteger-cpu-arguments-intercept": 179690, + "lessThanInteger-cpu-arguments-slope": 497, + "lessThanInteger-memory-arguments": 1, + "listData-cpu-arguments": 150000, + "listData-memory-arguments": 32, + "mapData-cpu-arguments": 150000, + "mapData-memory-arguments": 32, + "mkCons-cpu-arguments": 150000, + "mkCons-memory-arguments": 32, + "mkNilData-cpu-arguments": 150000, + "mkNilData-memory-arguments": 32, + "mkNilPairData-cpu-arguments": 150000, + "mkNilPairData-memory-arguments": 32, + "mkPairData-cpu-arguments": 150000, + "mkPairData-memory-arguments": 32, + "modInteger-cpu-arguments-constant": 148000, + "modInteger-cpu-arguments-model-arguments-intercept": 425507, + "modInteger-cpu-arguments-model-arguments-slope": 118, + "modInteger-memory-arguments-intercept": 0, + "modInteger-memory-arguments-minimum": 1, + "modInteger-memory-arguments-slope": 1, + "multiplyInteger-cpu-arguments-intercept": 61516, + "multiplyInteger-cpu-arguments-slope": 11218, + "multiplyInteger-memory-arguments-intercept": 0, + "multiplyInteger-memory-arguments-slope": 1, + "nullList-cpu-arguments": 150000, + "nullList-memory-arguments": 32, + "quotientInteger-cpu-arguments-constant": 148000, + "quotientInteger-cpu-arguments-model-arguments-intercept": 425507, + "quotientInteger-cpu-arguments-model-arguments-slope": 118, + "quotientInteger-memory-arguments-intercept": 0, + "quotientInteger-memory-arguments-minimum": 1, + "quotientInteger-memory-arguments-slope": 1, + "remainderInteger-cpu-arguments-constant": 148000, + "remainderInteger-cpu-arguments-model-arguments-intercept": 425507, + "remainderInteger-cpu-arguments-model-arguments-slope": 118, + "remainderInteger-memory-arguments-intercept": 0, + "remainderInteger-memory-arguments-minimum": 1, + "remainderInteger-memory-arguments-slope": 1, + "sha2_256-cpu-arguments-intercept": 2477736, + "sha2_256-cpu-arguments-slope": 29175, + "sha2_256-memory-arguments": 4, + "sha3_256-cpu-arguments-intercept": 0, + "sha3_256-cpu-arguments-slope": 82363, + "sha3_256-memory-arguments": 4, + "sliceByteString-cpu-arguments-intercept": 150000, + "sliceByteString-cpu-arguments-slope": 5000, + "sliceByteString-memory-arguments-intercept": 0, + "sliceByteString-memory-arguments-slope": 1, + "sndPair-cpu-arguments": 150000, + "sndPair-memory-arguments": 32, + "subtractInteger-cpu-arguments-intercept": 197209, + "subtractInteger-cpu-arguments-slope": 0, + "subtractInteger-memory-arguments-intercept": 1, + "subtractInteger-memory-arguments-slope": 1, + "tailList-cpu-arguments": 150000, + "tailList-memory-arguments": 32, + "trace-cpu-arguments": 150000, + "trace-memory-arguments": 32, + "unBData-cpu-arguments": 150000, + "unBData-memory-arguments": 32, + "unConstrData-cpu-arguments": 150000, + "unConstrData-memory-arguments": 32, + "unIData-cpu-arguments": 150000, + "unIData-memory-arguments": 32, + "unListData-cpu-arguments": 150000, + "unListData-memory-arguments": 32, + "unMapData-cpu-arguments": 150000, + "unMapData-memory-arguments": 32, + "verifyEd25519Signature-cpu-arguments-intercept": 3345831, + "verifyEd25519Signature-cpu-arguments-slope": 1, + "verifyEd25519Signature-memory-arguments": 1 + }, + "PlutusScriptV2": { + "addInteger-cpu-arguments-intercept": 205665, + "addInteger-cpu-arguments-slope": 812, + "addInteger-memory-arguments-intercept": 1, + "addInteger-memory-arguments-slope": 1, + "appendByteString-cpu-arguments-intercept": 1000, + "appendByteString-cpu-arguments-slope": 571, + "appendByteString-memory-arguments-intercept": 0, + "appendByteString-memory-arguments-slope": 1, + "appendString-cpu-arguments-intercept": 1000, + "appendString-cpu-arguments-slope": 24177, + "appendString-memory-arguments-intercept": 4, + "appendString-memory-arguments-slope": 1, + "bData-cpu-arguments": 1000, + "bData-memory-arguments": 32, + "blake2b_256-cpu-arguments-intercept": 117366, + "blake2b_256-cpu-arguments-slope": 10475, + "blake2b_256-memory-arguments": 4, + "cekApplyCost-exBudgetCPU": 23000, + "cekApplyCost-exBudgetMemory": 100, + "cekBuiltinCost-exBudgetCPU": 23000, + "cekBuiltinCost-exBudgetMemory": 100, + "cekConstCost-exBudgetCPU": 23000, + "cekConstCost-exBudgetMemory": 100, + "cekDelayCost-exBudgetCPU": 23000, + "cekDelayCost-exBudgetMemory": 100, + "cekForceCost-exBudgetCPU": 23000, + "cekForceCost-exBudgetMemory": 100, + "cekLamCost-exBudgetCPU": 23000, + "cekLamCost-exBudgetMemory": 100, + "cekStartupCost-exBudgetCPU": 100, + "cekStartupCost-exBudgetMemory": 100, + "cekVarCost-exBudgetCPU": 23000, + "cekVarCost-exBudgetMemory": 100, + "chooseData-cpu-arguments": 19537, + "chooseData-memory-arguments": 32, + "chooseList-cpu-arguments": 175354, + "chooseList-memory-arguments": 32, + "chooseUnit-cpu-arguments": 46417, + "chooseUnit-memory-arguments": 4, + "consByteString-cpu-arguments-intercept": 221973, + "consByteString-cpu-arguments-slope": 511, + "consByteString-memory-arguments-intercept": 0, + "consByteString-memory-arguments-slope": 1, + "constrData-cpu-arguments": 89141, + "constrData-memory-arguments": 32, + "decodeUtf8-cpu-arguments-intercept": 497525, + "decodeUtf8-cpu-arguments-slope": 14068, + "decodeUtf8-memory-arguments-intercept": 4, + "decodeUtf8-memory-arguments-slope": 2, + "divideInteger-cpu-arguments-constant": 196500, + "divideInteger-cpu-arguments-model-arguments-intercept": 453240, + "divideInteger-cpu-arguments-model-arguments-slope": 220, + "divideInteger-memory-arguments-intercept": 0, + "divideInteger-memory-arguments-minimum": 1, + "divideInteger-memory-arguments-slope": 1, + "encodeUtf8-cpu-arguments-intercept": 1000, + "encodeUtf8-cpu-arguments-slope": 28662, + "encodeUtf8-memory-arguments-intercept": 4, + "encodeUtf8-memory-arguments-slope": 2, + "equalsByteString-cpu-arguments-constant": 245000, + "equalsByteString-cpu-arguments-intercept": 216773, + "equalsByteString-cpu-arguments-slope": 62, + "equalsByteString-memory-arguments": 1, + "equalsData-cpu-arguments-intercept": 1060367, + "equalsData-cpu-arguments-slope": 12586, + "equalsData-memory-arguments": 1, + "equalsInteger-cpu-arguments-intercept": 208512, + "equalsInteger-cpu-arguments-slope": 421, + "equalsInteger-memory-arguments": 1, + "equalsString-cpu-arguments-constant": 187000, + "equalsString-cpu-arguments-intercept": 1000, + "equalsString-cpu-arguments-slope": 52998, + "equalsString-memory-arguments": 1, + "fstPair-cpu-arguments": 80436, + "fstPair-memory-arguments": 32, + "headList-cpu-arguments": 43249, + "headList-memory-arguments": 32, + "iData-cpu-arguments": 1000, + "iData-memory-arguments": 32, + "ifThenElse-cpu-arguments": 80556, + "ifThenElse-memory-arguments": 1, + "indexByteString-cpu-arguments": 57667, + "indexByteString-memory-arguments": 4, + "lengthOfByteString-cpu-arguments": 1000, + "lengthOfByteString-memory-arguments": 10, + "lessThanByteString-cpu-arguments-intercept": 197145, + "lessThanByteString-cpu-arguments-slope": 156, + "lessThanByteString-memory-arguments": 1, + "lessThanEqualsByteString-cpu-arguments-intercept": 197145, + "lessThanEqualsByteString-cpu-arguments-slope": 156, + "lessThanEqualsByteString-memory-arguments": 1, + "lessThanEqualsInteger-cpu-arguments-intercept": 204924, + "lessThanEqualsInteger-cpu-arguments-slope": 473, + "lessThanEqualsInteger-memory-arguments": 1, + "lessThanInteger-cpu-arguments-intercept": 208896, + "lessThanInteger-cpu-arguments-slope": 511, + "lessThanInteger-memory-arguments": 1, + "listData-cpu-arguments": 52467, + "listData-memory-arguments": 32, + "mapData-cpu-arguments": 64832, + "mapData-memory-arguments": 32, + "mkCons-cpu-arguments": 65493, + "mkCons-memory-arguments": 32, + "mkNilData-cpu-arguments": 22558, + "mkNilData-memory-arguments": 32, + "mkNilPairData-cpu-arguments": 16563, + "mkNilPairData-memory-arguments": 32, + "mkPairData-cpu-arguments": 76511, + "mkPairData-memory-arguments": 32, + "modInteger-cpu-arguments-constant": 196500, + "modInteger-cpu-arguments-model-arguments-intercept": 453240, + "modInteger-cpu-arguments-model-arguments-slope": 220, + "modInteger-memory-arguments-intercept": 0, + "modInteger-memory-arguments-minimum": 1, + "modInteger-memory-arguments-slope": 1, + "multiplyInteger-cpu-arguments-intercept": 69522, + "multiplyInteger-cpu-arguments-slope": 11687, + "multiplyInteger-memory-arguments-intercept": 0, + "multiplyInteger-memory-arguments-slope": 1, + "nullList-cpu-arguments": 60091, + "nullList-memory-arguments": 32, + "quotientInteger-cpu-arguments-constant": 196500, + "quotientInteger-cpu-arguments-model-arguments-intercept": 453240, + "quotientInteger-cpu-arguments-model-arguments-slope": 220, + "quotientInteger-memory-arguments-intercept": 0, + "quotientInteger-memory-arguments-minimum": 1, + "quotientInteger-memory-arguments-slope": 1, + "remainderInteger-cpu-arguments-constant": 196500, + "remainderInteger-cpu-arguments-model-arguments-intercept": 453240, + "remainderInteger-cpu-arguments-model-arguments-slope": 220, + "remainderInteger-memory-arguments-intercept": 0, + "remainderInteger-memory-arguments-minimum": 1, + "remainderInteger-memory-arguments-slope": 1, + "serialiseData-cpu-arguments-intercept": 1159724, + "serialiseData-cpu-arguments-slope": 392670, + "serialiseData-memory-arguments-intercept": 0, + "serialiseData-memory-arguments-slope": 2, + "sha2_256-cpu-arguments-intercept": 806990, + "sha2_256-cpu-arguments-slope": 30482, + "sha2_256-memory-arguments": 4, + "sha3_256-cpu-arguments-intercept": 1927926, + "sha3_256-cpu-arguments-slope": 82523, + "sha3_256-memory-arguments": 4, + "sliceByteString-cpu-arguments-intercept": 265318, + "sliceByteString-cpu-arguments-slope": 0, + "sliceByteString-memory-arguments-intercept": 4, + "sliceByteString-memory-arguments-slope": 0, + "sndPair-cpu-arguments": 85931, + "sndPair-memory-arguments": 32, + "subtractInteger-cpu-arguments-intercept": 205665, + "subtractInteger-cpu-arguments-slope": 812, + "subtractInteger-memory-arguments-intercept": 1, + "subtractInteger-memory-arguments-slope": 1, + "tailList-cpu-arguments": 41182, + "tailList-memory-arguments": 32, + "trace-cpu-arguments": 212342, + "trace-memory-arguments": 32, + "unBData-cpu-arguments": 31220, + "unBData-memory-arguments": 32, + "unConstrData-cpu-arguments": 32696, + "unConstrData-memory-arguments": 32, + "unIData-cpu-arguments": 43357, + "unIData-memory-arguments": 32, + "unListData-cpu-arguments": 32247, + "unListData-memory-arguments": 32, + "unMapData-cpu-arguments": 38314, + "unMapData-memory-arguments": 32, + "verifyEcdsaSecp256k1Signature-cpu-arguments": 35892428, + "verifyEcdsaSecp256k1Signature-memory-arguments": 10, + "verifyEd25519Signature-cpu-arguments-intercept": 9462713, + "verifyEd25519Signature-cpu-arguments-slope": 1021, + "verifyEd25519Signature-memory-arguments": 10, + "verifySchnorrSecp256k1Signature-cpu-arguments-intercept": 38887044, + "verifySchnorrSecp256k1Signature-cpu-arguments-slope": 32947, + "verifySchnorrSecp256k1Signature-memory-arguments": 10 + } + }, + "decentralization": null, + "executionUnitPrices": { + "priceMemory": 5.77e-2, + "priceSteps": 7.21e-5 + }, + "extraPraosEntropy": null, + "maxBlockBodySize": 65536, + "maxBlockExecutionUnits": { + "memory": 80000000, + "steps": 40000000000 + }, + "maxBlockHeaderSize": 1100, + "maxCollateralInputs": 3, + "maxTxExecutionUnits": { + "memory": 16000000, + "steps": 10000000000 + }, + "maxTxSize": 16384, + "maxValueSize": 5000, + "minPoolCost": 0, + "minUTxOValue": null, + "monetaryExpansion": 1.78650067e-3, + "poolPledgeInfluence": 0.1, + "poolRetireMaxEpoch": 18, + "protocolVersion": { + "major": 7, + "minor": 0 + }, + "stakeAddressDeposit": 400000, + "stakePoolDeposit": 500000000, + "stakePoolTargetNum": 50, + "treasuryCut": 0.1, + "txFeeFixed": 0, + "txFeePerByte": 0, + "utxoCostPerWord": 34488, + "utxoCostPerByte": 4310 +} diff --git a/dep/aeson-gadt-th/default.nix b/dep/aeson-gadt-th/default.nix new file mode 100644 index 0000000..2b4d4ab --- /dev/null +++ b/dep/aeson-gadt-th/default.nix @@ -0,0 +1,2 @@ +# DO NOT HAND-EDIT THIS FILE +import (import ./thunk.nix) \ No newline at end of file diff --git a/dep/aeson-gadt-th/github.json b/dep/aeson-gadt-th/github.json new file mode 100644 index 0000000..c2c4c18 --- /dev/null +++ b/dep/aeson-gadt-th/github.json @@ -0,0 +1,7 @@ +{ + "owner": "obsidiansystems", + "repo": "aeson-gadt-th", + "private": false, + "rev": "71a315a4873c2875ad737a3320320849bdcf8a2a", + "sha256": "1sjl0a0ig0xfssl4bglakk1b7sj8wqz8hwbg7k2fk10qi7z5hb50" +} diff --git a/dep/aeson-gadt-th/thunk.nix b/dep/aeson-gadt-th/thunk.nix new file mode 100644 index 0000000..bbf2dc1 --- /dev/null +++ b/dep/aeson-gadt-th/thunk.nix @@ -0,0 +1,9 @@ +# DO NOT HAND-EDIT THIS FILE +let fetch = { private ? false, fetchSubmodules ? false, owner, repo, rev, sha256, ... }: + if !fetchSubmodules && !private then builtins.fetchTarball { + url = "https://github.com/${owner}/${repo}/archive/${rev}.tar.gz"; inherit sha256; + } else (import {}).fetchFromGitHub { + inherit owner repo rev sha256 fetchSubmodules private; + }; + json = builtins.fromJSON (builtins.readFile ./github.json); +in fetch json \ No newline at end of file diff --git a/dep/aeson/default.nix b/dep/aeson/default.nix new file mode 100644 index 0000000..2b4d4ab --- /dev/null +++ b/dep/aeson/default.nix @@ -0,0 +1,2 @@ +# DO NOT HAND-EDIT THIS FILE +import (import ./thunk.nix) \ No newline at end of file diff --git a/dep/aeson/github.json b/dep/aeson/github.json new file mode 100644 index 0000000..51c742f --- /dev/null +++ b/dep/aeson/github.json @@ -0,0 +1,8 @@ +{ + "owner": "haskell", + "repo": "aeson", + "branch": "aeson-1.5", + "private": false, + "rev": "78e838df44288ac7d7ac2cd77863d2c026d86dbb", + "sha256": "181v1nz05jq992wgmz6ns7iwqx0c5w003hv5ki1kvc9zlg5dh3vf" +} diff --git a/dep/aeson/thunk.nix b/dep/aeson/thunk.nix new file mode 100644 index 0000000..bbf2dc1 --- /dev/null +++ b/dep/aeson/thunk.nix @@ -0,0 +1,9 @@ +# DO NOT HAND-EDIT THIS FILE +let fetch = { private ? false, fetchSubmodules ? false, owner, repo, rev, sha256, ... }: + if !fetchSubmodules && !private then builtins.fetchTarball { + url = "https://github.com/${owner}/${repo}/archive/${rev}.tar.gz"; inherit sha256; + } else (import {}).fetchFromGitHub { + inherit owner repo rev sha256 fetchSubmodules private; + }; + json = builtins.fromJSON (builtins.readFile ./github.json); +in fetch json \ No newline at end of file diff --git a/dep/constraints-extras/default.nix b/dep/constraints-extras/default.nix new file mode 100644 index 0000000..2b4d4ab --- /dev/null +++ b/dep/constraints-extras/default.nix @@ -0,0 +1,2 @@ +# DO NOT HAND-EDIT THIS FILE +import (import ./thunk.nix) \ No newline at end of file diff --git a/dep/constraints-extras/github.json b/dep/constraints-extras/github.json new file mode 100644 index 0000000..19bf5b3 --- /dev/null +++ b/dep/constraints-extras/github.json @@ -0,0 +1,8 @@ +{ + "owner": "obsidiansystems", + "repo": "constraints-extras", + "branch": "release/0.3.2.0", + "private": false, + "rev": "42835fd9e1b4b3c4a72cd1237c04789f01c92dd0", + "sha256": "0z7yfxxi4jywzhlkphs8ss3hd7fll8c90bbl6nr2bj63c87jx6sw" +} diff --git a/dep/constraints-extras/thunk.nix b/dep/constraints-extras/thunk.nix new file mode 100644 index 0000000..bbf2dc1 --- /dev/null +++ b/dep/constraints-extras/thunk.nix @@ -0,0 +1,9 @@ +# DO NOT HAND-EDIT THIS FILE +let fetch = { private ? false, fetchSubmodules ? false, owner, repo, rev, sha256, ... }: + if !fetchSubmodules && !private then builtins.fetchTarball { + url = "https://github.com/${owner}/${repo}/archive/${rev}.tar.gz"; inherit sha256; + } else (import {}).fetchFromGitHub { + inherit owner repo rev sha256 fetchSubmodules private; + }; + json = builtins.fromJSON (builtins.readFile ./github.json); +in fetch json \ No newline at end of file diff --git a/dep/entropy/default.nix b/dep/entropy/default.nix new file mode 100644 index 0000000..2b4d4ab --- /dev/null +++ b/dep/entropy/default.nix @@ -0,0 +1,2 @@ +# DO NOT HAND-EDIT THIS FILE +import (import ./thunk.nix) \ No newline at end of file diff --git a/dep/entropy/github.json b/dep/entropy/github.json new file mode 100644 index 0000000..6aa8b23 --- /dev/null +++ b/dep/entropy/github.json @@ -0,0 +1,8 @@ +{ + "owner": "obsidiansystems", + "repo": "entropy", + "branch": "aa/nonwindow-contexts", + "private": false, + "rev": "ddda007c44390d0ec8cad58810710864dee60ddd", + "sha256": "00b7cqdqbjf953r5gmwmkn2mn36zdxqwx90xih925cni94vi4vw9" +} diff --git a/dep/entropy/thunk.nix b/dep/entropy/thunk.nix new file mode 100644 index 0000000..bbf2dc1 --- /dev/null +++ b/dep/entropy/thunk.nix @@ -0,0 +1,9 @@ +# DO NOT HAND-EDIT THIS FILE +let fetch = { private ? false, fetchSubmodules ? false, owner, repo, rev, sha256, ... }: + if !fetchSubmodules && !private then builtins.fetchTarball { + url = "https://github.com/${owner}/${repo}/archive/${rev}.tar.gz"; inherit sha256; + } else (import {}).fetchFromGitHub { + inherit owner repo rev sha256 fetchSubmodules private; + }; + json = builtins.fromJSON (builtins.readFile ./github.json); +in fetch json \ No newline at end of file diff --git a/dep/hydra-poc/default.nix b/dep/hydra-poc/default.nix new file mode 100644 index 0000000..2b4d4ab --- /dev/null +++ b/dep/hydra-poc/default.nix @@ -0,0 +1,2 @@ +# DO NOT HAND-EDIT THIS FILE +import (import ./thunk.nix) \ No newline at end of file diff --git a/dep/hydra-poc/github.json b/dep/hydra-poc/github.json new file mode 100644 index 0000000..b9e8c57 --- /dev/null +++ b/dep/hydra-poc/github.json @@ -0,0 +1,7 @@ +{ + "owner": "input-output-hk", + "repo": "hydra-poc", + "private": false, + "rev": "b0ebec965f27553a1c99e5457441219dcb9306d6", + "sha256": "0i9sflwpy87hhrbb6c0wbjs1mj2nsln69yah6vnacb6l0j47ik4b" +} diff --git a/dep/hydra-poc/thunk.nix b/dep/hydra-poc/thunk.nix new file mode 100644 index 0000000..bbf2dc1 --- /dev/null +++ b/dep/hydra-poc/thunk.nix @@ -0,0 +1,9 @@ +# DO NOT HAND-EDIT THIS FILE +let fetch = { private ? false, fetchSubmodules ? false, owner, repo, rev, sha256, ... }: + if !fetchSubmodules && !private then builtins.fetchTarball { + url = "https://github.com/${owner}/${repo}/archive/${rev}.tar.gz"; inherit sha256; + } else (import {}).fetchFromGitHub { + inherit owner repo rev sha256 fetchSubmodules private; + }; + json = builtins.fromJSON (builtins.readFile ./github.json); +in fetch json \ No newline at end of file diff --git a/dep/logging-effect/default.nix b/dep/logging-effect/default.nix new file mode 100644 index 0000000..2b4d4ab --- /dev/null +++ b/dep/logging-effect/default.nix @@ -0,0 +1,2 @@ +# DO NOT HAND-EDIT THIS FILE +import (import ./thunk.nix) \ No newline at end of file diff --git a/dep/logging-effect/github.json b/dep/logging-effect/github.json new file mode 100644 index 0000000..d9fdbb5 --- /dev/null +++ b/dep/logging-effect/github.json @@ -0,0 +1,7 @@ +{ + "owner": "ocharles", + "repo": "logging-effect", + "private": false, + "rev": "efc856b62aec15f0087be0edb7ba621ed49b0bb1", + "sha256": "13nr3zw39415js1af2vd322vhzwqb2rkrv7b5lkd97h211d7zbj9" +} diff --git a/dep/logging-effect/thunk.nix b/dep/logging-effect/thunk.nix new file mode 100644 index 0000000..bbf2dc1 --- /dev/null +++ b/dep/logging-effect/thunk.nix @@ -0,0 +1,9 @@ +# DO NOT HAND-EDIT THIS FILE +let fetch = { private ? false, fetchSubmodules ? false, owner, repo, rev, sha256, ... }: + if !fetchSubmodules && !private then builtins.fetchTarball { + url = "https://github.com/${owner}/${repo}/archive/${rev}.tar.gz"; inherit sha256; + } else (import {}).fetchFromGitHub { + inherit owner repo rev sha256 fetchSubmodules private; + }; + json = builtins.fromJSON (builtins.readFile ./github.json); +in fetch json \ No newline at end of file diff --git a/dep/nix-thunk/default.nix b/dep/nix-thunk/default.nix new file mode 100644 index 0000000..2b4d4ab --- /dev/null +++ b/dep/nix-thunk/default.nix @@ -0,0 +1,2 @@ +# DO NOT HAND-EDIT THIS FILE +import (import ./thunk.nix) \ No newline at end of file diff --git a/dep/nix-thunk/github.json b/dep/nix-thunk/github.json new file mode 100644 index 0000000..0c817c5 --- /dev/null +++ b/dep/nix-thunk/github.json @@ -0,0 +1,7 @@ +{ + "owner": "obsidiansystems", + "repo": "nix-thunk", + "private": false, + "rev": "bd0de53129ca4ac5ce313a3e021edf3638a3a22c", + "sha256": "0cn74ylcfr9v2w94jpga9v18jn6zafb9k996afszn59iqlcfi74q" +} diff --git a/dep/nix-thunk/thunk.nix b/dep/nix-thunk/thunk.nix new file mode 100644 index 0000000..20f2d28 --- /dev/null +++ b/dep/nix-thunk/thunk.nix @@ -0,0 +1,12 @@ +# DO NOT HAND-EDIT THIS FILE +let fetch = { private ? false, fetchSubmodules ? false, owner, repo, rev, sha256, ... }: + if !fetchSubmodules && !private then builtins.fetchTarball { + url = "https://github.com/${owner}/${repo}/archive/${rev}.tar.gz"; inherit sha256; + } else (import (builtins.fetchTarball { + url = "https://github.com/NixOS/nixpkgs/archive/3aad50c30c826430b0270fcf8264c8c41b005403.tar.gz"; + sha256 = "0xwqsf08sywd23x0xvw4c4ghq0l28w2ki22h0bdn766i16z9q2gr"; +}) {}).fetchFromGitHub { + inherit owner repo rev sha256 fetchSubmodules private; + }; + json = builtins.fromJSON (builtins.readFile ./github.json); +in fetch json \ No newline at end of file diff --git a/dep/reflex-gadt-api/default.nix b/dep/reflex-gadt-api/default.nix new file mode 100644 index 0000000..2b4d4ab --- /dev/null +++ b/dep/reflex-gadt-api/default.nix @@ -0,0 +1,2 @@ +# DO NOT HAND-EDIT THIS FILE +import (import ./thunk.nix) \ No newline at end of file diff --git a/dep/reflex-gadt-api/github.json b/dep/reflex-gadt-api/github.json new file mode 100644 index 0000000..469864f --- /dev/null +++ b/dep/reflex-gadt-api/github.json @@ -0,0 +1,8 @@ +{ + "owner": "reflex-frp", + "repo": "reflex-gadt-api", + "branch": "develop", + "private": false, + "rev": "69aca72b57a74fbf0d06a1b2ac1d247ce9aa207f", + "sha256": "116c6lna8pkas95lclm4halagc4f6rxv5hmf7rnl10lxqi9m48qw" +} diff --git a/dep/reflex-gadt-api/thunk.nix b/dep/reflex-gadt-api/thunk.nix new file mode 100644 index 0000000..bbf2dc1 --- /dev/null +++ b/dep/reflex-gadt-api/thunk.nix @@ -0,0 +1,9 @@ +# DO NOT HAND-EDIT THIS FILE +let fetch = { private ? false, fetchSubmodules ? false, owner, repo, rev, sha256, ... }: + if !fetchSubmodules && !private then builtins.fetchTarball { + url = "https://github.com/${owner}/${repo}/archive/${rev}.tar.gz"; inherit sha256; + } else (import {}).fetchFromGitHub { + inherit owner repo rev sha256 fetchSubmodules private; + }; + json = builtins.fromJSON (builtins.readFile ./github.json); +in fetch json \ No newline at end of file diff --git a/dep/reflex-platform/default.nix b/dep/reflex-platform/default.nix new file mode 100644 index 0000000..2b4d4ab --- /dev/null +++ b/dep/reflex-platform/default.nix @@ -0,0 +1,2 @@ +# DO NOT HAND-EDIT THIS FILE +import (import ./thunk.nix) \ No newline at end of file diff --git a/dep/reflex-platform/github.json b/dep/reflex-platform/github.json new file mode 100644 index 0000000..3809598 --- /dev/null +++ b/dep/reflex-platform/github.json @@ -0,0 +1,8 @@ +{ + "owner": "reflex-frp", + "repo": "reflex-platform", + "branch": "release/0.9.2.0", + "private": false, + "rev": "123a6f487ca954fd983f6d4cd6b2a69d4c463d10", + "sha256": "16q1rq0rwi6l28fv46q8m0hvb9rxrzf574j865vaz04xy8d5p1ya" +} diff --git a/dep/reflex-platform/thunk.nix b/dep/reflex-platform/thunk.nix new file mode 100644 index 0000000..20f2d28 --- /dev/null +++ b/dep/reflex-platform/thunk.nix @@ -0,0 +1,12 @@ +# DO NOT HAND-EDIT THIS FILE +let fetch = { private ? false, fetchSubmodules ? false, owner, repo, rev, sha256, ... }: + if !fetchSubmodules && !private then builtins.fetchTarball { + url = "https://github.com/${owner}/${repo}/archive/${rev}.tar.gz"; inherit sha256; + } else (import (builtins.fetchTarball { + url = "https://github.com/NixOS/nixpkgs/archive/3aad50c30c826430b0270fcf8264c8c41b005403.tar.gz"; + sha256 = "0xwqsf08sywd23x0xvw4c4ghq0l28w2ki22h0bdn766i16z9q2gr"; +}) {}).fetchFromGitHub { + inherit owner repo rev sha256 fetchSubmodules private; + }; + json = builtins.fromJSON (builtins.readFile ./github.json); +in fetch json \ No newline at end of file diff --git a/hie.yaml b/hie.yaml new file mode 100644 index 0000000..7cec3ab --- /dev/null +++ b/hie.yaml @@ -0,0 +1,4 @@ +cradle: + cabal: + - path: "src" + component: "exe:hydra-head-demo" diff --git a/hydra-head-demo.cabal b/hydra-head-demo.cabal new file mode 100644 index 0000000..3d99286 --- /dev/null +++ b/hydra-head-demo.cabal @@ -0,0 +1,55 @@ +name: hydra-head-demo +version: 0.1 +cabal-version: >= 1.8 +build-type: Simple + + +executable hydra-head-demo + main-is: Main.hs + hs-source-dirs: src + ghc-options: -Wall -Wredundant-constraints -Wincomplete-uni-patterns -Wincomplete-record-updates -O -threaded -fno-show-valid-hole-fits + if impl(ghcjs) + buildable: False + other-modules: Hydra.ClientInput + , Hydra.Devnet + , Hydra.ServerOutput + , Hydra.Types + , Paths + build-depends: base + , process + , async + , which + -- , monad-logger + -- , logging-effect + , prettyprinter + , string-interpolate + , containers + , text + , witherable + -- , io-streams + , some + , directory + , aeson + , resource-pool + , bytestring + , uuid + , time + , reflex + , reflex-dom + , mtl + , jsaddle + + default-extensions: + OverloadedStrings + LambdaCase + GADTs + ScopedTypeVariables + OverloadedStrings + FlexibleContexts + QuasiQuotes + DeriveGeneric + RecursiveDo + RankNTypes + PartialTypeSignatures + TypeFamilies + TypeApplications diff --git a/src/Hydra/ClientInput.hs b/src/Hydra/ClientInput.hs new file mode 100644 index 0000000..3a319a4 --- /dev/null +++ b/src/Hydra/ClientInput.hs @@ -0,0 +1,26 @@ +-- | + +module Hydra.ClientInput where + +import GHC.Generics +import Data.Aeson +import qualified Data.Text as T +import Hydra.Types + +-- Copied and adapted from hydra-poc:hydra-node/src/hydra/ServerOutput.hs +-- Anything that took effort was replaced by Value + +data ClientInput + = Init {contestationPeriod :: ContestationPeriod} + | Abort + | Commit {utxo :: WholeUTXO} + | NewTx {transaction :: T.Text} + | GetUTxO + | Close + | Contest + | Fanout + deriving (Eq, Generic, Show) + + +instance ToJSON ClientInput +instance FromJSON ClientInput diff --git a/src/Hydra/Devnet.hs b/src/Hydra/Devnet.hs new file mode 100644 index 0000000..fe0d5bb --- /dev/null +++ b/src/Hydra/Devnet.hs @@ -0,0 +1,377 @@ +{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE TupleSections #-} + +-- | + +module Hydra.Devnet + ( HydraScriptTxId + , HydraKeyInfo(..) + , SigningKey + , KeyPair(..) + , getCardanoAddress + , seedAddressFromFaucetAndWait + , publishReferenceScripts + , queryAddressUTXOs + , buildSignedHydraTx + , generateKeys + , cardanoNodePath + , hydraNodePath + , prepareDevnet + , devnetMagic + , minTxLovelace + ) + +where + +import System.Which +import System.Directory +import System.Process + +import Control.Monad +import Control.Monad.IO.Class +import Data.Aeson + +import Control.Concurrent + + +import Data.Map (Map) + +import Data.Bool +import qualified Data.Text as T +import qualified Data.Map as Map +import Data.String.Interpolate (i) +import Paths + +import qualified Data.ByteString.Lazy.Char8 as BS + +import Hydra.Types +import qualified Data.UUID.V4 as UUIDV4 +import qualified Data.UUID as UUID +import Data.UUID (UUID) +import Data.Maybe (fromMaybe) + + +devnetMagic :: Int +devnetMagic = 42 + +prepareDevnet :: IO () +prepareDevnet = do + output <- readCreateProcess (shell "[ -d devnet ] || ./demo/prepare-devnet.sh") "" + putStrLn output + +cardanoNodePath :: FilePath +cardanoNodePath = $(staticWhich "cardano-node") + +cardanoCliPath :: FilePath +cardanoCliPath = $(staticWhich "cardano-cli") + +hydraNodePath :: FilePath +hydraNodePath = $(staticWhich "hydra-node") + +jqPath :: FilePath +jqPath = $(staticWhich "jq") + +type TxId = T.Text + +type HydraScriptTxId = T.Text + +type DraftTx = FilePath +type SignedTx = FilePath + +devnetNetworkId :: Int +devnetNetworkId = 42 + +generateKeys :: (MonadIO m) => m HydraKeyInfo +generateKeys = do + basePath <- liftIO getTempPath' + HydraKeyInfo <$> generateCardanoKeys basePath <*> generateHydraKeys basePath + + +type SigningKey = String +type VerificationKey = String + +data KeyPair = KeyPair + { _signingKey :: SigningKey + , _verificationKey :: VerificationKey + } + deriving (Show,Read) + + +data HydraKeyInfo = HydraKeyInfo + { _cardanoKeys :: KeyPair + , _hydraKeys :: KeyPair + } + deriving (Show,Read) + +-- | Generate Cardano keys. Calling with an e.g. "my/keys/alice" +-- argument results in "my/keys/alice.cardano.{vk,sk}" keys being +-- written. +generateCardanoKeys :: (MonadIO m) => String -> m KeyPair +generateCardanoKeys path = do + output <- liftIO $ + readCreateProcess + (proc cardanoCliPath [ "address" + , "key-gen" + , "--verification-key-file" + , [i|#{path}.cardano.vk|] + , "--signing-key-file" + , [i|#{path}.cardano.sk|] + ]) + "" + liftIO $ putStrLn output + pure $ KeyPair [i|#{path}.cardano.sk|] [i|#{path}.cardano.vk|] + +-- | Generate Hydra keys. Calling with an e.g. "my/keys/alice" +-- argument results in "my/keys/alice.hydra.{vk,sk}" keys being +-- written. +generateHydraKeys :: (MonadIO m) => String -> m KeyPair +generateHydraKeys path = do + output <- liftIO $ + readCreateProcess + (proc hydraToolsPath [ "gen-hydra-key" + , "--output-file" + , [i|#{path}.hydra|] + ]) + "" + liftIO $ putStrLn output + pure $ KeyPair [i|#{path}.hydra.sk|] [i|#{path}.hydra.vk|] + + +publishReferenceScripts :: (MonadIO m) => m HydraScriptTxId +publishReferenceScripts = do + liftIO . putStrLn $ "Publishing reference scripts ('νInitial' & 'νCommit')..." + fmap (T.strip . T.pack) $ liftIO $ readCreateProcess cp "" + where + cp = proc hydraNodePath [ "publish-scripts" + , "--network-id" + , show devnetNetworkId + , "--node-socket" + , "devnet/node.socket" + , "--cardano-signing-key" + , "devnet/credentials/faucet.sk" + ] + + +waitForTxIn :: (MonadIO m) => TxIn -> m () +waitForTxIn txin = do + liftIO . putStrLn $ "Waiting for utxo " <> show txin <> ".." + liftIO waitFn + where + waitFn = do + exists <- txInExists txin + threadDelay 10000 + unless exists waitFn + +txInExists :: TxIn -> IO Bool +txInExists txin = do + result <- fmap (T.strip . T.pack) $ readCreateProcess cp "" >>= readProcess jqPath (pure $ ".\"" <> asStr <> "\"") + pure $ case result of + "null" -> False + _ -> True + where + asStr = T.unpack txin + cp = (proc cardanoCliPath [ "query" + , "utxo" + , "--tx-in" + , asStr + , "--out-file" + , "/dev/stdout" + , "--testnet-magic" + , "42" + ]) { env = Just [("CARDANO_NODE_SOCKET_PATH", "devnet/node.socket")] } + +txInput :: Int -> TxId -> TxIn +txInput index txid = txid <> "#" <> (T.pack . show) index + +-- TODO: use this in checks? +minTxLovelace :: Int +minTxLovelace = 857690 + +queryAddressUTXOs :: MonadIO m => Address -> m WholeUTXO +queryAddressUTXOs addr = liftIO $ do + let queryProc = + (proc cardanoCliPath [ "query" + , "utxo" + , "--address" + , addr + , "--testnet-magic" + , "42" + , "--out-file" + , "/dev/stdout" + ]) + { env = Just [("CARDANO_NODE_SOCKET_PATH", "devnet/node.socket")] } + str <- readCreateProcess queryProc "" + pure $ fromMaybe mempty $ decode $ BS.pack str + + +getTempPath' :: IO FilePath +getTempPath' = snd <$> getTempPath + +getTempPath :: IO (UUID, FilePath) +getTempPath = do + createDirectoryIfMissing True "tmp" + uid <- UUIDV4.nextRandom + pure . (uid,) . ("tmp/" <>) . UUID.toString $ uid + +-- TODO(skylar): Check lovelace vs the full amount! +buildSignedHydraTx :: SigningKey -> Address -> Address -> Map TxIn Lovelace -> Lovelace -> IO String +buildSignedHydraTx signingKey fromAddr toAddr txInAmounts amount = do + let fullAmount = sum txInAmounts + txBodyPath <- snd <$> getTempPath + void $ readCreateProcess (proc cardanoCliPath + ([ "transaction" + , "build-raw" + , "--babbage-era" + ] + <> (concatMap (\txin -> ["--tx-in", T.unpack txin]) . Map.keys $ txInAmounts) + <> + [ "--tx-out" + , [i|#{toAddr}+#{amount}|] + , "--tx-out" + , [i|#{fromAddr}+#{fullAmount - amount}|] + , "--fee" + , "0" + , "--out-file" + , txBodyPath + ])) + "" + readCreateProcess + (proc cardanoCliPath + [ "transaction" + , "sign" + , "--tx-body-file" + , txBodyPath + , "--signing-key-file" + , signingKey + , "--out-file" + , "/dev/stdout" + ]) + "" +-- { env = Just [("CARDANO_NODE_SOCKET_PATH", "devnet/node.socket")] } + +-- | Convenience for getting faucet Output for seeding +getFirstTxIn :: Address -> IO TxIn +getFirstTxIn addr = + readCreateProcess cp "" >>= readProcess jqPath ["-r", "keys[0]"] >>= \a -> pure $ T.strip $ T.pack a + where + cp = (proc cardanoCliPath [ "query" + , "utxo" + , "--address" + , addr + , "--testnet-magic" + , "42" + , "--out-file" + , "/dev/stdout" + ]) { env = Just [("CARDANO_NODE_SOCKET_PATH", "devnet/node.socket")] } + + +getCardanoAddress :: VerificationKey -> IO Address +getCardanoAddress keyPath = + readCreateProcess cp "" + where + cp = (proc cardanoCliPath [ "address" + , "build" + , "--payment-verification-key-file" + , keyPath + , "--testnet-magic" + , "42" + ]) { env = Just [("CARDANO_NODE_SOCKET_PATH", "devnet/node.socket")] } + + +getFaucetAddress :: IO Address +getFaucetAddress = readCreateProcess cp "" + where + cp = (proc cardanoCliPath [ "address" + , "build" + , "--payment-verification-key-file" + , "devnet/credentials/faucet.vk" + , "--testnet-magic" + , "42" + ]) { env = Just [("CARDANO_NODE_SOCKET_PATH", "devnet/node.socket")] } + +seedAddressFromFaucetAndWait :: (MonadIO m) => Address -> Lovelace -> Bool -> m TxIn +seedAddressFromFaucetAndWait addr amount isFuel = do + txin <- liftIO $ seedAddressFromFaucet addr amount isFuel + waitForTxIn txin + pure txin + +-- | Send an amount in lovelace to the named actor +seedAddressFromFaucet :: Address -> Lovelace -> Bool -> IO TxIn +seedAddressFromFaucet addr amount isFuel = do + draftTx <- buildSeedTxForAddress addr amount isFuel + signedTx <- signSeedTx' draftTx + txin <- txInput 0 <$> seedTxIdFromSignedTx signedTx + submitTx signedTx + pure txin + + +buildSeedTxForAddress :: Address -> Lovelace -> Bool -> IO DraftTx +buildSeedTxForAddress addr amount isFuel = do + filename <- getTempPath' + -- when (amount < minTxLovelace) $ error $ "Minmum required UTxO: Lovelace " <> show minTxLovelace + let cp faucet hash = (proc cardanoCliPath $ filter (/= "") + [ "transaction" + , "build" + , "--babbage-era" + , "--cardano-mode" + , "--change-address" + , faucet + , "--tx-in" + , hash + , "--tx-out" + , addr <> "+" <> show amount + ] + <> bool [] [ "--tx-out-datum-hash", T.unpack fuelMarkerDatumHash ] isFuel + <> + [ "--out-file" + , filename + , "--testnet-magic" + , "42" + ]) + { env = Just [("CARDANO_NODE_SOCKET_PATH", "devnet/node.socket")] } + faucet <- getFaucetAddress + hash <- getFirstTxIn faucet + _ <- readCreateProcess (cp faucet (T.unpack hash)) "" + pure filename + + +signSeedTx' :: DraftTx -> IO SignedTx +signSeedTx' draftFile = do + outFile <- getTempPath' + let cp = (proc cardanoCliPath [ "transaction" + , "sign" + , "--tx-body-file" + , draftFile + , "--signing-key-file" + , "devnet/credentials/faucet.sk" + , "--out-file" + , outFile + , "--testnet-magic" + , "42" + ]) + { env = Just [("CARDANO_NODE_SOCKET_PATH", "devnet/node.socket")] } + _ <- readCreateProcess cp "" + pure outFile + +seedTxIdFromSignedTx :: SignedTx -> IO TxId +seedTxIdFromSignedTx filename = + T.strip . T.pack <$> readCreateProcess cp "" + where + cp = (proc cardanoCliPath [ "transaction" + , "txid" + , "--tx-file" + , filename + ]) { env = Just [("CARDANO_NODE_SOCKET_PATH", "devnet/node.socket")] } + +submitTx :: SignedTx -> IO () +submitTx signedFile = do + _ <- readCreateProcess cp "" + pure () + where + cp = (proc cardanoCliPath [ "transaction" + , "submit" + , "--tx-file" + , signedFile + , "--testnet-magic" + , "42" + ]) { env = Just [("CARDANO_NODE_SOCKET_PATH", "devnet/node.socket")] } diff --git a/src/Hydra/NodeTypes.hs b/src/Hydra/NodeTypes.hs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/Hydra/NodeTypes.hs @@ -0,0 +1 @@ + diff --git a/src/Hydra/ServerOutput.hs b/src/Hydra/ServerOutput.hs new file mode 100644 index 0000000..a50eef0 --- /dev/null +++ b/src/Hydra/ServerOutput.hs @@ -0,0 +1,54 @@ +-- | + +module Hydra.ServerOutput where + +import GHC.Generics +import Data.Aeson + +import Data.Time (UTCTime) +import Data.Text (Text) +import Hydra.Types +import Hydra.ClientInput + +-- Copied and adapted from hydra-poc:hydra-node/src/hydra/ServerOutput.hs +-- Anything that took effort was replaced by Value + +data ServerOutput tx + = PeerConnected {peer :: Host} + | PeerDisconnected {peer :: Host} + | ReadyToCommit {parties :: Value} + | Committed {party :: Party, utxo :: WholeUTXO} + | HeadIsOpen {utxo :: WholeUTXO} + | HeadIsClosed + { snapshotNumber :: SnapshotNumber + , -- | Nominal deadline until which contest can be submitted and after + -- which fanout is possible. NOTE: Use this only for informational + -- purpose and wait for 'ReadyToFanout' instead before sending 'Fanout' + -- as the ledger of our cardano-node might not have progressed + -- sufficiently in time yet and we do not re-submit transactions (yet). + contestationDeadline :: UTCTime + } + | HeadIsContested {snapshotNumber :: SnapshotNumber} + | ReadyToFanout + | HeadIsAborted {utxo :: WholeUTXO} + | HeadIsFinalized {utxo :: WholeUTXO} + | CommandFailed {clientInput :: ClientInput} + | TxSeen {transaction :: tx} + | TxValid {transaction :: tx} + | TxInvalid {utxo :: WholeUTXO, transaction :: tx, validationError :: ValidationError} + | SnapshotConfirmed + { snapshot :: Snapshot tx + , signatures :: MultiSignature (Snapshot tx) + } + | GetUTxOResponse {utxo :: WholeUTXO} + | InvalidInput {reason :: String, input :: Text} + | -- | A friendly welcome message which tells a client something about the + -- node. Currently used for knowing what signing key the server uses (it + -- only knows one). + Greetings {me :: Party} + | PostTxOnChainFailed {postChainTx :: PostChainTx tx, postTxError :: PostTxError tx} + | RolledBack + deriving (Eq, Show, Generic) + +instance (ToJSON tx) => ToJSON (ServerOutput tx) +instance (FromJSON tx) => FromJSON (ServerOutput tx) diff --git a/src/Hydra/Types.hs b/src/Hydra/Types.hs new file mode 100644 index 0000000..c5fccfc --- /dev/null +++ b/src/Hydra/Types.hs @@ -0,0 +1,63 @@ +-- | + +module Hydra.Types where + +import GHC.Generics +import Data.Aeson + +import Data.Map (Map) +import qualified Data.Text as T +import Data.Text (Text) +import Numeric.Natural (Natural) + +-- | Cardano address +type Address = String + +type Lovelace = Int + +type TxIn = T.Text +type WholeUTXO = Map TxIn TxInInfo + +data TxInInfo = TxInInfo + { address :: Address + , datumhash :: Maybe T.Text + , value :: Map T.Text Int + } + deriving (Eq, Show, Generic) + +instance FromJSON TxInInfo +instance ToJSON TxInInfo + +fuelMarkerDatumHash :: T.Text +fuelMarkerDatumHash = "a654fb60d21c1fed48db2c320aa6df9737ec0204c0ba53b9b94a09fb40e757f3" + + +-- REVIEW(SN): This is also used in hydra-tui + +-- Below various types copied/adapted from hydra-poc code + +data Host = Host + { hostname :: Text + , port :: PortNumber + } + deriving (Ord, Generic, Eq, Show) + +instance ToJSON Host +instance FromJSON Host + + +newtype Party = Party {vkey :: T.Text} + deriving (Eq, Show, Read, Generic) + +instance ToJSON Party +instance FromJSON Party + +type UTxOType tx = Value +type Snapshot tx = Value +type MultiSignature x = Value +type PostChainTx tx = Value +type PostTxError tx = Value +type ValidationError = Value +type SnapshotNumber = Natural +type PortNumber = Natural +type ContestationPeriod = Natural diff --git a/src/Main.hs b/src/Main.hs new file mode 100644 index 0000000..1e3dcad --- /dev/null +++ b/src/Main.hs @@ -0,0 +1,650 @@ +{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE PartialTypeSignatures #-} +{-# OPTIONS_GHC -Wno-unused-do-bind #-} +{-# LANGUAGE TupleSections #-} +{-# LANGUAGE ConstraintKinds #-} +{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-} + + +module Main + +(main) + +where + +import Prelude hiding (filter) + +import Hydra.Devnet + +import Control.Monad + +import System.Directory +import Control.Monad.IO.Class (MonadIO, liftIO) + +import qualified Data.Map as Map +import Data.Map (Map, (!)) +import Data.Witherable +import Data.String.Interpolate ( i, iii, __i ) +import qualified Data.Text as T + +import Control.Concurrent +import System.Process + +import Data.Aeson as Aeson + ( decode, (.:), withObject, Value ) + +import Data.Aeson.Text (encodeToTextBuilder) +import Data.Text.Lazy (toStrict) +import Data.Text.Lazy.Builder (toLazyText) + +import qualified Data.Map.Merge.Lazy as Map +import qualified Hydra.Types as HT +import Data.Maybe (fromJust, fromMaybe) +import Data.Aeson.Types (parseMaybe) +import System.IO (IOMode(WriteMode), openFile) +import Data.IORef (readIORef, writeIORef, IORef, newIORef) +import Hydra.Types +import Data.Text (Text) +import qualified Data.ByteString.Lazy.Char8 as ByteString.Char8 +import Data.Time (UTCTime, diffUTCTime) + +import Reflex +import Reflex.Dom +import Control.Monad.Fix +import Hydra.ClientInput +import Hydra.ServerOutput +import Data.Bool (bool) +import Text.Read (readMaybe) +import Data.Traversable (for) +import Data.Semigroup (First(getFirst, First)) +import Data.Aeson + +import Control.Monad.Trans (lift) +import Language.Javascript.JSaddle.Types ( MonadJSM ) + +standupDemoHydraNetwork :: (MonadIO m) + => HydraScriptTxId + -> Map Text HydraKeyInfo + -> m (Map Text (ProcessHandle, HydraNodeInfo)) +standupDemoHydraNetwork hstxid actors = do + liftIO $ createDirectoryIfMissing True "demo-logs" + liftIO $ sequence . flip Map.mapWithKey nodes $ \name node'' -> do + logHndl <- openFile [iii|demo-logs/hydra-node-#{name}.log|] WriteMode + errHndl <- openFile [iii|demo-logs/phydra-node-#{name}.error.log|] WriteMode + let cp = (mkHydraNodeCP sharedInfo node'' (filter ((/= _nodeId node'') . _nodeId) (Map.elems nodes))) + { std_out = UseHandle logHndl + , std_err = UseHandle errHndl + } + (_,_,_,handle) <- createProcess cp + pure (handle, node'') + where + portNum p n = p * 1000 + n + node' (n, (name, keys)) = + ( name + , HydraNodeInfo n (portNum 5 n) (portNum 9 n) (portNum 6 n) keys + ) + nodes = Map.fromList . fmap node' $ zip [1 ..] (Map.toList actors) + sharedInfo = HydraSharedInfo + { _hydraScriptsTxId = T.unpack hstxid + , _ledgerGenesis = "devnet/genesis-shelley.json" + , _ledgerProtocolParameters = "devnet/protocol-parameters.json" + , _networkId = show devnetMagic + , _nodeSocket = "devnet/node.socket" + } + +-- | Takes the node participant and the list of peers +mkHydraNodeCP :: HydraSharedInfo -> HydraNodeInfo -> [HydraNodeInfo] -> CreateProcess +mkHydraNodeCP sharedInfo node peers = + (proc hydraNodePath $ sharedArgs sharedInfo <> nodeArgs node <> concatMap peerArgs peers) + { std_out = Inherit + } + +data HydraSharedInfo = HydraSharedInfo + { _hydraScriptsTxId :: String + , _ledgerGenesis :: FilePath + , _ledgerProtocolParameters :: FilePath + , _networkId :: String + , _nodeSocket :: FilePath + } + +data HydraNodeInfo = HydraNodeInfo + { _nodeId :: Int + , _port :: Int + , _apiPort :: Int + , _monitoringPort :: Int + , _keys :: HydraKeyInfo + } + +sharedArgs :: HydraSharedInfo -> [String] +sharedArgs (HydraSharedInfo hydraScriptsTxId ledgerGenesis protocolParams networkId nodeSocket) = + [ "--ledger-genesis" + , ledgerGenesis + , "--ledger-protocol-parameters" + , protocolParams + , "--network-id" + , networkId + , "--node-socket" + , nodeSocket + , "--hydra-scripts-tx-id" + , hydraScriptsTxId + ] + +nodeArgs :: HydraNodeInfo -> [String] +nodeArgs (HydraNodeInfo nodeId port' apiPort monitoringPort + (HydraKeyInfo + (KeyPair cskPath _cvkPath) + (KeyPair hskPath _hvkPath))) = + [ "--node-id" + , show nodeId + , "--port" + , show port' + , "--api-port" + , show apiPort + , "--monitoring-port" + , show monitoringPort + , "--hydra-signing-key" + , hskPath + , "--cardano-signing-key" + , cskPath + ] + +peerArgs :: HydraNodeInfo -> [String] +peerArgs ni = + [ "--peer" + , [i|127.0.0.1:#{_port ni}|] + , "--hydra-verification-key" + , _verificationKey . _hydraKeys . _keys $ ni + , "--cardano-verification-key" + , _verificationKey . _cardanoKeys . _keys $ ni + ] + +cardanoNodeCreateProcess :: CreateProcess +cardanoNodeCreateProcess = + (proc cardanoNodePath + [ "run" + , "--config" + , "devnet/cardano-node.json" + , "--topology" + , "devnet/topology.json" + , "--database-path" + , "devnet/db" + , "--socket-path" + , "devnet/node.socket" + , "--shelley-operational-certificate" + , "devnet/opcert.cert" + , "--shelley-kes-key" + , "devnet/kes.skey" + , "--shelley-vrf-key" + , "devnet/vrf.skey" + ]) { std_out = CreatePipe + } + +runHydraDemo :: (MonadIO m) + => HydraDemo + -> m (Map Text ( ProcessHandle + , Address -- Cardano address + , HydraNodeInfo + )) +runHydraDemo nodes = do + keysAddresses <- forM nodes $ \(actorSeed, fuelSeed) -> do + keys@(HydraKeyInfo (KeyPair _ vk) _) <- generateKeys + addr <- liftIO $ getCardanoAddress vk + void $ seedAddressFromFaucetAndWait addr actorSeed False + void $ seedAddressFromFaucetAndWait addr fuelSeed True + pure (keys, addr) + liftIO . putStrLn $ "Publishing reference scripts" + hstxid <- publishReferenceScripts + handles <- standupDemoHydraNetwork hstxid (fmap fst keysAddresses) + liftIO . putStrLn $ [i|"Hydra Network Running for nodes #{Map.keys nodes}|] + pure $ Map.merge Map.dropMissing Map.dropMissing (Map.zipWithMatched (\_ addr (handle, nodeInfo) -> (handle, addr, nodeInfo))) (fmap snd keysAddresses) handles + + +type State = Map Text ( ProcessHandle + , Address -- Cardano address + , HydraNodeInfo + ) + +headElement :: forall t m. ( TriggerEvent t m, DomBuilder t m) =>m () +headElement = do + el "title" $ text "Hydra Head Demo" + elAttr "script" ("src"=:"https://cdn.tailwindcss.com") blank + +main :: IO () +main = liftIO $ do + prepareDevnet + withCreateProcess cardanoNodeCreateProcess $ \_ _stdout _ _handle -> do + putStrLn "Devnet is running" + threadDelay $ seconds 3 + mainWidgetWithHead headElement app + +makeTx :: () => IORef State -> Text + -> Map TxIn TxInInfo -> Lovelace -> Text -> IO Text +makeTx hydraProcessHandlesRef fromName utxos lovelace toName = do + print (fromName, utxos, toName) + let lovelaceUtxos = mapMaybe (Map.lookup "lovelace" . HT.value) utxos + actors <- readIORef hydraProcessHandlesRef + jsonStr <- + buildSignedHydraTx + (_signingKey . _cardanoKeys . _keys . (\(_, _, hn) -> hn) $ actors ! fromName) + ((\(_, addr, _) -> addr) $ actors ! fromName) + ((\(_, addr, _) -> addr) $ actors ! toName) + lovelaceUtxos + lovelace + let jsonTx :: Aeson.Value = fromMaybe (error "Failed to parse TX") . Aeson.decode . ByteString.Char8.pack $ jsonStr + pure . fromJust . parseMaybe (withObject "signed tx" (.: "cborHex")) $ jsonTx + +startDemo :: MonadIO m => IORef State -> HydraDemo -> m RunningNodes +startDemo hydraProcessHandlesRef demo = do + liftIO (mapM (terminateProcess . (\(hndl, _, _) -> hndl)) =<< readIORef hydraProcessHandlesRef) + nodeInfos <- runHydraDemo demo + liftIO . writeIORef hydraProcessHandlesRef $ nodeInfos + actorList :: RunningNodes <- forM nodeInfos $ \(_, addr, nInfo) -> do + pure + ( addr, + [iii|ws://localhost:#{_apiPort nInfo}|] + ) + pure actorList + +-- | Friendly name for a Hydra node. +type DemoNodeName = Text + +-- | WebSocket URL +type ApiUrl = Text + +type RunningNodes = Map DemoNodeName ( Address -- Cardano address + , ApiUrl + ) + +type HydraDemo = Map + DemoNodeName + ( Lovelace -- Seed for actor + , Lovelace -- Seed for fuel + ) + + +seconds :: Int -> Int +seconds = (* 1000000) + +alicebobcarolDemo :: HydraDemo +alicebobcarolDemo = Map.fromList [("Alice", (1000000000, 100000000)), ("Bob", (500000000, 100000000)), ("Carol", (250000000, 100000000))] + + +filterOutFuel :: WholeUTXO -> WholeUTXO +filterOutFuel = Map.filter (not . isFuel) + +isFuel :: TxInInfo -> Bool +isFuel txinfo = datumhash txinfo == Just fuelMarkerDatumHash + +-- | Tracks the state of the head based on Hydra Node responses +data HeadState + = Idle + | Initializing + | Open + | Closed UTCTime + | StateReadyToFanout + deriving (Eq, Show) + + +buttonClass :: (PostBuild t m, DomBuilder t m) => Dynamic t T.Text -> m b -> m (Event t ()) +buttonClass cls content = do + (buttonEl, _) <- elDynClass' "button" cls content + pure $ domEvent Click buttonEl + + +utxoPicker :: forall t m. (DomBuilder t m, MonadFix m, MonadHold t m, PostBuild t m) => Bool -> WholeUTXO -> m (Dynamic t (Maybe WholeUTXO)) +utxoPicker pickable wholeUtxo = mdo + elClass "div" "font-semibold text-lg mb-2" $ text "UTxOs" + + currentUtxo <- holdDyn Nothing selectedUtxo + selectedUtxo <- fmap (leftmost . Map.elems) $ elClass "div" "flex flex-row flex-wrap gap-2" $ flip Map.traverseWithKey wholeUtxo $ \k v -> mdo + let amiSelected = maybe False ((k ==) . fst) <$> currentUtxo + let cls = ("text-white font-bold text-xl px-4 py-2 rounded-md flex flex-row cursor-pointer mr-2 " <>) + . bool + "bg-gray-500 hover:bg-gray-400 active:bg-gray-300" + "bg-blue-500 hover:bg-blue-400 active:bg-blue-300" + <$> amiSelected + (buttonEl, _) <- elDynClass' "button" cls $ do + elClass "div" "text-sm text-gray-300 font-semibold flex justify-between" $ do + elClass "div" "flex flex-col" $ do + elClass "div" "w-full flex flex-row justify-between" $ do + elClass "div" "text-gray-400 mr-4" $ text "lovelace" + when (isFuel v) $ elClass "div" "px-2 py-0 flex items-center justify-center leading-node bg-green-500 text-xs text-white font-semibold text-sm rounded-full flex" $ + el "div" $ text "FUEL" + elClass "div" "text-lg text-left font-semibold" $ text $ maybe "" (T.pack . show) (Map.lookup "lovelace" $ HT.value v) + + pure $ bool Nothing (Just (k, v)) . (pickable &&) . not <$> current amiSelected <@ domEvent Click buttonEl + pure $ fmap (uncurry Map.singleton) <$> currentUtxo + +demoSettings :: (DomBuilder t m, PostBuild t m, MonadHold t m, MonadFix m) => HydraDemo -> m (Dynamic t HydraDemo) +demoSettings setngs = elClass "div" "flex flex-col pl-4 pr-4" $ do + let initSize = Map.size setngs + let initialList = Map.fromList (zip [1 .. ] (Map.toList setngs)) + rec + nextIdentityNumber <- fmap (1 + initSize +) <$> count newNode + let updates = + ((\n -> Map.singleton n (Just ([i|Node #{n}|], (100000000, 100000000)))) <$> current nextIdentityNumber <@ newNode) + <> deleteEs + (((), deleteEs), demoDyn) <- runDynamicWriterT $ runEventWriterT $ void $ elClass "div" "flex-col space-y-2" $ do + elClass "p" "text-white text-2xl my-4" $ text "Configure a Hydra Head by specifying the node names and their initial funds in Lovelace." + listHoldWithKey initialList updates $ \k (name, (actorSeed, _hydraSeed)) -> elClass "div" "flex flex-col" $ do + name' <- elClass "div" "flex flex-row space-x-2" $ do + name' <- fmap _inputElement_value . inputElement $ + def & inputElementConfig_initialValue .~ name + & initialAttributes .~ ("class" =: "text-white bg-gray-800 text-2xl font-bold focus:outline-none p-2" <> "type" =: "text") + amount' <- fmap _inputElement_value . inputElement $ + def & inputElementConfig_initialValue .~ (T.pack . show $ actorSeed) + & initialAttributes .~ ("class" =: "text-white bg-gray-800 text-2xl font-bold focus:outline-none p-2" <> "type" =: "number") + deleteE <- buttonClass "bg-gray-400 hover:bg-gray-300 active:bg-gray-200 text-white font-bold text-xl px-4 py-2 rounded-md" $ + text "×" + let actorSeed' = (\n a -> (n,) <$> readMaybe (T.unpack a)) <$> name' <*> amount' + tellDyn (maybe mempty (Map.singleton k. (\(actor,sd) -> (actor, (sd, 100000000)))) <$> actorSeed') + tellEvent (Map.singleton k Nothing <$ deleteE) + pure name' + let hasDuplicateName = (\n ns -> (> 1) . Map.size . Map.filter (\(n',_) -> n == n') $ ns) <$> name' <*> demoDyn + let duplicateNameMsg = elClass "div" "text-red-400 m-2" $ text "Duplicate name" + dyn_ (bool blank duplicateNameMsg <$> fromUniqDynamic (uniqDynamic hasDuplicateName)) + pure () + newNode <- buttonClass "bg-gray-400 hover:bg-gray-300 active:bg-gray-200 text-white font-bold text-xl my-4 px-4 py-2 rounded-md w-32" $ + text "Add node" + let demoDyn' = Map.fromList . Map.elems <$> demoDyn + pure demoDyn' + +startStopDemoControls :: + ( DomBuilder t m, + MonadFix m, + PostBuild t m, + MonadHold t m, MonadIO (Performable m), PerformEvent t m) => + IORef State -> + m (Event t RunningNodes) +startStopDemoControls hydraProcessHandlesRef = mdo + headRunning <- toggle False headStartedOrStoppedE + ((), demoConfig) <- runDynamicWriterT $ dyn_ (bool (tellDyn =<< demoSettings alicebobcarolDemo) blank <$> headRunning) + startStopHeadE <- buttonClass ((\running -> + let color :: Text = bool "green" "red" running + in [__i|bg-#{color}-500 hover:bg-#{color}-400 active:bg-#{color}-300 + text-white font-bold text-xl m-4 px-4 py-2 rounded-md|] + :: Text) + <$> headRunning) + $ dynText (bool "Start head" "Stop head" <$> headRunning) + let startStopWithConfE = current demoConfig <@ startStopHeadE + headStartedOrStoppedE <- performEvent $ + -- Start with mempty to stop the demo: + (\running conf -> startDemo hydraProcessHandlesRef $ bool conf mempty running) + <$> current headRunning + <@> startStopWithConfE + let headStartingDom conf = + if Map.null conf + then blank + else elClass "div" "text-white text-2xl m-4" $ text "Head starting..." + void $ runWithReplace blank $ leftmost [ headStartingDom <$> startStopWithConfE + , blank <$ headStartedOrStoppedE + ] + pure headStartedOrStoppedE + + +app :: + forall t m. + ( PostBuild t m, + DomBuilder t m, + MonadFix m, + MonadJSM m, MonadJSM (Performable m), + MonadHold t m, PerformEvent t m, TriggerEvent t m) => + m () +app = do + hydraProcessHandlesRef :: IORef State <- liftIO (newIORef mempty) + elClass "div" "w-screen h-screen bg-gray-900 overflow-y-scroll overflow-x-hidden" $ do + elClass "div" "p-4 m-4 text-white text-5xl font-bold" $ text "Hydra Proof Of Concept Demo" + mdo + headStartedE <- startStopDemoControls hydraProcessHandlesRef + void $ runWithReplace blank $ ffor headStartedE $ \actors -> mdo + let actorNames = ffor (Map.toList actors) $ \(name, (_,_)) -> name + headState <- holdDyn Idle newState + let headStateDom = elClass "div" "text-lg" . text . ("Head State: " <>) + unless (null actors) $ elClass "div" "ml-4 mt-8 mr-4 mb-2 w-full font-black text-green-500" $ dyn_ $ ffor headState $ \case + Idle -> do + headStateDom "Idle" + elClass "div" "text-green-700 text-sm" $ text "Waiting for participant to init..." + Initializing -> do + headStateDom "Initializing" + elClass "div" "text-green-700 text-sm" $ text $ "Waiting for commits from: " <> T.intercalate ", " actorNames + Open -> headStateDom "Open" + Closed _ -> headStateDom "Closed/Contestation period" + StateReadyToFanout -> headStateDom "Ready to fanout" + + newState <- elClass "div" "ml-4 mr-4 overflow-hidden rounded-lg hover:drop-shadow-xl transition-all drop-shadow bg-gray-800" $ mdo + rec + currentTab <- holdDyn (head actorNames) changeTab + + changeTab <- fmap leftmost $ elClass "div" "w-full flex flex-row justify-start" $ for actorNames $ \name -> do + let + isSelected = (== name) <$> currentTab + mkClasses selected = + T.intercalate " " [ "leading-none p-4 font-bold text-2xl text-gray-100 flex items-center justify-center" + , bool "bg-gray-800 text-gray-300 pointer-cursor" "bg-gray-700 text-gray-100" selected + ] + (buttonEl, _) <- elDynClass' "button" (mkClasses <$> isSelected) $ text name + pure $ name <$ domEvent Click buttonEl + fmap (fmap getFirst . snd) . runEventWriterT $ forM (Map.toList actors) $ \(name, (actorAddress, wsUrl)) -> mdo + let wsCfg = (WebSocketConfig @t @ClientInput) action never True [] + ws <- jsonWebSocket wsUrl wsCfg + let isSelected = (== name) <$> currentTab + let mkClasses selected = + T.intercalate " " [ "p-2 bg-gray-700 text-white flex flex-col items-left" + , bool "hidden" "" selected + ] + (_, action) <- elDynClass "div" (mkClasses <$> isSelected) $ runEventWriterT $ runWithReplace (elClass "div" "text-white" $ text "Connecting to node...") . ffor (_webSocket_open ws) $ \() -> do + let + webSocketMessage :: Event t (ServerOutput Aeson.Value) = + fromMaybe (error "Parsing message from Hydra node failed") <$> _webSocket_recv ws + processLog = \case + ReadyToCommit {} -> Just Initializing + HeadIsOpen {} -> Just Open + HeadIsClosed _ fanoutTime -> Just (Closed fanoutTime) + ReadyToFanout {} -> Just StateReadyToFanout + HeadIsAborted {} -> Just Idle + HeadIsFinalized {} -> Just Idle + _ -> Nothing + let stateChange = fmapMaybe processLog webSocketMessage + let + + myVKeyB :: Behavior t (Maybe T.Text) <- + hold Nothing + . fmap Just + . mapMaybe (\case + Greetings (Party vkey') -> Just vkey' + _ -> Nothing) + $ webSocketMessage + headStateE <- mdo + void $ dyn $ ffor headState $ \case + Idle -> idleScreen name + Initializing -> initializingScreen actorAddress myVKeyB webSocketMessage + Open -> openScreen hydraProcessHandlesRef name actorNames actorAddress webSocketMessage + Closed fanoutTime -> closedScreen fanoutTime + StateReadyToFanout -> + tellAction + . (Fanout <$) + <=< buttonClass "bg-green-400 hover:bg-green-400 active:bg-green-200 text-white font-bold text-xl my-2 px-4 py-2 rounded-md w-32" $ text "Do fanout" + elClass "div" "mt-4" $ do + elClass "div" "mb-1 font-semibold text-sm" $ text "Hydra Node Log" + elClass "div" "p-2 bg-gray-800 rounded-md drop-shadow" $ + el "ul" $ do + comms <- foldDyn (++) [] $ + ((:[]) . ("Rcv: " <>) . toStrict . toLazyText . encodeToTextBuilder . toJSON <$> webSocketMessage) + <> + fmap (fmap (("Snd: " <>) . toStrict . toLazyText . encodeToTextBuilder . toJSON)) action + dyn_ $ mapM (el "li" . text) <$> comms + pure stateChange + lift $ tellEvent (First <$> headStateE) + pure () + pure () + +filterUtxos :: Address -> WholeUTXO -> WholeUTXO +filterUtxos addr = Map.filter ((== addr) . HT.address) + +tellAction :: (EventWriter t [a] m, Reflex t) => Event t a -> m () +tellAction = tellEvent . fmap (:[]) + +idleScreen :: (EventWriter t [ClientInput] m, DomBuilder t m) => Text -> m () +idleScreen name = + elClass "div" "p-2 flex flex-row" $ do + (buttonEl, _) <- elClass' "button" "bg-blue-500 hover:bg-blue-400 active:bg-blue-300 text-white font-bold text-xl px-4 py-2 rounded-md" $ text $ "Initialize head as " <> name + tellAction $ Init 10 <$ domEvent Click buttonEl + +initializingScreen :: + ( EventWriter t [ClientInput] m, + DomBuilder t m, + MonadFix m, + MonadHold t m, + PostBuild t m, MonadIO m) => + Address -> + Behavior t (Maybe Text) -> + Event t (ServerOutput tx) -> + m () +initializingScreen actorAddress myVKeyB webSocketMessage = do + elClass "div" "p-2 flex flex-col" $ do + -- TODO: did not use performEvent here + newUTXOs <- liftIO $ queryAddressUTXOs actorAddress -- fmapMaybe eitherToMaybe <$> (undefined . (DemoApi_GetActorUTXO actorAddress <$) =<< getPostBuild) + let commitSelection doCommit = do + (_, currentSet) <- + runDynamicWriterT $ (tellDyn <=< utxoPicker True) newUTXOs +-- runWithReplace (elClass "div" "p-4 bg-gray-800 rounded mb-2" $ text $ "Getting " <> name <> "'s UTXOs...") $ +-- (tellDyn <=< utxoPicker True) <$> newUTXOs + tellAction $ fmap (Commit . fromMaybe mempty) $ current currentSet <@ doCommit + let hasCommitted = + attachWithMaybe + ( \mvkey -> \case + Committed (Party vk) _ -> guard (Just vk == mvkey) + _ -> Nothing + ) + myVKeyB + webSocketMessage + + mdo + void . runWithReplace (commitSelection doCommit) . ffor hasCommitted $ \() -> + elClass "div" "text-xl py-4" $ text "Committed, waiting for the others." + doCommit <- elClass "div" "flex flex-row mt-4" $ do + -- Until the head is committed starting the head can be aborted: + tellAction + . (Hydra.ClientInput.Abort <$) + <=< buttonClass "bg-gray-400 hover:bg-gray-300 active:bg-gray-200 text-white font-bold text-xl px-4 py-2 rounded-md mr-2" + $ text "Abort" + isDisabled <- holdDyn False (True <$ hasCommitted) + let cls = + (bool "bg-blue-500 hover:bg-blue-400 active:bg-blue-300" "bg-gray-500 hover:bg-gray-500 active:bg-gray-500 cursor-not-allowed " <$> isDisabled) + <> " text-white font-bold text-xl px-4 py-2 rounded-md" + buttonClass cls $ text "Commit" + pure () + pure () + + +openScreen :: + ( EventWriter t [ClientInput] m, + DomBuilder t m, + MonadFix m, + MonadHold t m, + PostBuild t m, + MonadIO (Performable m), PerformEvent t m) => + IORef State -> + Text -> + [Text] -> + Address -> + Event t (ServerOutput tx) -> + m () +openScreen hydraProcessHandlesRef name actorNames actorAddress webSocketMessage = do + -- Get your UTxOs on page load and when we observe a transaction + tellAction . (GetUTxO <$) + . ( ( void $ + filter + ( \case + TxSeen {} -> True + _ -> False + ) + webSocketMessage + ) + <> + ) + =<< getPostBuild + let updatedUTXOs = + fmap (filterUtxos actorAddress) + . mapMaybe + ( \case + GetUTxOResponse utxoz -> Just utxoz + _ -> Nothing + ) + $ webSocketMessage + currentUTXOs <- holdDyn mempty updatedUTXOs + let ifUTXOs yes no = dyn_ (bool yes no <$> fmap Map.null currentUTXOs) + ifUTXOsDyn yes no = dyn (bool yes no <$> fmap Map.null currentUTXOs) + mdo + (_, currentSet) <- + runDynamicWriterT + . runWithReplace (elClass "div" "text-white text-2xl" $ text "Getting your UTxOs") + $ fmap (tellDyn <=< (pure . pure . filterOutFuel)) updatedUTXOs + _ <- elClass "div" "mb-4 ml-2" $ dyn_ $ utxoPicker False <$> currentSet + elClass "div" "text-xl mb-8 ml-2" $ ifUTXOs (text "Send Ada to a participant:") (text "No UTXOs for this participant") + flip ifUTXOs blank $ do + (recipientDyn, lovelaceDyn) <- elClass "div" "flex ml-2 mb-2" $ + elClass "div" "w-auto flex flex-row rounded bg-gray-800 mb-2 overflow-hidden" $ do + ie <- elClass "div" "flex flex-col p-2" $ do + elClass "div" "text-gray-600 text-sm font-semibold" $ text "LOVELACES" + inputElement $ + def + & initialAttributes .~ ("class" =: "bg-gray-800 text-2xl font-bold focus:outline-none p-2" <> "type" =: "number") + & inputElementConfig_initialValue .~ "1000000" + recipient <- fmap Reflex.Dom.value $ + elClass "div" "flex flex-col p-2" $ do + elClass "div" "text-gray-600 text-sm font-semibold uppercase" $ text "To" + -- FIXME: unsafe head, will crash with <= 1 actors + dropdown + (head $ filter (/= name) actorNames) + (pure (Map.filter (/= name) $ Map.fromList (fmap (\n -> (n, n)) actorNames))) + $ def & dropdownConfig_attributes .~ pure ("class" =: "bg-gray-800 hover:bg-gray-700 active:bg-gray-900 text-gray-100 font-semibold text-xl px-4 py-2 rounded-md m-2") + pure (recipient, readMaybe . T.unpack <$> _inputElement_value ie) + elClass "div" "flex" $ do + signedTxE <- + performEvent . fmap liftIO $ + makeTx hydraProcessHandlesRef name + <$> current currentSet + -- NOTE/TODO(skylar): This is just to default to the minimum + <*> current (fromMaybe 1000000 <$> lovelaceDyn) + <*> current recipientDyn + <@ doSend + tellAction + . fmap NewTx + $ signedTxE + + doSend <- elClass "div" "flex flex-row ml-2" $ do + sendButtonClick <- flip ifUTXOsDyn (pure never) $ do + buttonClass "bg-green-500 hover:bg-green-400 active:bg-green-200 text-white font-bold text-xl mr-2 px-4 py-2 rounded-md" $ text "Send" + tellAction + . (Close <$) + <=< buttonClass "bg-red-500 hover:bg-red-400 active:bg-red-200 text-white font-bold text-xl px-4 py-2 rounded-md" + $ text "Close Head" + switchHold never sendButtonClick + pure () + pure () + +closedScreen :: + ( MonadFix m, + MonadIO m, + MonadIO (Performable m), + DomBuilder t m, + PostBuild t m, + TriggerEvent t m, + PerformEvent t m, + MonadHold t m + ) => + UTCTime -> + m () +closedScreen fanoutTime = do + countDownDyn <- clockLossy 1 fanoutTime + elClass "div" "text-white text-2xl my-4 ml-2" $ do + text "Fanout time left: " + dyn_ + ( text . T.pack . show @Integer + . ceiling + . diffUTCTime fanoutTime + . _tickInfo_lastUTC + <$> countDownDyn + ) + text " seconds" diff --git a/src/Paths.hs b/src/Paths.hs new file mode 100644 index 0000000..b50c423 --- /dev/null +++ b/src/Paths.hs @@ -0,0 +1,14 @@ +{-# LANGUAGE TemplateHaskell #-} +module Paths where + +import System.Which (staticWhich) + +hydraToolsPath :: FilePath +hydraToolsPath = $(staticWhich "hydra-tools") + +realpathPath :: FilePath +realpathPath = $(staticWhich "realpath") + +dirnamePath :: FilePath +dirnamePath = $(staticWhich "dirname") +