diff --git a/.gitignore b/.gitignore index 50cf6de..158a4d3 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /config +node_modules diff --git a/deno.jsonc b/deno.jsonc index d27b8b6..b861dd6 100644 --- a/deno.jsonc +++ b/deno.jsonc @@ -1,21 +1,24 @@ { + "nodeModulesDir": "auto", "tasks": { - "generate": "deno run --allow-write=config --allow-read=config,generator ./generator/mod.ts", + "generate": "deno run --allow-write=config --allow-read=config ./generator/mod.ts", + "dev:relay": "DEBUG=* RELAY_CONFIG=./config/chain-aaa-relay.localhost.json deno run --watch -ENS -R=config ./relay/mod.ts" }, "imports": { "@david/dax": "jsr:@david/dax@^0.43.2", "@faker-js/faker": "npm:@faker-js/faker@^9.9.0", - "@iroha/client": "jsr:@iroha/client@^0.4.0", - "@iroha/core": "jsr:@iroha/core@^0.4.0", + "@iroha/client": "jsr:@iroha/client@0.5.0-alpha", + "@iroha/core": "jsr:@iroha/core@0.5.0-alpha", "@std/assert": "jsr:@std/assert@^1.0.13", "@std/async": "jsr:@std/async@^1.0.14", "@std/fs": "jsr:@std/fs@^1.0.19", "@std/path": "jsr:@std/path@^1.1.1", "@std/toml": "jsr:@std/toml@^1.0.8", "@std/yaml": "jsr:@std/yaml@^1.0.9", - "debug": "npm:debug@^4.4.1", + "pino": "npm:pino@^10.0.0", + "pino-pretty": "npm:pino-pretty@^13.1.1", "true-myth": "npm:true-myth@^9.0.1", "ts-pattern": "npm:ts-pattern@^5.8.0", - "zod": "npm:zod@^4.0.15", + "zod": "npm:zod@^4.1.11", } } diff --git a/deno.lock b/deno.lock index 803130e..1de8b47 100644 --- a/deno.lock +++ b/deno.lock @@ -2,15 +2,14 @@ "version": "5", "specifiers": { "jsr:@david/console-static-text@0.3": "0.3.0", - "jsr:@david/dax@*": "0.43.2", "jsr:@david/dax@~0.43.2": "0.43.2", "jsr:@david/path@0.2": "0.2.0", "jsr:@david/which@~0.4.1": "0.4.1", - "jsr:@iroha/client@0.4": "0.4.0", - "jsr:@iroha/core@0.4": "0.4.0", - "jsr:@std/assert@*": "1.0.13", - "jsr:@std/assert@^1.0.11": "1.0.13", - "jsr:@std/assert@^1.0.13": "1.0.13", + "jsr:@iroha/client@0.5.0-alpha": "0.5.0-alpha", + "jsr:@iroha/core@0.5.0-alpha": "0.5.0-alpha", + "jsr:@iroha/core@~0.5.0-alpha": "0.5.0-alpha", + "jsr:@std/assert@^1.0.11": "1.0.14", + "jsr:@std/assert@^1.0.13": "1.0.14", "jsr:@std/async@^1.0.14": "1.0.14", "jsr:@std/bytes@^1.0.5": "1.0.6", "jsr:@std/collections@^1.1.1": "1.1.2", @@ -18,12 +17,11 @@ "jsr:@std/fmt@1": "1.0.8", "jsr:@std/fs@1": "1.0.19", "jsr:@std/fs@^1.0.19": "1.0.19", - "jsr:@std/internal@^1.0.6": "1.0.10", + "jsr:@std/internal@^1.0.10": "1.0.10", "jsr:@std/internal@^1.0.9": "1.0.10", "jsr:@std/io@0.225": "0.225.2", - "jsr:@std/path@*": "1.1.1", - "jsr:@std/path@1": "1.1.1", - "jsr:@std/path@^1.1.1": "1.1.1", + "jsr:@std/path@1": "1.1.2", + "jsr:@std/path@^1.1.1": "1.1.2", "jsr:@std/toml@*": "1.0.8", "jsr:@std/toml@^1.0.8": "1.0.8", "jsr:@std/yaml@*": "1.0.9", @@ -31,13 +29,14 @@ "npm:@faker-js/faker@^9.9.0": "9.9.0", "npm:@scale-codec/core@^2.0.1": "2.0.1", "npm:@types/node@*": "22.15.15", - "npm:debug@^4.4.1": "4.4.1", - "npm:emittery@^1.1.0": "1.1.0", + "npm:emittery@^1.1.0": "1.2.0", "npm:p-defer@^4.0.1": "4.0.1", + "npm:pino-pretty@^13.1.1": "13.1.1", + "npm:pino@10": "10.0.0", "npm:true-myth@^9.0.1": "9.0.1", "npm:ts-pattern@^5.8.0": "5.8.0", "npm:type-fest@^4.33.0": "4.41.0", - "npm:zod@^4.0.15": "4.0.15" + "npm:zod@^4.1.11": "4.1.11" }, "jsr": { "@david/console-static-text@0.3.0": { @@ -65,18 +64,18 @@ "@david/which@0.4.1": { "integrity": "896a682b111f92ab866cc70c5b4afab2f5899d2f9bde31ed00203b9c250f225e" }, - "@iroha/client@0.4.0": { - "integrity": "4abd4bd3951f1b7f2936d9965f734e0be7f2c963b096463b83b7fb9da0aa60b3", + "@iroha/client@0.5.0-alpha": { + "integrity": "37cbf8cb120542268636f34b78f57718f9811916415bb0c306b7ac4bd316e161", "dependencies": [ - "jsr:@iroha/core", + "jsr:@iroha/core@~0.5.0-alpha", "jsr:@std/assert@^1.0.11", "npm:emittery", "npm:p-defer", "npm:type-fest" ] }, - "@iroha/core@0.4.0": { - "integrity": "3786372580fea5e3ef0fafcacba4f44c1f3505a437457aa1fe60e00ea454b974", + "@iroha/core@0.5.0-alpha": { + "integrity": "3bdc20b5af69434e926499da4f9e35eccb5d7da6596f68523ced60204ab38b6c", "dependencies": [ "jsr:@std/assert@^1.0.11", "jsr:@std/encoding", @@ -84,10 +83,10 @@ "npm:type-fest" ] }, - "@std/assert@1.0.13": { - "integrity": "ae0d31e41919b12c656c742b22522c32fb26ed0cba32975cb0de2a273cb68b29", + "@std/assert@1.0.14": { + "integrity": "68d0d4a43b365abc927f45a9b85c639ea18a9fab96ad92281e493e4ed84abaa4", "dependencies": [ - "jsr:@std/internal@^1.0.6" + "jsr:@std/internal@^1.0.10" ] }, "@std/async@1.0.14": { @@ -124,10 +123,10 @@ "jsr:@std/bytes" ] }, - "@std/path@1.1.1": { - "integrity": "fe00026bd3a7e6a27f73709b83c607798be40e20c81dde655ce34052fd82ec76", + "@std/path@1.1.2": { + "integrity": "c0b13b97dfe06546d5e16bf3966b1cadf92e1cc83e56ba5476ad8b498d9e3038", "dependencies": [ - "jsr:@std/internal@^1.0.9" + "jsr:@std/internal@^1.0.10" ] }, "@std/toml@1.0.8": { @@ -163,21 +162,139 @@ "undici-types" ] }, - "debug@4.4.1": { - "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "atomic-sleep@1.0.0": { + "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==" + }, + "colorette@2.0.20": { + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==" + }, + "dateformat@4.6.3": { + "integrity": "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==" + }, + "emittery@1.2.0": { + "integrity": "sha512-KxdRyyFcS85pH3dnU8Y5yFUm2YJdaHwcBZWrfG8o89ZY9a13/f9itbN+YG3ELbBo9Pg5zvIozstmuV8bX13q6g==" + }, + "end-of-stream@1.4.5": { + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", "dependencies": [ - "ms" + "once" ] }, - "emittery@1.1.0": { - "integrity": "sha512-rsX7ktqARv/6UQDgMaLfIqUWAEzzbCQiVh7V9rhDXp6c37yoJcks12NVD+XPkgl4AEavmNhVfrhGoqYwIsMYYA==" + "fast-copy@3.0.2": { + "integrity": "sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==" + }, + "fast-safe-stringify@2.1.1": { + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==" }, - "ms@2.1.3": { - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + "help-me@5.0.0": { + "integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==" + }, + "joycon@3.1.1": { + "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==" + }, + "minimist@1.2.8": { + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==" + }, + "on-exit-leak-free@2.1.2": { + "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==" + }, + "once@1.4.0": { + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": [ + "wrappy" + ] }, "p-defer@4.0.1": { "integrity": "sha512-Mr5KC5efvAK5VUptYEIopP1bakB85k2IWXaRC0rsh1uwn1L6M0LVml8OIQ4Gudg4oyZakf7FmeRLkMMtZW1i5A==" }, + "pino-abstract-transport@2.0.0": { + "integrity": "sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==", + "dependencies": [ + "split2" + ] + }, + "pino-pretty@13.1.1": { + "integrity": "sha512-TNNEOg0eA0u+/WuqH0MH0Xui7uqVk9D74ESOpjtebSQYbNWJk/dIxCXIxFsNfeN53JmtWqYHP2OrIZjT/CBEnA==", + "dependencies": [ + "colorette", + "dateformat", + "fast-copy", + "fast-safe-stringify", + "help-me", + "joycon", + "minimist", + "on-exit-leak-free", + "pino-abstract-transport", + "pump", + "secure-json-parse", + "sonic-boom", + "strip-json-comments" + ], + "bin": true + }, + "pino-std-serializers@7.0.0": { + "integrity": "sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==" + }, + "pino@10.0.0": { + "integrity": "sha512-eI9pKwWEix40kfvSzqEP6ldqOoBIN7dwD/o91TY5z8vQI12sAffpR/pOqAD1IVVwIVHDpHjkq0joBPdJD0rafA==", + "dependencies": [ + "atomic-sleep", + "on-exit-leak-free", + "pino-abstract-transport", + "pino-std-serializers", + "process-warning", + "quick-format-unescaped", + "real-require", + "safe-stable-stringify", + "slow-redact", + "sonic-boom", + "thread-stream" + ], + "bin": true + }, + "process-warning@5.0.0": { + "integrity": "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==" + }, + "pump@3.0.3": { + "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", + "dependencies": [ + "end-of-stream", + "once" + ] + }, + "quick-format-unescaped@4.0.4": { + "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==" + }, + "real-require@0.2.0": { + "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==" + }, + "safe-stable-stringify@2.5.0": { + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==" + }, + "secure-json-parse@4.1.0": { + "integrity": "sha512-l4KnYfEyqYJxDwlNVyRfO2E4NTHfMKAWdUuA8J0yve2Dz/E/PdBepY03RvyJpssIpRFwJoCD55wA+mEDs6ByWA==" + }, + "slow-redact@0.3.1": { + "integrity": "sha512-NvFvl1GuLZNW4U046Tfi8b26zXo8aBzgCAS2f7yVJR/fArN93mOqSA99cB9uITm92ajSz01bsu1K7SCVVjIMpQ==" + }, + "sonic-boom@4.2.0": { + "integrity": "sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww==", + "dependencies": [ + "atomic-sleep" + ] + }, + "split2@4.2.0": { + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==" + }, + "strip-json-comments@5.0.3": { + "integrity": "sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==" + }, + "thread-stream@3.1.0": { + "integrity": "sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==", + "dependencies": [ + "real-require" + ] + }, "true-myth@9.0.1": { "integrity": "sha512-8ePgamjgV3CKDI43o6eUtid+9iadfEKUiu2WTucbeCnPTyDOQpZ4svCuozLwm9S4hzUolOclsUCJf3yjQg3g/Q==" }, @@ -190,15 +307,18 @@ "undici-types@6.21.0": { "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==" }, - "zod@4.0.15": { - "integrity": "sha512-2IVHb9h4Mt6+UXkyMs0XbfICUh1eUrlJJAOupBHUhLRnKkruawyDddYRCs0Eizt900ntIMk9/4RksYl+FgSpcQ==" + "wrappy@1.0.2": { + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "zod@4.1.11": { + "integrity": "sha512-WPsqwxITS2tzx1bzhIKsEs19ABD5vmCVa4xBo2tq/SrV4RNZtfws1EnCWQXM6yh8bD08a1idvkB5MZSBiZsjwg==" } }, "workspace": { "dependencies": [ "jsr:@david/dax@~0.43.2", - "jsr:@iroha/client@0.4", - "jsr:@iroha/core@0.4", + "jsr:@iroha/client@0.5.0-alpha", + "jsr:@iroha/core@0.5.0-alpha", "jsr:@std/assert@^1.0.13", "jsr:@std/async@^1.0.14", "jsr:@std/fs@^1.0.19", @@ -206,10 +326,11 @@ "jsr:@std/toml@^1.0.8", "jsr:@std/yaml@^1.0.9", "npm:@faker-js/faker@^9.9.0", - "npm:debug@^4.4.1", + "npm:pino-pretty@^13.1.1", + "npm:pino@10", "npm:true-myth@^9.0.1", "npm:ts-pattern@^5.8.0", - "npm:zod@^4.0.15" + "npm:zod@^4.1.11" ] } } diff --git a/executor/Dockerfile b/executor/Dockerfile new file mode 100644 index 0000000..5a05e92 --- /dev/null +++ b/executor/Dockerfile @@ -0,0 +1,16 @@ +FROM hyperledger/iroha:experimental-xx-858df795cc8ea480a214ff73f3087a3bbf5f7d85 AS iroha + +FROM rust:1.89-bullseye +WORKDIR /app + +ARG IROHA_REV=a84bc8893451cf08f346eb476097c13ca7bf65fb +RUN git init && \ + git remote add origin https://github.com/hyperledger-iroha/iroha.git && \ + git fetch origin $IROHA_REV && \ + git reset --hard FETCH_HEAD + +COPY --from=iroha /usr/local/bin/kagami /usr/local/bin/ +# TODO: add rust-src component to Iroha's rust-toolchain.toml +RUN mkdir -p outputs && \ + rustup component add rust-src && \ + kagami wasm build wasm/libs/default_executor --out-file outputs/executor.wasm diff --git a/generator/executor.wasm b/generator/executor.wasm deleted file mode 100644 index c4e7a11..0000000 Binary files a/generator/executor.wasm and /dev/null differ diff --git a/generator/mod.ts b/generator/mod.ts index 7fab903..dfad845 100644 --- a/generator/mod.ts +++ b/generator/mod.ts @@ -6,19 +6,24 @@ import * as fs from "@std/fs"; import * as path from "@std/path"; import * as TOML from "@std/toml"; import * as YAML from "@std/yaml"; -import { JsonValue } from "npm:type-fest@^4.33.0"; import { z } from "zod"; -import { RelayConfigSchema, UiConfigSchema } from "../ui/shared.ts"; +import { + CheckpointSchema, + KeyValueEntitySchema, + RelayConfigSchema, + TriggerConfigSchema, + UiConfigSchema, +} from "../ui/shared.ts"; const dirname = import.meta.dirname; assert(dirname); const CONFIG_DIR = path.relative(Deno.cwd(), path.resolve(dirname, "../config")); -const EXECUTOR = path.resolve(dirname, "executor.wasm"); -const IROHA_IMAGE = `hyperledger/iroha:experimental-xx-8c67c3eb749af3b9c468d5b601d6fd40e1d8a453`; +// const IROHA_IMAGE = `hyperledger/iroha:experimental-xx-858df795cc8ea480a214ff73f3087a3bbf5f7d85`; +const IROHA_IMAGE = `hyperledger/iroha:local-uwp`; const CHAINS = ["aaa", "bbb", "ccc"]; -const PEERS_ON_CHAIN = 4; +const PEERS_ON_CHAIN = 1; const ACCOUNTS_ON_CHAIN = 3; const ASSETS = [ iroha.AssetDefinitionId.parse("rose#wonderland"), @@ -28,6 +33,23 @@ const ASSETS = [ // ============================= +const CONFIG_MOUNT = "/config"; + +const EXECUTOR_BUILDER_SERVICE_NAME = "executor-builder"; +const TRIGGER_BUILDER_SERVICE_NAME = "trigger-builder"; +const TRIGGER_WASM_NAME = "hub_chain_trigger.wasm"; +const TRIGGER_PATH_IN_CONFIG = path.join("wasm", TRIGGER_WASM_NAME); + +const METADATA_KEYS = { + TRIGGER: { + CONFIG: "config", + CHECKPOINT: "checkpoint", + }, + RELAY_ACCOUNT: { + BLOCK_MESSAGE: "block_message", + }, +}; + const Hub = Symbol("hub-chain"); type ChainId = typeof Hub | string; @@ -67,14 +89,11 @@ const relayAccounts = new Map(CHAINS.map((chain) => { return [chain, { alias: `Relay ${chain}`, key, + // FIXME: Relays must non-privileged id: new iroha.AccountId(key.publicKey(), new iroha.DomainId("system")), }]; })); -const genesisKeys = new Map( - ([...CHAINS, Hub] as const).map((chain) => [chain, iroha.KeyPair.random()]), -); - const peerKeys = new Map( ([...CHAINS, Hub] as const).map( chain => [chain, Array.from({ length: PEERS_ON_CHAIN }, () => iroha.KeyPair.random())], @@ -95,7 +114,11 @@ const sharedConfig = { torii: { address: "0.0.0.0:8080", }, - logger: { format: "pretty", filter: "iroha_core=debug" }, + logger: { + format: "pretty", + // TODO: in iroha, change "WASM" module to something with "iroha_" prefix? + filter: "iroha_core=debug,WASM=trace", + }, }; function chainToStr(chain: ChainId): string { @@ -121,6 +144,17 @@ function genesisFor(chain: ChainId) { let mintAssets: { id: iroha.AssetId; quantity: number | string }[]; let transferPermissions: { account: iroha.AccountId; asset: iroha.AssetDefinitionId }[]; + let wasmTriggers: { + id: string; + action: { + executable: string; + repeats: string; + authority: string; + filter: unknown; + }; + }[]; + let setKeyValueInstructions: ({ key: string; value: unknown } & z.infer)[]; + if (chain !== Hub) { const accounts = userAccounts.get(chain)!; const relay = relayAccounts.get(chain)!; @@ -143,6 +177,54 @@ function genesisFor(chain: ChainId) { account: acc.id, })) ); + + const TRIGGER_ID = "hub_chain"; + + wasmTriggers = [ + { + id: TRIGGER_ID, + action: { + executable: TRIGGER_PATH_IN_CONFIG, + repeats: "Indefinitely", + authority: admin.id.toString(), + filter: { Time: { PreCommit: null } }, + }, + }, + ]; + + const triggerConfig: z.infer = { + mode: { type: "Domestic", chain }, + checkpoint_addr: { + entity: { type: "Trigger", id: TRIGGER_ID }, + key: METADATA_KEYS.TRIGGER.CHECKPOINT, + }, + block_message_addr: { + entity: { type: "Account", id: relay.id }, + key: METADATA_KEYS.RELAY_ACCOUNT.BLOCK_MESSAGE, + }, + chains: Object.fromEntries( + [...omnibusAccounts] + .filter(([chainX]) => chainX !== chain) + .map(([chain, acc]) => [chain, { omnibus_account: acc.id }]), + ), + }; + + setKeyValueInstructions = [ + { + type: "Trigger", + id: TRIGGER_ID, + key: METADATA_KEYS.TRIGGER.CONFIG, + value: triggerConfig, + }, + { + type: "Trigger", + id: TRIGGER_ID, + key: METADATA_KEYS.TRIGGER.CHECKPOINT, + value: CheckpointSchema.encode({ + validators: new Set(peerKeys.get(Hub)!.map(x => x.publicKey())), + }), + }, + ]; } else { const relays = CHAINS.map(x => relayAccounts.get(x)!); @@ -161,6 +243,54 @@ function genesisFor(chain: ChainId) { account: relay.id, })) ); + + const triggerId = (chain: string) => `hub_chain_for_${chain}`; + + wasmTriggers = CHAINS.map(chain => ({ + id: triggerId(chain), + action: { + executable: TRIGGER_PATH_IN_CONFIG, + repeats: "Indefinitely", + authority: admin.id.toString(), + filter: { Time: { PreCommit: null } }, + }, + })); + + setKeyValueInstructions = CHAINS.flatMap((chain) => { + const triggerConfig: z.infer = { + mode: { type: "Domestic", chain }, + checkpoint_addr: { + entity: { type: "Trigger", id: triggerId(chain) }, + key: METADATA_KEYS.TRIGGER.CHECKPOINT, + }, + block_message_addr: { + entity: { type: "Account", id: relayAccounts.get(chain)!.id }, + key: METADATA_KEYS.RELAY_ACCOUNT.BLOCK_MESSAGE, + }, + chains: Object.fromEntries( + [...omnibusAccounts] + .filter(([chainX]) => chainX !== chain) + .map(([chain, acc]) => [chain, { omnibus_account: acc.id }]), + ), + }; + + return [ + { + type: "Trigger", + id: triggerId(chain), + key: METADATA_KEYS.TRIGGER.CONFIG, + value: triggerConfig, + }, + { + type: "Trigger", + id: triggerId(chain), + key: METADATA_KEYS.TRIGGER.CHECKPOINT, + value: CheckpointSchema.encode({ + validators: new Set(peerKeys.get(Hub)!.map(x => x.publicKey())), + }), + }, + ]; + }); } const instructions = [ @@ -215,22 +345,33 @@ function genesisFor(chain: ChainId) { }, }, })), + + ...setKeyValueInstructions.map(x => ({ + SetKeyValue: { + [x.type]: { + object: x.id, + key: x.key, + value: x.value, + }, + }, + })), ]; const topology = peerKeys.get(chain)!.map(x => x.publicKey()); return { + creation_time: new Date().toISOString(), chain: chainToStr(chain), - executor: "executor.wasm", + executor: "wasm/executor.wasm", instructions, - wasm_dir: "PLACEHOLDER", - wasm_triggers: [], + wasm_dir: ".", + wasm_triggers: wasmTriggers, topology, - "parameters": { - "sumeragi": { - "block_time_ms": 500, - "commit_time_ms": 1000, - "max_clock_drift_ms": 1000, + parameters: { + sumeragi: { + block_time_ms: 500, + commit_time_ms: 1000, + max_clock_drift_ms: 1000, }, }, }; @@ -248,7 +389,6 @@ function chainPublicPort(chain: ChainId): number { function peerComposeService(chain: ChainId, i: number) { const peerKey = peerKeys.get(chain)!.at(i)!; - const genesisKey = genesisKeys.get(chain)!; const id = peerServiceId(chain, i); const trustedPeers = JSON.stringify( @@ -261,31 +401,15 @@ function peerComposeService(chain: ChainId, i: number) { const environment = { CHAIN: chainToStr(chain), + GENESIS: `${CONFIG_MOUNT}/chain-${chainToStr(chain)}-genesis.json`, PUBLIC_KEY: peerKey.publicKey().multihash(), PRIVATE_KEY: peerKey.privateKey().multihash(), - GENESIS_PUBLIC_KEY: genesisKey.publicKey().multihash(), P2P_PUBLIC_ADDRESS: `${id}:1337`, TRUSTED_PEERS: trustedPeers, TERMINAL_COLORS: "true", }; - const isGenesis = i === 0; - if (isGenesis) { - Object.assign(environment, { - GENESIS: "/tmp/genesis.signed.scale", - GENESIS_PRIVATE_KEY: genesisKey.privateKey().multihash(), - }); - } - - const command = isGenesis - ? `/bin/sh -c " - kagami genesis sign /config/chain-${chainToStr(chain)}-genesis.json \\\n\ - --public-key $GENESIS_PUBLIC_KEY \\\n\ - --private-key $GENESIS_PRIVATE_KEY \\\n\ - --out-file /tmp/genesis.signed.scale \\\n\ - && irohad --config /config/irohad.toml -"` - : `irohad --config /config/irohad.toml`; + const command = `irohad --config ${CONFIG_MOUNT}/irohad.toml`; const ports = i === 0 ? [`${chainPublicPort(chain)}:8080`] : []; @@ -293,15 +417,23 @@ function peerComposeService(chain: ChainId, i: number) { [id]: { image: IROHA_IMAGE, volumes: [ - ".:/config", + `.:${CONFIG_MOUNT}`, ], environment, ports, init: true, command, + depends_on: { + [TRIGGER_BUILDER_SERVICE_NAME]: { + condition: "service_completed_successfully", + }, + [EXECUTOR_BUILDER_SERVICE_NAME]: { + condition: "service_completed_successfully", + }, + }, healthcheck: { test: "test $(curl -s http://127.0.0.1:8080/status/blocks) -gt 0", - interval: "1s", + interval: "3s", timeout: "200ms", retries: "10", start_period: "2s", @@ -316,11 +448,13 @@ function peerServices() { .reduce((acc, obj) => ({ ...acc, ...obj }), {}); } -function relayConfigPath(chain: string) { - return `chain-${chain}-relay.json`; +type RelayConfigKind = "docker" | "localhost"; + +function relayConfigPath(chain: string, mode: RelayConfigKind) { + return `chain-${chain}-relay${mode === "localhost" ? ".localhost" : ""}.json`; } -function relayConfig(chain: string): z.input { +function relayConfig(chain: string, mode: RelayConfigKind): z.input { const account = relayAccounts.get(chain)!; return { @@ -328,10 +462,18 @@ function relayConfig(chain: string): z.input { authorityPrivateKey: account.key.privateKey().multihash(), omnibusAccounts: [...omnibusAccounts.values()].map(acc => acc.id.toString()), domesticChainId: chain, - domesticToriiUrl: `http://${peerServiceId(chain, 0)}:8080`, + domesticToriiUrl: mode === "docker" + ? `http://${peerServiceId(chain, 0)}:8080` + : `http://localhost:${chainPublicPort(chain)}`, domesticOmnibusAccount: omnibusAccounts.get(chain)!.id.toString(), + domesticCheckpoint: { entity: { type: "Trigger", id: "hub_chain" }, key: "checkpoint" }, + domesticBlockMessage: { entity: { type: "Account", id: account.id.toString() }, key: "block_message" }, hubChainId: chainToStr(Hub), - hubToriiUrl: `http://${peerServiceId(Hub, 0)}:8080`, + hubToriiUrl: mode === "docker" + ? `http://${peerServiceId(Hub, 0)}:8080` + : `http://localhost:${chainPublicPort(Hub)}`, + hubCheckpoint: { entity: { type: "Trigger", id: "hub_chain" }, key: "checkpoint" }, + hubBlockMessage: { entity: { type: "Account", id: account.id.toString() }, key: "block_message" }, }; } @@ -344,7 +486,7 @@ function relayServices() { }, volumes: [".:/config/relay"], environment: { - RELAY_CONFIG: `/config/relay/${relayConfigPath(chain)}`, + RELAY_CONFIG: `/config/relay/${relayConfigPath(chain, "docker")}`, DEBUG: "relay", }, depends_on: { @@ -394,11 +536,33 @@ function uiService() { }; } +function triggerBuilderService() { + return { + build: { + context: "../trigger", + }, + volumes: [`../config/wasm:/usr/wasm`], + command: `\ +sh -c " + cp /app/outputs/* /usr/wasm/ && + echo 'Copied WASMs' +"`, + }; +} + +function defaultExecutorBuilderService() { + const cfg = triggerBuilderService(); + cfg.build.context = `../executor`; + return cfg; +} + const dockerCompose = { services: { + [TRIGGER_BUILDER_SERVICE_NAME]: triggerBuilderService(), + [EXECUTOR_BUILDER_SERVICE_NAME]: defaultExecutorBuilderService(), ...peerServices(), - ...relayServices(), - ui: uiService(), + // ...relayServices(), + // ui: uiService(), }, }; @@ -415,14 +579,12 @@ await writeConfig("irohad.toml", TOML.stringify(sharedConfig)); for (const chain of ALL_CHAINS) { await writeConfig(`chain-${chainToStr(chain)}-genesis.json`, JSON.stringify(genesisFor(chain), null, 2)); if (chain !== Hub) { - await writeConfig(relayConfigPath(chain), JSON.stringify(relayConfig(chain), null, 2)); + for (const mode of ["docker", "localhost"] as const) { + await writeConfig(relayConfigPath(chain, mode), JSON.stringify(relayConfig(chain, mode), null, 2)); + } } } -const executorDest = path.join(CONFIG_DIR, "executor.wasm"); -$.logStep("Writing", executorDest); -await Deno.copyFile(EXECUTOR, executorDest); - await writeConfig("ui.json", JSON.stringify(uiConfig(), null, 2)); $.logStep("Completed!", `Now you can run "docker-compose -f ${path.join(CONFIG_DIR, "docker-compose.yml")} up"`); diff --git a/relay/mod.ts b/relay/mod.ts index 91de9e4..9d197e9 100644 --- a/relay/mod.ts +++ b/relay/mod.ts @@ -1,20 +1,26 @@ -import { Client, SetupEventsReturn } from "@iroha/client"; -import { blockHash } from "@iroha/core"; +import { Client } from "@iroha/client"; import * as iroha from "@iroha/core/data-model"; -import { assert } from "@std/assert"; +import { assert, fail, unimplemented } from "@std/assert"; import { delay } from "@std/async"; -import Debug from "debug"; +import { pino } from "pino"; import * as tm from "true-myth"; -import { match, P } from "ts-pattern"; +import { match } from "ts-pattern"; import { z } from "zod"; -import { RelayConfigSchema } from "../ui/shared.ts"; +import { BlockMessageSchema, CheckpointSchema, KeyValueAddressSchema, RelayConfigSchema } from "../ui/shared.ts"; -const dbg = Debug("relay"); +type KeyValueAddress = z.output; +type Checkpoint = z.output; +type BlockMessage = z.output; const configPath = Deno.env.get("RELAY_CONFIG"); -assert(configPath, "Set config to RELAY_CONFIG"); +assert(configPath, "Set config path to RELAY_CONFIG"); -dbg("Loading config from", configPath); +const log = pino({ + transport: { target: "pino-pretty" }, + base: { config: configPath }, +}); + +log.info("Loading config"); const config = await Deno.readTextFile(configPath).then(text => RelayConfigSchema.parse(JSON.parse(text))); const clients = { @@ -32,170 +38,114 @@ const clients = { }), }; -await Promise.all([listenDomestic(), listenHub()]); - -async function listenDomestic() { - for await (const tx of interceptTransactions(clients.domestic)) { - const transfer = findTransfer(tx); - if (transfer.isJust) { - dbg("submitting transaction on hub chain..."); - (await forwardTransferToHub(transfer.value)) - .mapOrElse((err) => { - dbg("transfer err", err); - }, () => { - dbg("transfer is made on the hub chain"); - }); - } - } -} - -async function listenHub() { - for await (const tx of interceptTransactions(clients.hub)) { - const transfer = findTransfer(tx); - if (transfer.isJust) { - dbg("submitting transaction on domestic chain..."); - (await forwardTransferToDomestic(transfer.value)) - .mapOrElse((err) => { - dbg("transfer err", err); - }, () => { - dbg("transfer is made on the domestic chain"); - }); - } - } -} - -type Transfer = { - destination: iroha.MapEntry; - transfer: iroha.Transfer; -}; - -async function* eventsGenerator(events: SetupEventsReturn) { - while (true) { - const event = await Promise.race([ - events.ee.once("event").then(x => tm.result.ok(x)), - events.ee.once("close").then(() => tm.result.err(null)), - ]); - - if (event.isOk) yield event.value; - return; - } -} +await Promise.all([ + loop({ + targetClient: clients.hub, + targetCheckpoint: createKeyValue(config.hubCheckpoint, CheckpointSchema), + targetBlockMessage: createKeyValue(config.hubBlockMessage, BlockMessageSchema), + sourceClient: clients.domestic, + }), + // TODO: reverse loop +]); -async function* interceptTransactions(client: Client): AsyncGenerator { +/** + * Main relay loop. + * + * 1. On the target chain, wait until the checkpoint is synced with the block message + * 2. On the source chain, wait until the next block on appears + * 3. Post a new block message to the target chain + */ +async function loop(opts: { + targetClient: Client; + targetCheckpoint: KeyValueReadWrite; + targetBlockMessage: KeyValueReadWrite; + sourceClient: Client; +}) { + const log1 = log.child({}); while (true) { try { - const events = await client.events({ - filters: [iroha.EventFilterBox.Pipeline.Block({ - status: iroha.BlockStatus.Applied, - height: null, - })], - }); - - for await (const event of eventsGenerator(events)) { - assert( - event.kind === "Pipeline" && event.value.kind === "Block" && event.value.value.status.kind === "Applied", - "Bad filter", - ); - const hash = blockHash(event.value.value.header); - - const block = await client.find.blocks() - .filterWith(block => iroha.CompoundPredicate.Atom(block.header.hash.equals(hash))) - .executeSingle(); - - const errors = new Set(block.value.errors.map(x => Number(x.index))); - - for (const tx of block.value.payload.transactions.filter((_tx, i) => !errors.has(i))) { - yield tx; - } - } - - dbg("Events stream closed, try again"); + const checkpoint = (await opts.targetCheckpoint.read(opts.targetClient)) + .unwrapOrElse(() => fail("checkpoint must always exist")); + + const blockMessage = await opts.targetBlockMessage.read(opts.targetClient); + + // TODO: implement + // compare checkpoint & block message; + // if checkpoint is sync with the block message, wait for it, restart the loop; + // wait for the block (on source chain) next to the block message; + // prepare block message, post to the target chain; + // ????? + // PROFIT!!! } catch (err) { - dbg("Failed to connect, try again", err); - await delay(2000); + log1.error({ err }, "Loop failed, waiting before retrying"); + await delay(5000); + continue; } - } -} -function findTransfer( - tx: iroha.SignedTransaction, -): tm.Maybe { - return match(tx) - .with({ - value: { - payload: { - instructions: { - kind: "Instructions", - value: [{ kind: "Transfer", value: { kind: "Asset", value: P.select("transfer") } }], - }, - metadata: [P.select("destination", { key: { value: "destination" } })], - }, - }, - }, (found) => tm.maybe.just(found as Transfer)) - .otherwise(() => tm.maybe.nothing()); -} - -/** - * Forward a transfer that happened on the domestic, _source_ chain: - * - * - From user account - * - To target chain omnibus account - * - With destination account on the target chain in metadata - * - * as a transfer on the hub chain: - * - * - From domestic chain omnibus account - * - To target chain omnibus account - * - With the same metadata - */ -function forwardTransferToHub({ transfer, destination }: Transfer): tm.Task { - return tm.task.safelyTry(() => - clients.hub.transaction( - iroha.Executable.Instructions([iroha.InstructionBox.Transfer.Asset({ - object: transfer.object, - source: new iroha.AssetId(config.domesticOmnibusAccount, transfer.source.definition), - destination: transfer.destination, - })]), - { metadata: [destination] }, - ).submit({ verify: true }) - ); + log1.info("loop finished"); + // TODO: remove the delay, loop can restart immediately and wait for conditions + await delay(60000); + } } -/** - * Forward a transfer that happened on the hub chain: - * - * - From the source chain omnibus account - * - To the target chain omnibus account - * - With destination account on the domestic chain in metadata - * - * as a transfer on the domestic chain. There are two cases: - * - * 1. Domestic chain is the target chain. Then, create a transfer from the source chain omnibus account - * to the final destination account. - * 2. Domestic chain is neither the target nor the source chain. Then, simply replicate the transfer between - * the omnibus accounts of the respective chains (to maintain totals). - */ -function forwardTransferToDomestic({ transfer, destination }: Transfer): tm.Task { - return tm.task.safelyTry(async () => { - const isSource = transfer.source.account.compare(config.domesticOmnibusAccount) === 0; - const isTarget = transfer.destination.compare(config.domesticOmnibusAccount) === 0; - - let instruction: iroha.InstructionBox; - - if (isTarget) { - instruction = iroha.InstructionBox.Transfer.Asset({ - object: transfer.object, - source: transfer.source, - destination: iroha.AccountId.parse(z.string().parse(destination.value.asValue())), - }); - } else if (!isSource) { - instruction = iroha.InstructionBox.Transfer.Asset({ - object: transfer.object, - source: transfer.source, - destination: transfer.destination, - }); - } else return; +type KeyValueReadWrite = { + read: (client: Client) => Promise>; + write: (client: Client, value: T) => Promise; +}; - await clients.domestic.transaction(iroha.Executable.Instructions([instruction])).submit({ verify: true }); - }); +function createKeyValue(addr: KeyValueAddress, schema: T): KeyValueReadWrite> { + return { + read: async (client) => { + const metadata = await match(addr.entity) + .returnType>() + .with( + { type: "Domain" }, + ({ id }) => + client.find.domains() + .filterWith((x) => iroha.CompoundPredicate.Atom(x.id.equals(id))) + .selectWith(x => x.metadata) + .executeSingleOpt(), + ) + .with( + { type: "Account" }, + ({ id }) => + client.find.accounts() + .filterWith((x) => iroha.CompoundPredicate.Atom(x.id.equals(id))) + .selectWith(x => x.metadata) + .executeSingleOpt(), + ) + .with( + { type: "AssetDefinition" }, + ({ id }) => + client.find.assetsDefinitions() + .filterWith((x) => iroha.CompoundPredicate.Atom(x.id.equals(id))) + .selectWith(x => x.metadata) + .executeSingleOpt(), + ) + .with( + { type: "Nft" }, + ({ id }) => + client.find.nfts() + .filterWith((x) => iroha.CompoundPredicate.Atom(x.id.equals(id))) + .selectWith(x => x.metadata) + .executeSingleOpt(), + ) + .with( + { type: "Trigger" }, + ({ id }) => + client.find.triggers() + .filterWith((x) => iroha.CompoundPredicate.Atom(x.id.equals(id))) + .selectWith(x => x.action.metadata) + .executeSingleOpt(), + ) + .exhaustive(); + + return tm.maybe.of(metadata) + .andThen((meta) => tm.maybe.of(meta.find(x => x.key.value === addr.key))) + .map((entry) => schema.parse(entry.value.asValue()) as z.output & {}); + }, + write: async (client, value) => { + unimplemented(); + }, + }; } diff --git a/trigger/.cargo/config.toml b/trigger/.cargo/config.toml new file mode 100644 index 0000000..f4e8c00 --- /dev/null +++ b/trigger/.cargo/config.toml @@ -0,0 +1,2 @@ +[build] +target = "wasm32-unknown-unknown" diff --git a/trigger/.dockerignore b/trigger/.dockerignore new file mode 100644 index 0000000..51bce33 --- /dev/null +++ b/trigger/.dockerignore @@ -0,0 +1,4 @@ +.dockerignore +.gitignore +Dockerfile +/target diff --git a/trigger/.gitignore b/trigger/.gitignore new file mode 100644 index 0000000..d913617 --- /dev/null +++ b/trigger/.gitignore @@ -0,0 +1,2 @@ +target + diff --git a/trigger/Cargo.lock b/trigger/Cargo.lock new file mode 100644 index 0000000..63be079 --- /dev/null +++ b/trigger/Cargo.lock @@ -0,0 +1,1794 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array", +] + +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "anyhow" +version = "1.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" + +[[package]] +name = "ark-bls12-377" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb00293ba84f51ce3bd026bd0de55899c4e68f0a39a5728cebae3a73ffdc0a4f" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-std", +] + +[[package]] +name = "ark-bls12-381" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c775f0d12169cba7aae4caeb547bb6a50781c7449a8aa53793827c9ec4abf488" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-std", +] + +[[package]] +name = "ark-ec" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" +dependencies = [ + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", + "itertools", + "num-traits", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm", + "ark-ff-macros", + "ark-serialize", + "ark-std", + "derivative", + "digest", + "itertools", + "num-bigint", + "num-traits", + "paste", + "rustc_version", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-poly" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" +dependencies = [ + "ark-ff", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-serialize-derive", + "ark-std", + "digest", + "num-bigint", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand", +] + +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" + +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "byte-slice-cast" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7575182f7272186991736b70173b0ea045398f984bf5ebbb3804736ce1330c9d" + +[[package]] +name = "cfg-if" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" + +[[package]] +name = "chacha20" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "chacha20poly1305" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" +dependencies = [ + "aead", + "chacha20", + "cipher", + "poly1305", + "zeroize", +] + +[[package]] +name = "chrono" +version = "0.4.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" +dependencies = [ + "num-traits", + "serde", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", + "zeroize", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "const_format" +version = "0.2.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "126f97965c8ad46d6d9163268ff28432e8f6a1196a55578867832e3049df63dd" +dependencies = [ + "const_format_proc_macros", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest", + "fiat-crypto", + "rustc_version", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "darling" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +dependencies = [ + "darling_core 0.20.11", + "darling_macro 0.20.11", +] + +[[package]] +name = "darling" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" +dependencies = [ + "darling_core 0.21.3", + "darling_macro 0.21.3", +] + +[[package]] +name = "darling_core" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.106", +] + +[[package]] +name = "darling_core" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.106", +] + +[[package]] +name = "darling_macro" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core 0.20.11", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "darling_macro" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" +dependencies = [ + "darling_core 0.21.3", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "deranged" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a41953f86f8a05768a6cda24def994fd2f424b04ec5c719cf89989779f199071" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive-where" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef941ded77d15ca19b40374869ac6000af1c9f2a4c0f3d4c70926287e6364a8f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "derive_more" +version = "0.99.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "dlmalloc" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06cdfe340b16dd990c54cce79743613fa09fbb16774f33a77c9fd196f8f3fa30" +dependencies = [ + "cfg-if", + "libc", + "windows-sys", +] + +[[package]] +name = "drop_bomb" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bda8e21c04aca2ae33ffc2fd8c23134f3cac46db123ba97bd9d3f3b8a4a85e1" + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8", + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" +dependencies = [ + "curve25519-dalek", + "ed25519", + "rand_core", + "serde", + "sha2", + "subtle", + "zeroize", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "ff" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" +dependencies = [ + "rand_core", + "subtle", +] + +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "getset" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf0fc11e47561d47397154977bc219f4cf809b2974facc3ccb3b89e2436f912" +dependencies = [ + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashbrown" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +dependencies = [ + "serde", +] + +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "hub_chain_trigger" +version = "0.0.0" +dependencies = [ + "anyhow", + "dlmalloc", + "iroha_crypto", + "iroha_trigger", + "panic-halt", + "serde", + "serde_json", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "indexmap" +version = "2.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" +dependencies = [ + "equivalent", + "hashbrown 0.16.0", +] + +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "generic-array", +] + +[[package]] +name = "iroha_crypto" +version = "2.0.0-rc.2.0" +source = "git+https://github.com/hyperledger-iroha/iroha.git?rev=a84bc8893451cf08f346eb476097c13ca7bf65fb#a84bc8893451cf08f346eb476097c13ca7bf65fb" +dependencies = [ + "aead", + "arrayref", + "blake2", + "chacha20poly1305", + "curve25519-dalek", + "derive_more", + "digest", + "displaydoc", + "ed25519-dalek", + "elliptic-curve", + "getset", + "hex", + "hkdf", + "iroha_macro", + "iroha_primitives", + "iroha_schema", + "k256", + "parity-scale-codec", + "rand", + "rand_chacha", + "rand_core", + "serde", + "serde_with", + "sha2", + "signature", + "w3f-bls", + "x25519-dalek", + "zeroize", +] + +[[package]] +name = "iroha_data_model" +version = "2.0.0-rc.2.0" +source = "git+https://github.com/hyperledger-iroha/iroha.git?rev=a84bc8893451cf08f346eb476097c13ca7bf65fb#a84bc8893451cf08f346eb476097c13ca7bf65fb" +dependencies = [ + "base64", + "derive-where", + "derive_more", + "displaydoc", + "getset", + "iroha_crypto", + "iroha_data_model_derive", + "iroha_macro", + "iroha_primitives", + "iroha_schema", + "iroha_version", + "nonzero_ext", + "parity-scale-codec", + "serde", + "serde_json", + "serde_with", + "strum", +] + +[[package]] +name = "iroha_data_model_derive" +version = "2.0.0-rc.2.0" +source = "git+https://github.com/hyperledger-iroha/iroha.git?rev=a84bc8893451cf08f346eb476097c13ca7bf65fb#a84bc8893451cf08f346eb476097c13ca7bf65fb" +dependencies = [ + "darling 0.20.11", + "iroha_macro_utils", + "manyhow", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "iroha_derive" +version = "2.0.0-rc.2.0" +source = "git+https://github.com/hyperledger-iroha/iroha.git?rev=a84bc8893451cf08f346eb476097c13ca7bf65fb#a84bc8893451cf08f346eb476097c13ca7bf65fb" +dependencies = [ + "darling 0.20.11", + "iroha_macro_utils", + "manyhow", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "iroha_macro" +version = "2.0.0-rc.2.0" +source = "git+https://github.com/hyperledger-iroha/iroha.git?rev=a84bc8893451cf08f346eb476097c13ca7bf65fb#a84bc8893451cf08f346eb476097c13ca7bf65fb" +dependencies = [ + "iroha_derive", +] + +[[package]] +name = "iroha_macro_utils" +version = "2.0.0-rc.2.0" +source = "git+https://github.com/hyperledger-iroha/iroha.git?rev=a84bc8893451cf08f346eb476097c13ca7bf65fb#a84bc8893451cf08f346eb476097c13ca7bf65fb" +dependencies = [ + "darling 0.20.11", + "drop_bomb", + "manyhow", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "iroha_numeric" +version = "2.0.0-rc.2.0" +source = "git+https://github.com/hyperledger-iroha/iroha.git?rev=a84bc8893451cf08f346eb476097c13ca7bf65fb#a84bc8893451cf08f346eb476097c13ca7bf65fb" +dependencies = [ + "derive_more", + "displaydoc", + "iroha_schema", + "parity-scale-codec", + "rust_decimal", + "serde", + "serde_with", +] + +[[package]] +name = "iroha_primitives" +version = "2.0.0-rc.2.0" +source = "git+https://github.com/hyperledger-iroha/iroha.git?rev=a84bc8893451cf08f346eb476097c13ca7bf65fb#a84bc8893451cf08f346eb476097c13ca7bf65fb" +dependencies = [ + "derive_more", + "displaydoc", + "iroha_macro", + "iroha_numeric", + "iroha_primitives_derive", + "iroha_schema", + "parity-scale-codec", + "serde", + "serde_json", + "serde_with", + "smallstr", + "smallvec", +] + +[[package]] +name = "iroha_primitives_derive" +version = "2.0.0-rc.2.0" +source = "git+https://github.com/hyperledger-iroha/iroha.git?rev=a84bc8893451cf08f346eb476097c13ca7bf65fb#a84bc8893451cf08f346eb476097c13ca7bf65fb" +dependencies = [ + "iroha_numeric", + "manyhow", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "iroha_schema" +version = "2.0.0-rc.2.0" +source = "git+https://github.com/hyperledger-iroha/iroha.git?rev=a84bc8893451cf08f346eb476097c13ca7bf65fb#a84bc8893451cf08f346eb476097c13ca7bf65fb" +dependencies = [ + "iroha_schema_derive", + "serde", +] + +[[package]] +name = "iroha_schema_derive" +version = "2.0.0-rc.2.0" +source = "git+https://github.com/hyperledger-iroha/iroha.git?rev=a84bc8893451cf08f346eb476097c13ca7bf65fb#a84bc8893451cf08f346eb476097c13ca7bf65fb" +dependencies = [ + "darling 0.20.11", + "iroha_macro_utils", + "manyhow", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "iroha_smart_contract" +version = "2.0.0-rc.2.0" +source = "git+https://github.com/hyperledger-iroha/iroha.git?rev=a84bc8893451cf08f346eb476097c13ca7bf65fb#a84bc8893451cf08f346eb476097c13ca7bf65fb" +dependencies = [ + "derive_more", + "displaydoc", + "iroha_data_model", + "iroha_macro", + "iroha_smart_contract_derive", + "iroha_smart_contract_utils", + "parity-scale-codec", +] + +[[package]] +name = "iroha_smart_contract_derive" +version = "2.0.0-rc.2.0" +source = "git+https://github.com/hyperledger-iroha/iroha.git?rev=a84bc8893451cf08f346eb476097c13ca7bf65fb#a84bc8893451cf08f346eb476097c13ca7bf65fb" +dependencies = [ + "iroha_macro_utils", + "manyhow", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "iroha_smart_contract_utils" +version = "2.0.0-rc.2.0" +source = "git+https://github.com/hyperledger-iroha/iroha.git?rev=a84bc8893451cf08f346eb476097c13ca7bf65fb#a84bc8893451cf08f346eb476097c13ca7bf65fb" +dependencies = [ + "cfg-if", + "getrandom", + "iroha_data_model", + "parity-scale-codec", +] + +[[package]] +name = "iroha_trigger" +version = "2.0.0-rc.2.0" +source = "git+https://github.com/hyperledger-iroha/iroha.git?rev=a84bc8893451cf08f346eb476097c13ca7bf65fb#a84bc8893451cf08f346eb476097c13ca7bf65fb" +dependencies = [ + "iroha_smart_contract", + "iroha_smart_contract_utils", + "iroha_trigger_derive", +] + +[[package]] +name = "iroha_trigger_derive" +version = "2.0.0-rc.2.0" +source = "git+https://github.com/hyperledger-iroha/iroha.git?rev=a84bc8893451cf08f346eb476097c13ca7bf65fb#a84bc8893451cf08f346eb476097c13ca7bf65fb" +dependencies = [ + "darling 0.20.11", + "iroha_macro_utils", + "manyhow", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "iroha_version" +version = "2.0.0-rc.2.0" +source = "git+https://github.com/hyperledger-iroha/iroha.git?rev=a84bc8893451cf08f346eb476097c13ca7bf65fb#a84bc8893451cf08f346eb476097c13ca7bf65fb" +dependencies = [ + "iroha_macro", + "iroha_version_derive", + "parity-scale-codec", + "serde", + "serde_json", +] + +[[package]] +name = "iroha_version_derive" +version = "2.0.0-rc.2.0" +source = "git+https://github.com/hyperledger-iroha/iroha.git?rev=a84bc8893451cf08f346eb476097c13ca7bf65fb#a84bc8893451cf08f346eb476097c13ca7bf65fb" +dependencies = [ + "darling 0.20.11", + "manyhow", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "k256" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "sha2", +] + +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "libc" +version = "0.2.176" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" + +[[package]] +name = "manyhow" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "516b76546495d933baa165075b95c0a15e8f7ef75e53f56b19b7144d80fd52bd" +dependencies = [ + "darling_core 0.20.11", + "manyhow-macros", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "manyhow-macros" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ba072c0eadade3160232e70893311f1f8903974488096e2eb8e48caba2f0cf1" +dependencies = [ + "proc-macro-utils", + "proc-macro2", + "quote", +] + +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "nonzero_ext" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38bf9645c8b145698bb0b18a4637dcacbc421ea49bef2317e4fd8065a387cf21" + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "panic-halt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de96540e0ebde571dc55c73d60ef407c653844e6f9a1e2fdbd40c07b9252d812" + +[[package]] +name = "parity-scale-codec" +version = "3.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799781ae679d79a948e13d4824a40970bfa500058d245760dd857301059810fa" +dependencies = [ + "arrayvec", + "byte-slice-cast", + "const_format", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "rustversion", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34b4653168b563151153c9e4c08ebed57fb8262bebfa79711552fa983c623e7a" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "poly1305" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" +dependencies = [ + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro-crate" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "proc-macro-utils" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f59e109e2f795a5070e69578c4dc101068139f74616778025ae1011d4cd41a8" +dependencies = [ + "proc-macro2", + "quote", + "smallvec", +] + +[[package]] +name = "proc-macro2" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "rust_decimal" +version = "1.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8975fc98059f365204d635119cf9c5a60ae67b841ed49b5422a9a7e56cdfac0" +dependencies = [ + "arrayvec", + "num-traits", + "serde", +] + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "serde_json" +version = "1.0.145" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", + "serde_core", +] + +[[package]] +name = "serde_with" +version = "3.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c522100790450cf78eeac1507263d0a350d4d5b30df0c8e1fe051a10c22b376e" +dependencies = [ + "base64", + "chrono", + "hex", + "serde", + "serde_derive", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327ada00f7d64abaac1e55a6911e90cf665aa051b9a561c7006c157f4633135e" +dependencies = [ + "darling 0.21.3", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest", + "keccak", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core", +] + +[[package]] +name = "smallstr" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "862077b1e764f04c251fe82a2ef562fd78d7cadaeb072ca7c2bcaf7217b1ff3b" +dependencies = [ + "serde", + "smallvec", +] + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +dependencies = [ + "serde", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "strum" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.106", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "time" +version = "0.3.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "serde", + "time-core", +] + +[[package]] +name = "time-core" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" + +[[package]] +name = "toml_datetime" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f1085dec27c2b6632b04c80b3bb1b4300d6495d1e129693bdda7d91e72eec1" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.23.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3effe7c0e86fdff4f69cdd2ccc1b96f933e24811c5441d44904e8683e27184b" +dependencies = [ + "indexmap", + "toml_datetime", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cf893c33be71572e0e9aa6dd15e6677937abd686b066eac3f8cd3531688a627" +dependencies = [ + "winnow", +] + +[[package]] +name = "typenum" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" + +[[package]] +name = "unicode-ident" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle", +] + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "w3f-bls" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6bfb937b3d12077654a9e43e32a4e9c20177dd9fea0f3aba673e7840bb54f32" +dependencies = [ + "ark-bls12-377", + "ark-bls12-381", + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-serialize-derive", + "arrayref", + "digest", + "rand", + "rand_chacha", + "rand_core", + "sha2", + "sha3", + "zeroize", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "windows-link" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.53.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d42b7b7f66d2a06854650af09cfdf8713e427a439c97ad65a6375318033ac4b" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + +[[package]] +name = "winnow" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" +dependencies = [ + "memchr", +] + +[[package]] +name = "x25519-dalek" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" +dependencies = [ + "curve25519-dalek", + "rand_core", +] + +[[package]] +name = "zerocopy" +version = "0.8.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] diff --git a/trigger/Cargo.toml b/trigger/Cargo.toml new file mode 100644 index 0000000..5cfefaf --- /dev/null +++ b/trigger/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "hub_chain_trigger" +edition = "2024" + +[features] +debug = [] + +[lib] +crate-type = ['cdylib'] + +[dependencies] +iroha_crypto = { git = "https://github.com/hyperledger-iroha/iroha.git", rev = "a84bc8893451cf08f346eb476097c13ca7bf65fb", default-features = false } +iroha_trigger = { git = "https://github.com/hyperledger-iroha/iroha.git", rev = "a84bc8893451cf08f346eb476097c13ca7bf65fb" } + +anyhow = { version = "1.0", default-features = false } +dlmalloc = { version = "0.2.6", features = ["global"] } +panic-halt = "0.2.0" +serde = { version = "1.0.219", default-features = false, features = ["alloc", "derive"] } +serde_json = { version = "1.0.143", default-features = false } diff --git a/trigger/Dockerfile b/trigger/Dockerfile new file mode 100644 index 0000000..8caae7e --- /dev/null +++ b/trigger/Dockerfile @@ -0,0 +1,15 @@ +FROM hyperledger/iroha:experimental-xx-858df795cc8ea480a214ff73f3087a3bbf5f7d85 AS iroha + +FROM rust:1.89-bullseye +WORKDIR /app + +COPY rust-toolchain.toml . +RUN rustup install + +COPY . . +RUN --mount=type=cache,target=/root/.cargo/git/db \ + --mount=type=cache,target=/root/.cargo/registry/cache \ + --mount=type=cache,target=/root/.cargo/registry/index \ + cargo fetch +COPY --from=iroha /usr/local/bin/kagami /usr/local/bin/ +RUN mkdir -p outputs && kagami wasm build . --out-file outputs/hub_chain_trigger.wasm diff --git a/trigger/rust-toolchain.toml b/trigger/rust-toolchain.toml new file mode 100644 index 0000000..779863a --- /dev/null +++ b/trigger/rust-toolchain.toml @@ -0,0 +1,4 @@ +[toolchain] +channel = "nightly-2025-05-08" +targets = ["wasm32-unknown-unknown"] +components = ["rust-src"] diff --git a/trigger/src/lib.rs b/trigger/src/lib.rs new file mode 100644 index 0000000..20a71d3 --- /dev/null +++ b/trigger/src/lib.rs @@ -0,0 +1,467 @@ +//! Smartcontract which creates new NFT for every user +#![no_std] + +extern crate alloc; +#[cfg(not(test))] +extern crate panic_halt; + +use core::marker::PhantomData; +use core::ops::ControlFlow; +use core::str::FromStr as _; + +use alloc::borrow::ToOwned; +use alloc::collections::btree_map::BTreeMap; +use alloc::collections::btree_set::BTreeSet; +use alloc::format; +use alloc::string::String; +use alloc::vec::Vec; + +use anyhow::{Context as _, Result, anyhow, bail}; +use dlmalloc::GlobalDlmalloc; +use iroha_crypto::SignatureOf; +use iroha_trigger::data_model::block::BlockHeader; +use iroha_trigger::data_model::query::builder::SingleQueryError; +use iroha_trigger::data_model::query::error::FindError; +use iroha_trigger::data_model::query::error::QueryExecutionFail; +use iroha_trigger::log::*; +use iroha_trigger::prelude::*; +use serde::de::DeserializeOwned; +use serde::{Deserialize, Serialize}; + +#[global_allocator] +static ALLOC: GlobalDlmalloc = GlobalDlmalloc; + +/// The key from which the trigger will read its config in its own metadata. +const SELF_CONFIG_KEY: &str = "config"; + +#[derive(Deserialize)] +struct Config { + /// Operation mode of this trigger - hub or domestic. + /// + /// Alters the behaviour of how transfers are made upon verification. + mode: OperationMode, + /// Storage with admin-only write access. Contains the [`Checkpoint`] this trigger works with. + checkpoint_addr: KeyValueAddress, + /// Storage to which the relay has write access. Contains [`RelayBlockMessage`]. + block_message_addr: KeyValueAddress, + /// Global information about all the chains in the hub chain network. + chains: BTreeMap, +} + +/// Generic address in an on-chain key-value storage (metadata) pointing to a specific metadata +/// key. +#[derive(Deserialize)] +struct KeyValueAddress { + /// What entity to look in for metadata + entity: KeyValueAddressEntity, + /// Metadata key + key: Name, + #[serde(skip)] + _value: PhantomData, +} + +#[derive(Deserialize, Debug)] +#[serde(tag = "type", content = "id")] +enum KeyValueAddressEntity { + Domain(DomainId), + Account(AccountId), + AssetDefinition(AssetDefinitionId), + Nft(NftId), + Trigger(TriggerId), +} + +/// Trigger operation mode +#[derive(Deserialize)] +#[serde(tag = "type")] +enum OperationMode { + /// Trigger is deployed on the hub chain + Hub { + /// The chain id this trigger works with. (i.e. whose [`Checkpoint`] it tracks) + domestic_chain: ChainId, + approved_transfers_addr: KeyValueAddress, + }, + /// Trigger is deployed on a domestic chain + Domestic { + /// Which domestic chain + chain: ChainId, + }, +} + +/// Information about a specific chain +#[derive(Deserialize)] +struct ChainConfig { + /// Omnibus account of that chain presented on the chain _this trigger is deployed on_. + omnibus_account: AccountId, +} + +/// Message provided by an untrusted relay that the trigger is going to verify +#[derive(Deserialize)] +struct RelayBlockMessage { + /// Header of the new block. Must be consequent to the block in [`Checkpoint`]. + header: BlockHeader, + /// Block signatures. Will be verified against validators set in [`Checkpoint`]. + signatures: BTreeSet>, + /// _Interesting_ transactions in the given block. + /// + /// Interesting means they contain e.g. [`Transfer`] instructions that the trigger will + /// scan and act on. Currently, it is only transfers; later, it could include + /// [`RegisterBox::Peer`] (and unregister) to change the validators set. + /// + /// The goal of the PoC is to show that a relay does not need to send the **entire block** + /// (i.e. all of its transactions), but only a subset of them. Trigger can verify them using + /// their [`CommittedTransaction::entrypoint_proof`] against [`BlockHeader::merkle_root`]. + interesting_transactions: Vec, +} + +/// Memory about a chain. +#[derive(Deserialize, Serialize)] +struct Checkpoint { + /// Must be set in the beginning + validators: BTreeSet, + /// None in the beginning + block: Option, +} + +/// Since the trigger on hub chain cannot "show" the transfer as a [`Transfer`] itself, +/// we have to use a JSON payload and set it as a metadata somewhere. +#[derive(Serialize, Deserialize, Debug)] +struct HubChainTransferPayload { + source_chain: ChainId, + source_account: AccountId, + destination_chain: ChainId, + destination_account: AccountId, + asset: AssetDefinitionId, + object: Numeric, +} + +#[iroha_trigger::main] +fn main(host: Iroha, ctx: Context) { + // Iroha does not print anything useful when just `unwrap` or `dbg_unwrap` the result + if let Err(error) = main_result(host, ctx) { + error!(&format!("Trigger encountered an error: {error:?}")); + panic!("boom"); + } +} + +fn main_result(host: Iroha, ctx: Context) -> Result<()> { + info!("Hello from the Hub Chain Trigger!"); + + if ctx.curr_block.is_genesis() { + debug!("Skipping genesis block"); + return Ok(()); + } + + if !matches!(ctx.event, EventBox::Time(_)) { + bail!("Trigger is designed to work as a time trigger"); + } + // TODO: verify authority? + + let config: Config = KeyValueAddress::new( + KeyValueAddressEntity::Trigger(ctx.id.to_owned()), + Name::from_str(SELF_CONFIG_KEY).unwrap(), + ) + .read(&host)? + .ok_or_else(|| anyhow!("cannot find config"))?; + let mut checkpoint = config + .checkpoint_addr + .read(&host)? + .ok_or_else(|| anyhow!("cannot find checkpoint"))?; + let Some(message) = config.block_message_addr.read(&host)? else { + info!("No messages found, exiting"); + return Ok(()); + }; + + match check_block_height(&checkpoint, &message)? { + ControlFlow::Break(()) => { + info!("No updates detected, exiting"); + return Ok(()); + } + ControlFlow::Continue(()) => { + debug!("Updates found, processing"); + } + } + + validate_prev_block_hash(&checkpoint, &message)?; + validate_block_signatures(&checkpoint, &message)?; + process_transactions(&host, &config, &message)?; + + checkpoint.block = Some(message.header); + config.checkpoint_addr.write(&host, &checkpoint)?; + + info!("Trigger completed successfully!"); + Ok(()) +} + +impl Config { + fn chain_by_omnibus_account(&self, account: &AccountId) -> Option<&ChainId> { + self.chains + .iter() + .find(|(_, x)| &x.omnibus_account == account) + .map(|(chain, _)| chain) + } + + fn omnibus_account_by_chain(&self, chain: &ChainId) -> Option<&AccountId> { + self.chains.get(chain).map(|x| &x.omnibus_account) + } +} + +impl KeyValueAddress { + fn new(entity: KeyValueAddressEntity, key: impl Into) -> Self { + Self { + entity, + key: key.into(), + _value: <_>::default(), + } + } +} + +impl KeyValueAddress { + fn read(&self, host: &Iroha) -> Result> { + let result = match &self.entity { + KeyValueAddressEntity::Domain(id) => host + .query(FindDomains) + .filter_with(|x| x.id.eq(id.to_owned())) + .select_with(|x| x.metadata.key(self.key.to_owned())) + .execute_single(), + KeyValueAddressEntity::Account(id) => host + .query(FindAccounts) + .filter_with(|x| x.id.eq(id.to_owned())) + .select_with(|x| x.metadata.key(self.key.to_owned())) + .execute_single(), + KeyValueAddressEntity::AssetDefinition(id) => host + .query(FindAssetsDefinitions) + .filter_with(|x| x.id.eq(id.to_owned())) + .select_with(|x| x.metadata.key(self.key.to_owned())) + .execute_single(), + KeyValueAddressEntity::Nft(id) => host + .query(FindNfts) + .filter_with(|x| x.id.eq(id.to_owned())) + .select_with(|x| x.content.key(self.key.to_owned())) + .execute_single(), + KeyValueAddressEntity::Trigger(id) => host + .query(FindTriggers) + .filter_with(|x| x.id.eq(id.to_owned())) + .select_with(|x| x.action.metadata.key(self.key.to_owned())) + .execute_single(), + }; + + let result = match result { + Ok(json) => Ok(Some(json)), + Err(SingleQueryError::QueryError(ValidationFail::QueryFailed( + QueryExecutionFail::Find(FindError::MetadataKey(_)), + ))) => Ok(None), + Err(other) => Err(other), + }; + + let value_opt = result + .map_err(|err| anyhow!("failed query: {err:?}")) + .and_then(|json_opt| { + json_opt + .map(|json| { + json.try_into_any() + .with_context(|| format!("cannot deserialize JSON: {json}")) + }) + .transpose() + }) + .with_context(|| format!("while reading \"{}\" from {:?}", self.key, self.entity))?; + + Ok(value_opt) + } +} + +impl KeyValueAddress { + fn write(&self, host: &Iroha, value: &T) -> Result<()> { + match &self.entity { + KeyValueAddressEntity::Domain(id) => host.submit(&SetKeyValue::domain( + id.to_owned(), + self.key.to_owned(), + Json::new(value), + )), + KeyValueAddressEntity::Account(id) => host.submit(&SetKeyValue::account( + id.to_owned(), + self.key.to_owned(), + Json::new(value), + )), + KeyValueAddressEntity::AssetDefinition(id) => { + host.submit(&SetKeyValue::asset_definition( + id.to_owned(), + self.key.to_owned(), + Json::new(value), + )) + } + KeyValueAddressEntity::Nft(id) => host.submit(&SetKeyValue::nft( + id.to_owned(), + self.key.to_owned(), + Json::new(value), + )), + KeyValueAddressEntity::Trigger(id) => host.submit(&SetKeyValue::trigger( + id.to_owned(), + self.key.to_owned(), + Json::new(value), + )), + } + .map_err(|err| anyhow!("failed tx: {err:?}")) + .with_context(|| format!("while writing \"{}\" to {:?}", self.key, self.entity)) + } +} + +fn check_block_height( + checkpoint: &Checkpoint, + message: &RelayBlockMessage, +) -> Result> { + let snapshot_height = checkpoint.block.map(|x| x.height().get()).unwrap_or(0); + let msg_height = message.header.height().get(); + + if snapshot_height == msg_height { + Ok(ControlFlow::Break(())) + } else if snapshot_height + 1 == msg_height { + Ok(ControlFlow::Continue(())) + } else { + Err(anyhow!( + "Expected message with height {snapshot_height} or + 1, got {msg_height}" + )) + } +} + +fn validate_prev_block_hash(chain: &Checkpoint, message: &RelayBlockMessage) -> Result<()> { + let expected = chain.block.map(|x| x.hash()); + let actual = message.header.prev_block_hash(); + + if actual != expected { + bail!("Previous block hash mismatch: expected {expected:?}, got {actual:?}"); + } + + Ok(()) +} + +fn validate_block_signatures(chain: &Checkpoint, message: &RelayBlockMessage) -> Result<()> { + if message.signatures.is_empty() { + bail!("No signatures") + } + + let required_count = chain.validators.len() / 3 * 2; + + // PERF: naive implementation + let hash = message.header.hash(); + let recognized = chain + .validators + .iter() + .filter(|pubkey| { + message + .signatures + .iter() + .any(|signature| signature.verify_hash(pubkey, hash).is_ok()) + }) + .count(); + + if recognized < required_count { + bail!( + "Invalid block signatures: recognized {recognized}, required at least {required_count}" + ); + } + + Ok(()) +} + +// Assuming max 2^9 = 512 transactions per block +const MAX_VERIFY_DEPTH: usize = 9; +const METADATA_DESTINATION: &str = "destination"; + +fn process_transactions(host: &Iroha, config: &Config, message: &RelayBlockMessage) -> Result<()> { + let block_merkle_root = message + .header + .merkle_root() + .ok_or_else(|| anyhow!("Block contains no transactions"))?; + + for tx in &message.interesting_transactions { + let tx_hash = tx.entrypoint_hash(); + + if *tx.block_hash() != message.header.hash() { + bail!("Transaction {tx_hash} block hash differs"); + } + + let proof = tx.entrypoint_proof().clone(); + if !proof.verify(&tx_hash, &block_merkle_root, MAX_VERIFY_DEPTH) { + bail!("Cannot prove that the transaction {tx_hash} is part of the block"); + } + + // boom - valid + // now match and apply + + match &config.mode { + OperationMode::Hub { + domestic_chain: other_chain, + approved_transfers_addr, + } => handle_tx_hub(tx, other_chain, approved_transfers_addr, host, config)?, + OperationMode::Domestic { chain } => handle_tx_domestic(tx, chain, host, config)?, + } + } + + Ok(()) +} + +fn handle_tx_hub( + tx: &CommittedTransaction, + other_chain: &ChainId, + approved_transfers_addr: &KeyValueAddress, + host: &Iroha, + config: &Config, +) -> Result<()> { + if let TransactionEntrypoint::External(tx) = tx.entrypoint() + && let Executable::Instructions(instructions) = tx.instructions() + && let [InstructionBox::Transfer(TransferBox::Asset(transfer))] = + instructions.iter().as_slice() + { + // Detect transfer from a user account to an omnibus account + // Detect destination account in metadata + + let None = config.chain_by_omnibus_account(transfer.source().account()) else { + debug!("ignoring, source account is omnibus"); + return Ok(()); + }; + let Some(destination_chain) = config.chain_by_omnibus_account(transfer.destination()) + else { + debug!("ignoring, destination account is not omnibus"); + return Ok(()); + }; + let Some(destination_account) = tx + .metadata() + .get(METADATA_DESTINATION) + .map(|json| { + let str: String = json.try_into_any().with_context(|| "bad json string")?; + let acc = + AccountId::from_str(&str).map_err(|err| anyhow!("bad account id: {err}"))?; + Ok::(acc) + }) + .transpose()? + else { + debug!("ingoring, could not find `{METADATA_DESTINATION}` in metadata"); + return Ok(()); + }; + + // Okay - now produce a `SetKeyValue` instruction with the record of the transfer + + let hub_transfer = HubChainTransferPayload { + source_chain: other_chain.to_owned(), + source_account: transfer.source().account().to_owned(), + destination_chain: destination_chain.to_owned(), + destination_account, + asset: transfer.source().definition().to_owned(), + object: transfer.object().to_owned(), + }; + + approved_transfers_addr.write(&host, &hub_transfer)?; + } + + Ok(()) +} + +fn handle_tx_domestic( + _tx: &CommittedTransaction, + _chain: &ChainId, + _host: &Iroha, + _config: &Config, +) -> Result<()> { + // TODO: extract SetKeyValue instructions produced by the trigger on the hub chain + Ok(()) +} diff --git a/ui/package.json b/ui/package.json index 6a578a5..95f11eb 100644 --- a/ui/package.json +++ b/ui/package.json @@ -8,18 +8,20 @@ "preview": "vite preview" }, "dependencies": { - "@iroha/client": "jsr:0.4.0", - "@iroha/core": "jsr:0.4.0", + "@iroha/client": "jsr:0.5.0-alpha-1", + "@iroha/core": "jsr:0.5.0-alpha", "@unocss/reset": "^66.4.1", "@vue-kakuyaku/core": "^0.4.3", "@vueuse/core": "^13.6.0", + "remeda": "^2.32.0", "ringbufferjs": "^2.0.0", "tiny-invariant": "^1.3.3", "true-myth": "^9.0.1", "ts-pattern": "^5.8.0", "unocss": "^66.4.1", "vue": "^3.5.17", - "zod": "^4.0.15" + "vue3-json-viewer": "^2.4.1", + "zod": "^4.1.11" }, "devDependencies": { "@types/ringbufferjs": "^1.1.2", diff --git a/ui/pnpm-lock.yaml b/ui/pnpm-lock.yaml index c26644c..208fdb2 100644 --- a/ui/pnpm-lock.yaml +++ b/ui/pnpm-lock.yaml @@ -9,11 +9,11 @@ importers: .: dependencies: '@iroha/client': - specifier: jsr:0.4.0 - version: '@jsr/iroha__client@0.4.0' + specifier: jsr:0.5.0-alpha-1 + version: '@jsr/iroha__client@0.5.0-alpha-1' '@iroha/core': - specifier: jsr:0.4.0 - version: '@jsr/iroha__core@0.4.0' + specifier: jsr:0.5.0-alpha + version: '@jsr/iroha__core@0.5.0-alpha' '@unocss/reset': specifier: ^66.4.1 version: 66.4.1 @@ -23,6 +23,9 @@ importers: '@vueuse/core': specifier: ^13.6.0 version: 13.6.0(vue@3.5.18(typescript@5.8.3)) + remeda: + specifier: ^2.32.0 + version: 2.32.0 ringbufferjs: specifier: ^2.0.0 version: 2.0.0 @@ -41,9 +44,12 @@ importers: vue: specifier: ^3.5.17 version: 3.5.18(typescript@5.8.3) + vue3-json-viewer: + specifier: ^2.4.1 + version: 2.4.1(vue@3.5.18(typescript@5.8.3)) zod: - specifier: ^4.0.15 - version: 4.0.15 + specifier: ^4.1.11 + version: 4.1.11 devDependencies: '@types/ringbufferjs': specifier: ^1.1.2 @@ -400,11 +406,11 @@ packages: '@jridgewell/trace-mapping@0.3.29': resolution: {integrity: sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==} - '@jsr/iroha__client@0.4.0': - resolution: {integrity: sha512-6tv+GOlS6UZ/XhrxcFu3cUpPSUiZ9f2zlQ+WvTtdRrHPk8kwyVSB+WudglAGMl9hKeh+vBtmG7GUlBryNFrE9g==, tarball: https://npm.jsr.io/~/11/@jsr/iroha__client/0.4.0.tgz} + '@jsr/iroha__client@0.5.0-alpha-1': + resolution: {integrity: sha512-pG8rXmxQ1X0OdzbxN18iI1HUZ8hKbtSfW0PN5P3tYxCL95hy8zF51BROsYdGxdgZfQqkImuOZJu9yh2jyXLa2g==, tarball: https://npm.jsr.io/~/11/@jsr/iroha__client/0.5.0-alpha-1.tgz} - '@jsr/iroha__core@0.4.0': - resolution: {integrity: sha512-HDvS/pEMaNz51oRpvLYNI5m4SXcOoEj5ZWKU2t4PS2w4LR6pMgb4cDHGwTRQgnijX3dwaE9Pd4wU2AfFHkuLGQ==, tarball: https://npm.jsr.io/~/11/@jsr/iroha__core/0.4.0.tgz} + '@jsr/iroha__core@0.5.0-alpha': + resolution: {integrity: sha512-DS8yuA6rTYUekdbf130hYpFajw6x40F/ivWTVkx+QwsxdyRfafiPtjlHiNX2PyCCjEb8RV8QsHpS2SFscTUeYg==, tarball: https://npm.jsr.io/~/11/@jsr/iroha__core/0.5.0-alpha.tgz} '@jsr/std__assert@1.0.13': resolution: {integrity: sha512-rZ44REoi2/p+gqu8OfkcNeaTOSiG1kD6v8gyA0YjkXsOkDsiGw9g8h7JuGC/OD7GgOVgTEY+9Cih49Y18rkrCQ==, tarball: https://npm.jsr.io/~/11/@jsr/std__assert/1.0.13.tgz} @@ -917,6 +923,9 @@ packages: resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} engines: {node: '>= 14.16.0'} + clipboard@2.0.11: + resolution: {integrity: sha512-C+0bbOqkezLIsmWSvlsXS0Q0bmkugu7jcfMIACB+RDEntIzQIkdr148we28AfSloQLRdZlYL/QYyrq05j/3Faw==} + colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} @@ -978,6 +987,9 @@ packages: defu@6.1.4: resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} + delegate@3.2.0: + resolution: {integrity: sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==} + destr@2.0.5: resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==} @@ -1059,6 +1071,9 @@ packages: resolution: {integrity: sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==} engines: {node: '>=18'} + good-listener@1.2.2: + resolution: {integrity: sha512-goW1b+d9q/HIwbVYZzZ6SsTr4IgE+WA44A0GmPIQstuOrgsFcT7VEJ48nmr9GaRtNu0XTKacFLGnBPAM6Afouw==} + gzip-size@6.0.0: resolution: {integrity: sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==} engines: {node: '>=10'} @@ -1288,6 +1303,9 @@ packages: resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} engines: {node: '>= 14.18.0'} + remeda@2.32.0: + resolution: {integrity: sha512-BZx9DsT4FAgXDTOdgJIc5eY6ECIXMwtlSPQoPglF20ycSWigttDDe88AozEsPPT4OWk5NujroGSBC1phw5uU+w==} + rfdc@1.4.1: resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} @@ -1420,6 +1438,9 @@ packages: engines: {node: '>=14.0.0'} hasBin: true + select@1.1.2: + resolution: {integrity: sha512-OwpTSOfy6xSs1+pwcNrv0RBMOzI39Lp3qQKUTPVVPRjCdNa5JH/oPRiqsesIskK8TVgmRiHwO4KXlV2Li9dANA==} + semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true @@ -1468,6 +1489,9 @@ packages: resolution: {integrity: sha512-GTt8rSKje5FilG+wEdfCkOcLL7LWqpMlr2c3LRuKt/YXxcJ52aGSbGBAdI4L3aaqfrBt6y711El53ItyH1NWzg==} engines: {node: '>=16.0.0'} + tiny-emitter@2.1.0: + resolution: {integrity: sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==} + tiny-invariant@1.3.3: resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} @@ -1638,6 +1662,11 @@ packages: peerDependencies: typescript: '>=5.0.0' + vue3-json-viewer@2.4.1: + resolution: {integrity: sha512-Z1sunvS58lJ3ZcpNhl3jYQapBVw2wjnXbemigfMWm3QnjCeg3CPMq8R6pxHUYahxMfPKLvrbGve6mUXqhWyLaQ==} + peerDependencies: + vue: ^3.5.16 + vue@3.5.18: resolution: {integrity: sha512-7W4Y4ZbMiQ3SEo+m9lnoNpV9xG7QVMLa+/0RFwwiAVkeYoyGXqWE85jabU4pllJNUzqfLShJ5YLptewhCWUgNA==} peerDependencies: @@ -1662,8 +1691,8 @@ packages: resolution: {integrity: sha512-GQHQqAopRhwU8Kt1DDM8NjibDXHC8eoh1erhGAJPEyveY9qqVeXvVikNKrDz69sHowPMorbPUrH/mx8c50eiBQ==} engines: {node: '>=18'} - zod@4.0.15: - resolution: {integrity: sha512-2IVHb9h4Mt6+UXkyMs0XbfICUh1eUrlJJAOupBHUhLRnKkruawyDddYRCs0Eizt900ntIMk9/4RksYl+FgSpcQ==} + zod@4.1.11: + resolution: {integrity: sha512-WPsqwxITS2tzx1bzhIKsEs19ABD5vmCVa4xBo2tq/SrV4RNZtfws1EnCWQXM6yh8bD08a1idvkB5MZSBiZsjwg==} snapshots: @@ -1979,15 +2008,15 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.4 - '@jsr/iroha__client@0.4.0': + '@jsr/iroha__client@0.5.0-alpha-1': dependencies: - '@jsr/iroha__core': 0.4.0 + '@jsr/iroha__core': 0.5.0-alpha '@jsr/std__assert': 1.0.13 emittery: 1.2.0 p-defer: 4.0.1 type-fest: 4.41.0 - '@jsr/iroha__core@0.4.0': + '@jsr/iroha__core@0.5.0-alpha': dependencies: '@jsr/std__assert': 1.0.13 '@jsr/std__encoding': 1.0.10 @@ -2550,6 +2579,12 @@ snapshots: readdirp: 4.1.2 optional: true + clipboard@2.0.11: + dependencies: + good-listener: 1.2.2 + select: 1.1.2 + tiny-emitter: 2.1.0 + colorette@2.0.20: {} colorjs.io@0.5.2: {} @@ -2596,6 +2631,8 @@ snapshots: defu@6.1.4: {} + delegate@3.2.0: {} + destr@2.0.5: {} detect-libc@1.0.3: @@ -2689,6 +2726,10 @@ snapshots: globals@15.15.0: {} + good-listener@1.2.2: + dependencies: + delegate: 3.2.0 + gzip-size@6.0.0: dependencies: duplexer: 0.1.2 @@ -2872,6 +2913,10 @@ snapshots: readdirp@4.1.2: optional: true + remeda@2.32.0: + dependencies: + type-fest: 4.41.0 + rfdc@1.4.1: {} ringbufferjs@2.0.0: {} @@ -3005,6 +3050,8 @@ snapshots: '@parcel/watcher': 2.5.1 optional: true + select@1.1.2: {} + semver@6.3.1: {} shebang-command@2.0.0: @@ -3041,6 +3088,8 @@ snapshots: sync-message-port@1.1.3: {} + tiny-emitter@2.1.0: {} + tiny-invariant@1.3.3: {} tinyexec@1.0.1: {} @@ -3202,6 +3251,11 @@ snapshots: '@vue/language-core': 2.2.12(typescript@5.8.3) typescript: 5.8.3 + vue3-json-viewer@2.4.1(vue@3.5.18(typescript@5.8.3)): + dependencies: + clipboard: 2.0.11 + vue: 3.5.18(typescript@5.8.3) + vue@3.5.18(typescript@5.8.3): dependencies: '@vue/compiler-dom': 3.5.18 @@ -3224,4 +3278,4 @@ snapshots: yoctocolors@2.1.1: {} - zod@4.0.15: {} + zod@4.1.11: {} diff --git a/ui/shared.ts b/ui/shared.ts index 6e0fb09..fb1e3ce 100644 --- a/ui/shared.ts +++ b/ui/shared.ts @@ -2,10 +2,17 @@ // The problem is that Vite won't discover `zod` from outside the `ui` directory // Ugly, I know... -import { AccountId, AssetDefinitionId, PrivateKey } from "@iroha/core/data-model"; +import { AccountId, AssetDefinitionId, Name, NftId, PrivateKey, PublicKey } from "@iroha/core/data-model"; import { z } from "zod"; -const AccountSchema = z.string().transform(x => AccountId.parse(x)); +const AccountSchema = z.codec( + z.string(), + z.instanceof(AccountId), + { + encode: (x) => x.toString(), + decode: (x) => AccountId.parse(x), + }, +); const PrivKeySchema = z.string().transform(x => PrivateKey.fromMultihash(x)); const AssetDefinitionIdSchema = z.string().transform(x => AssetDefinitionId.parse(x)); @@ -34,6 +41,76 @@ export const RelayConfigSchema = z.object({ domesticChainId: z.string(), domesticToriiUrl: z.url(), domesticOmnibusAccount: AccountSchema, + domesticCheckpoint: z.lazy(() => KeyValueAddressSchema), + domesticBlockMessage: z.lazy(() => KeyValueAddressSchema), hubToriiUrl: z.url(), hubChainId: z.string(), + hubCheckpoint: z.lazy(() => KeyValueAddressSchema), + hubBlockMessage: z.lazy(() => KeyValueAddressSchema), +}); + +export const KeyValueEntitySchema = z.discriminatedUnion("type", [ + z.object({ type: z.literal("Domain"), id: z.string().transform(x => new Name(x)) }), + z.object({ type: z.literal("Account"), id: AccountSchema }), + z.object({ type: z.literal("AssetDefinition"), id: AssetDefinitionIdSchema }), + z.object({ type: z.literal("Nft"), id: z.string().transform(x => NftId.parse(x)) }), + z.object({ type: z.literal("Trigger"), id: z.string().transform(x => new Name(x)) }), +]); + +export const KeyValueAddressSchema = z.object({ + entity: KeyValueEntitySchema, + key: z.string(), +}); + +export const TriggerConfigSchema = z.object({ + mode: z.discriminatedUnion("type", [ + z.object({ + type: z.literal("Hub"), + domestic_chain: z.string(), + approved_transfers_addr: KeyValueAddressSchema, + }), + z.object({ + type: z.literal("Domestic"), + chain: z.string(), + }), + ]), + checkpoint_addr: KeyValueAddressSchema, + block_message_addr: KeyValueAddressSchema, + chains: z.record(z.string(), z.object({ omnibus_account: AccountSchema })), +}); + +type PubKeyFixed = { new(): PublicKey }; + +const PublicKeySchema = z.codec( + z.string(), + z.instanceof(PublicKey as unknown as PubKeyFixed), + { + encode: (key) => key.multihash(), + decode: (hash) => PublicKey.fromMultihash(hash), + }, +); + +export const CheckpointSchema = z.object({ + validators: z.codec( + z.array(PublicKeySchema.in), + z.set(PublicKeySchema.out), + { + encode: (set) => [...set].map(x => x.multihash()), + decode: (x) => new Set([...x].map(x => PublicKey.fromMultihash(x))), + }, + ), + // there is also "block", but it is only set from within the trigger +}); + +export const BlockMessageSchema = z.object({ + // TODO +}); + +export const HubChainTransferPayload = z.object({ + source_chain: z.string(), + source_account: AccountSchema, + destination_chain: z.string(), + destination_account: AccountSchema, + asset: z.string(), + object: z.object({ scale: z.number(), mantissa: z.number() }), }); diff --git a/ui/src/App.vue b/ui/src/App.vue index 89b5258..abcb98f 100644 --- a/ui/src/App.vue +++ b/ui/src/App.vue @@ -15,12 +15,6 @@ const chainsSorted = computed(() => state.chains.toSorted(x => x.chain === "HUB" :chain="x.chain" /> - - @@ -31,6 +25,6 @@ html, body { } body { - font-family: monospace; + font-family: serif; } diff --git a/ui/src/components/Chain.vue b/ui/src/components/Chain.vue index b6a8cb2..09fc7c4 100644 --- a/ui/src/components/Chain.vue +++ b/ui/src/components/Chain.vue @@ -1,12 +1,10 @@ diff --git a/ui/src/components/VMetadata.vue b/ui/src/components/VMetadata.vue new file mode 100644 index 0000000..2552585 --- /dev/null +++ b/ui/src/components/VMetadata.vue @@ -0,0 +1,33 @@ + + + + + diff --git a/ui/src/state.ts b/ui/src/state.ts index 19afdc3..d82b867 100644 --- a/ui/src/state.ts +++ b/ui/src/state.ts @@ -1,5 +1,17 @@ import { Client } from "@iroha/client"; -import { Account, Asset, AssetDefinition, AssetDefinitionId, EventBox, EventFilterBox } from "@iroha/core/data-model"; +import { + Account, + AccountId, + Asset, + AssetDefinition, + AssetDefinitionId, + Domain, + EventBox, + EventFilterBox, + Metadata, + Trigger, + TriggerId, +} from "@iroha/core/data-model"; import { type PromiseStaleState, useParamScope, useStaleState, useTask } from "@vue-kakuyaku/core"; import { useLocalStorage } from "@vueuse/core"; import RingBuffer from "ringbufferjs"; @@ -29,19 +41,36 @@ export function domesticChains() { } type ChainData = { - data: PromiseStaleState<{ accounts: Account[]; assets: Asset[]; assetDefinitions: AssetDefinition[] }>; + data: PromiseStaleState<{ + domains: Domain[]; + accounts: Account[]; + assets: Asset[]; + assetDefinitions: AssetDefinition[]; + triggers: { id: TriggerId; metadata: Metadata; authority: AccountId }[]; + }>; reload: () => void; }; function useChainData(client: Client): ChainData { const task = useTask(async () => { - const [accounts, defs, assets] = await Promise.all([ + const [domains, accounts, defs, assets, triggers] = await Promise.all([ + client.find.domains().executeAll(), client.find.accounts().executeAll(), client.find.assetsDefinitions().executeAll(), client.find.assets().executeAll(), + client.find.triggers() + // .selectWith((trig) => [trig.id, trig.action. trig.action.metadata]) + .executeAll(), ]); - return { accounts, assets, assetDefinitions: defs }; + return { + domains, + accounts, + assets, + assetDefinitions: defs, + triggers: triggers + .map(({ id, action: { metadata, authority } }) => ({ id, authority, metadata })), + }; }, { immediate: true }); const stale = useStaleState(task.state);