From a41384c60affb0e8125ef4962c748618333f42bb Mon Sep 17 00:00:00 2001 From: Alberto Centelles Date: Mon, 15 Aug 2022 17:51:42 +0100 Subject: [PATCH 001/118] Fix links --- README.md | 5 ++--- documentation/README.md | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 939653c596..30a6589027 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,6 @@ interaction with the protocol. ## 📓 Docs - user docs: built from [docs mdBook](./documentation/docs/) -- dev docs: built from [dev mdBook](./documentation/dev/) - specifications: built from [specs mdBook](./documentation/specs/) ## Warning @@ -38,10 +37,10 @@ make install After installation, the main `anoma` executable will be available on path. -To find how to use it, check out the [User Guide section of the docs](https://docs.anoma.net/user-guide/). +To find how to use it, check out the [User Guide section of the docs](https://docs.namada.net/user-guide/index.html). For more detailed instructions and more install options, see the [Install -section](https://docs.anoma.net/user-guide/install.html) of the User +section](https://docs.namada.net/user-guide/install.html) of the User Guide. ## ⚙️ Development diff --git a/documentation/README.md b/documentation/README.md index a740b8d387..99dd836220 100644 --- a/documentation/README.md +++ b/documentation/README.md @@ -2,7 +2,6 @@ - `docs` contains user and operator documentation. -- `dev` contains developer documentation for building on top of Namada. - `spec` contains the specifications for Namada. From c1aca2d2f139021cc85b383a539b430ebc1175fc Mon Sep 17 00:00:00 2001 From: Alberto Centelles Date: Mon, 15 Aug 2022 18:49:36 +0100 Subject: [PATCH 002/118] Change anoma to namada in install docs --- documentation/docs/src/user-guide/install.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/documentation/docs/src/user-guide/install.md b/documentation/docs/src/user-guide/install.md index ee3ce622df..dcf6966cb4 100644 --- a/documentation/docs/src/user-guide/install.md +++ b/documentation/docs/src/user-guide/install.md @@ -56,8 +56,8 @@ During internal and private testnets, checkout the latest testnet branch using ` ``` ```shell -git clone https://github.com/anoma/anoma.git -cd anoma +git clone https://github.com/anoma/namada.git +cd namada make install ``` From 6b3a98f886fe7a34a12758ad30a36c6a86b3e762 Mon Sep 17 00:00:00 2001 From: Alberto Centelles Date: Tue, 16 Aug 2022 13:21:17 +0100 Subject: [PATCH 003/118] Add dev docs back --- README.md | 5 +++-- documentation/README.md | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 30a6589027..939653c596 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ interaction with the protocol. ## 📓 Docs - user docs: built from [docs mdBook](./documentation/docs/) +- dev docs: built from [dev mdBook](./documentation/dev/) - specifications: built from [specs mdBook](./documentation/specs/) ## Warning @@ -37,10 +38,10 @@ make install After installation, the main `anoma` executable will be available on path. -To find how to use it, check out the [User Guide section of the docs](https://docs.namada.net/user-guide/index.html). +To find how to use it, check out the [User Guide section of the docs](https://docs.anoma.net/user-guide/). For more detailed instructions and more install options, see the [Install -section](https://docs.namada.net/user-guide/install.html) of the User +section](https://docs.anoma.net/user-guide/install.html) of the User Guide. ## ⚙️ Development diff --git a/documentation/README.md b/documentation/README.md index 99dd836220..a740b8d387 100644 --- a/documentation/README.md +++ b/documentation/README.md @@ -2,6 +2,7 @@ - `docs` contains user and operator documentation. +- `dev` contains developer documentation for building on top of Namada. - `spec` contains the specifications for Namada. From facdeeb7b38fecc0a73657cc6e62af977f1ccad9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zemanovi=C4=8D?= Date: Tue, 2 Aug 2022 17:52:24 +0200 Subject: [PATCH 004/118] re-add dev docs from cd3886453ac60655622805e1fecf35f5eceb8c5e --- documentation/dev/.gitignore | 1 + documentation/dev/Makefile | 16 + documentation/dev/README.md | 11 + documentation/dev/assets/custom.css | 10 + documentation/dev/assets/mdbook-admonish.css | 316 +++ documentation/dev/assets/mermaid-init.js | 1 + documentation/dev/assets/mermaid.min.js | 32 + documentation/dev/book.toml | 32 + documentation/dev/src/README.md | 40 + documentation/dev/src/SUMMARY.md | 63 + documentation/dev/src/archive/README.md | 3 + .../dev/src/archive/domain-name-addresses.md | 21 + documentation/dev/src/explore/README.md | 5 + .../dev/src/explore/design/README.md | 3 + .../dev/src/explore/design/actors.md | 41 + .../src/explore/design/crypto-primitives.md | 7 + documentation/dev/src/explore/design/dkg.md | 2 + .../dev/src/explore/design/glossary.md | 17 + .../dev/src/explore/design/gossip.md | 17 + .../explore/design/gossip_process.excalidraw | 966 ++++++++ .../dev/src/explore/design/gossip_process.svg | 16 + .../design/intent_gossip/example.excalidraw | 2202 +++++++++++++++++ .../explore/design/intent_gossip/example.svg | 16 + .../design/intent_gossip/fungible_token.md | 35 + .../intent_gossip/gossip_process.excalidraw | 966 ++++++++ .../design/intent_gossip/gossip_process.svg | 16 + .../explore/design/intent_gossip/incentive.md | 9 + .../explore/design/intent_gossip/intent.md | 28 + .../design/intent_gossip/intent_gossip.md | 51 + .../intent_life_cycle.excalidraw | 1686 +++++++++++++ .../intent_gossip/intent_life_cycle.svg | 16 + .../design/intent_gossip/matchmaker.md | 80 + .../intent_gossip/matchmaker_graph.excalidraw | 1648 ++++++++++++ .../design/intent_gossip/matchmaker_graph.png | Bin 0 -> 156552 bytes .../design/intent_gossip/matchmaker_graph.svg | 16 + .../matchmaker_process.excalidraw | 1883 ++++++++++++++ .../intent_gossip/matchmaker_process.svg | 16 + .../src/explore/design/intent_gossip/topic.md | 11 + .../dev/src/explore/design/ledger.md | 80 + .../dev/src/explore/design/ledger/accounts.md | 54 + .../dev/src/explore/design/ledger/epochs.md | 15 + .../explore/design/ledger/fractal-scaling.md | 5 + .../explore/design/ledger/front-running.md | 7 + .../src/explore/design/ledger/governance.md | 104 + .../design/ledger/ledger_threads.excalidraw | 1340 ++++++++++ .../explore/design/ledger/ledger_threads.svg | 16 + .../src/explore/design/ledger/parameters.md | 13 + .../explore/design/ledger/pos-integration.md | 245 ++ .../dev/src/explore/design/ledger/storage.md | 146 ++ .../design/ledger/storage/data-schema.md | 93 + .../dev/src/explore/design/ledger/tx.md | 88 + .../dev/src/explore/design/ledger/vp.md | 53 + .../dev/src/explore/design/ledger/wasm-vm.md | 125 + .../wasm-vm/storage-write-log.excalidraw | 2194 ++++++++++++++++ .../ledger/wasm-vm/storage-write-log.svg | 16 + .../dev/src/explore/design/overview.md | 10 + .../explore/design/overview/crates.excalidraw | 1560 ++++++++++++ .../src/explore/design/overview/crates.svg | 16 + documentation/dev/src/explore/design/pos.md | 282 +++ .../dev/src/explore/design/summary.png | Bin 0 -> 149153 bytes .../design/testnet-launch-procedure/README.md | 30 + .../dev/src/explore/design/testnet-setup.md | 39 + .../dev/src/explore/design/upgrade-system.md | 5 + .../dev/src/explore/libraries/README.md | 3 + .../dev/src/explore/libraries/async.md | 16 + .../dev/src/explore/libraries/cli.md | 19 + documentation/dev/src/explore/libraries/db.md | 95 + .../dev/src/explore/libraries/errors.md | 36 + .../dev/src/explore/libraries/logging.md | 29 + .../dev/src/explore/libraries/network.md | 22 + .../dev/src/explore/libraries/packaging.md | 27 + .../src/explore/libraries/serialization.md | 81 + .../dev/src/explore/libraries/wasm.md | 40 + .../dev/src/explore/prototypes/README.md | 23 + .../dev/src/explore/prototypes/base-ledger.md | 112 + .../src/explore/prototypes/gossip-layer.md | 61 + .../dev/src/explore/resources/README.md | 11 + .../dev/src/explore/resources/ide.md | 133 + documentation/dev/src/rustdoc-logo.png | Bin 0 -> 5188 bytes documentation/dev/src/specs/README.md | 7 + documentation/dev/src/specs/crypto.md | 16 + documentation/dev/src/specs/encoding.md | 48 + .../dev/src/specs/encoding/.gitignore | 1 + documentation/dev/src/specs/ledger.md | 284 +++ .../src/specs/ledger/default-transactions.md | 57 + .../ledger/default-validity-predicates.md | 7 + documentation/dev/src/specs/ledger/rpc.md | 45 + documentation/dev/src/specs/overview.md | 19 + documentation/dev/theme/favicon.png | Bin 0 -> 5037 bytes documentation/dev/theme/favicon.svg | 6 + 90 files changed, 18033 insertions(+) create mode 100644 documentation/dev/.gitignore create mode 100644 documentation/dev/Makefile create mode 100644 documentation/dev/README.md create mode 100644 documentation/dev/assets/custom.css create mode 100644 documentation/dev/assets/mdbook-admonish.css create mode 100644 documentation/dev/assets/mermaid-init.js create mode 100644 documentation/dev/assets/mermaid.min.js create mode 100644 documentation/dev/book.toml create mode 100644 documentation/dev/src/README.md create mode 100644 documentation/dev/src/SUMMARY.md create mode 100644 documentation/dev/src/archive/README.md create mode 100644 documentation/dev/src/archive/domain-name-addresses.md create mode 100644 documentation/dev/src/explore/README.md create mode 100644 documentation/dev/src/explore/design/README.md create mode 100644 documentation/dev/src/explore/design/actors.md create mode 100644 documentation/dev/src/explore/design/crypto-primitives.md create mode 100644 documentation/dev/src/explore/design/dkg.md create mode 100644 documentation/dev/src/explore/design/glossary.md create mode 100644 documentation/dev/src/explore/design/gossip.md create mode 100644 documentation/dev/src/explore/design/gossip_process.excalidraw create mode 100644 documentation/dev/src/explore/design/gossip_process.svg create mode 100644 documentation/dev/src/explore/design/intent_gossip/example.excalidraw create mode 100644 documentation/dev/src/explore/design/intent_gossip/example.svg create mode 100644 documentation/dev/src/explore/design/intent_gossip/fungible_token.md create mode 100644 documentation/dev/src/explore/design/intent_gossip/gossip_process.excalidraw create mode 100644 documentation/dev/src/explore/design/intent_gossip/gossip_process.svg create mode 100644 documentation/dev/src/explore/design/intent_gossip/incentive.md create mode 100644 documentation/dev/src/explore/design/intent_gossip/intent.md create mode 100644 documentation/dev/src/explore/design/intent_gossip/intent_gossip.md create mode 100644 documentation/dev/src/explore/design/intent_gossip/intent_life_cycle.excalidraw create mode 100644 documentation/dev/src/explore/design/intent_gossip/intent_life_cycle.svg create mode 100644 documentation/dev/src/explore/design/intent_gossip/matchmaker.md create mode 100644 documentation/dev/src/explore/design/intent_gossip/matchmaker_graph.excalidraw create mode 100644 documentation/dev/src/explore/design/intent_gossip/matchmaker_graph.png create mode 100644 documentation/dev/src/explore/design/intent_gossip/matchmaker_graph.svg create mode 100644 documentation/dev/src/explore/design/intent_gossip/matchmaker_process.excalidraw create mode 100644 documentation/dev/src/explore/design/intent_gossip/matchmaker_process.svg create mode 100644 documentation/dev/src/explore/design/intent_gossip/topic.md create mode 100644 documentation/dev/src/explore/design/ledger.md create mode 100644 documentation/dev/src/explore/design/ledger/accounts.md create mode 100644 documentation/dev/src/explore/design/ledger/epochs.md create mode 100644 documentation/dev/src/explore/design/ledger/fractal-scaling.md create mode 100644 documentation/dev/src/explore/design/ledger/front-running.md create mode 100644 documentation/dev/src/explore/design/ledger/governance.md create mode 100644 documentation/dev/src/explore/design/ledger/ledger_threads.excalidraw create mode 100644 documentation/dev/src/explore/design/ledger/ledger_threads.svg create mode 100644 documentation/dev/src/explore/design/ledger/parameters.md create mode 100644 documentation/dev/src/explore/design/ledger/pos-integration.md create mode 100644 documentation/dev/src/explore/design/ledger/storage.md create mode 100644 documentation/dev/src/explore/design/ledger/storage/data-schema.md create mode 100644 documentation/dev/src/explore/design/ledger/tx.md create mode 100644 documentation/dev/src/explore/design/ledger/vp.md create mode 100644 documentation/dev/src/explore/design/ledger/wasm-vm.md create mode 100644 documentation/dev/src/explore/design/ledger/wasm-vm/storage-write-log.excalidraw create mode 100644 documentation/dev/src/explore/design/ledger/wasm-vm/storage-write-log.svg create mode 100644 documentation/dev/src/explore/design/overview.md create mode 100644 documentation/dev/src/explore/design/overview/crates.excalidraw create mode 100644 documentation/dev/src/explore/design/overview/crates.svg create mode 100644 documentation/dev/src/explore/design/pos.md create mode 100644 documentation/dev/src/explore/design/summary.png create mode 100644 documentation/dev/src/explore/design/testnet-launch-procedure/README.md create mode 100644 documentation/dev/src/explore/design/testnet-setup.md create mode 100644 documentation/dev/src/explore/design/upgrade-system.md create mode 100644 documentation/dev/src/explore/libraries/README.md create mode 100644 documentation/dev/src/explore/libraries/async.md create mode 100644 documentation/dev/src/explore/libraries/cli.md create mode 100644 documentation/dev/src/explore/libraries/db.md create mode 100644 documentation/dev/src/explore/libraries/errors.md create mode 100644 documentation/dev/src/explore/libraries/logging.md create mode 100644 documentation/dev/src/explore/libraries/network.md create mode 100644 documentation/dev/src/explore/libraries/packaging.md create mode 100644 documentation/dev/src/explore/libraries/serialization.md create mode 100644 documentation/dev/src/explore/libraries/wasm.md create mode 100644 documentation/dev/src/explore/prototypes/README.md create mode 100644 documentation/dev/src/explore/prototypes/base-ledger.md create mode 100644 documentation/dev/src/explore/prototypes/gossip-layer.md create mode 100644 documentation/dev/src/explore/resources/README.md create mode 100644 documentation/dev/src/explore/resources/ide.md create mode 100644 documentation/dev/src/rustdoc-logo.png create mode 100644 documentation/dev/src/specs/README.md create mode 100644 documentation/dev/src/specs/crypto.md create mode 100644 documentation/dev/src/specs/encoding.md create mode 100644 documentation/dev/src/specs/encoding/.gitignore create mode 100644 documentation/dev/src/specs/ledger.md create mode 100644 documentation/dev/src/specs/ledger/default-transactions.md create mode 100644 documentation/dev/src/specs/ledger/default-validity-predicates.md create mode 100644 documentation/dev/src/specs/ledger/rpc.md create mode 100644 documentation/dev/src/specs/overview.md create mode 100644 documentation/dev/theme/favicon.png create mode 100644 documentation/dev/theme/favicon.svg diff --git a/documentation/dev/.gitignore b/documentation/dev/.gitignore new file mode 100644 index 0000000000..3006b271da --- /dev/null +++ b/documentation/dev/.gitignore @@ -0,0 +1 @@ +book/ diff --git a/documentation/dev/Makefile b/documentation/dev/Makefile new file mode 100644 index 0000000000..804a2f00d8 --- /dev/null +++ b/documentation/dev/Makefile @@ -0,0 +1,16 @@ +cargo = $(env) cargo + +build: + mdbook build + +serve: + mdbook serve --open + +dev-deps: + $(cargo) install mdbook + $(cargo) install mdbook-mermaid + $(cargo) install mdbook-linkcheck + $(cargo) install mdbook-open-on-gh + $(cargo) install mdbook-admonish + +.PHONY: build serve diff --git a/documentation/dev/README.md b/documentation/dev/README.md new file mode 100644 index 0000000000..99d845411c --- /dev/null +++ b/documentation/dev/README.md @@ -0,0 +1,11 @@ +See the [Introduction](./src/). + +In short: +- `make dev-deps` install dependencies +- `make serve` open the rendered mdBook in your default browser + +Using Nix: + +```bash +nix develop ..#anoma-docs -c make serve +``` diff --git a/documentation/dev/assets/custom.css b/documentation/dev/assets/custom.css new file mode 100644 index 0000000000..cf7a00c870 --- /dev/null +++ b/documentation/dev/assets/custom.css @@ -0,0 +1,10 @@ +pre.mermaid { + background: white; +} + +footer { + font-size: 0.8em; + text-align: center; + border-top: 1px solid black; + padding: 10px 0; +} \ No newline at end of file diff --git a/documentation/dev/assets/mdbook-admonish.css b/documentation/dev/assets/mdbook-admonish.css new file mode 100644 index 0000000000..5d83c334d6 --- /dev/null +++ b/documentation/dev/assets/mdbook-admonish.css @@ -0,0 +1,316 @@ +:root { + --md-admonition-icon--note: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--abstract: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--info: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--tip: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--success: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--question: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--warning: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--failure: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--danger: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--bug: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--example: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--quote: + url("data:image/svg+xml;charset=utf-8,"); +} + +:is(.admonition) { + display: flow-root; + margin: 1.5625em 0; + padding: 0 1.2rem; + color: var(--fg); + page-break-inside: avoid; + background-color: var(--bg); + border: 0 solid black; + border-inline-start-width: 0.4rem; + border-radius: 0.2rem; + box-shadow: 0 0.2rem 1rem rgba(0, 0, 0, 0.05), 0 0 0.1rem rgba(0, 0, 0, 0.1); +} +@media print { + :is(.admonition) { + box-shadow: none; + } +} +:is(.admonition) > * { + box-sizing: border-box; +} +:is(.admonition) :is(.admonition) { + margin-top: 1em; + margin-bottom: 1em; +} +:is(.admonition) > .tabbed-set:only-child { + margin-top: 0; +} +html :is(.admonition) > :last-child { + margin-bottom: 1.2rem; +} + +a.admonition-anchor-link:link, a.admonition-anchor-link:visited { + color: var(--fg); +} +a.admonition-anchor-link:link:hover, a.admonition-anchor-link:visited:hover { + text-decoration: none; +} + +:is(.admonition-title, summary) { + position: relative; + margin-block: 0; + margin-inline: -1.6rem -1.2rem; + padding-block: 0.8rem; + padding-inline: 4.4rem 1.2rem; + font-weight: 700; + background-color: rgba(68, 138, 255, 0.1); + display: flex; +} +:is(.admonition-title, summary) p { + margin: 0; +} +html :is(.admonition-title, summary):last-child { + margin-bottom: 0; +} +:is(.admonition-title, summary)::before { + position: absolute; + top: 0.625em; + inset-inline-start: 1.6rem; + width: 2rem; + height: 2rem; + background-color: #448aff; + mask-image: url('data:image/svg+xml;charset=utf-8,'); + -webkit-mask-image: url('data:image/svg+xml;charset=utf-8,'); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-size: contain; + content: ""; +} + +:is(.admonition):is(.note) { + border-color: #448aff; +} + +:is(.note) > :is(.admonition-title, summary) { + background-color: rgba(68, 138, 255, 0.1); +} +:is(.note) > :is(.admonition-title, summary)::before { + background-color: #448aff; + mask-image: var(--md-admonition-icon--note); + -webkit-mask-image: var(--md-admonition-icon--note); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.abstract, .summary, .tldr) { + border-color: #00b0ff; +} + +:is(.abstract, .summary, .tldr) > :is(.admonition-title, summary) { + background-color: rgba(0, 176, 255, 0.1); +} +:is(.abstract, .summary, .tldr) > :is(.admonition-title, summary)::before { + background-color: #00b0ff; + mask-image: var(--md-admonition-icon--abstract); + -webkit-mask-image: var(--md-admonition-icon--abstract); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.info, .todo) { + border-color: #00b8d4; +} + +:is(.info, .todo) > :is(.admonition-title, summary) { + background-color: rgba(0, 184, 212, 0.1); +} +:is(.info, .todo) > :is(.admonition-title, summary)::before { + background-color: #00b8d4; + mask-image: var(--md-admonition-icon--info); + -webkit-mask-image: var(--md-admonition-icon--info); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.tip, .hint, .important) { + border-color: #00bfa5; +} + +:is(.tip, .hint, .important) > :is(.admonition-title, summary) { + background-color: rgba(0, 191, 165, 0.1); +} +:is(.tip, .hint, .important) > :is(.admonition-title, summary)::before { + background-color: #00bfa5; + mask-image: var(--md-admonition-icon--tip); + -webkit-mask-image: var(--md-admonition-icon--tip); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.success, .check, .done) { + border-color: #00c853; +} + +:is(.success, .check, .done) > :is(.admonition-title, summary) { + background-color: rgba(0, 200, 83, 0.1); +} +:is(.success, .check, .done) > :is(.admonition-title, summary)::before { + background-color: #00c853; + mask-image: var(--md-admonition-icon--success); + -webkit-mask-image: var(--md-admonition-icon--success); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.question, .help, .faq) { + border-color: #64dd17; +} + +:is(.question, .help, .faq) > :is(.admonition-title, summary) { + background-color: rgba(100, 221, 23, 0.1); +} +:is(.question, .help, .faq) > :is(.admonition-title, summary)::before { + background-color: #64dd17; + mask-image: var(--md-admonition-icon--question); + -webkit-mask-image: var(--md-admonition-icon--question); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.warning, .caution, .attention) { + border-color: #ff9100; +} + +:is(.warning, .caution, .attention) > :is(.admonition-title, summary) { + background-color: rgba(255, 145, 0, 0.1); +} +:is(.warning, .caution, .attention) > :is(.admonition-title, summary)::before { + background-color: #ff9100; + mask-image: var(--md-admonition-icon--warning); + -webkit-mask-image: var(--md-admonition-icon--warning); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.failure, .fail, .missing) { + border-color: #ff5252; +} + +:is(.failure, .fail, .missing) > :is(.admonition-title, summary) { + background-color: rgba(255, 82, 82, 0.1); +} +:is(.failure, .fail, .missing) > :is(.admonition-title, summary)::before { + background-color: #ff5252; + mask-image: var(--md-admonition-icon--failure); + -webkit-mask-image: var(--md-admonition-icon--failure); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.danger, .error) { + border-color: #ff1744; +} + +:is(.danger, .error) > :is(.admonition-title, summary) { + background-color: rgba(255, 23, 68, 0.1); +} +:is(.danger, .error) > :is(.admonition-title, summary)::before { + background-color: #ff1744; + mask-image: var(--md-admonition-icon--danger); + -webkit-mask-image: var(--md-admonition-icon--danger); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.bug) { + border-color: #f50057; +} + +:is(.bug) > :is(.admonition-title, summary) { + background-color: rgba(245, 0, 87, 0.1); +} +:is(.bug) > :is(.admonition-title, summary)::before { + background-color: #f50057; + mask-image: var(--md-admonition-icon--bug); + -webkit-mask-image: var(--md-admonition-icon--bug); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.example) { + border-color: #7c4dff; +} + +:is(.example) > :is(.admonition-title, summary) { + background-color: rgba(124, 77, 255, 0.1); +} +:is(.example) > :is(.admonition-title, summary)::before { + background-color: #7c4dff; + mask-image: var(--md-admonition-icon--example); + -webkit-mask-image: var(--md-admonition-icon--example); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.quote, .cite) { + border-color: #9e9e9e; +} + +:is(.quote, .cite) > :is(.admonition-title, summary) { + background-color: rgba(158, 158, 158, 0.1); +} +:is(.quote, .cite) > :is(.admonition-title, summary)::before { + background-color: #9e9e9e; + mask-image: var(--md-admonition-icon--quote); + -webkit-mask-image: var(--md-admonition-icon--quote); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +.navy :is(.admonition) { + background-color: var(--sidebar-bg); +} + +.ayu :is(.admonition), .coal :is(.admonition) { + background-color: var(--theme-hover); +} + +.rust :is(.admonition) { + background-color: var(--sidebar-bg); + color: var(--sidebar-fg); +} +.rust .admonition-anchor-link:link, .rust .admonition-anchor-link:visited { + color: var(--sidebar-fg); +} diff --git a/documentation/dev/assets/mermaid-init.js b/documentation/dev/assets/mermaid-init.js new file mode 100644 index 0000000000..256e4c7359 --- /dev/null +++ b/documentation/dev/assets/mermaid-init.js @@ -0,0 +1 @@ +mermaid.initialize({ startOnLoad: true, theme: "neutral", logLevel: "warn" }); diff --git a/documentation/dev/assets/mermaid.min.js b/documentation/dev/assets/mermaid.min.js new file mode 100644 index 0000000000..14ef691fa9 --- /dev/null +++ b/documentation/dev/assets/mermaid.min.js @@ -0,0 +1,32 @@ +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.mermaid=e():t.mermaid=e()}("undefined"!=typeof self?self:this,(function(){return function(t){var e={};function n(r){if(e[r])return e[r].exports;var i=e[r]={i:r,l:!1,exports:{}};return t[r].call(i.exports,i,i.exports,n),i.l=!0,i.exports}return n.m=t,n.c=e,n.d=function(t,e,r){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:r})},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var i in t)n.d(r,i,function(e){return t[e]}.bind(null,i));return r},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="",n(n.s=383)}([function(t,e,n){"use strict";n.r(e);var r=function(t,e){return te?1:t>=e?0:NaN},i=function(t){var e;return 1===t.length&&(e=t,t=function(t,n){return r(e(t),n)}),{left:function(e,n,r,i){for(null==r&&(r=0),null==i&&(i=e.length);r>>1;t(e[a],n)<0?r=a+1:i=a}return r},right:function(e,n,r,i){for(null==r&&(r=0),null==i&&(i=e.length);r>>1;t(e[a],n)>0?i=a:r=a+1}return r}}};var a=i(r),o=a.right,s=a.left,c=o,u=function(t,e){null==e&&(e=l);for(var n=0,r=t.length-1,i=t[0],a=new Array(r<0?0:r);nt?1:e>=t?0:NaN},d=function(t){return null===t?NaN:+t},p=function(t,e){var n,r,i=t.length,a=0,o=-1,s=0,c=0;if(null==e)for(;++o1)return c/(a-1)},g=function(t,e){var n=p(t,e);return n?Math.sqrt(n):n},y=function(t,e){var n,r,i,a=t.length,o=-1;if(null==e){for(;++o=n)for(r=i=n;++on&&(r=n),i=n)for(r=i=n;++on&&(r=n),i0)return[t];if((r=e0)for(t=Math.ceil(t/o),e=Math.floor(e/o),a=new Array(i=Math.ceil(e-t+1));++s=0?(a>=w?10:a>=E?5:a>=T?2:1)*Math.pow(10,i):-Math.pow(10,-i)/(a>=w?10:a>=E?5:a>=T?2:1)}function S(t,e,n){var r=Math.abs(e-t)/Math.max(0,n),i=Math.pow(10,Math.floor(Math.log(r)/Math.LN10)),a=r/i;return a>=w?i*=10:a>=E?i*=5:a>=T&&(i*=2),eh;)f.pop(),--d;var p,g=new Array(d+1);for(i=0;i<=d;++i)(p=g[i]=[]).x0=i>0?f[i-1]:l,p.x1=i=1)return+n(t[r-1],r-1,t);var r,i=(r-1)*e,a=Math.floor(i),o=+n(t[a],a,t);return o+(+n(t[a+1],a+1,t)-o)*(i-a)}},N=function(t,e,n){return t=b.call(t,d).sort(r),Math.ceil((n-e)/(2*(D(t,.75)-D(t,.25))*Math.pow(t.length,-1/3)))},B=function(t,e,n){return Math.ceil((n-e)/(3.5*g(t)*Math.pow(t.length,-1/3)))},L=function(t,e){var n,r,i=t.length,a=-1;if(null==e){for(;++a=n)for(r=n;++ar&&(r=n)}else for(;++a=n)for(r=n;++ar&&(r=n);return r},F=function(t,e){var n,r=t.length,i=r,a=-1,o=0;if(null==e)for(;++a=0;)for(e=(r=t[i]).length;--e>=0;)n[--o]=r[e];return n},j=function(t,e){var n,r,i=t.length,a=-1;if(null==e){for(;++a=n)for(r=n;++an&&(r=n)}else for(;++a=n)for(r=n;++an&&(r=n);return r},R=function(t,e){for(var n=e.length,r=new Array(n);n--;)r[n]=t[e[n]];return r},Y=function(t,e){if(n=t.length){var n,i,a=0,o=0,s=t[o];for(null==e&&(e=r);++a=0&&(n=t.slice(r+1),t=t.slice(0,r)),t&&!e.hasOwnProperty(t))throw new Error("unknown type: "+t);return{type:t,name:n}}))}function ct(t,e){for(var n,r=0,i=t.length;r0)for(var n,r,i=new Array(n),a=0;ae?1:t>=e?0:NaN}var _t="http://www.w3.org/1999/xhtml",kt={svg:"http://www.w3.org/2000/svg",xhtml:_t,xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"},wt=function(t){var e=t+="",n=e.indexOf(":");return n>=0&&"xmlns"!==(e=t.slice(0,n))&&(t=t.slice(n+1)),kt.hasOwnProperty(e)?{space:kt[e],local:t}:t};function Et(t){return function(){this.removeAttribute(t)}}function Tt(t){return function(){this.removeAttributeNS(t.space,t.local)}}function Ct(t,e){return function(){this.setAttribute(t,e)}}function At(t,e){return function(){this.setAttributeNS(t.space,t.local,e)}}function St(t,e){return function(){var n=e.apply(this,arguments);null==n?this.removeAttribute(t):this.setAttribute(t,n)}}function Mt(t,e){return function(){var n=e.apply(this,arguments);null==n?this.removeAttributeNS(t.space,t.local):this.setAttributeNS(t.space,t.local,n)}}var Ot=function(t){return t.ownerDocument&&t.ownerDocument.defaultView||t.document&&t||t.defaultView};function Dt(t){return function(){this.style.removeProperty(t)}}function Nt(t,e,n){return function(){this.style.setProperty(t,e,n)}}function Bt(t,e,n){return function(){var r=e.apply(this,arguments);null==r?this.style.removeProperty(t):this.style.setProperty(t,r,n)}}function Lt(t,e){return t.style.getPropertyValue(e)||Ot(t).getComputedStyle(t,null).getPropertyValue(e)}function Ft(t){return function(){delete this[t]}}function Pt(t,e){return function(){this[t]=e}}function It(t,e){return function(){var n=e.apply(this,arguments);null==n?delete this[t]:this[t]=n}}function jt(t){return t.trim().split(/^|\s+/)}function Rt(t){return t.classList||new Yt(t)}function Yt(t){this._node=t,this._names=jt(t.getAttribute("class")||"")}function zt(t,e){for(var n=Rt(t),r=-1,i=e.length;++r=0&&(this._names.splice(e,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(t){return this._names.indexOf(t)>=0}};function Vt(){this.textContent=""}function Gt(t){return function(){this.textContent=t}}function qt(t){return function(){var e=t.apply(this,arguments);this.textContent=null==e?"":e}}function Xt(){this.innerHTML=""}function Zt(t){return function(){this.innerHTML=t}}function Jt(t){return function(){var e=t.apply(this,arguments);this.innerHTML=null==e?"":e}}function Kt(){this.nextSibling&&this.parentNode.appendChild(this)}function Qt(){this.previousSibling&&this.parentNode.insertBefore(this,this.parentNode.firstChild)}function te(t){return function(){var e=this.ownerDocument,n=this.namespaceURI;return n===_t&&e.documentElement.namespaceURI===_t?e.createElement(t):e.createElementNS(n,t)}}function ee(t){return function(){return this.ownerDocument.createElementNS(t.space,t.local)}}var ne=function(t){var e=wt(t);return(e.local?ee:te)(e)};function re(){return null}function ie(){var t=this.parentNode;t&&t.removeChild(this)}function ae(){var t=this.cloneNode(!1),e=this.parentNode;return e?e.insertBefore(t,this.nextSibling):t}function oe(){var t=this.cloneNode(!0),e=this.parentNode;return e?e.insertBefore(t,this.nextSibling):t}var se={},ce=null;"undefined"!=typeof document&&("onmouseenter"in document.documentElement||(se={mouseenter:"mouseover",mouseleave:"mouseout"}));function ue(t,e,n){return t=le(t,e,n),function(e){var n=e.relatedTarget;n&&(n===this||8&n.compareDocumentPosition(this))||t.call(this,e)}}function le(t,e,n){return function(r){var i=ce;ce=r;try{t.call(this,this.__data__,e,n)}finally{ce=i}}}function he(t){return t.trim().split(/^|\s+/).map((function(t){var e="",n=t.indexOf(".");return n>=0&&(e=t.slice(n+1),t=t.slice(0,n)),{type:t,name:e}}))}function fe(t){return function(){var e=this.__on;if(e){for(var n,r=0,i=-1,a=e.length;r=_&&(_=x+1);!(b=v[_])&&++_=0;)(r=i[a])&&(o&&4^r.compareDocumentPosition(o)&&o.parentNode.insertBefore(r,o),o=r);return this},sort:function(t){function e(e,n){return e&&n?t(e.__data__,n.__data__):!e-!n}t||(t=xt);for(var n=this._groups,r=n.length,i=new Array(r),a=0;a1?this.each((null==e?Dt:"function"==typeof e?Bt:Nt)(t,e,null==n?"":n)):Lt(this.node(),t)},property:function(t,e){return arguments.length>1?this.each((null==e?Ft:"function"==typeof e?It:Pt)(t,e)):this.node()[t]},classed:function(t,e){var n=jt(t+"");if(arguments.length<2){for(var r=Rt(this.node()),i=-1,a=n.length;++i>8&15|e>>4&240,e>>4&15|240&e,(15&e)<<4|15&e,1):8===n?new qe(e>>24&255,e>>16&255,e>>8&255,(255&e)/255):4===n?new qe(e>>12&15|e>>8&240,e>>8&15|e>>4&240,e>>4&15|240&e,((15&e)<<4|15&e)/255):null):(e=Le.exec(t))?new qe(e[1],e[2],e[3],1):(e=Fe.exec(t))?new qe(255*e[1]/100,255*e[2]/100,255*e[3]/100,1):(e=Pe.exec(t))?He(e[1],e[2],e[3],e[4]):(e=Ie.exec(t))?He(255*e[1]/100,255*e[2]/100,255*e[3]/100,e[4]):(e=je.exec(t))?Ke(e[1],e[2]/100,e[3]/100,1):(e=Re.exec(t))?Ke(e[1],e[2]/100,e[3]/100,e[4]):Ye.hasOwnProperty(t)?We(Ye[t]):"transparent"===t?new qe(NaN,NaN,NaN,0):null}function We(t){return new qe(t>>16&255,t>>8&255,255&t,1)}function He(t,e,n,r){return r<=0&&(t=e=n=NaN),new qe(t,e,n,r)}function Ve(t){return t instanceof Me||(t=$e(t)),t?new qe((t=t.rgb()).r,t.g,t.b,t.opacity):new qe}function Ge(t,e,n,r){return 1===arguments.length?Ve(t):new qe(t,e,n,null==r?1:r)}function qe(t,e,n,r){this.r=+t,this.g=+e,this.b=+n,this.opacity=+r}function Xe(){return"#"+Je(this.r)+Je(this.g)+Je(this.b)}function Ze(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"rgb(":"rgba(")+Math.max(0,Math.min(255,Math.round(this.r)||0))+", "+Math.max(0,Math.min(255,Math.round(this.g)||0))+", "+Math.max(0,Math.min(255,Math.round(this.b)||0))+(1===t?")":", "+t+")")}function Je(t){return((t=Math.max(0,Math.min(255,Math.round(t)||0)))<16?"0":"")+t.toString(16)}function Ke(t,e,n,r){return r<=0?t=e=n=NaN:n<=0||n>=1?t=e=NaN:e<=0&&(t=NaN),new en(t,e,n,r)}function Qe(t){if(t instanceof en)return new en(t.h,t.s,t.l,t.opacity);if(t instanceof Me||(t=$e(t)),!t)return new en;if(t instanceof en)return t;var e=(t=t.rgb()).r/255,n=t.g/255,r=t.b/255,i=Math.min(e,n,r),a=Math.max(e,n,r),o=NaN,s=a-i,c=(a+i)/2;return s?(o=e===a?(n-r)/s+6*(n0&&c<1?0:o,new en(o,s,c,t.opacity)}function tn(t,e,n,r){return 1===arguments.length?Qe(t):new en(t,e,n,null==r?1:r)}function en(t,e,n,r){this.h=+t,this.s=+e,this.l=+n,this.opacity=+r}function nn(t,e,n){return 255*(t<60?e+(n-e)*t/60:t<180?n:t<240?e+(n-e)*(240-t)/60:e)}function rn(t,e,n,r,i){var a=t*t,o=a*t;return((1-3*t+3*a-o)*e+(4-6*a+3*o)*n+(1+3*t+3*a-3*o)*r+o*i)/6}Ae(Me,$e,{copy:function(t){return Object.assign(new this.constructor,this,t)},displayable:function(){return this.rgb().displayable()},hex:ze,formatHex:ze,formatHsl:function(){return Qe(this).formatHsl()},formatRgb:Ue,toString:Ue}),Ae(qe,Ge,Se(Me,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new qe(this.r*t,this.g*t,this.b*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new qe(this.r*t,this.g*t,this.b*t,this.opacity)},rgb:function(){return this},displayable:function(){return-.5<=this.r&&this.r<255.5&&-.5<=this.g&&this.g<255.5&&-.5<=this.b&&this.b<255.5&&0<=this.opacity&&this.opacity<=1},hex:Xe,formatHex:Xe,formatRgb:Ze,toString:Ze})),Ae(en,tn,Se(Me,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new en(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new en(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=this.h%360+360*(this.h<0),e=isNaN(t)||isNaN(this.s)?0:this.s,n=this.l,r=n+(n<.5?n:1-n)*e,i=2*n-r;return new qe(nn(t>=240?t-240:t+120,i,r),nn(t,i,r),nn(t<120?t+240:t-120,i,r),this.opacity)},displayable:function(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1},formatHsl:function(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"hsl(":"hsla(")+(this.h||0)+", "+100*(this.s||0)+"%, "+100*(this.l||0)+"%"+(1===t?")":", "+t+")")}}));var an=function(t){var e=t.length-1;return function(n){var r=n<=0?n=0:n>=1?(n=1,e-1):Math.floor(n*e),i=t[r],a=t[r+1],o=r>0?t[r-1]:2*i-a,s=r180||n<-180?n-360*Math.round(n/360):n):sn(isNaN(t)?e:t)}function ln(t){return 1==(t=+t)?hn:function(e,n){return n-e?function(t,e,n){return t=Math.pow(t,n),e=Math.pow(e,n)-t,n=1/n,function(r){return Math.pow(t+r*e,n)}}(e,n,t):sn(isNaN(e)?n:e)}}function hn(t,e){var n=e-t;return n?cn(t,n):sn(isNaN(t)?e:t)}var fn=function t(e){var n=ln(e);function r(t,e){var r=n((t=Ge(t)).r,(e=Ge(e)).r),i=n(t.g,e.g),a=n(t.b,e.b),o=hn(t.opacity,e.opacity);return function(e){return t.r=r(e),t.g=i(e),t.b=a(e),t.opacity=o(e),t+""}}return r.gamma=t,r}(1);function dn(t){return function(e){var n,r,i=e.length,a=new Array(i),o=new Array(i),s=new Array(i);for(n=0;na&&(i=e.slice(a,i),s[o]?s[o]+=i:s[++o]=i),(n=n[0])===(r=r[0])?s[o]?s[o]+=r:s[++o]=r:(s[++o]=null,c.push({i:o,x:_n(n,r)})),a=En.lastIndex;return a=0&&e._call.call(null,t),e=e._next;--Bn}function Vn(){In=(Pn=Rn.now())+jn,Bn=Ln=0;try{Hn()}finally{Bn=0,function(){var t,e,n=Tn,r=1/0;for(;n;)n._call?(r>n._time&&(r=n._time),t=n,n=n._next):(e=n._next,n._next=null,n=t?t._next=e:Tn=e);Cn=t,qn(r)}(),In=0}}function Gn(){var t=Rn.now(),e=t-Pn;e>1e3&&(jn-=e,Pn=t)}function qn(t){Bn||(Ln&&(Ln=clearTimeout(Ln)),t-In>24?(t<1/0&&(Ln=setTimeout(Vn,t-Rn.now()-jn)),Fn&&(Fn=clearInterval(Fn))):(Fn||(Pn=Rn.now(),Fn=setInterval(Gn,1e3)),Bn=1,Yn(Vn)))}$n.prototype=Wn.prototype={constructor:$n,restart:function(t,e,n){if("function"!=typeof t)throw new TypeError("callback is not a function");n=(null==n?zn():+n)+(null==e?0:+e),this._next||Cn===this||(Cn?Cn._next=this:Tn=this,Cn=this),this._call=t,this._time=n,qn()},stop:function(){this._call&&(this._call=null,this._time=1/0,qn())}};var Xn=function(t,e,n){var r=new $n;return e=null==e?0:+e,r.restart((function(n){r.stop(),t(n+e)}),e,n),r},Zn=lt("start","end","cancel","interrupt"),Jn=[],Kn=function(t,e,n,r,i,a){var o=t.__transition;if(o){if(n in o)return}else t.__transition={};!function(t,e,n){var r,i=t.__transition;function a(c){var u,l,h,f;if(1!==n.state)return s();for(u in i)if((f=i[u]).name===n.name){if(3===f.state)return Xn(a);4===f.state?(f.state=6,f.timer.stop(),f.on.call("interrupt",t,t.__data__,f.index,f.group),delete i[u]):+u0)throw new Error("too late; already scheduled");return n}function tr(t,e){var n=er(t,e);if(n.state>3)throw new Error("too late; already running");return n}function er(t,e){var n=t.__transition;if(!n||!(n=n[e]))throw new Error("transition not found");return n}var nr,rr,ir,ar,or=function(t,e){var n,r,i,a=t.__transition,o=!0;if(a){for(i in e=null==e?null:e+"",a)(n=a[i]).name===e?(r=n.state>2&&n.state<5,n.state=6,n.timer.stop(),n.on.call(r?"interrupt":"cancel",t,t.__data__,n.index,n.group),delete a[i]):o=!1;o&&delete t.__transition}},sr=180/Math.PI,cr={translateX:0,translateY:0,rotate:0,skewX:0,scaleX:1,scaleY:1},ur=function(t,e,n,r,i,a){var o,s,c;return(o=Math.sqrt(t*t+e*e))&&(t/=o,e/=o),(c=t*n+e*r)&&(n-=t*c,r-=e*c),(s=Math.sqrt(n*n+r*r))&&(n/=s,r/=s,c/=s),t*r180?e+=360:e-t>180&&(t+=360),a.push({i:n.push(i(n)+"rotate(",null,r)-2,x:_n(t,e)})):e&&n.push(i(n)+"rotate("+e+r)}(a.rotate,o.rotate,s,c),function(t,e,n,a){t!==e?a.push({i:n.push(i(n)+"skewX(",null,r)-2,x:_n(t,e)}):e&&n.push(i(n)+"skewX("+e+r)}(a.skewX,o.skewX,s,c),function(t,e,n,r,a,o){if(t!==n||e!==r){var s=a.push(i(a)+"scale(",null,",",null,")");o.push({i:s-4,x:_n(t,n)},{i:s-2,x:_n(e,r)})}else 1===n&&1===r||a.push(i(a)+"scale("+n+","+r+")")}(a.scaleX,a.scaleY,o.scaleX,o.scaleY,s,c),a=o=null,function(t){for(var e,n=-1,r=c.length;++n=0&&(t=t.slice(0,e)),!t||"start"===t}))}(e)?Qn:tr;return function(){var o=a(this,t),s=o.on;s!==r&&(i=(r=s).copy()).on(e,n),o.on=i}}var Br=_e.prototype.constructor;function Lr(t){return function(){this.style.removeProperty(t)}}function Fr(t,e,n){return function(r){this.style.setProperty(t,e.call(this,r),n)}}function Pr(t,e,n){var r,i;function a(){var a=e.apply(this,arguments);return a!==i&&(r=(i=a)&&Fr(t,a,n)),r}return a._value=e,a}function Ir(t){return function(e){this.textContent=t.call(this,e)}}function jr(t){var e,n;function r(){var r=t.apply(this,arguments);return r!==n&&(e=(n=r)&&Ir(r)),e}return r._value=t,r}var Rr=0;function Yr(t,e,n,r){this._groups=t,this._parents=e,this._name=n,this._id=r}function zr(t){return _e().transition(t)}function Ur(){return++Rr}var $r=_e.prototype;function Wr(t){return t*t*t}function Hr(t){return--t*t*t+1}function Vr(t){return((t*=2)<=1?t*t*t:(t-=2)*t*t+2)/2}Yr.prototype=zr.prototype={constructor:Yr,select:function(t){var e=this._name,n=this._id;"function"!=typeof t&&(t=ft(t));for(var r=this._groups,i=r.length,a=new Array(i),o=0;o1&&n.name===e)return new Yr([[t]],Xr,e,+r);return null},Jr=function(t){return function(){return t}},Kr=function(t,e,n){this.target=t,this.type=e,this.selection=n};function Qr(){ce.stopImmediatePropagation()}var ti=function(){ce.preventDefault(),ce.stopImmediatePropagation()},ei={name:"drag"},ni={name:"space"},ri={name:"handle"},ii={name:"center"};function ai(t){return[+t[0],+t[1]]}function oi(t){return[ai(t[0]),ai(t[1])]}function si(t){return function(e){return Dn(e,ce.touches,t)}}var ci={name:"x",handles:["w","e"].map(yi),input:function(t,e){return null==t?null:[[+t[0],e[0][1]],[+t[1],e[1][1]]]},output:function(t){return t&&[t[0][0],t[1][0]]}},ui={name:"y",handles:["n","s"].map(yi),input:function(t,e){return null==t?null:[[e[0][0],+t[0]],[e[1][0],+t[1]]]},output:function(t){return t&&[t[0][1],t[1][1]]}},li={name:"xy",handles:["n","w","e","s","nw","ne","sw","se"].map(yi),input:function(t){return null==t?null:oi(t)},output:function(t){return t}},hi={overlay:"crosshair",selection:"move",n:"ns-resize",e:"ew-resize",s:"ns-resize",w:"ew-resize",nw:"nwse-resize",ne:"nesw-resize",se:"nwse-resize",sw:"nesw-resize"},fi={e:"w",w:"e",nw:"ne",ne:"nw",se:"sw",sw:"se"},di={n:"s",s:"n",nw:"sw",ne:"se",se:"ne",sw:"nw"},pi={overlay:1,selection:1,n:null,e:1,s:null,w:-1,nw:-1,ne:1,se:1,sw:-1},gi={overlay:1,selection:1,n:-1,e:null,s:1,w:null,nw:-1,ne:-1,se:1,sw:1};function yi(t){return{type:t}}function vi(){return!ce.ctrlKey&&!ce.button}function mi(){var t=this.ownerSVGElement||this;return t.hasAttribute("viewBox")?[[(t=t.viewBox.baseVal).x,t.y],[t.x+t.width,t.y+t.height]]:[[0,0],[t.width.baseVal.value,t.height.baseVal.value]]}function bi(){return navigator.maxTouchPoints||"ontouchstart"in this}function xi(t){for(;!t.__brush;)if(!(t=t.parentNode))return;return t.__brush}function _i(t){return t[0][0]===t[1][0]||t[0][1]===t[1][1]}function ki(t){var e=t.__brush;return e?e.dim.output(e.selection):null}function wi(){return Ci(ci)}function Ei(){return Ci(ui)}var Ti=function(){return Ci(li)};function Ci(t){var e,n=mi,r=vi,i=bi,a=!0,o=lt("start","brush","end"),s=6;function c(e){var n=e.property("__brush",g).selectAll(".overlay").data([yi("overlay")]);n.enter().append("rect").attr("class","overlay").attr("pointer-events","all").attr("cursor",hi.overlay).merge(n).each((function(){var t=xi(this).extent;ke(this).attr("x",t[0][0]).attr("y",t[0][1]).attr("width",t[1][0]-t[0][0]).attr("height",t[1][1]-t[0][1])})),e.selectAll(".selection").data([yi("selection")]).enter().append("rect").attr("class","selection").attr("cursor",hi.selection).attr("fill","#777").attr("fill-opacity",.3).attr("stroke","#fff").attr("shape-rendering","crispEdges");var r=e.selectAll(".handle").data(t.handles,(function(t){return t.type}));r.exit().remove(),r.enter().append("rect").attr("class",(function(t){return"handle handle--"+t.type})).attr("cursor",(function(t){return hi[t.type]})),e.each(u).attr("fill","none").attr("pointer-events","all").on("mousedown.brush",f).filter(i).on("touchstart.brush",f).on("touchmove.brush",d).on("touchend.brush touchcancel.brush",p).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function u(){var t=ke(this),e=xi(this).selection;e?(t.selectAll(".selection").style("display",null).attr("x",e[0][0]).attr("y",e[0][1]).attr("width",e[1][0]-e[0][0]).attr("height",e[1][1]-e[0][1]),t.selectAll(".handle").style("display",null).attr("x",(function(t){return"e"===t.type[t.type.length-1]?e[1][0]-s/2:e[0][0]-s/2})).attr("y",(function(t){return"s"===t.type[0]?e[1][1]-s/2:e[0][1]-s/2})).attr("width",(function(t){return"n"===t.type||"s"===t.type?e[1][0]-e[0][0]+s:s})).attr("height",(function(t){return"e"===t.type||"w"===t.type?e[1][1]-e[0][1]+s:s}))):t.selectAll(".selection,.handle").style("display","none").attr("x",null).attr("y",null).attr("width",null).attr("height",null)}function l(t,e,n){return!n&&t.__brush.emitter||new h(t,e)}function h(t,e){this.that=t,this.args=e,this.state=t.__brush,this.active=0}function f(){if((!e||ce.touches)&&r.apply(this,arguments)){var n,i,o,s,c,h,f,d,p,g,y,v=this,m=ce.target.__data__.type,b="selection"===(a&&ce.metaKey?m="overlay":m)?ei:a&&ce.altKey?ii:ri,x=t===ui?null:pi[m],_=t===ci?null:gi[m],k=xi(v),w=k.extent,E=k.selection,T=w[0][0],C=w[0][1],A=w[1][0],S=w[1][1],M=0,O=0,D=x&&_&&a&&ce.shiftKey,N=ce.touches?si(ce.changedTouches[0].identifier):Nn,B=N(v),L=B,F=l(v,arguments,!0).beforestart();"overlay"===m?(E&&(p=!0),k.selection=E=[[n=t===ui?T:B[0],o=t===ci?C:B[1]],[c=t===ui?A:n,f=t===ci?S:o]]):(n=E[0][0],o=E[0][1],c=E[1][0],f=E[1][1]),i=n,s=o,h=c,d=f;var P=ke(v).attr("pointer-events","none"),I=P.selectAll(".overlay").attr("cursor",hi[m]);if(ce.touches)F.moved=R,F.ended=z;else{var j=ke(ce.view).on("mousemove.brush",R,!0).on("mouseup.brush",z,!0);a&&j.on("keydown.brush",U,!0).on("keyup.brush",$,!0),Te(ce.view)}Qr(),or(v),u.call(v),F.start()}function R(){var t=N(v);!D||g||y||(Math.abs(t[0]-L[0])>Math.abs(t[1]-L[1])?y=!0:g=!0),L=t,p=!0,ti(),Y()}function Y(){var t;switch(M=L[0]-B[0],O=L[1]-B[1],b){case ni:case ei:x&&(M=Math.max(T-n,Math.min(A-c,M)),i=n+M,h=c+M),_&&(O=Math.max(C-o,Math.min(S-f,O)),s=o+O,d=f+O);break;case ri:x<0?(M=Math.max(T-n,Math.min(A-n,M)),i=n+M,h=c):x>0&&(M=Math.max(T-c,Math.min(A-c,M)),i=n,h=c+M),_<0?(O=Math.max(C-o,Math.min(S-o,O)),s=o+O,d=f):_>0&&(O=Math.max(C-f,Math.min(S-f,O)),s=o,d=f+O);break;case ii:x&&(i=Math.max(T,Math.min(A,n-M*x)),h=Math.max(T,Math.min(A,c+M*x))),_&&(s=Math.max(C,Math.min(S,o-O*_)),d=Math.max(C,Math.min(S,f+O*_)))}h0&&(n=i-M),_<0?f=d-O:_>0&&(o=s-O),b=ni,I.attr("cursor",hi.selection),Y());break;default:return}ti()}function $(){switch(ce.keyCode){case 16:D&&(g=y=D=!1,Y());break;case 18:b===ii&&(x<0?c=h:x>0&&(n=i),_<0?f=d:_>0&&(o=s),b=ri,Y());break;case 32:b===ni&&(ce.altKey?(x&&(c=h-M*x,n=i+M*x),_&&(f=d-O*_,o=s+O*_),b=ii):(x<0?c=h:x>0&&(n=i),_<0?f=d:_>0&&(o=s),b=ri),I.attr("cursor",hi[m]),Y());break;default:return}ti()}}function d(){l(this,arguments).moved()}function p(){l(this,arguments).ended()}function g(){var e=this.__brush||{selection:null};return e.extent=oi(n.apply(this,arguments)),e.dim=t,e}return c.move=function(e,n){e.selection?e.on("start.brush",(function(){l(this,arguments).beforestart().start()})).on("interrupt.brush end.brush",(function(){l(this,arguments).end()})).tween("brush",(function(){var e=this,r=e.__brush,i=l(e,arguments),a=r.selection,o=t.input("function"==typeof n?n.apply(this,arguments):n,r.extent),s=Sn(a,o);function c(t){r.selection=1===t&&null===o?null:s(t),u.call(e),i.brush()}return null!==a&&null!==o?c:c(1)})):e.each((function(){var e=this,r=arguments,i=e.__brush,a=t.input("function"==typeof n?n.apply(e,r):n,i.extent),o=l(e,r).beforestart();or(e),i.selection=null===a?null:a,u.call(e),o.start().brush().end()}))},c.clear=function(t){c.move(t,null)},h.prototype={beforestart:function(){return 1==++this.active&&(this.state.emitter=this,this.starting=!0),this},start:function(){return this.starting?(this.starting=!1,this.emit("start")):this.emit("brush"),this},brush:function(){return this.emit("brush"),this},end:function(){return 0==--this.active&&(delete this.state.emitter,this.emit("end")),this},emit:function(e){pe(new Kr(c,e,t.output(this.state.selection)),o.apply,o,[e,this.that,this.args])}},c.extent=function(t){return arguments.length?(n="function"==typeof t?t:Jr(oi(t)),c):n},c.filter=function(t){return arguments.length?(r="function"==typeof t?t:Jr(!!t),c):r},c.touchable=function(t){return arguments.length?(i="function"==typeof t?t:Jr(!!t),c):i},c.handleSize=function(t){return arguments.length?(s=+t,c):s},c.keyModifiers=function(t){return arguments.length?(a=!!t,c):a},c.on=function(){var t=o.on.apply(o,arguments);return t===o?c:t},c}var Ai=Math.cos,Si=Math.sin,Mi=Math.PI,Oi=Mi/2,Di=2*Mi,Ni=Math.max;function Bi(t){return function(e,n){return t(e.source.value+e.target.value,n.source.value+n.target.value)}}var Li=function(){var t=0,e=null,n=null,r=null;function i(i){var a,o,s,c,u,l,h=i.length,f=[],d=k(h),p=[],g=[],y=g.groups=new Array(h),v=new Array(h*h);for(a=0,u=-1;++u1e-6)if(Math.abs(l*s-c*u)>1e-6&&i){var f=n-a,d=r-o,p=s*s+c*c,g=f*f+d*d,y=Math.sqrt(p),v=Math.sqrt(h),m=i*Math.tan((Ii-Math.acos((p+h-g)/(2*y*v)))/2),b=m/v,x=m/y;Math.abs(b-1)>1e-6&&(this._+="L"+(t+b*u)+","+(e+b*l)),this._+="A"+i+","+i+",0,0,"+ +(l*f>u*d)+","+(this._x1=t+x*s)+","+(this._y1=e+x*c)}else this._+="L"+(this._x1=t)+","+(this._y1=e);else;},arc:function(t,e,n,r,i,a){t=+t,e=+e,a=!!a;var o=(n=+n)*Math.cos(r),s=n*Math.sin(r),c=t+o,u=e+s,l=1^a,h=a?r-i:i-r;if(n<0)throw new Error("negative radius: "+n);null===this._x1?this._+="M"+c+","+u:(Math.abs(this._x1-c)>1e-6||Math.abs(this._y1-u)>1e-6)&&(this._+="L"+c+","+u),n&&(h<0&&(h=h%ji+ji),h>Ri?this._+="A"+n+","+n+",0,1,"+l+","+(t-o)+","+(e-s)+"A"+n+","+n+",0,1,"+l+","+(this._x1=c)+","+(this._y1=u):h>1e-6&&(this._+="A"+n+","+n+",0,"+ +(h>=Ii)+","+l+","+(this._x1=t+n*Math.cos(i))+","+(this._y1=e+n*Math.sin(i))))},rect:function(t,e,n,r){this._+="M"+(this._x0=this._x1=+t)+","+(this._y0=this._y1=+e)+"h"+ +n+"v"+ +r+"h"+-n+"Z"},toString:function(){return this._}};var Ui=zi;function $i(t){return t.source}function Wi(t){return t.target}function Hi(t){return t.radius}function Vi(t){return t.startAngle}function Gi(t){return t.endAngle}var qi=function(){var t=$i,e=Wi,n=Hi,r=Vi,i=Gi,a=null;function o(){var o,s=Fi.call(arguments),c=t.apply(this,s),u=e.apply(this,s),l=+n.apply(this,(s[0]=c,s)),h=r.apply(this,s)-Oi,f=i.apply(this,s)-Oi,d=l*Ai(h),p=l*Si(h),g=+n.apply(this,(s[0]=u,s)),y=r.apply(this,s)-Oi,v=i.apply(this,s)-Oi;if(a||(a=o=Ui()),a.moveTo(d,p),a.arc(0,0,l,h,f),h===y&&f===v||(a.quadraticCurveTo(0,0,g*Ai(y),g*Si(y)),a.arc(0,0,g,y,v)),a.quadraticCurveTo(0,0,d,p),a.closePath(),o)return a=null,o+""||null}return o.radius=function(t){return arguments.length?(n="function"==typeof t?t:Pi(+t),o):n},o.startAngle=function(t){return arguments.length?(r="function"==typeof t?t:Pi(+t),o):r},o.endAngle=function(t){return arguments.length?(i="function"==typeof t?t:Pi(+t),o):i},o.source=function(e){return arguments.length?(t=e,o):t},o.target=function(t){return arguments.length?(e=t,o):e},o.context=function(t){return arguments.length?(a=null==t?null:t,o):a},o};function Xi(){}function Zi(t,e){var n=new Xi;if(t instanceof Xi)t.each((function(t,e){n.set(e,t)}));else if(Array.isArray(t)){var r,i=-1,a=t.length;if(null==e)for(;++i=r.length)return null!=t&&n.sort(t),null!=e?e(n):n;for(var c,u,l,h=-1,f=n.length,d=r[i++],p=Ji(),g=o();++hr.length)return n;var o,s=i[a-1];return null!=e&&a>=r.length?o=n.entries():(o=[],n.each((function(e,n){o.push({key:n,values:t(e,a)})}))),null!=s?o.sort((function(t,e){return s(t.key,e.key)})):o}(a(t,0,ea,na),0)},key:function(t){return r.push(t),n},sortKeys:function(t){return i[r.length-1]=t,n},sortValues:function(e){return t=e,n},rollup:function(t){return e=t,n}}};function Qi(){return{}}function ta(t,e,n){t[e]=n}function ea(){return Ji()}function na(t,e,n){t.set(e,n)}function ra(){}var ia=Ji.prototype;function aa(t,e){var n=new ra;if(t instanceof ra)t.each((function(t){n.add(t)}));else if(t){var r=-1,i=t.length;if(null==e)for(;++r6/29*(6/29)*(6/29)?Math.pow(t,1/3):t/(6/29*3*(6/29))+4/29}function va(t){return t>6/29?t*t*t:6/29*3*(6/29)*(t-4/29)}function ma(t){return 255*(t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055)}function ba(t){return(t/=255)<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4)}function xa(t){if(t instanceof wa)return new wa(t.h,t.c,t.l,t.opacity);if(t instanceof ga||(t=fa(t)),0===t.a&&0===t.b)return new wa(NaN,0r!=d>r&&n<(f-u)*(r-l)/(d-l)+u&&(i=-i)}return i}function Ia(t,e,n){var r,i,a,o;return function(t,e,n){return(e[0]-t[0])*(n[1]-t[1])==(n[0]-t[0])*(e[1]-t[1])}(t,e,n)&&(i=t[r=+(t[0]===e[0])],a=n[r],o=e[r],i<=a&&a<=o||o<=a&&a<=i)}var ja=function(){},Ra=[[],[[[1,1.5],[.5,1]]],[[[1.5,1],[1,1.5]]],[[[1.5,1],[.5,1]]],[[[1,.5],[1.5,1]]],[[[1,1.5],[.5,1]],[[1,.5],[1.5,1]]],[[[1,.5],[1,1.5]]],[[[1,.5],[.5,1]]],[[[.5,1],[1,.5]]],[[[1,1.5],[1,.5]]],[[[.5,1],[1,.5]],[[1.5,1],[1,1.5]]],[[[1.5,1],[1,.5]]],[[[.5,1],[1.5,1]]],[[[1,1.5],[1.5,1]]],[[[.5,1],[1,1.5]]],[]],Ya=function(){var t=1,e=1,n=M,r=s;function i(t){var e=n(t);if(Array.isArray(e))e=e.slice().sort(Ba);else{var r=y(t),i=r[0],o=r[1];e=S(i,o,e),e=k(Math.floor(i/e)*e,Math.floor(o/e)*e,e)}return e.map((function(e){return a(t,e)}))}function a(n,i){var a=[],s=[];return function(n,r,i){var a,s,c,u,l,h,f=new Array,d=new Array;a=s=-1,u=n[0]>=r,Ra[u<<1].forEach(p);for(;++a=r,Ra[c|u<<1].forEach(p);Ra[u<<0].forEach(p);for(;++s=r,l=n[s*t]>=r,Ra[u<<1|l<<2].forEach(p);++a=r,h=l,l=n[s*t+a+1]>=r,Ra[c|u<<1|l<<2|h<<3].forEach(p);Ra[u|l<<3].forEach(p)}a=-1,l=n[s*t]>=r,Ra[l<<2].forEach(p);for(;++a=r,Ra[l<<2|h<<3].forEach(p);function p(t){var e,n,r=[t[0][0]+a,t[0][1]+s],c=[t[1][0]+a,t[1][1]+s],u=o(r),l=o(c);(e=d[u])?(n=f[l])?(delete d[e.end],delete f[n.start],e===n?(e.ring.push(c),i(e.ring)):f[e.start]=d[n.end]={start:e.start,end:n.end,ring:e.ring.concat(n.ring)}):(delete d[e.end],e.ring.push(c),d[e.end=l]=e):(e=f[l])?(n=d[u])?(delete f[e.start],delete d[n.end],e===n?(e.ring.push(c),i(e.ring)):f[n.start]=d[e.end]={start:n.start,end:e.end,ring:n.ring.concat(e.ring)}):(delete f[e.start],e.ring.unshift(r),f[e.start=u]=e):f[u]=d[l]={start:u,end:l,ring:[r,c]}}Ra[l<<3].forEach(p)}(n,i,(function(t){r(t,n,i),function(t){for(var e=0,n=t.length,r=t[n-1][1]*t[0][0]-t[n-1][0]*t[0][1];++e0?a.push([t]):s.push(t)})),s.forEach((function(t){for(var e,n=0,r=a.length;n0&&o0&&s0&&a>0))throw new Error("invalid size");return t=r,e=a,i},i.thresholds=function(t){return arguments.length?(n="function"==typeof t?t:Array.isArray(t)?La(Na.call(t)):La(t),i):n},i.smooth=function(t){return arguments.length?(r=t?s:ja,i):r===s},i};function za(t,e,n){for(var r=t.width,i=t.height,a=1+(n<<1),o=0;o=n&&(s>=a&&(c-=t.data[s-a+o*r]),e.data[s-n+o*r]=c/Math.min(s+1,r-1+a-s,a))}function Ua(t,e,n){for(var r=t.width,i=t.height,a=1+(n<<1),o=0;o=n&&(s>=a&&(c-=t.data[o+(s-a)*r]),e.data[o+(s-n)*r]=c/Math.min(s+1,i-1+a-s,a))}function $a(t){return t[0]}function Wa(t){return t[1]}function Ha(){return 1}var Va=function(){var t=$a,e=Wa,n=Ha,r=960,i=500,a=20,o=2,s=3*a,c=r+2*s>>o,u=i+2*s>>o,l=La(20);function h(r){var i=new Float32Array(c*u),h=new Float32Array(c*u);r.forEach((function(r,a,l){var h=+t(r,a,l)+s>>o,f=+e(r,a,l)+s>>o,d=+n(r,a,l);h>=0&&h=0&&f>o),Ua({width:c,height:u,data:h},{width:c,height:u,data:i},a>>o),za({width:c,height:u,data:i},{width:c,height:u,data:h},a>>o),Ua({width:c,height:u,data:h},{width:c,height:u,data:i},a>>o),za({width:c,height:u,data:i},{width:c,height:u,data:h},a>>o),Ua({width:c,height:u,data:h},{width:c,height:u,data:i},a>>o);var d=l(i);if(!Array.isArray(d)){var p=L(i);d=S(0,p,d),(d=k(0,Math.floor(p/d)*d,d)).shift()}return Ya().thresholds(d).size([c,u])(i).map(f)}function f(t){return t.value*=Math.pow(2,-2*o),t.coordinates.forEach(d),t}function d(t){t.forEach(p)}function p(t){t.forEach(g)}function g(t){t[0]=t[0]*Math.pow(2,o)-s,t[1]=t[1]*Math.pow(2,o)-s}function y(){return c=r+2*(s=3*a)>>o,u=i+2*s>>o,h}return h.x=function(e){return arguments.length?(t="function"==typeof e?e:La(+e),h):t},h.y=function(t){return arguments.length?(e="function"==typeof t?t:La(+t),h):e},h.weight=function(t){return arguments.length?(n="function"==typeof t?t:La(+t),h):n},h.size=function(t){if(!arguments.length)return[r,i];var e=Math.ceil(t[0]),n=Math.ceil(t[1]);if(!(e>=0||e>=0))throw new Error("invalid size");return r=e,i=n,y()},h.cellSize=function(t){if(!arguments.length)return 1<=1))throw new Error("invalid cell size");return o=Math.floor(Math.log(t)/Math.LN2),y()},h.thresholds=function(t){return arguments.length?(l="function"==typeof t?t:Array.isArray(t)?La(Na.call(t)):La(t),h):l},h.bandwidth=function(t){if(!arguments.length)return Math.sqrt(a*(a+1));if(!((t=+t)>=0))throw new Error("invalid bandwidth");return a=Math.round((Math.sqrt(4*t*t+1)-1)/2),y()},h},Ga=function(t){return function(){return t}};function qa(t,e,n,r,i,a,o,s,c,u){this.target=t,this.type=e,this.subject=n,this.identifier=r,this.active=i,this.x=a,this.y=o,this.dx=s,this.dy=c,this._=u}function Xa(){return!ce.ctrlKey&&!ce.button}function Za(){return this.parentNode}function Ja(t){return null==t?{x:ce.x,y:ce.y}:t}function Ka(){return navigator.maxTouchPoints||"ontouchstart"in this}qa.prototype.on=function(){var t=this._.on.apply(this._,arguments);return t===this._?this:t};var Qa=function(){var t,e,n,r,i=Xa,a=Za,o=Ja,s=Ka,c={},u=lt("start","drag","end"),l=0,h=0;function f(t){t.on("mousedown.drag",d).filter(s).on("touchstart.drag",y).on("touchmove.drag",v).on("touchend.drag touchcancel.drag",m).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function d(){if(!r&&i.apply(this,arguments)){var o=b("mouse",a.apply(this,arguments),Nn,this,arguments);o&&(ke(ce.view).on("mousemove.drag",p,!0).on("mouseup.drag",g,!0),Te(ce.view),we(),n=!1,t=ce.clientX,e=ce.clientY,o("start"))}}function p(){if(Ee(),!n){var r=ce.clientX-t,i=ce.clientY-e;n=r*r+i*i>h}c.mouse("drag")}function g(){ke(ce.view).on("mousemove.drag mouseup.drag",null),Ce(ce.view,n),Ee(),c.mouse("end")}function y(){if(i.apply(this,arguments)){var t,e,n=ce.changedTouches,r=a.apply(this,arguments),o=n.length;for(t=0;t9999?"+"+io(e,6):io(e,4))+"-"+io(t.getUTCMonth()+1,2)+"-"+io(t.getUTCDate(),2)+(a?"T"+io(n,2)+":"+io(r,2)+":"+io(i,2)+"."+io(a,3)+"Z":i?"T"+io(n,2)+":"+io(r,2)+":"+io(i,2)+"Z":r||n?"T"+io(n,2)+":"+io(r,2)+"Z":"")}var oo=function(t){var e=new RegExp('["'+t+"\n\r]"),n=t.charCodeAt(0);function r(t,e){var r,i=[],a=t.length,o=0,s=0,c=a<=0,u=!1;function l(){if(c)return eo;if(u)return u=!1,to;var e,r,i=o;if(34===t.charCodeAt(i)){for(;o++=a?c=!0:10===(r=t.charCodeAt(o++))?u=!0:13===r&&(u=!0,10===t.charCodeAt(o)&&++o),t.slice(i+1,e-1).replace(/""/g,'"')}for(;o=(a=(g+v)/2))?g=a:v=a,(l=n>=(o=(y+m)/2))?y=o:m=o,i=d,!(d=d[h=l<<1|u]))return i[h]=p,t;if(s=+t._x.call(null,d.data),c=+t._y.call(null,d.data),e===s&&n===c)return p.next=d,i?i[h]=p:t._root=p,t;do{i=i?i[h]=new Array(4):t._root=new Array(4),(u=e>=(a=(g+v)/2))?g=a:v=a,(l=n>=(o=(y+m)/2))?y=o:m=o}while((h=l<<1|u)==(f=(c>=o)<<1|s>=a));return i[f]=d,i[h]=p,t}var _s=function(t,e,n,r,i){this.node=t,this.x0=e,this.y0=n,this.x1=r,this.y1=i};function ks(t){return t[0]}function ws(t){return t[1]}function Es(t,e,n){var r=new Ts(null==e?ks:e,null==n?ws:n,NaN,NaN,NaN,NaN);return null==t?r:r.addAll(t)}function Ts(t,e,n,r,i,a){this._x=t,this._y=e,this._x0=n,this._y0=r,this._x1=i,this._y1=a,this._root=void 0}function Cs(t){for(var e={data:t.data},n=e;t=t.next;)n=n.next={data:t.data};return e}var As=Es.prototype=Ts.prototype;function Ss(t){return t.x+t.vx}function Ms(t){return t.y+t.vy}As.copy=function(){var t,e,n=new Ts(this._x,this._y,this._x0,this._y0,this._x1,this._y1),r=this._root;if(!r)return n;if(!r.length)return n._root=Cs(r),n;for(t=[{source:r,target:n._root=new Array(4)}];r=t.pop();)for(var i=0;i<4;++i)(e=r.source[i])&&(e.length?t.push({source:e,target:r.target[i]=new Array(4)}):r.target[i]=Cs(e));return n},As.add=function(t){var e=+this._x.call(null,t),n=+this._y.call(null,t);return xs(this.cover(e,n),e,n,t)},As.addAll=function(t){var e,n,r,i,a=t.length,o=new Array(a),s=new Array(a),c=1/0,u=1/0,l=-1/0,h=-1/0;for(n=0;nl&&(l=r),ih&&(h=i));if(c>l||u>h)return this;for(this.cover(c,u).cover(l,h),n=0;nt||t>=i||r>e||e>=a;)switch(s=(ef||(a=c.y0)>d||(o=c.x1)=v)<<1|t>=y)&&(c=p[p.length-1],p[p.length-1]=p[p.length-1-u],p[p.length-1-u]=c)}else{var m=t-+this._x.call(null,g.data),b=e-+this._y.call(null,g.data),x=m*m+b*b;if(x=(s=(p+y)/2))?p=s:y=s,(l=o>=(c=(g+v)/2))?g=c:v=c,e=d,!(d=d[h=l<<1|u]))return this;if(!d.length)break;(e[h+1&3]||e[h+2&3]||e[h+3&3])&&(n=e,f=h)}for(;d.data!==t;)if(r=d,!(d=d.next))return this;return(i=d.next)&&delete d.next,r?(i?r.next=i:delete r.next,this):e?(i?e[h]=i:delete e[h],(d=e[0]||e[1]||e[2]||e[3])&&d===(e[3]||e[2]||e[1]||e[0])&&!d.length&&(n?n[f]=d:this._root=d),this):(this._root=i,this)},As.removeAll=function(t){for(var e=0,n=t.length;ec+d||iu+d||as.index){var p=c-o.x-o.vx,g=u-o.y-o.vy,y=p*p+g*g;yt.r&&(t.r=t[e].r)}function s(){if(e){var r,i,a=e.length;for(n=new Array(a),r=0;r1?(null==n?s.remove(t):s.set(t,d(n)),e):s.get(t)},find:function(e,n,r){var i,a,o,s,c,u=0,l=t.length;for(null==r?r=1/0:r*=r,u=0;u1?(u.on(t,n),e):u.on(t)}}},js=function(){var t,e,n,r,i=ms(-30),a=1,o=1/0,s=.81;function c(r){var i,a=t.length,o=Es(t,Ls,Fs).visitAfter(l);for(n=r,i=0;i=o)){(t.data!==e||t.next)&&(0===l&&(d+=(l=bs())*l),0===h&&(d+=(h=bs())*h),d1?r[0]+r.slice(2):r,+t.slice(n+1)]},$s=function(t){return(t=Us(Math.abs(t)))?t[1]:NaN},Ws=/^(?:(.)?([<>=^]))?([+\-( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?(~)?([a-z%])?$/i;function Hs(t){if(!(e=Ws.exec(t)))throw new Error("invalid format: "+t);var e;return new Vs({fill:e[1],align:e[2],sign:e[3],symbol:e[4],zero:e[5],width:e[6],comma:e[7],precision:e[8]&&e[8].slice(1),trim:e[9],type:e[10]})}function Vs(t){this.fill=void 0===t.fill?" ":t.fill+"",this.align=void 0===t.align?">":t.align+"",this.sign=void 0===t.sign?"-":t.sign+"",this.symbol=void 0===t.symbol?"":t.symbol+"",this.zero=!!t.zero,this.width=void 0===t.width?void 0:+t.width,this.comma=!!t.comma,this.precision=void 0===t.precision?void 0:+t.precision,this.trim=!!t.trim,this.type=void 0===t.type?"":t.type+""}Hs.prototype=Vs.prototype,Vs.prototype.toString=function(){return this.fill+this.align+this.sign+this.symbol+(this.zero?"0":"")+(void 0===this.width?"":Math.max(1,0|this.width))+(this.comma?",":"")+(void 0===this.precision?"":"."+Math.max(0,0|this.precision))+(this.trim?"~":"")+this.type};var Gs,qs,Xs,Zs,Js=function(t,e){var n=Us(t,e);if(!n)return t+"";var r=n[0],i=n[1];return i<0?"0."+new Array(-i).join("0")+r:r.length>i+1?r.slice(0,i+1)+"."+r.slice(i+1):r+new Array(i-r.length+2).join("0")},Ks={"%":function(t,e){return(100*t).toFixed(e)},b:function(t){return Math.round(t).toString(2)},c:function(t){return t+""},d:function(t){return Math.round(t).toString(10)},e:function(t,e){return t.toExponential(e)},f:function(t,e){return t.toFixed(e)},g:function(t,e){return t.toPrecision(e)},o:function(t){return Math.round(t).toString(8)},p:function(t,e){return Js(100*t,e)},r:Js,s:function(t,e){var n=Us(t,e);if(!n)return t+"";var r=n[0],i=n[1],a=i-(Gs=3*Math.max(-8,Math.min(8,Math.floor(i/3))))+1,o=r.length;return a===o?r:a>o?r+new Array(a-o+1).join("0"):a>0?r.slice(0,a)+"."+r.slice(a):"0."+new Array(1-a).join("0")+Us(t,Math.max(0,e+a-1))[0]},X:function(t){return Math.round(t).toString(16).toUpperCase()},x:function(t){return Math.round(t).toString(16)}},Qs=function(t){return t},tc=Array.prototype.map,ec=["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"],nc=function(t){var e,n,r=void 0===t.grouping||void 0===t.thousands?Qs:(e=tc.call(t.grouping,Number),n=t.thousands+"",function(t,r){for(var i=t.length,a=[],o=0,s=e[0],c=0;i>0&&s>0&&(c+s+1>r&&(s=Math.max(1,r-c)),a.push(t.substring(i-=s,i+s)),!((c+=s+1)>r));)s=e[o=(o+1)%e.length];return a.reverse().join(n)}),i=void 0===t.currency?"":t.currency[0]+"",a=void 0===t.currency?"":t.currency[1]+"",o=void 0===t.decimal?".":t.decimal+"",s=void 0===t.numerals?Qs:function(t){return function(e){return e.replace(/[0-9]/g,(function(e){return t[+e]}))}}(tc.call(t.numerals,String)),c=void 0===t.percent?"%":t.percent+"",u=void 0===t.minus?"-":t.minus+"",l=void 0===t.nan?"NaN":t.nan+"";function h(t){var e=(t=Hs(t)).fill,n=t.align,h=t.sign,f=t.symbol,d=t.zero,p=t.width,g=t.comma,y=t.precision,v=t.trim,m=t.type;"n"===m?(g=!0,m="g"):Ks[m]||(void 0===y&&(y=12),v=!0,m="g"),(d||"0"===e&&"="===n)&&(d=!0,e="0",n="=");var b="$"===f?i:"#"===f&&/[boxX]/.test(m)?"0"+m.toLowerCase():"",x="$"===f?a:/[%p]/.test(m)?c:"",_=Ks[m],k=/[defgprs%]/.test(m);function w(t){var i,a,c,f=b,w=x;if("c"===m)w=_(t)+w,t="";else{var E=(t=+t)<0;if(t=isNaN(t)?l:_(Math.abs(t),y),v&&(t=function(t){t:for(var e,n=t.length,r=1,i=-1;r0&&(i=0)}return i>0?t.slice(0,i)+t.slice(e+1):t}(t)),E&&0==+t&&(E=!1),f=(E?"("===h?h:u:"-"===h||"("===h?"":h)+f,w=("s"===m?ec[8+Gs/3]:"")+w+(E&&"("===h?")":""),k)for(i=-1,a=t.length;++i(c=t.charCodeAt(i))||c>57){w=(46===c?o+t.slice(i+1):t.slice(i))+w,t=t.slice(0,i);break}}g&&!d&&(t=r(t,1/0));var T=f.length+t.length+w.length,C=T>1)+f+t+w+C.slice(T);break;default:t=C+f+t+w}return s(t)}return y=void 0===y?6:/[gprs]/.test(m)?Math.max(1,Math.min(21,y)):Math.max(0,Math.min(20,y)),w.toString=function(){return t+""},w}return{format:h,formatPrefix:function(t,e){var n=h(((t=Hs(t)).type="f",t)),r=3*Math.max(-8,Math.min(8,Math.floor($s(e)/3))),i=Math.pow(10,-r),a=ec[8+r/3];return function(t){return n(i*t)+a}}}};function rc(t){return qs=nc(t),Xs=qs.format,Zs=qs.formatPrefix,qs}rc({decimal:".",thousands:",",grouping:[3],currency:["$",""],minus:"-"});var ic=function(t){return Math.max(0,-$s(Math.abs(t)))},ac=function(t,e){return Math.max(0,3*Math.max(-8,Math.min(8,Math.floor($s(e)/3)))-$s(Math.abs(t)))},oc=function(t,e){return t=Math.abs(t),e=Math.abs(e)-t,Math.max(0,$s(e)-$s(t))+1},sc=function(){return new cc};function cc(){this.reset()}cc.prototype={constructor:cc,reset:function(){this.s=this.t=0},add:function(t){lc(uc,t,this.t),lc(this,uc.s,this.s),this.s?this.t+=uc.t:this.s=uc.t},valueOf:function(){return this.s}};var uc=new cc;function lc(t,e,n){var r=t.s=e+n,i=r-e,a=r-i;t.t=e-a+(n-i)}var hc=Math.PI,fc=hc/2,dc=hc/4,pc=2*hc,gc=180/hc,yc=hc/180,vc=Math.abs,mc=Math.atan,bc=Math.atan2,xc=Math.cos,_c=Math.ceil,kc=Math.exp,wc=(Math.floor,Math.log),Ec=Math.pow,Tc=Math.sin,Cc=Math.sign||function(t){return t>0?1:t<0?-1:0},Ac=Math.sqrt,Sc=Math.tan;function Mc(t){return t>1?0:t<-1?hc:Math.acos(t)}function Oc(t){return t>1?fc:t<-1?-fc:Math.asin(t)}function Dc(t){return(t=Tc(t/2))*t}function Nc(){}function Bc(t,e){t&&Fc.hasOwnProperty(t.type)&&Fc[t.type](t,e)}var Lc={Feature:function(t,e){Bc(t.geometry,e)},FeatureCollection:function(t,e){for(var n=t.features,r=-1,i=n.length;++r=0?1:-1,i=r*n,a=xc(e=(e*=yc)/2+dc),o=Tc(e),s=Uc*o,c=zc*a+s*xc(i),u=s*r*Tc(i);Wc.add(bc(u,c)),Yc=t,zc=a,Uc=o}var Jc=function(t){return Hc.reset(),$c(t,Vc),2*Hc};function Kc(t){return[bc(t[1],t[0]),Oc(t[2])]}function Qc(t){var e=t[0],n=t[1],r=xc(n);return[r*xc(e),r*Tc(e),Tc(n)]}function tu(t,e){return t[0]*e[0]+t[1]*e[1]+t[2]*e[2]}function eu(t,e){return[t[1]*e[2]-t[2]*e[1],t[2]*e[0]-t[0]*e[2],t[0]*e[1]-t[1]*e[0]]}function nu(t,e){t[0]+=e[0],t[1]+=e[1],t[2]+=e[2]}function ru(t,e){return[t[0]*e,t[1]*e,t[2]*e]}function iu(t){var e=Ac(t[0]*t[0]+t[1]*t[1]+t[2]*t[2]);t[0]/=e,t[1]/=e,t[2]/=e}var au,ou,su,cu,uu,lu,hu,fu,du,pu,gu=sc(),yu={point:vu,lineStart:bu,lineEnd:xu,polygonStart:function(){yu.point=_u,yu.lineStart=ku,yu.lineEnd=wu,gu.reset(),Vc.polygonStart()},polygonEnd:function(){Vc.polygonEnd(),yu.point=vu,yu.lineStart=bu,yu.lineEnd=xu,Wc<0?(au=-(su=180),ou=-(cu=90)):gu>1e-6?cu=90:gu<-1e-6&&(ou=-90),pu[0]=au,pu[1]=su},sphere:function(){au=-(su=180),ou=-(cu=90)}};function vu(t,e){du.push(pu=[au=t,su=t]),ecu&&(cu=e)}function mu(t,e){var n=Qc([t*yc,e*yc]);if(fu){var r=eu(fu,n),i=eu([r[1],-r[0],0],r);iu(i),i=Kc(i);var a,o=t-uu,s=o>0?1:-1,c=i[0]*gc*s,u=vc(o)>180;u^(s*uucu&&(cu=a):u^(s*uu<(c=(c+360)%360-180)&&ccu&&(cu=e)),u?tEu(au,su)&&(su=t):Eu(t,su)>Eu(au,su)&&(au=t):su>=au?(tsu&&(su=t)):t>uu?Eu(au,t)>Eu(au,su)&&(su=t):Eu(t,su)>Eu(au,su)&&(au=t)}else du.push(pu=[au=t,su=t]);ecu&&(cu=e),fu=n,uu=t}function bu(){yu.point=mu}function xu(){pu[0]=au,pu[1]=su,yu.point=vu,fu=null}function _u(t,e){if(fu){var n=t-uu;gu.add(vc(n)>180?n+(n>0?360:-360):n)}else lu=t,hu=e;Vc.point(t,e),mu(t,e)}function ku(){Vc.lineStart()}function wu(){_u(lu,hu),Vc.lineEnd(),vc(gu)>1e-6&&(au=-(su=180)),pu[0]=au,pu[1]=su,fu=null}function Eu(t,e){return(e-=t)<0?e+360:e}function Tu(t,e){return t[0]-e[0]}function Cu(t,e){return t[0]<=t[1]?t[0]<=e&&e<=t[1]:eEu(r[0],r[1])&&(r[1]=i[1]),Eu(i[0],r[1])>Eu(r[0],r[1])&&(r[0]=i[0])):a.push(r=i);for(o=-1/0,e=0,r=a[n=a.length-1];e<=n;r=i,++e)i=a[e],(s=Eu(r[1],i[0]))>o&&(o=s,au=i[0],su=r[1])}return du=pu=null,au===1/0||ou===1/0?[[NaN,NaN],[NaN,NaN]]:[[au,ou],[su,cu]]},Wu={sphere:Nc,point:Hu,lineStart:Gu,lineEnd:Zu,polygonStart:function(){Wu.lineStart=Ju,Wu.lineEnd=Ku},polygonEnd:function(){Wu.lineStart=Gu,Wu.lineEnd=Zu}};function Hu(t,e){t*=yc;var n=xc(e*=yc);Vu(n*xc(t),n*Tc(t),Tc(e))}function Vu(t,e,n){++Au,Mu+=(t-Mu)/Au,Ou+=(e-Ou)/Au,Du+=(n-Du)/Au}function Gu(){Wu.point=qu}function qu(t,e){t*=yc;var n=xc(e*=yc);Yu=n*xc(t),zu=n*Tc(t),Uu=Tc(e),Wu.point=Xu,Vu(Yu,zu,Uu)}function Xu(t,e){t*=yc;var n=xc(e*=yc),r=n*xc(t),i=n*Tc(t),a=Tc(e),o=bc(Ac((o=zu*a-Uu*i)*o+(o=Uu*r-Yu*a)*o+(o=Yu*i-zu*r)*o),Yu*r+zu*i+Uu*a);Su+=o,Nu+=o*(Yu+(Yu=r)),Bu+=o*(zu+(zu=i)),Lu+=o*(Uu+(Uu=a)),Vu(Yu,zu,Uu)}function Zu(){Wu.point=Hu}function Ju(){Wu.point=Qu}function Ku(){tl(ju,Ru),Wu.point=Hu}function Qu(t,e){ju=t,Ru=e,t*=yc,e*=yc,Wu.point=tl;var n=xc(e);Yu=n*xc(t),zu=n*Tc(t),Uu=Tc(e),Vu(Yu,zu,Uu)}function tl(t,e){t*=yc;var n=xc(e*=yc),r=n*xc(t),i=n*Tc(t),a=Tc(e),o=zu*a-Uu*i,s=Uu*r-Yu*a,c=Yu*i-zu*r,u=Ac(o*o+s*s+c*c),l=Oc(u),h=u&&-l/u;Fu+=h*o,Pu+=h*s,Iu+=h*c,Su+=l,Nu+=l*(Yu+(Yu=r)),Bu+=l*(zu+(zu=i)),Lu+=l*(Uu+(Uu=a)),Vu(Yu,zu,Uu)}var el=function(t){Au=Su=Mu=Ou=Du=Nu=Bu=Lu=Fu=Pu=Iu=0,$c(t,Wu);var e=Fu,n=Pu,r=Iu,i=e*e+n*n+r*r;return i<1e-12&&(e=Nu,n=Bu,r=Lu,Su<1e-6&&(e=Mu,n=Ou,r=Du),(i=e*e+n*n+r*r)<1e-12)?[NaN,NaN]:[bc(n,e)*gc,Oc(r/Ac(i))*gc]},nl=function(t){return function(){return t}},rl=function(t,e){function n(n,r){return n=t(n,r),e(n[0],n[1])}return t.invert&&e.invert&&(n.invert=function(n,r){return(n=e.invert(n,r))&&t.invert(n[0],n[1])}),n};function il(t,e){return[vc(t)>hc?t+Math.round(-t/pc)*pc:t,e]}function al(t,e,n){return(t%=pc)?e||n?rl(sl(t),cl(e,n)):sl(t):e||n?cl(e,n):il}function ol(t){return function(e,n){return[(e+=t)>hc?e-pc:e<-hc?e+pc:e,n]}}function sl(t){var e=ol(t);return e.invert=ol(-t),e}function cl(t,e){var n=xc(t),r=Tc(t),i=xc(e),a=Tc(e);function o(t,e){var o=xc(e),s=xc(t)*o,c=Tc(t)*o,u=Tc(e),l=u*n+s*r;return[bc(c*i-l*a,s*n-u*r),Oc(l*i+c*a)]}return o.invert=function(t,e){var o=xc(e),s=xc(t)*o,c=Tc(t)*o,u=Tc(e),l=u*i-c*a;return[bc(c*i+u*a,s*n+l*r),Oc(l*n-s*r)]},o}il.invert=il;var ul=function(t){function e(e){return(e=t(e[0]*yc,e[1]*yc))[0]*=gc,e[1]*=gc,e}return t=al(t[0]*yc,t[1]*yc,t.length>2?t[2]*yc:0),e.invert=function(e){return(e=t.invert(e[0]*yc,e[1]*yc))[0]*=gc,e[1]*=gc,e},e};function ll(t,e,n,r,i,a){if(n){var o=xc(e),s=Tc(e),c=r*n;null==i?(i=e+r*pc,a=e-c/2):(i=hl(o,i),a=hl(o,a),(r>0?ia)&&(i+=r*pc));for(var u,l=i;r>0?l>a:l1&&e.push(e.pop().concat(e.shift()))},result:function(){var n=e;return e=[],t=null,n}}},pl=function(t,e){return vc(t[0]-e[0])<1e-6&&vc(t[1]-e[1])<1e-6};function gl(t,e,n,r){this.x=t,this.z=e,this.o=n,this.e=r,this.v=!1,this.n=this.p=null}var yl=function(t,e,n,r,i){var a,o,s=[],c=[];if(t.forEach((function(t){if(!((e=t.length-1)<=0)){var e,n,r=t[0],o=t[e];if(pl(r,o)){for(i.lineStart(),a=0;a=0;--a)i.point((l=u[a])[0],l[1]);else r(f.x,f.p.x,-1,i);f=f.p}u=(f=f.o).z,d=!d}while(!f.v);i.lineEnd()}}};function vl(t){if(e=t.length){for(var e,n,r=0,i=t[0];++r=0?1:-1,T=E*w,C=T>hc,A=g*_;if(ml.add(bc(A*E*Tc(T),y*k+A*xc(T))),o+=C?w+E*pc:w,C^d>=n^b>=n){var S=eu(Qc(f),Qc(m));iu(S);var M=eu(a,S);iu(M);var O=(C^w>=0?-1:1)*Oc(M[2]);(r>O||r===O&&(S[0]||S[1]))&&(s+=C^w>=0?1:-1)}}return(o<-1e-6||o<1e-6&&ml<-1e-6)^1&s},_l=function(t,e,n,r){return function(i){var a,o,s,c=e(i),u=dl(),l=e(u),h=!1,f={point:d,lineStart:g,lineEnd:y,polygonStart:function(){f.point=v,f.lineStart=m,f.lineEnd=b,o=[],a=[]},polygonEnd:function(){f.point=d,f.lineStart=g,f.lineEnd=y,o=I(o);var t=xl(a,r);o.length?(h||(i.polygonStart(),h=!0),yl(o,wl,t,n,i)):t&&(h||(i.polygonStart(),h=!0),i.lineStart(),n(null,null,1,i),i.lineEnd()),h&&(i.polygonEnd(),h=!1),o=a=null},sphere:function(){i.polygonStart(),i.lineStart(),n(null,null,1,i),i.lineEnd(),i.polygonEnd()}};function d(e,n){t(e,n)&&i.point(e,n)}function p(t,e){c.point(t,e)}function g(){f.point=p,c.lineStart()}function y(){f.point=d,c.lineEnd()}function v(t,e){s.push([t,e]),l.point(t,e)}function m(){l.lineStart(),s=[]}function b(){v(s[0][0],s[0][1]),l.lineEnd();var t,e,n,r,c=l.clean(),f=u.result(),d=f.length;if(s.pop(),a.push(s),s=null,d)if(1&c){if((e=(n=f[0]).length-1)>0){for(h||(i.polygonStart(),h=!0),i.lineStart(),t=0;t1&&2&c&&f.push(f.pop().concat(f.shift())),o.push(f.filter(kl))}return f}};function kl(t){return t.length>1}function wl(t,e){return((t=t.x)[0]<0?t[1]-fc-1e-6:fc-t[1])-((e=e.x)[0]<0?e[1]-fc-1e-6:fc-e[1])}var El=_l((function(){return!0}),(function(t){var e,n=NaN,r=NaN,i=NaN;return{lineStart:function(){t.lineStart(),e=1},point:function(a,o){var s=a>0?hc:-hc,c=vc(a-n);vc(c-hc)<1e-6?(t.point(n,r=(r+o)/2>0?fc:-fc),t.point(i,r),t.lineEnd(),t.lineStart(),t.point(s,r),t.point(a,r),e=0):i!==s&&c>=hc&&(vc(n-i)<1e-6&&(n-=1e-6*i),vc(a-s)<1e-6&&(a-=1e-6*s),r=function(t,e,n,r){var i,a,o=Tc(t-n);return vc(o)>1e-6?mc((Tc(e)*(a=xc(r))*Tc(n)-Tc(r)*(i=xc(e))*Tc(t))/(i*a*o)):(e+r)/2}(n,r,a,o),t.point(i,r),t.lineEnd(),t.lineStart(),t.point(s,r),e=0),t.point(n=a,r=o),i=s},lineEnd:function(){t.lineEnd(),n=r=NaN},clean:function(){return 2-e}}}),(function(t,e,n,r){var i;if(null==t)i=n*fc,r.point(-hc,i),r.point(0,i),r.point(hc,i),r.point(hc,0),r.point(hc,-i),r.point(0,-i),r.point(-hc,-i),r.point(-hc,0),r.point(-hc,i);else if(vc(t[0]-e[0])>1e-6){var a=t[0]0,i=vc(e)>1e-6;function a(t,n){return xc(t)*xc(n)>e}function o(t,n,r){var i=[1,0,0],a=eu(Qc(t),Qc(n)),o=tu(a,a),s=a[0],c=o-s*s;if(!c)return!r&&t;var u=e*o/c,l=-e*s/c,h=eu(i,a),f=ru(i,u);nu(f,ru(a,l));var d=h,p=tu(f,d),g=tu(d,d),y=p*p-g*(tu(f,f)-1);if(!(y<0)){var v=Ac(y),m=ru(d,(-p-v)/g);if(nu(m,f),m=Kc(m),!r)return m;var b,x=t[0],_=n[0],k=t[1],w=n[1];_0^m[1]<(vc(m[0]-x)<1e-6?k:w):k<=m[1]&&m[1]<=w:E>hc^(x<=m[0]&&m[0]<=_)){var C=ru(d,(-p+v)/g);return nu(C,f),[m,Kc(C)]}}}function s(e,n){var i=r?t:hc-t,a=0;return e<-i?a|=1:e>i&&(a|=2),n<-i?a|=4:n>i&&(a|=8),a}return _l(a,(function(t){var e,n,c,u,l;return{lineStart:function(){u=c=!1,l=1},point:function(h,f){var d,p=[h,f],g=a(h,f),y=r?g?0:s(h,f):g?s(h+(h<0?hc:-hc),f):0;if(!e&&(u=c=g)&&t.lineStart(),g!==c&&(!(d=o(e,p))||pl(e,d)||pl(p,d))&&(p[0]+=1e-6,p[1]+=1e-6,g=a(p[0],p[1])),g!==c)l=0,g?(t.lineStart(),d=o(p,e),t.point(d[0],d[1])):(d=o(e,p),t.point(d[0],d[1]),t.lineEnd()),e=d;else if(i&&e&&r^g){var v;y&n||!(v=o(p,e,!0))||(l=0,r?(t.lineStart(),t.point(v[0][0],v[0][1]),t.point(v[1][0],v[1][1]),t.lineEnd()):(t.point(v[1][0],v[1][1]),t.lineEnd(),t.lineStart(),t.point(v[0][0],v[0][1])))}!g||e&&pl(e,p)||t.point(p[0],p[1]),e=p,c=g,n=y},lineEnd:function(){c&&t.lineEnd(),e=null},clean:function(){return l|(u&&c)<<1}}}),(function(e,r,i,a){ll(a,t,n,i,e,r)}),r?[0,-t]:[-hc,t-hc])};function Cl(t,e,n,r){function i(i,a){return t<=i&&i<=n&&e<=a&&a<=r}function a(i,a,s,u){var l=0,h=0;if(null==i||(l=o(i,s))!==(h=o(a,s))||c(i,a)<0^s>0)do{u.point(0===l||3===l?t:n,l>1?r:e)}while((l=(l+s+4)%4)!==h);else u.point(a[0],a[1])}function o(r,i){return vc(r[0]-t)<1e-6?i>0?0:3:vc(r[0]-n)<1e-6?i>0?2:1:vc(r[1]-e)<1e-6?i>0?1:0:i>0?3:2}function s(t,e){return c(t.x,e.x)}function c(t,e){var n=o(t,1),r=o(e,1);return n!==r?n-r:0===n?e[1]-t[1]:1===n?t[0]-e[0]:2===n?t[1]-e[1]:e[0]-t[0]}return function(o){var c,u,l,h,f,d,p,g,y,v,m,b=o,x=dl(),_={point:k,lineStart:function(){_.point=w,u&&u.push(l=[]);v=!0,y=!1,p=g=NaN},lineEnd:function(){c&&(w(h,f),d&&y&&x.rejoin(),c.push(x.result()));_.point=k,y&&b.lineEnd()},polygonStart:function(){b=x,c=[],u=[],m=!0},polygonEnd:function(){var e=function(){for(var e=0,n=0,i=u.length;nr&&(f-a)*(r-o)>(d-o)*(t-a)&&++e:d<=r&&(f-a)*(r-o)<(d-o)*(t-a)&&--e;return e}(),n=m&&e,i=(c=I(c)).length;(n||i)&&(o.polygonStart(),n&&(o.lineStart(),a(null,null,1,o),o.lineEnd()),i&&yl(c,s,e,a,o),o.polygonEnd());b=o,c=u=l=null}};function k(t,e){i(t,e)&&b.point(t,e)}function w(a,o){var s=i(a,o);if(u&&l.push([a,o]),v)h=a,f=o,d=s,v=!1,s&&(b.lineStart(),b.point(a,o));else if(s&&y)b.point(a,o);else{var c=[p=Math.max(-1e9,Math.min(1e9,p)),g=Math.max(-1e9,Math.min(1e9,g))],x=[a=Math.max(-1e9,Math.min(1e9,a)),o=Math.max(-1e9,Math.min(1e9,o))];!function(t,e,n,r,i,a){var o,s=t[0],c=t[1],u=0,l=1,h=e[0]-s,f=e[1]-c;if(o=n-s,h||!(o>0)){if(o/=h,h<0){if(o0){if(o>l)return;o>u&&(u=o)}if(o=i-s,h||!(o<0)){if(o/=h,h<0){if(o>l)return;o>u&&(u=o)}else if(h>0){if(o0)){if(o/=f,f<0){if(o0){if(o>l)return;o>u&&(u=o)}if(o=a-c,f||!(o<0)){if(o/=f,f<0){if(o>l)return;o>u&&(u=o)}else if(f>0){if(o0&&(t[0]=s+u*h,t[1]=c+u*f),l<1&&(e[0]=s+l*h,e[1]=c+l*f),!0}}}}}(c,x,t,e,n,r)?s&&(b.lineStart(),b.point(a,o),m=!1):(y||(b.lineStart(),b.point(c[0],c[1])),b.point(x[0],x[1]),s||b.lineEnd(),m=!1)}p=a,g=o,y=s}return _}}var Al,Sl,Ml,Ol=function(){var t,e,n,r=0,i=0,a=960,o=500;return n={stream:function(n){return t&&e===n?t:t=Cl(r,i,a,o)(e=n)},extent:function(s){return arguments.length?(r=+s[0][0],i=+s[0][1],a=+s[1][0],o=+s[1][1],t=e=null,n):[[r,i],[a,o]]}}},Dl=sc(),Nl={sphere:Nc,point:Nc,lineStart:function(){Nl.point=Ll,Nl.lineEnd=Bl},lineEnd:Nc,polygonStart:Nc,polygonEnd:Nc};function Bl(){Nl.point=Nl.lineEnd=Nc}function Ll(t,e){Al=t*=yc,Sl=Tc(e*=yc),Ml=xc(e),Nl.point=Fl}function Fl(t,e){t*=yc;var n=Tc(e*=yc),r=xc(e),i=vc(t-Al),a=xc(i),o=r*Tc(i),s=Ml*n-Sl*r*a,c=Sl*n+Ml*r*a;Dl.add(bc(Ac(o*o+s*s),c)),Al=t,Sl=n,Ml=r}var Pl=function(t){return Dl.reset(),$c(t,Nl),+Dl},Il=[null,null],jl={type:"LineString",coordinates:Il},Rl=function(t,e){return Il[0]=t,Il[1]=e,Pl(jl)},Yl={Feature:function(t,e){return Ul(t.geometry,e)},FeatureCollection:function(t,e){for(var n=t.features,r=-1,i=n.length;++r0&&(i=Rl(t[a],t[a-1]))>0&&n<=i&&r<=i&&(n+r-i)*(1-Math.pow((n-r)/i,2))<1e-12*i)return!0;n=r}return!1}function Hl(t,e){return!!xl(t.map(Vl),Gl(e))}function Vl(t){return(t=t.map(Gl)).pop(),t}function Gl(t){return[t[0]*yc,t[1]*yc]}var ql=function(t,e){return(t&&Yl.hasOwnProperty(t.type)?Yl[t.type]:Ul)(t,e)};function Xl(t,e,n){var r=k(t,e-1e-6,n).concat(e);return function(t){return r.map((function(e){return[t,e]}))}}function Zl(t,e,n){var r=k(t,e-1e-6,n).concat(e);return function(t){return r.map((function(e){return[e,t]}))}}function Jl(){var t,e,n,r,i,a,o,s,c,u,l,h,f=10,d=f,p=90,g=360,y=2.5;function v(){return{type:"MultiLineString",coordinates:m()}}function m(){return k(_c(r/p)*p,n,p).map(l).concat(k(_c(s/g)*g,o,g).map(h)).concat(k(_c(e/f)*f,t,f).filter((function(t){return vc(t%p)>1e-6})).map(c)).concat(k(_c(a/d)*d,i,d).filter((function(t){return vc(t%g)>1e-6})).map(u))}return v.lines=function(){return m().map((function(t){return{type:"LineString",coordinates:t}}))},v.outline=function(){return{type:"Polygon",coordinates:[l(r).concat(h(o).slice(1),l(n).reverse().slice(1),h(s).reverse().slice(1))]}},v.extent=function(t){return arguments.length?v.extentMajor(t).extentMinor(t):v.extentMinor()},v.extentMajor=function(t){return arguments.length?(r=+t[0][0],n=+t[1][0],s=+t[0][1],o=+t[1][1],r>n&&(t=r,r=n,n=t),s>o&&(t=s,s=o,o=t),v.precision(y)):[[r,s],[n,o]]},v.extentMinor=function(n){return arguments.length?(e=+n[0][0],t=+n[1][0],a=+n[0][1],i=+n[1][1],e>t&&(n=e,e=t,t=n),a>i&&(n=a,a=i,i=n),v.precision(y)):[[e,a],[t,i]]},v.step=function(t){return arguments.length?v.stepMajor(t).stepMinor(t):v.stepMinor()},v.stepMajor=function(t){return arguments.length?(p=+t[0],g=+t[1],v):[p,g]},v.stepMinor=function(t){return arguments.length?(f=+t[0],d=+t[1],v):[f,d]},v.precision=function(f){return arguments.length?(y=+f,c=Xl(a,i,90),u=Zl(e,t,y),l=Xl(s,o,90),h=Zl(r,n,y),v):y},v.extentMajor([[-180,1e-6-90],[180,90-1e-6]]).extentMinor([[-180,-80-1e-6],[180,80+1e-6]])}function Kl(){return Jl()()}var Ql,th,eh,nh,rh=function(t,e){var n=t[0]*yc,r=t[1]*yc,i=e[0]*yc,a=e[1]*yc,o=xc(r),s=Tc(r),c=xc(a),u=Tc(a),l=o*xc(n),h=o*Tc(n),f=c*xc(i),d=c*Tc(i),p=2*Oc(Ac(Dc(a-r)+o*c*Dc(i-n))),g=Tc(p),y=p?function(t){var e=Tc(t*=p)/g,n=Tc(p-t)/g,r=n*l+e*f,i=n*h+e*d,a=n*s+e*u;return[bc(i,r)*gc,bc(a,Ac(r*r+i*i))*gc]}:function(){return[n*gc,r*gc]};return y.distance=p,y},ih=function(t){return t},ah=sc(),oh=sc(),sh={point:Nc,lineStart:Nc,lineEnd:Nc,polygonStart:function(){sh.lineStart=ch,sh.lineEnd=hh},polygonEnd:function(){sh.lineStart=sh.lineEnd=sh.point=Nc,ah.add(vc(oh)),oh.reset()},result:function(){var t=ah/2;return ah.reset(),t}};function ch(){sh.point=uh}function uh(t,e){sh.point=lh,Ql=eh=t,th=nh=e}function lh(t,e){oh.add(nh*t-eh*e),eh=t,nh=e}function hh(){lh(Ql,th)}var fh=sh,dh=1/0,ph=dh,gh=-dh,yh=gh;var vh,mh,bh,xh,_h={point:function(t,e){tgh&&(gh=t);eyh&&(yh=e)},lineStart:Nc,lineEnd:Nc,polygonStart:Nc,polygonEnd:Nc,result:function(){var t=[[dh,ph],[gh,yh]];return gh=yh=-(ph=dh=1/0),t}},kh=0,wh=0,Eh=0,Th=0,Ch=0,Ah=0,Sh=0,Mh=0,Oh=0,Dh={point:Nh,lineStart:Bh,lineEnd:Ph,polygonStart:function(){Dh.lineStart=Ih,Dh.lineEnd=jh},polygonEnd:function(){Dh.point=Nh,Dh.lineStart=Bh,Dh.lineEnd=Ph},result:function(){var t=Oh?[Sh/Oh,Mh/Oh]:Ah?[Th/Ah,Ch/Ah]:Eh?[kh/Eh,wh/Eh]:[NaN,NaN];return kh=wh=Eh=Th=Ch=Ah=Sh=Mh=Oh=0,t}};function Nh(t,e){kh+=t,wh+=e,++Eh}function Bh(){Dh.point=Lh}function Lh(t,e){Dh.point=Fh,Nh(bh=t,xh=e)}function Fh(t,e){var n=t-bh,r=e-xh,i=Ac(n*n+r*r);Th+=i*(bh+t)/2,Ch+=i*(xh+e)/2,Ah+=i,Nh(bh=t,xh=e)}function Ph(){Dh.point=Nh}function Ih(){Dh.point=Rh}function jh(){Yh(vh,mh)}function Rh(t,e){Dh.point=Yh,Nh(vh=bh=t,mh=xh=e)}function Yh(t,e){var n=t-bh,r=e-xh,i=Ac(n*n+r*r);Th+=i*(bh+t)/2,Ch+=i*(xh+e)/2,Ah+=i,Sh+=(i=xh*t-bh*e)*(bh+t),Mh+=i*(xh+e),Oh+=3*i,Nh(bh=t,xh=e)}var zh=Dh;function Uh(t){this._context=t}Uh.prototype={_radius:4.5,pointRadius:function(t){return this._radius=t,this},polygonStart:function(){this._line=0},polygonEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){0===this._line&&this._context.closePath(),this._point=NaN},point:function(t,e){switch(this._point){case 0:this._context.moveTo(t,e),this._point=1;break;case 1:this._context.lineTo(t,e);break;default:this._context.moveTo(t+this._radius,e),this._context.arc(t,e,this._radius,0,pc)}},result:Nc};var $h,Wh,Hh,Vh,Gh,qh=sc(),Xh={point:Nc,lineStart:function(){Xh.point=Zh},lineEnd:function(){$h&&Jh(Wh,Hh),Xh.point=Nc},polygonStart:function(){$h=!0},polygonEnd:function(){$h=null},result:function(){var t=+qh;return qh.reset(),t}};function Zh(t,e){Xh.point=Jh,Wh=Vh=t,Hh=Gh=e}function Jh(t,e){Vh-=t,Gh-=e,qh.add(Ac(Vh*Vh+Gh*Gh)),Vh=t,Gh=e}var Kh=Xh;function Qh(){this._string=[]}function tf(t){return"m0,"+t+"a"+t+","+t+" 0 1,1 0,"+-2*t+"a"+t+","+t+" 0 1,1 0,"+2*t+"z"}Qh.prototype={_radius:4.5,_circle:tf(4.5),pointRadius:function(t){return(t=+t)!==this._radius&&(this._radius=t,this._circle=null),this},polygonStart:function(){this._line=0},polygonEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){0===this._line&&this._string.push("Z"),this._point=NaN},point:function(t,e){switch(this._point){case 0:this._string.push("M",t,",",e),this._point=1;break;case 1:this._string.push("L",t,",",e);break;default:null==this._circle&&(this._circle=tf(this._radius)),this._string.push("M",t,",",e,this._circle)}},result:function(){if(this._string.length){var t=this._string.join("");return this._string=[],t}return null}};var ef=function(t,e){var n,r,i=4.5;function a(t){return t&&("function"==typeof i&&r.pointRadius(+i.apply(this,arguments)),$c(t,n(r))),r.result()}return a.area=function(t){return $c(t,n(fh)),fh.result()},a.measure=function(t){return $c(t,n(Kh)),Kh.result()},a.bounds=function(t){return $c(t,n(_h)),_h.result()},a.centroid=function(t){return $c(t,n(zh)),zh.result()},a.projection=function(e){return arguments.length?(n=null==e?(t=null,ih):(t=e).stream,a):t},a.context=function(t){return arguments.length?(r=null==t?(e=null,new Qh):new Uh(e=t),"function"!=typeof i&&r.pointRadius(i),a):e},a.pointRadius=function(t){return arguments.length?(i="function"==typeof t?t:(r.pointRadius(+t),+t),a):i},a.projection(t).context(e)},nf=function(t){return{stream:rf(t)}};function rf(t){return function(e){var n=new af;for(var r in t)n[r]=t[r];return n.stream=e,n}}function af(){}function of(t,e,n){var r=t.clipExtent&&t.clipExtent();return t.scale(150).translate([0,0]),null!=r&&t.clipExtent(null),$c(n,t.stream(_h)),e(_h.result()),null!=r&&t.clipExtent(r),t}function sf(t,e,n){return of(t,(function(n){var r=e[1][0]-e[0][0],i=e[1][1]-e[0][1],a=Math.min(r/(n[1][0]-n[0][0]),i/(n[1][1]-n[0][1])),o=+e[0][0]+(r-a*(n[1][0]+n[0][0]))/2,s=+e[0][1]+(i-a*(n[1][1]+n[0][1]))/2;t.scale(150*a).translate([o,s])}),n)}function cf(t,e,n){return sf(t,[[0,0],e],n)}function uf(t,e,n){return of(t,(function(n){var r=+e,i=r/(n[1][0]-n[0][0]),a=(r-i*(n[1][0]+n[0][0]))/2,o=-i*n[0][1];t.scale(150*i).translate([a,o])}),n)}function lf(t,e,n){return of(t,(function(n){var r=+e,i=r/(n[1][1]-n[0][1]),a=-i*n[0][0],o=(r-i*(n[1][1]+n[0][1]))/2;t.scale(150*i).translate([a,o])}),n)}af.prototype={constructor:af,point:function(t,e){this.stream.point(t,e)},sphere:function(){this.stream.sphere()},lineStart:function(){this.stream.lineStart()},lineEnd:function(){this.stream.lineEnd()},polygonStart:function(){this.stream.polygonStart()},polygonEnd:function(){this.stream.polygonEnd()}};var hf=xc(30*yc),ff=function(t,e){return+e?function(t,e){function n(r,i,a,o,s,c,u,l,h,f,d,p,g,y){var v=u-r,m=l-i,b=v*v+m*m;if(b>4*e&&g--){var x=o+f,_=s+d,k=c+p,w=Ac(x*x+_*_+k*k),E=Oc(k/=w),T=vc(vc(k)-1)<1e-6||vc(a-h)<1e-6?(a+h)/2:bc(_,x),C=t(T,E),A=C[0],S=C[1],M=A-r,O=S-i,D=m*M-v*O;(D*D/b>e||vc((v*M+m*O)/b-.5)>.3||o*f+s*d+c*p2?t[2]%360*yc:0,A()):[y*gc,v*gc,m*gc]},T.angle=function(t){return arguments.length?(b=t%360*yc,A()):b*gc},T.precision=function(t){return arguments.length?(o=ff(s,E=t*t),S()):Ac(E)},T.fitExtent=function(t,e){return sf(T,t,e)},T.fitSize=function(t,e){return cf(T,t,e)},T.fitWidth=function(t,e){return uf(T,t,e)},T.fitHeight=function(t,e){return lf(T,t,e)},function(){return e=t.apply(this,arguments),T.invert=e.invert&&C,A()}}function mf(t){var e=0,n=hc/3,r=vf(t),i=r(e,n);return i.parallels=function(t){return arguments.length?r(e=t[0]*yc,n=t[1]*yc):[e*gc,n*gc]},i}function bf(t,e){var n=Tc(t),r=(n+Tc(e))/2;if(vc(r)<1e-6)return function(t){var e=xc(t);function n(t,n){return[t*e,Tc(n)/e]}return n.invert=function(t,n){return[t/e,Oc(n*e)]},n}(t);var i=1+n*(2*r-n),a=Ac(i)/r;function o(t,e){var n=Ac(i-2*r*Tc(e))/r;return[n*Tc(t*=r),a-n*xc(t)]}return o.invert=function(t,e){var n=a-e;return[bc(t,vc(n))/r*Cc(n),Oc((i-(t*t+n*n)*r*r)/(2*r))]},o}var xf=function(){return mf(bf).scale(155.424).center([0,33.6442])},_f=function(){return xf().parallels([29.5,45.5]).scale(1070).translate([480,250]).rotate([96,0]).center([-.6,38.7])};var kf=function(){var t,e,n,r,i,a,o=_f(),s=xf().rotate([154,0]).center([-2,58.5]).parallels([55,65]),c=xf().rotate([157,0]).center([-3,19.9]).parallels([8,18]),u={point:function(t,e){a=[t,e]}};function l(t){var e=t[0],o=t[1];return a=null,n.point(e,o),a||(r.point(e,o),a)||(i.point(e,o),a)}function h(){return t=e=null,l}return l.invert=function(t){var e=o.scale(),n=o.translate(),r=(t[0]-n[0])/e,i=(t[1]-n[1])/e;return(i>=.12&&i<.234&&r>=-.425&&r<-.214?s:i>=.166&&i<.234&&r>=-.214&&r<-.115?c:o).invert(t)},l.stream=function(n){return t&&e===n?t:(r=[o.stream(e=n),s.stream(n),c.stream(n)],i=r.length,t={point:function(t,e){for(var n=-1;++n0?e<1e-6-fc&&(e=1e-6-fc):e>fc-1e-6&&(e=fc-1e-6);var n=i/Ec(Nf(e),r);return[n*Tc(r*t),i-n*xc(r*t)]}return a.invert=function(t,e){var n=i-e,a=Cc(r)*Ac(t*t+n*n);return[bc(t,vc(n))/r*Cc(n),2*mc(Ec(i/a,1/r))-fc]},a}var Lf=function(){return mf(Bf).scale(109.5).parallels([30,30])};function Ff(t,e){return[t,e]}Ff.invert=Ff;var Pf=function(){return yf(Ff).scale(152.63)};function If(t,e){var n=xc(t),r=t===e?Tc(t):(n-xc(e))/(e-t),i=n/r+t;if(vc(r)<1e-6)return Ff;function a(t,e){var n=i-e,a=r*t;return[n*Tc(a),i-n*xc(a)]}return a.invert=function(t,e){var n=i-e;return[bc(t,vc(n))/r*Cc(n),i-Cc(r)*Ac(t*t+n*n)]},a}var jf=function(){return mf(If).scale(131.154).center([0,13.9389])},Rf=1.340264,Yf=-.081106,zf=893e-6,Uf=.003796,$f=Ac(3)/2;function Wf(t,e){var n=Oc($f*Tc(e)),r=n*n,i=r*r*r;return[t*xc(n)/($f*(Rf+3*Yf*r+i*(7*zf+9*Uf*r))),n*(Rf+Yf*r+i*(zf+Uf*r))]}Wf.invert=function(t,e){for(var n,r=e,i=r*r,a=i*i*i,o=0;o<12&&(a=(i=(r-=n=(r*(Rf+Yf*i+a*(zf+Uf*i))-e)/(Rf+3*Yf*i+a*(7*zf+9*Uf*i)))*r)*i*i,!(vc(n)<1e-12));++o);return[$f*t*(Rf+3*Yf*i+a*(7*zf+9*Uf*i))/xc(r),Oc(Tc(r)/$f)]};var Hf=function(){return yf(Wf).scale(177.158)};function Vf(t,e){var n=xc(e),r=xc(t)*n;return[n*Tc(t)/r,Tc(e)/r]}Vf.invert=Ef(mc);var Gf=function(){return yf(Vf).scale(144.049).clipAngle(60)};function qf(t,e,n,r){return 1===t&&1===e&&0===n&&0===r?ih:rf({point:function(i,a){this.stream.point(i*t+n,a*e+r)}})}var Xf=function(){var t,e,n,r,i,a,o=1,s=0,c=0,u=1,l=1,h=ih,f=null,d=ih;function p(){return r=i=null,a}return a={stream:function(t){return r&&i===t?r:r=h(d(i=t))},postclip:function(r){return arguments.length?(d=r,f=t=e=n=null,p()):d},clipExtent:function(r){return arguments.length?(d=null==r?(f=t=e=n=null,ih):Cl(f=+r[0][0],t=+r[0][1],e=+r[1][0],n=+r[1][1]),p()):null==f?null:[[f,t],[e,n]]},scale:function(t){return arguments.length?(h=qf((o=+t)*u,o*l,s,c),p()):o},translate:function(t){return arguments.length?(h=qf(o*u,o*l,s=+t[0],c=+t[1]),p()):[s,c]},reflectX:function(t){return arguments.length?(h=qf(o*(u=t?-1:1),o*l,s,c),p()):u<0},reflectY:function(t){return arguments.length?(h=qf(o*u,o*(l=t?-1:1),s,c),p()):l<0},fitExtent:function(t,e){return sf(a,t,e)},fitSize:function(t,e){return cf(a,t,e)},fitWidth:function(t,e){return uf(a,t,e)},fitHeight:function(t,e){return lf(a,t,e)}}};function Zf(t,e){var n=e*e,r=n*n;return[t*(.8707-.131979*n+r*(r*(.003971*n-.001529*r)-.013791)),e*(1.007226+n*(.015085+r*(.028874*n-.044475-.005916*r)))]}Zf.invert=function(t,e){var n,r=e,i=25;do{var a=r*r,o=a*a;r-=n=(r*(1.007226+a*(.015085+o*(.028874*a-.044475-.005916*o)))-e)/(1.007226+a*(.045255+o*(.259866*a-.311325-.005916*11*o)))}while(vc(n)>1e-6&&--i>0);return[t/(.8707+(a=r*r)*(a*(a*a*a*(.003971-.001529*a)-.013791)-.131979)),r]};var Jf=function(){return yf(Zf).scale(175.295)};function Kf(t,e){return[xc(e)*Tc(t),Tc(e)]}Kf.invert=Ef(Oc);var Qf=function(){return yf(Kf).scale(249.5).clipAngle(90+1e-6)};function td(t,e){var n=xc(e),r=1+xc(t)*n;return[n*Tc(t)/r,Tc(e)/r]}td.invert=Ef((function(t){return 2*mc(t)}));var ed=function(){return yf(td).scale(250).clipAngle(142)};function nd(t,e){return[wc(Sc((fc+e)/2)),-t]}nd.invert=function(t,e){return[-e,2*mc(kc(t))-fc]};var rd=function(){var t=Df(nd),e=t.center,n=t.rotate;return t.center=function(t){return arguments.length?e([-t[1],t[0]]):[(t=e())[1],-t[0]]},t.rotate=function(t){return arguments.length?n([t[0],t[1],t.length>2?t[2]+90:90]):[(t=n())[0],t[1],t[2]-90]},n([0,0,90]).scale(159.155)};function id(t,e){return t.parent===e.parent?1:2}function ad(t,e){return t+e.x}function od(t,e){return Math.max(t,e.y)}var sd=function(){var t=id,e=1,n=1,r=!1;function i(i){var a,o=0;i.eachAfter((function(e){var n=e.children;n?(e.x=function(t){return t.reduce(ad,0)/t.length}(n),e.y=function(t){return 1+t.reduce(od,0)}(n)):(e.x=a?o+=t(e,a):0,e.y=0,a=e)}));var s=function(t){for(var e;e=t.children;)t=e[0];return t}(i),c=function(t){for(var e;e=t.children;)t=e[e.length-1];return t}(i),u=s.x-t(s,c)/2,l=c.x+t(c,s)/2;return i.eachAfter(r?function(t){t.x=(t.x-i.x)*e,t.y=(i.y-t.y)*n}:function(t){t.x=(t.x-u)/(l-u)*e,t.y=(1-(i.y?t.y/i.y:1))*n})}return i.separation=function(e){return arguments.length?(t=e,i):t},i.size=function(t){return arguments.length?(r=!1,e=+t[0],n=+t[1],i):r?null:[e,n]},i.nodeSize=function(t){return arguments.length?(r=!0,e=+t[0],n=+t[1],i):r?[e,n]:null},i};function cd(t){var e=0,n=t.children,r=n&&n.length;if(r)for(;--r>=0;)e+=n[r].value;else e=1;t.value=e}function ud(t,e){var n,r,i,a,o,s=new dd(t),c=+t.value&&(s.value=t.value),u=[s];for(null==e&&(e=ld);n=u.pop();)if(c&&(n.value=+n.data.value),(i=e(n.data))&&(o=i.length))for(n.children=new Array(o),a=o-1;a>=0;--a)u.push(r=n.children[a]=new dd(i[a])),r.parent=n,r.depth=n.depth+1;return s.eachBefore(fd)}function ld(t){return t.children}function hd(t){t.data=t.data.data}function fd(t){var e=0;do{t.height=e}while((t=t.parent)&&t.height<++e)}function dd(t){this.data=t,this.depth=this.height=0,this.parent=null}dd.prototype=ud.prototype={constructor:dd,count:function(){return this.eachAfter(cd)},each:function(t){var e,n,r,i,a=this,o=[a];do{for(e=o.reverse(),o=[];a=e.pop();)if(t(a),n=a.children)for(r=0,i=n.length;r=0;--n)i.push(e[n]);return this},sum:function(t){return this.eachAfter((function(e){for(var n=+t(e.data)||0,r=e.children,i=r&&r.length;--i>=0;)n+=r[i].value;e.value=n}))},sort:function(t){return this.eachBefore((function(e){e.children&&e.children.sort(t)}))},path:function(t){for(var e=this,n=function(t,e){if(t===e)return t;var n=t.ancestors(),r=e.ancestors(),i=null;t=n.pop(),e=r.pop();for(;t===e;)i=t,t=n.pop(),e=r.pop();return i}(e,t),r=[e];e!==n;)e=e.parent,r.push(e);for(var i=r.length;t!==n;)r.splice(i,0,t),t=t.parent;return r},ancestors:function(){for(var t=this,e=[t];t=t.parent;)e.push(t);return e},descendants:function(){var t=[];return this.each((function(e){t.push(e)})),t},leaves:function(){var t=[];return this.eachBefore((function(e){e.children||t.push(e)})),t},links:function(){var t=this,e=[];return t.each((function(n){n!==t&&e.push({source:n.parent,target:n})})),e},copy:function(){return ud(this).eachBefore(hd)}};var pd=Array.prototype.slice;var gd=function(t){for(var e,n,r=0,i=(t=function(t){for(var e,n,r=t.length;r;)n=Math.random()*r--|0,e=t[r],t[r]=t[n],t[n]=e;return t}(pd.call(t))).length,a=[];r0&&n*n>r*r+i*i}function bd(t,e){for(var n=0;n(o*=o)?(r=(u+o-i)/(2*u),a=Math.sqrt(Math.max(0,o/u-r*r)),n.x=t.x-r*s-a*c,n.y=t.y-r*c+a*s):(r=(u+i-o)/(2*u),a=Math.sqrt(Math.max(0,i/u-r*r)),n.x=e.x+r*s-a*c,n.y=e.y+r*c+a*s)):(n.x=e.x+n.r,n.y=e.y)}function Ed(t,e){var n=t.r+e.r-1e-6,r=e.x-t.x,i=e.y-t.y;return n>0&&n*n>r*r+i*i}function Td(t){var e=t._,n=t.next._,r=e.r+n.r,i=(e.x*n.r+n.x*e.r)/r,a=(e.y*n.r+n.y*e.r)/r;return i*i+a*a}function Cd(t){this._=t,this.next=null,this.previous=null}function Ad(t){if(!(i=t.length))return 0;var e,n,r,i,a,o,s,c,u,l,h;if((e=t[0]).x=0,e.y=0,!(i>1))return e.r;if(n=t[1],e.x=-n.r,n.x=e.r,n.y=0,!(i>2))return e.r+n.r;wd(n,e,r=t[2]),e=new Cd(e),n=new Cd(n),r=new Cd(r),e.next=r.previous=n,n.next=e.previous=r,r.next=n.previous=e;t:for(s=3;s0)throw new Error("cycle");return a}return n.id=function(e){return arguments.length?(t=Od(e),n):t},n.parentId=function(t){return arguments.length?(e=Od(t),n):e},n};function Vd(t,e){return t.parent===e.parent?1:2}function Gd(t){var e=t.children;return e?e[0]:t.t}function qd(t){var e=t.children;return e?e[e.length-1]:t.t}function Xd(t,e,n){var r=n/(e.i-t.i);e.c-=r,e.s+=n,t.c+=r,e.z+=n,e.m+=n}function Zd(t,e,n){return t.a.parent===e.parent?t.a:n}function Jd(t,e){this._=t,this.parent=null,this.children=null,this.A=null,this.a=this,this.z=0,this.m=0,this.c=0,this.s=0,this.t=null,this.i=e}Jd.prototype=Object.create(dd.prototype);var Kd=function(){var t=Vd,e=1,n=1,r=null;function i(i){var c=function(t){for(var e,n,r,i,a,o=new Jd(t,0),s=[o];e=s.pop();)if(r=e._.children)for(e.children=new Array(a=r.length),i=a-1;i>=0;--i)s.push(n=e.children[i]=new Jd(r[i],i)),n.parent=e;return(o.parent=new Jd(null,0)).children=[o],o}(i);if(c.eachAfter(a),c.parent.m=-c.z,c.eachBefore(o),r)i.eachBefore(s);else{var u=i,l=i,h=i;i.eachBefore((function(t){t.xl.x&&(l=t),t.depth>h.depth&&(h=t)}));var f=u===l?1:t(u,l)/2,d=f-u.x,p=e/(l.x+f+d),g=n/(h.depth||1);i.eachBefore((function(t){t.x=(t.x+d)*p,t.y=t.depth*g}))}return i}function a(e){var n=e.children,r=e.parent.children,i=e.i?r[e.i-1]:null;if(n){!function(t){for(var e,n=0,r=0,i=t.children,a=i.length;--a>=0;)(e=i[a]).z+=n,e.m+=n,n+=e.s+(r+=e.c)}(e);var a=(n[0].z+n[n.length-1].z)/2;i?(e.z=i.z+t(e._,i._),e.m=e.z-a):e.z=a}else i&&(e.z=i.z+t(e._,i._));e.parent.A=function(e,n,r){if(n){for(var i,a=e,o=e,s=n,c=a.parent.children[0],u=a.m,l=o.m,h=s.m,f=c.m;s=qd(s),a=Gd(a),s&&a;)c=Gd(c),(o=qd(o)).a=e,(i=s.z+h-a.z-u+t(s._,a._))>0&&(Xd(Zd(s,e,r),e,i),u+=i,l+=i),h+=s.m,u+=a.m,f+=c.m,l+=o.m;s&&!qd(o)&&(o.t=s,o.m+=h-l),a&&!Gd(c)&&(c.t=a,c.m+=u-f,r=e)}return r}(e,i,e.parent.A||r[0])}function o(t){t._.x=t.z+t.parent.m,t.m+=t.parent.m}function s(t){t.x*=e,t.y=t.depth*n}return i.separation=function(e){return arguments.length?(t=e,i):t},i.size=function(t){return arguments.length?(r=!1,e=+t[0],n=+t[1],i):r?null:[e,n]},i.nodeSize=function(t){return arguments.length?(r=!0,e=+t[0],n=+t[1],i):r?[e,n]:null},i},Qd=function(t,e,n,r,i){for(var a,o=t.children,s=-1,c=o.length,u=t.value&&(i-n)/t.value;++sf&&(f=s),y=l*l*g,(d=Math.max(f/y,y/h))>p){l-=s;break}p=d}v.push(o={value:l,dice:c1?e:1)},n}(tp),rp=function(){var t=np,e=!1,n=1,r=1,i=[0],a=Dd,o=Dd,s=Dd,c=Dd,u=Dd;function l(t){return t.x0=t.y0=0,t.x1=n,t.y1=r,t.eachBefore(h),i=[0],e&&t.eachBefore(jd),t}function h(e){var n=i[e.depth],r=e.x0+n,l=e.y0+n,h=e.x1-n,f=e.y1-n;h=n-1){var l=s[e];return l.x0=i,l.y0=a,l.x1=o,void(l.y1=c)}var h=u[e],f=r/2+h,d=e+1,p=n-1;for(;d>>1;u[g]c-a){var m=(i*v+o*y)/r;t(e,d,y,i,a,m,c),t(d,n,v,m,a,o,c)}else{var b=(a*v+c*y)/r;t(e,d,y,i,a,o,b),t(d,n,v,i,b,o,c)}}(0,c,t.value,e,n,r,i)},ap=function(t,e,n,r,i){(1&t.depth?Qd:Rd)(t,e,n,r,i)},op=function t(e){function n(t,n,r,i,a){if((o=t._squarify)&&o.ratio===e)for(var o,s,c,u,l,h=-1,f=o.length,d=t.value;++h1?e:1)},n}(tp),sp=function(t){var e=t.length;return function(n){return t[Math.max(0,Math.min(e-1,Math.floor(n*e)))]}},cp=function(t,e){var n=un(+t,+e);return function(t){var e=n(t);return e-360*Math.floor(e/360)}},up=function(t,e){return t=+t,e=+e,function(n){return Math.round(t*(1-n)+e*n)}},lp=Math.SQRT2;function hp(t){return((t=Math.exp(t))+1/t)/2}var fp=function(t,e){var n,r,i=t[0],a=t[1],o=t[2],s=e[0],c=e[1],u=e[2],l=s-i,h=c-a,f=l*l+h*h;if(f<1e-12)r=Math.log(u/o)/lp,n=function(t){return[i+t*l,a+t*h,o*Math.exp(lp*t*r)]};else{var d=Math.sqrt(f),p=(u*u-o*o+4*f)/(2*o*2*d),g=(u*u-o*o-4*f)/(2*u*2*d),y=Math.log(Math.sqrt(p*p+1)-p),v=Math.log(Math.sqrt(g*g+1)-g);r=(v-y)/lp,n=function(t){var e,n=t*r,s=hp(y),c=o/(2*d)*(s*(e=lp*n+y,((e=Math.exp(2*e))-1)/(e+1))-function(t){return((t=Math.exp(t))-1/t)/2}(y));return[i+c*l,a+c*h,o*s/hp(lp*n+y)]}}return n.duration=1e3*r,n};function dp(t){return function(e,n){var r=t((e=tn(e)).h,(n=tn(n)).h),i=hn(e.s,n.s),a=hn(e.l,n.l),o=hn(e.opacity,n.opacity);return function(t){return e.h=r(t),e.s=i(t),e.l=a(t),e.opacity=o(t),e+""}}}var pp=dp(un),gp=dp(hn);function yp(t,e){var n=hn((t=pa(t)).l,(e=pa(e)).l),r=hn(t.a,e.a),i=hn(t.b,e.b),a=hn(t.opacity,e.opacity);return function(e){return t.l=n(e),t.a=r(e),t.b=i(e),t.opacity=a(e),t+""}}function vp(t){return function(e,n){var r=t((e=ka(e)).h,(n=ka(n)).h),i=hn(e.c,n.c),a=hn(e.l,n.l),o=hn(e.opacity,n.opacity);return function(t){return e.h=r(t),e.c=i(t),e.l=a(t),e.opacity=o(t),e+""}}}var mp=vp(un),bp=vp(hn);function xp(t){return function e(n){function r(e,r){var i=t((e=Oa(e)).h,(r=Oa(r)).h),a=hn(e.s,r.s),o=hn(e.l,r.l),s=hn(e.opacity,r.opacity);return function(t){return e.h=i(t),e.s=a(t),e.l=o(Math.pow(t,n)),e.opacity=s(t),e+""}}return n=+n,r.gamma=e,r}(1)}var _p=xp(un),kp=xp(hn);function wp(t,e){for(var n=0,r=e.length-1,i=e[0],a=new Array(r<0?0:r);n1&&(e=t[a[o-2]],n=t[a[o-1]],r=t[s],(n[0]-e[0])*(r[1]-e[1])-(n[1]-e[1])*(r[0]-e[0])<=0);)--o;a[o++]=s}return a.slice(0,o)}var Mp=function(t){if((n=t.length)<3)return null;var e,n,r=new Array(n),i=new Array(n);for(e=0;e=0;--e)u.push(t[r[a[e]][2]]);for(e=+s;es!=u>s&&o<(c-n)*(s-r)/(u-r)+n&&(l=!l),c=n,u=r;return l},Dp=function(t){for(var e,n,r=-1,i=t.length,a=t[i-1],o=a[0],s=a[1],c=0;++r1);return t+n*a*Math.sqrt(-2*Math.log(i)/i)}}return n.source=t,n}(Np),Fp=function t(e){function n(){var t=Lp.source(e).apply(this,arguments);return function(){return Math.exp(t())}}return n.source=t,n}(Np),Pp=function t(e){function n(t){return function(){for(var n=0,r=0;rr&&(e=n,n=r,r=e),function(t){return Math.max(n,Math.min(r,t))}}function tg(t,e,n){var r=t[0],i=t[1],a=e[0],o=e[1];return i2?eg:tg,i=a=null,h}function h(e){return isNaN(e=+e)?n:(i||(i=r(o.map(t),s,c)))(t(u(e)))}return h.invert=function(n){return u(e((a||(a=r(s,o.map(t),_n)))(n)))},h.domain=function(t){return arguments.length?(o=Up.call(t,Xp),u===Jp||(u=Qp(o)),l()):o.slice()},h.range=function(t){return arguments.length?(s=$p.call(t),l()):s.slice()},h.rangeRound=function(t){return s=$p.call(t),c=up,l()},h.clamp=function(t){return arguments.length?(u=t?Qp(o):Jp,h):u!==Jp},h.interpolate=function(t){return arguments.length?(c=t,l()):c},h.unknown=function(t){return arguments.length?(n=t,h):n},function(n,r){return t=n,e=r,l()}}function ig(t,e){return rg()(t,e)}var ag=function(t,e,n,r){var i,a=S(t,e,n);switch((r=Hs(null==r?",f":r)).type){case"s":var o=Math.max(Math.abs(t),Math.abs(e));return null!=r.precision||isNaN(i=ac(a,o))||(r.precision=i),Zs(r,o);case"":case"e":case"g":case"p":case"r":null!=r.precision||isNaN(i=oc(a,Math.max(Math.abs(t),Math.abs(e))))||(r.precision=i-("e"===r.type));break;case"f":case"%":null!=r.precision||isNaN(i=ic(a))||(r.precision=i-2*("%"===r.type))}return Xs(r)};function og(t){var e=t.domain;return t.ticks=function(t){var n=e();return C(n[0],n[n.length-1],null==t?10:t)},t.tickFormat=function(t,n){var r=e();return ag(r[0],r[r.length-1],null==t?10:t,n)},t.nice=function(n){null==n&&(n=10);var r,i=e(),a=0,o=i.length-1,s=i[a],c=i[o];return c0?r=A(s=Math.floor(s/r)*r,c=Math.ceil(c/r)*r,n):r<0&&(r=A(s=Math.ceil(s*r)/r,c=Math.floor(c*r)/r,n)),r>0?(i[a]=Math.floor(s/r)*r,i[o]=Math.ceil(c/r)*r,e(i)):r<0&&(i[a]=Math.ceil(s*r)/r,i[o]=Math.floor(c*r)/r,e(i)),t},t}function sg(){var t=ig(Jp,Jp);return t.copy=function(){return ng(t,sg())},Rp.apply(t,arguments),og(t)}function cg(t){var e;function n(t){return isNaN(t=+t)?e:t}return n.invert=n,n.domain=n.range=function(e){return arguments.length?(t=Up.call(e,Xp),n):t.slice()},n.unknown=function(t){return arguments.length?(e=t,n):e},n.copy=function(){return cg(t).unknown(e)},t=arguments.length?Up.call(t,Xp):[0,1],og(n)}var ug=function(t,e){var n,r=0,i=(t=t.slice()).length-1,a=t[r],o=t[i];return o0){for(;fc)break;g.push(h)}}else for(;f=1;--l)if(!((h=u*l)c)break;g.push(h)}}else g=C(f,d,Math.min(d-f,p)).map(n);return r?g.reverse():g},r.tickFormat=function(t,i){if(null==i&&(i=10===a?".0e":","),"function"!=typeof i&&(i=Xs(i)),t===1/0)return i;null==t&&(t=10);var o=Math.max(1,a*t/r.ticks().length);return function(t){var r=t/n(Math.round(e(t)));return r*a0?i[r-1]:e[0],r=r?[i[r-1],n]:[i[o-1],i[o]]},o.unknown=function(e){return arguments.length?(t=e,o):o},o.thresholds=function(){return i.slice()},o.copy=function(){return Mg().domain([e,n]).range(a).unknown(t)},Rp.apply(og(o),arguments)}function Og(){var t,e=[.5],n=[0,1],r=1;function i(i){return i<=i?n[c(e,i,0,r)]:t}return i.domain=function(t){return arguments.length?(e=$p.call(t),r=Math.min(e.length,n.length-1),i):e.slice()},i.range=function(t){return arguments.length?(n=$p.call(t),r=Math.min(e.length,n.length-1),i):n.slice()},i.invertExtent=function(t){var r=n.indexOf(t);return[e[r-1],e[r]]},i.unknown=function(e){return arguments.length?(t=e,i):t},i.copy=function(){return Og().domain(e).range(n).unknown(t)},Rp.apply(i,arguments)}var Dg=new Date,Ng=new Date;function Bg(t,e,n,r){function i(e){return t(e=0===arguments.length?new Date:new Date(+e)),e}return i.floor=function(e){return t(e=new Date(+e)),e},i.ceil=function(n){return t(n=new Date(n-1)),e(n,1),t(n),n},i.round=function(t){var e=i(t),n=i.ceil(t);return t-e0))return s;do{s.push(o=new Date(+n)),e(n,a),t(n)}while(o=e)for(;t(e),!n(e);)e.setTime(e-1)}),(function(t,r){if(t>=t)if(r<0)for(;++r<=0;)for(;e(t,-1),!n(t););else for(;--r>=0;)for(;e(t,1),!n(t););}))},n&&(i.count=function(e,r){return Dg.setTime(+e),Ng.setTime(+r),t(Dg),t(Ng),Math.floor(n(Dg,Ng))},i.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?i.filter(r?function(e){return r(e)%t==0}:function(e){return i.count(0,e)%t==0}):i:null}),i}var Lg=Bg((function(t){t.setMonth(0,1),t.setHours(0,0,0,0)}),(function(t,e){t.setFullYear(t.getFullYear()+e)}),(function(t,e){return e.getFullYear()-t.getFullYear()}),(function(t){return t.getFullYear()}));Lg.every=function(t){return isFinite(t=Math.floor(t))&&t>0?Bg((function(e){e.setFullYear(Math.floor(e.getFullYear()/t)*t),e.setMonth(0,1),e.setHours(0,0,0,0)}),(function(e,n){e.setFullYear(e.getFullYear()+n*t)})):null};var Fg=Lg,Pg=Lg.range,Ig=Bg((function(t){t.setDate(1),t.setHours(0,0,0,0)}),(function(t,e){t.setMonth(t.getMonth()+e)}),(function(t,e){return e.getMonth()-t.getMonth()+12*(e.getFullYear()-t.getFullYear())}),(function(t){return t.getMonth()})),jg=Ig,Rg=Ig.range;function Yg(t){return Bg((function(e){e.setDate(e.getDate()-(e.getDay()+7-t)%7),e.setHours(0,0,0,0)}),(function(t,e){t.setDate(t.getDate()+7*e)}),(function(t,e){return(e-t-6e4*(e.getTimezoneOffset()-t.getTimezoneOffset()))/6048e5}))}var zg=Yg(0),Ug=Yg(1),$g=Yg(2),Wg=Yg(3),Hg=Yg(4),Vg=Yg(5),Gg=Yg(6),qg=zg.range,Xg=Ug.range,Zg=$g.range,Jg=Wg.range,Kg=Hg.range,Qg=Vg.range,ty=Gg.range,ey=Bg((function(t){t.setHours(0,0,0,0)}),(function(t,e){t.setDate(t.getDate()+e)}),(function(t,e){return(e-t-6e4*(e.getTimezoneOffset()-t.getTimezoneOffset()))/864e5}),(function(t){return t.getDate()-1})),ny=ey,ry=ey.range,iy=Bg((function(t){t.setTime(t-t.getMilliseconds()-1e3*t.getSeconds()-6e4*t.getMinutes())}),(function(t,e){t.setTime(+t+36e5*e)}),(function(t,e){return(e-t)/36e5}),(function(t){return t.getHours()})),ay=iy,oy=iy.range,sy=Bg((function(t){t.setTime(t-t.getMilliseconds()-1e3*t.getSeconds())}),(function(t,e){t.setTime(+t+6e4*e)}),(function(t,e){return(e-t)/6e4}),(function(t){return t.getMinutes()})),cy=sy,uy=sy.range,ly=Bg((function(t){t.setTime(t-t.getMilliseconds())}),(function(t,e){t.setTime(+t+1e3*e)}),(function(t,e){return(e-t)/1e3}),(function(t){return t.getUTCSeconds()})),hy=ly,fy=ly.range,dy=Bg((function(){}),(function(t,e){t.setTime(+t+e)}),(function(t,e){return e-t}));dy.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?Bg((function(e){e.setTime(Math.floor(e/t)*t)}),(function(e,n){e.setTime(+e+n*t)}),(function(e,n){return(n-e)/t})):dy:null};var py=dy,gy=dy.range;function yy(t){return Bg((function(e){e.setUTCDate(e.getUTCDate()-(e.getUTCDay()+7-t)%7),e.setUTCHours(0,0,0,0)}),(function(t,e){t.setUTCDate(t.getUTCDate()+7*e)}),(function(t,e){return(e-t)/6048e5}))}var vy=yy(0),my=yy(1),by=yy(2),xy=yy(3),_y=yy(4),ky=yy(5),wy=yy(6),Ey=vy.range,Ty=my.range,Cy=by.range,Ay=xy.range,Sy=_y.range,My=ky.range,Oy=wy.range,Dy=Bg((function(t){t.setUTCHours(0,0,0,0)}),(function(t,e){t.setUTCDate(t.getUTCDate()+e)}),(function(t,e){return(e-t)/864e5}),(function(t){return t.getUTCDate()-1})),Ny=Dy,By=Dy.range,Ly=Bg((function(t){t.setUTCMonth(0,1),t.setUTCHours(0,0,0,0)}),(function(t,e){t.setUTCFullYear(t.getUTCFullYear()+e)}),(function(t,e){return e.getUTCFullYear()-t.getUTCFullYear()}),(function(t){return t.getUTCFullYear()}));Ly.every=function(t){return isFinite(t=Math.floor(t))&&t>0?Bg((function(e){e.setUTCFullYear(Math.floor(e.getUTCFullYear()/t)*t),e.setUTCMonth(0,1),e.setUTCHours(0,0,0,0)}),(function(e,n){e.setUTCFullYear(e.getUTCFullYear()+n*t)})):null};var Fy=Ly,Py=Ly.range;function Iy(t){if(0<=t.y&&t.y<100){var e=new Date(-1,t.m,t.d,t.H,t.M,t.S,t.L);return e.setFullYear(t.y),e}return new Date(t.y,t.m,t.d,t.H,t.M,t.S,t.L)}function jy(t){if(0<=t.y&&t.y<100){var e=new Date(Date.UTC(-1,t.m,t.d,t.H,t.M,t.S,t.L));return e.setUTCFullYear(t.y),e}return new Date(Date.UTC(t.y,t.m,t.d,t.H,t.M,t.S,t.L))}function Ry(t,e,n){return{y:t,m:e,d:n,H:0,M:0,S:0,L:0}}function Yy(t){var e=t.dateTime,n=t.date,r=t.time,i=t.periods,a=t.days,o=t.shortDays,s=t.months,c=t.shortMonths,u=Ky(i),l=Qy(i),h=Ky(a),f=Qy(a),d=Ky(o),p=Qy(o),g=Ky(s),y=Qy(s),v=Ky(c),m=Qy(c),b={a:function(t){return o[t.getDay()]},A:function(t){return a[t.getDay()]},b:function(t){return c[t.getMonth()]},B:function(t){return s[t.getMonth()]},c:null,d:xv,e:xv,f:Tv,H:_v,I:kv,j:wv,L:Ev,m:Cv,M:Av,p:function(t){return i[+(t.getHours()>=12)]},q:function(t){return 1+~~(t.getMonth()/3)},Q:em,s:nm,S:Sv,u:Mv,U:Ov,V:Dv,w:Nv,W:Bv,x:null,X:null,y:Lv,Y:Fv,Z:Pv,"%":tm},x={a:function(t){return o[t.getUTCDay()]},A:function(t){return a[t.getUTCDay()]},b:function(t){return c[t.getUTCMonth()]},B:function(t){return s[t.getUTCMonth()]},c:null,d:Iv,e:Iv,f:Uv,H:jv,I:Rv,j:Yv,L:zv,m:$v,M:Wv,p:function(t){return i[+(t.getUTCHours()>=12)]},q:function(t){return 1+~~(t.getUTCMonth()/3)},Q:em,s:nm,S:Hv,u:Vv,U:Gv,V:qv,w:Xv,W:Zv,x:null,X:null,y:Jv,Y:Kv,Z:Qv,"%":tm},_={a:function(t,e,n){var r=d.exec(e.slice(n));return r?(t.w=p[r[0].toLowerCase()],n+r[0].length):-1},A:function(t,e,n){var r=h.exec(e.slice(n));return r?(t.w=f[r[0].toLowerCase()],n+r[0].length):-1},b:function(t,e,n){var r=v.exec(e.slice(n));return r?(t.m=m[r[0].toLowerCase()],n+r[0].length):-1},B:function(t,e,n){var r=g.exec(e.slice(n));return r?(t.m=y[r[0].toLowerCase()],n+r[0].length):-1},c:function(t,n,r){return E(t,e,n,r)},d:lv,e:lv,f:yv,H:fv,I:fv,j:hv,L:gv,m:uv,M:dv,p:function(t,e,n){var r=u.exec(e.slice(n));return r?(t.p=l[r[0].toLowerCase()],n+r[0].length):-1},q:cv,Q:mv,s:bv,S:pv,u:ev,U:nv,V:rv,w:tv,W:iv,x:function(t,e,r){return E(t,n,e,r)},X:function(t,e,n){return E(t,r,e,n)},y:ov,Y:av,Z:sv,"%":vv};function k(t,e){return function(n){var r,i,a,o=[],s=-1,c=0,u=t.length;for(n instanceof Date||(n=new Date(+n));++s53)return null;"w"in a||(a.w=1),"Z"in a?(i=(r=jy(Ry(a.y,0,1))).getUTCDay(),r=i>4||0===i?my.ceil(r):my(r),r=Ny.offset(r,7*(a.V-1)),a.y=r.getUTCFullYear(),a.m=r.getUTCMonth(),a.d=r.getUTCDate()+(a.w+6)%7):(i=(r=Iy(Ry(a.y,0,1))).getDay(),r=i>4||0===i?Ug.ceil(r):Ug(r),r=ny.offset(r,7*(a.V-1)),a.y=r.getFullYear(),a.m=r.getMonth(),a.d=r.getDate()+(a.w+6)%7)}else("W"in a||"U"in a)&&("w"in a||(a.w="u"in a?a.u%7:"W"in a?1:0),i="Z"in a?jy(Ry(a.y,0,1)).getUTCDay():Iy(Ry(a.y,0,1)).getDay(),a.m=0,a.d="W"in a?(a.w+6)%7+7*a.W-(i+5)%7:a.w+7*a.U-(i+6)%7);return"Z"in a?(a.H+=a.Z/100|0,a.M+=a.Z%100,jy(a)):Iy(a)}}function E(t,e,n,r){for(var i,a,o=0,s=e.length,c=n.length;o=c)return-1;if(37===(i=e.charCodeAt(o++))){if(i=e.charAt(o++),!(a=_[i in Vy?e.charAt(o++):i])||(r=a(t,n,r))<0)return-1}else if(i!=n.charCodeAt(r++))return-1}return r}return(b.x=k(n,b),b.X=k(r,b),b.c=k(e,b),x.x=k(n,x),x.X=k(r,x),x.c=k(e,x),{format:function(t){var e=k(t+="",b);return e.toString=function(){return t},e},parse:function(t){var e=w(t+="",!1);return e.toString=function(){return t},e},utcFormat:function(t){var e=k(t+="",x);return e.toString=function(){return t},e},utcParse:function(t){var e=w(t+="",!0);return e.toString=function(){return t},e}})}var zy,Uy,$y,Wy,Hy,Vy={"-":"",_:" ",0:"0"},Gy=/^\s*\d+/,qy=/^%/,Xy=/[\\^$*+?|[\]().{}]/g;function Zy(t,e,n){var r=t<0?"-":"",i=(r?-t:t)+"",a=i.length;return r+(a68?1900:2e3),n+r[0].length):-1}function sv(t,e,n){var r=/^(Z)|([+-]\d\d)(?::?(\d\d))?/.exec(e.slice(n,n+6));return r?(t.Z=r[1]?0:-(r[2]+(r[3]||"00")),n+r[0].length):-1}function cv(t,e,n){var r=Gy.exec(e.slice(n,n+1));return r?(t.q=3*r[0]-3,n+r[0].length):-1}function uv(t,e,n){var r=Gy.exec(e.slice(n,n+2));return r?(t.m=r[0]-1,n+r[0].length):-1}function lv(t,e,n){var r=Gy.exec(e.slice(n,n+2));return r?(t.d=+r[0],n+r[0].length):-1}function hv(t,e,n){var r=Gy.exec(e.slice(n,n+3));return r?(t.m=0,t.d=+r[0],n+r[0].length):-1}function fv(t,e,n){var r=Gy.exec(e.slice(n,n+2));return r?(t.H=+r[0],n+r[0].length):-1}function dv(t,e,n){var r=Gy.exec(e.slice(n,n+2));return r?(t.M=+r[0],n+r[0].length):-1}function pv(t,e,n){var r=Gy.exec(e.slice(n,n+2));return r?(t.S=+r[0],n+r[0].length):-1}function gv(t,e,n){var r=Gy.exec(e.slice(n,n+3));return r?(t.L=+r[0],n+r[0].length):-1}function yv(t,e,n){var r=Gy.exec(e.slice(n,n+6));return r?(t.L=Math.floor(r[0]/1e3),n+r[0].length):-1}function vv(t,e,n){var r=qy.exec(e.slice(n,n+1));return r?n+r[0].length:-1}function mv(t,e,n){var r=Gy.exec(e.slice(n));return r?(t.Q=+r[0],n+r[0].length):-1}function bv(t,e,n){var r=Gy.exec(e.slice(n));return r?(t.s=+r[0],n+r[0].length):-1}function xv(t,e){return Zy(t.getDate(),e,2)}function _v(t,e){return Zy(t.getHours(),e,2)}function kv(t,e){return Zy(t.getHours()%12||12,e,2)}function wv(t,e){return Zy(1+ny.count(Fg(t),t),e,3)}function Ev(t,e){return Zy(t.getMilliseconds(),e,3)}function Tv(t,e){return Ev(t,e)+"000"}function Cv(t,e){return Zy(t.getMonth()+1,e,2)}function Av(t,e){return Zy(t.getMinutes(),e,2)}function Sv(t,e){return Zy(t.getSeconds(),e,2)}function Mv(t){var e=t.getDay();return 0===e?7:e}function Ov(t,e){return Zy(zg.count(Fg(t)-1,t),e,2)}function Dv(t,e){var n=t.getDay();return t=n>=4||0===n?Hg(t):Hg.ceil(t),Zy(Hg.count(Fg(t),t)+(4===Fg(t).getDay()),e,2)}function Nv(t){return t.getDay()}function Bv(t,e){return Zy(Ug.count(Fg(t)-1,t),e,2)}function Lv(t,e){return Zy(t.getFullYear()%100,e,2)}function Fv(t,e){return Zy(t.getFullYear()%1e4,e,4)}function Pv(t){var e=t.getTimezoneOffset();return(e>0?"-":(e*=-1,"+"))+Zy(e/60|0,"0",2)+Zy(e%60,"0",2)}function Iv(t,e){return Zy(t.getUTCDate(),e,2)}function jv(t,e){return Zy(t.getUTCHours(),e,2)}function Rv(t,e){return Zy(t.getUTCHours()%12||12,e,2)}function Yv(t,e){return Zy(1+Ny.count(Fy(t),t),e,3)}function zv(t,e){return Zy(t.getUTCMilliseconds(),e,3)}function Uv(t,e){return zv(t,e)+"000"}function $v(t,e){return Zy(t.getUTCMonth()+1,e,2)}function Wv(t,e){return Zy(t.getUTCMinutes(),e,2)}function Hv(t,e){return Zy(t.getUTCSeconds(),e,2)}function Vv(t){var e=t.getUTCDay();return 0===e?7:e}function Gv(t,e){return Zy(vy.count(Fy(t)-1,t),e,2)}function qv(t,e){var n=t.getUTCDay();return t=n>=4||0===n?_y(t):_y.ceil(t),Zy(_y.count(Fy(t),t)+(4===Fy(t).getUTCDay()),e,2)}function Xv(t){return t.getUTCDay()}function Zv(t,e){return Zy(my.count(Fy(t)-1,t),e,2)}function Jv(t,e){return Zy(t.getUTCFullYear()%100,e,2)}function Kv(t,e){return Zy(t.getUTCFullYear()%1e4,e,4)}function Qv(){return"+0000"}function tm(){return"%"}function em(t){return+t}function nm(t){return Math.floor(+t/1e3)}function rm(t){return zy=Yy(t),Uy=zy.format,$y=zy.parse,Wy=zy.utcFormat,Hy=zy.utcParse,zy}rm({dateTime:"%x, %X",date:"%-m/%-d/%Y",time:"%-I:%M:%S %p",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});function im(t){return new Date(t)}function am(t){return t instanceof Date?+t:+new Date(+t)}function om(t,e,n,r,a,o,s,c,u){var l=ig(Jp,Jp),h=l.invert,f=l.domain,d=u(".%L"),p=u(":%S"),g=u("%I:%M"),y=u("%I %p"),v=u("%a %d"),m=u("%b %d"),b=u("%B"),x=u("%Y"),_=[[s,1,1e3],[s,5,5e3],[s,15,15e3],[s,30,3e4],[o,1,6e4],[o,5,3e5],[o,15,9e5],[o,30,18e5],[a,1,36e5],[a,3,108e5],[a,6,216e5],[a,12,432e5],[r,1,864e5],[r,2,1728e5],[n,1,6048e5],[e,1,2592e6],[e,3,7776e6],[t,1,31536e6]];function k(i){return(s(i)1)&&(t-=Math.floor(t));var e=Math.abs(t-.5);return qb.h=360*t-100,qb.s=1.5-1.5*e,qb.l=.8-.9*e,qb+""},Zb=Ge(),Jb=Math.PI/3,Kb=2*Math.PI/3,Qb=function(t){var e;return t=(.5-t)*Math.PI,Zb.r=255*(e=Math.sin(t))*e,Zb.g=255*(e=Math.sin(t+Jb))*e,Zb.b=255*(e=Math.sin(t+Kb))*e,Zb+""},tx=function(t){return t=Math.max(0,Math.min(1,t)),"rgb("+Math.max(0,Math.min(255,Math.round(34.61+t*(1172.33-t*(10793.56-t*(33300.12-t*(38394.49-14825.05*t)))))))+", "+Math.max(0,Math.min(255,Math.round(23.31+t*(557.33+t*(1225.33-t*(3574.96-t*(1073.77+707.56*t)))))))+", "+Math.max(0,Math.min(255,Math.round(27.2+t*(3211.1-t*(15327.97-t*(27814-t*(22569.18-6838.66*t)))))))+")"};function ex(t){var e=t.length;return function(n){return t[Math.max(0,Math.min(e-1,Math.floor(n*e)))]}}var nx=ex(Nm("44015444025645045745055946075a46085c460a5d460b5e470d60470e6147106347116447136548146748166848176948186a481a6c481b6d481c6e481d6f481f70482071482173482374482475482576482677482878482979472a7a472c7a472d7b472e7c472f7d46307e46327e46337f463480453581453781453882443983443a83443b84433d84433e85423f854240864241864142874144874045884046883f47883f48893e49893e4a893e4c8a3d4d8a3d4e8a3c4f8a3c508b3b518b3b528b3a538b3a548c39558c39568c38588c38598c375a8c375b8d365c8d365d8d355e8d355f8d34608d34618d33628d33638d32648e32658e31668e31678e31688e30698e306a8e2f6b8e2f6c8e2e6d8e2e6e8e2e6f8e2d708e2d718e2c718e2c728e2c738e2b748e2b758e2a768e2a778e2a788e29798e297a8e297b8e287c8e287d8e277e8e277f8e27808e26818e26828e26828e25838e25848e25858e24868e24878e23888e23898e238a8d228b8d228c8d228d8d218e8d218f8d21908d21918c20928c20928c20938c1f948c1f958b1f968b1f978b1f988b1f998a1f9a8a1e9b8a1e9c891e9d891f9e891f9f881fa0881fa1881fa1871fa28720a38620a48621a58521a68522a78522a88423a98324aa8325ab8225ac8226ad8127ad8128ae8029af7f2ab07f2cb17e2db27d2eb37c2fb47c31b57b32b67a34b67935b77937b87838b9773aba763bbb753dbc743fbc7340bd7242be7144bf7046c06f48c16e4ac16d4cc26c4ec36b50c46a52c56954c56856c66758c7655ac8645cc8635ec96260ca6063cb5f65cb5e67cc5c69cd5b6ccd5a6ece5870cf5773d05675d05477d1537ad1517cd2507fd34e81d34d84d44b86d54989d5488bd6468ed64590d74393d74195d84098d83e9bd93c9dd93ba0da39a2da37a5db36a8db34aadc32addc30b0dd2fb2dd2db5de2bb8de29bade28bddf26c0df25c2df23c5e021c8e020cae11fcde11dd0e11cd2e21bd5e21ad8e219dae319dde318dfe318e2e418e5e419e7e419eae51aece51befe51cf1e51df4e61ef6e620f8e621fbe723fde725")),rx=ex(Nm("00000401000501010601010802010902020b02020d03030f03031204041405041606051806051a07061c08071e0907200a08220b09240c09260d0a290e0b2b100b2d110c2f120d31130d34140e36150e38160f3b180f3d19103f1a10421c10441d11471e114920114b21114e22115024125325125527125829115a2a115c2c115f2d11612f116331116533106734106936106b38106c390f6e3b0f703d0f713f0f72400f74420f75440f764510774710784910784a10794c117a4e117b4f127b51127c52137c54137d56147d57157e59157e5a167e5c167f5d177f5f187f601880621980641a80651a80671b80681c816a1c816b1d816d1d816e1e81701f81721f817320817521817621817822817922827b23827c23827e24828025828125818326818426818627818827818928818b29818c29818e2a81902a81912b81932b80942c80962c80982d80992d809b2e7f9c2e7f9e2f7fa02f7fa1307ea3307ea5317ea6317da8327daa337dab337cad347cae347bb0357bb2357bb3367ab5367ab73779b83779ba3878bc3978bd3977bf3a77c03a76c23b75c43c75c53c74c73d73c83e73ca3e72cc3f71cd4071cf4070d0416fd2426fd3436ed5446dd6456cd8456cd9466bdb476adc4869de4968df4a68e04c67e24d66e34e65e44f64e55064e75263e85362e95462ea5661eb5760ec5860ed5a5fee5b5eef5d5ef05f5ef1605df2625df2645cf3655cf4675cf4695cf56b5cf66c5cf66e5cf7705cf7725cf8745cf8765cf9785df9795df97b5dfa7d5efa7f5efa815ffb835ffb8560fb8761fc8961fc8a62fc8c63fc8e64fc9065fd9266fd9467fd9668fd9869fd9a6afd9b6bfe9d6cfe9f6dfea16efea36ffea571fea772fea973feaa74feac76feae77feb078feb27afeb47bfeb67cfeb77efeb97ffebb81febd82febf84fec185fec287fec488fec68afec88cfeca8dfecc8ffecd90fecf92fed194fed395fed597fed799fed89afdda9cfddc9efddea0fde0a1fde2a3fde3a5fde5a7fde7a9fde9aafdebacfcecaefceeb0fcf0b2fcf2b4fcf4b6fcf6b8fcf7b9fcf9bbfcfbbdfcfdbf")),ix=ex(Nm("00000401000501010601010802010a02020c02020e03021004031204031405041706041907051b08051d09061f0a07220b07240c08260d08290e092b10092d110a30120a32140b34150b37160b39180c3c190c3e1b0c411c0c431e0c451f0c48210c4a230c4c240c4f260c51280b53290b552b0b572d0b592f0a5b310a5c320a5e340a5f3609613809623909633b09643d09653e0966400a67420a68440a68450a69470b6a490b6a4a0c6b4c0c6b4d0d6c4f0d6c510e6c520e6d540f6d550f6d57106e59106e5a116e5c126e5d126e5f136e61136e62146e64156e65156e67166e69166e6a176e6c186e6d186e6f196e71196e721a6e741a6e751b6e771c6d781c6d7a1d6d7c1d6d7d1e6d7f1e6c801f6c82206c84206b85216b87216b88226a8a226a8c23698d23698f24699025689225689326679526679727669827669a28659b29649d29649f2a63a02a63a22b62a32c61a52c60a62d60a82e5fa92e5eab2f5ead305dae305cb0315bb1325ab3325ab43359b63458b73557b93556ba3655bc3754bd3853bf3952c03a51c13a50c33b4fc43c4ec63d4dc73e4cc83f4bca404acb4149cc4248ce4347cf4446d04545d24644d34743d44842d54a41d74b3fd84c3ed94d3dda4e3cdb503bdd513ade5238df5337e05536e15635e25734e35933e45a31e55c30e65d2fe75e2ee8602de9612bea632aeb6429eb6628ec6726ed6925ee6a24ef6c23ef6e21f06f20f1711ff1731df2741cf3761bf37819f47918f57b17f57d15f67e14f68013f78212f78410f8850ff8870ef8890cf98b0bf98c0af98e09fa9008fa9207fa9407fb9606fb9706fb9906fb9b06fb9d07fc9f07fca108fca309fca50afca60cfca80dfcaa0ffcac11fcae12fcb014fcb216fcb418fbb61afbb81dfbba1ffbbc21fbbe23fac026fac228fac42afac62df9c72ff9c932f9cb35f8cd37f8cf3af7d13df7d340f6d543f6d746f5d949f5db4cf4dd4ff4df53f4e156f3e35af3e55df2e661f2e865f2ea69f1ec6df1ed71f1ef75f1f179f2f27df2f482f3f586f3f68af4f88ef5f992f6fa96f8fb9af9fc9dfafda1fcffa4")),ax=ex(Nm("0d088710078813078916078a19068c1b068d1d068e20068f2206902406912605912805922a05932c05942e05952f059631059733059735049837049938049a3a049a3c049b3e049c3f049c41049d43039e44039e46039f48039f4903a04b03a14c02a14e02a25002a25102a35302a35502a45601a45801a45901a55b01a55c01a65e01a66001a66100a76300a76400a76600a76700a86900a86a00a86c00a86e00a86f00a87100a87201a87401a87501a87701a87801a87a02a87b02a87d03a87e03a88004a88104a78305a78405a78606a68707a68808a68a09a58b0aa58d0ba58e0ca48f0da4910ea3920fa39410a29511a19613a19814a099159f9a169f9c179e9d189d9e199da01a9ca11b9ba21d9aa31e9aa51f99a62098a72197a82296aa2395ab2494ac2694ad2793ae2892b02991b12a90b22b8fb32c8eb42e8db52f8cb6308bb7318ab83289ba3388bb3488bc3587bd3786be3885bf3984c03a83c13b82c23c81c33d80c43e7fc5407ec6417dc7427cc8437bc9447aca457acb4679cc4778cc4977cd4a76ce4b75cf4c74d04d73d14e72d24f71d35171d45270d5536fd5546ed6556dd7566cd8576bd9586ada5a6ada5b69db5c68dc5d67dd5e66de5f65de6164df6263e06363e16462e26561e26660e3685fe4695ee56a5de56b5de66c5ce76e5be76f5ae87059e97158e97257ea7457eb7556eb7655ec7754ed7953ed7a52ee7b51ef7c51ef7e50f07f4ff0804ef1814df1834cf2844bf3854bf3874af48849f48948f58b47f58c46f68d45f68f44f79044f79143f79342f89441f89540f9973ff9983ef99a3efa9b3dfa9c3cfa9e3bfb9f3afba139fba238fca338fca537fca636fca835fca934fdab33fdac33fdae32fdaf31fdb130fdb22ffdb42ffdb52efeb72dfeb82cfeba2cfebb2bfebd2afebe2afec029fdc229fdc328fdc527fdc627fdc827fdca26fdcb26fccd25fcce25fcd025fcd225fbd324fbd524fbd724fad824fada24f9dc24f9dd25f8df25f8e125f7e225f7e425f6e626f6e826f5e926f5eb27f4ed27f3ee27f3f027f2f227f1f426f1f525f0f724f0f921")),ox=function(t){return ke(ne(t).call(document.documentElement))},sx=0;function cx(){return new ux}function ux(){this._="@"+(++sx).toString(36)}ux.prototype=cx.prototype={constructor:ux,get:function(t){for(var e=this._;!(e in t);)if(!(t=t.parentNode))return;return t[e]},set:function(t,e){return t[this._]=e},remove:function(t){return this._ in t&&delete t[this._]},toString:function(){return this._}};var lx=function(t){return"string"==typeof t?new be([document.querySelectorAll(t)],[document.documentElement]):new be([null==t?[]:t],me)},hx=function(t,e){null==e&&(e=Mn().touches);for(var n=0,r=e?e.length:0,i=new Array(r);n1?0:t<-1?xx:Math.acos(t)}function Ex(t){return t>=1?_x:t<=-1?-_x:Math.asin(t)}function Tx(t){return t.innerRadius}function Cx(t){return t.outerRadius}function Ax(t){return t.startAngle}function Sx(t){return t.endAngle}function Mx(t){return t&&t.padAngle}function Ox(t,e,n,r,i,a,o,s){var c=n-t,u=r-e,l=o-i,h=s-a,f=h*c-l*u;if(!(f*f<1e-12))return[t+(f=(l*(e-a)-h*(t-i))/f)*c,e+f*u]}function Dx(t,e,n,r,i,a,o){var s=t-n,c=e-r,u=(o?a:-a)/bx(s*s+c*c),l=u*c,h=-u*s,f=t+l,d=e+h,p=n+l,g=r+h,y=(f+p)/2,v=(d+g)/2,m=p-f,b=g-d,x=m*m+b*b,_=i-a,k=f*g-p*d,w=(b<0?-1:1)*bx(yx(0,_*_*x-k*k)),E=(k*b-m*w)/x,T=(-k*m-b*w)/x,C=(k*b+m*w)/x,A=(-k*m+b*w)/x,S=E-y,M=T-v,O=C-y,D=A-v;return S*S+M*M>O*O+D*D&&(E=C,T=A),{cx:E,cy:T,x01:-l,y01:-h,x11:E*(i/_-1),y11:T*(i/_-1)}}var Nx=function(){var t=Tx,e=Cx,n=fx(0),r=null,i=Ax,a=Sx,o=Mx,s=null;function c(){var c,u,l=+t.apply(this,arguments),h=+e.apply(this,arguments),f=i.apply(this,arguments)-_x,d=a.apply(this,arguments)-_x,p=dx(d-f),g=d>f;if(s||(s=c=Ui()),h1e-12)if(p>kx-1e-12)s.moveTo(h*gx(f),h*mx(f)),s.arc(0,0,h,f,d,!g),l>1e-12&&(s.moveTo(l*gx(d),l*mx(d)),s.arc(0,0,l,d,f,g));else{var y,v,m=f,b=d,x=f,_=d,k=p,w=p,E=o.apply(this,arguments)/2,T=E>1e-12&&(r?+r.apply(this,arguments):bx(l*l+h*h)),C=vx(dx(h-l)/2,+n.apply(this,arguments)),A=C,S=C;if(T>1e-12){var M=Ex(T/l*mx(E)),O=Ex(T/h*mx(E));(k-=2*M)>1e-12?(x+=M*=g?1:-1,_-=M):(k=0,x=_=(f+d)/2),(w-=2*O)>1e-12?(m+=O*=g?1:-1,b-=O):(w=0,m=b=(f+d)/2)}var D=h*gx(m),N=h*mx(m),B=l*gx(_),L=l*mx(_);if(C>1e-12){var F,P=h*gx(b),I=h*mx(b),j=l*gx(x),R=l*mx(x);if(p1e-12?S>1e-12?(y=Dx(j,R,D,N,h,S,g),v=Dx(P,I,B,L,h,S,g),s.moveTo(y.cx+y.x01,y.cy+y.y01),S1e-12&&k>1e-12?A>1e-12?(y=Dx(B,L,P,I,l,-A,g),v=Dx(D,N,j,R,l,-A,g),s.lineTo(y.cx+y.x01,y.cy+y.y01),A=l;--h)s.point(y[h],v[h]);s.lineEnd(),s.areaEnd()}g&&(y[u]=+t(f,u,c),v[u]=+n(f,u,c),s.point(e?+e(f,u,c):y[u],r?+r(f,u,c):v[u]))}if(d)return s=null,d+""||null}function u(){return Ix().defined(i).curve(o).context(a)}return c.x=function(n){return arguments.length?(t="function"==typeof n?n:fx(+n),e=null,c):t},c.x0=function(e){return arguments.length?(t="function"==typeof e?e:fx(+e),c):t},c.x1=function(t){return arguments.length?(e=null==t?null:"function"==typeof t?t:fx(+t),c):e},c.y=function(t){return arguments.length?(n="function"==typeof t?t:fx(+t),r=null,c):n},c.y0=function(t){return arguments.length?(n="function"==typeof t?t:fx(+t),c):n},c.y1=function(t){return arguments.length?(r=null==t?null:"function"==typeof t?t:fx(+t),c):r},c.lineX0=c.lineY0=function(){return u().x(t).y(n)},c.lineY1=function(){return u().x(t).y(r)},c.lineX1=function(){return u().x(e).y(n)},c.defined=function(t){return arguments.length?(i="function"==typeof t?t:fx(!!t),c):i},c.curve=function(t){return arguments.length?(o=t,null!=a&&(s=o(a)),c):o},c.context=function(t){return arguments.length?(null==t?a=s=null:s=o(a=t),c):a},c},Rx=function(t,e){return et?1:e>=t?0:NaN},Yx=function(t){return t},zx=function(){var t=Yx,e=Rx,n=null,r=fx(0),i=fx(kx),a=fx(0);function o(o){var s,c,u,l,h,f=o.length,d=0,p=new Array(f),g=new Array(f),y=+r.apply(this,arguments),v=Math.min(kx,Math.max(-kx,i.apply(this,arguments)-y)),m=Math.min(Math.abs(v)/f,a.apply(this,arguments)),b=m*(v<0?-1:1);for(s=0;s0&&(d+=h);for(null!=e?p.sort((function(t,n){return e(g[t],g[n])})):null!=n&&p.sort((function(t,e){return n(o[t],o[e])})),s=0,u=d?(v-f*b)/d:0;s0?h*u:0)+b,g[c]={data:o[c],index:s,value:h,startAngle:y,endAngle:l,padAngle:m};return g}return o.value=function(e){return arguments.length?(t="function"==typeof e?e:fx(+e),o):t},o.sortValues=function(t){return arguments.length?(e=t,n=null,o):e},o.sort=function(t){return arguments.length?(n=t,e=null,o):n},o.startAngle=function(t){return arguments.length?(r="function"==typeof t?t:fx(+t),o):r},o.endAngle=function(t){return arguments.length?(i="function"==typeof t?t:fx(+t),o):i},o.padAngle=function(t){return arguments.length?(a="function"==typeof t?t:fx(+t),o):a},o},Ux=Wx(Lx);function $x(t){this._curve=t}function Wx(t){function e(e){return new $x(t(e))}return e._curve=t,e}function Hx(t){var e=t.curve;return t.angle=t.x,delete t.x,t.radius=t.y,delete t.y,t.curve=function(t){return arguments.length?e(Wx(t)):e()._curve},t}$x.prototype={areaStart:function(){this._curve.areaStart()},areaEnd:function(){this._curve.areaEnd()},lineStart:function(){this._curve.lineStart()},lineEnd:function(){this._curve.lineEnd()},point:function(t,e){this._curve.point(e*Math.sin(t),e*-Math.cos(t))}};var Vx=function(){return Hx(Ix().curve(Ux))},Gx=function(){var t=jx().curve(Ux),e=t.curve,n=t.lineX0,r=t.lineX1,i=t.lineY0,a=t.lineY1;return t.angle=t.x,delete t.x,t.startAngle=t.x0,delete t.x0,t.endAngle=t.x1,delete t.x1,t.radius=t.y,delete t.y,t.innerRadius=t.y0,delete t.y0,t.outerRadius=t.y1,delete t.y1,t.lineStartAngle=function(){return Hx(n())},delete t.lineX0,t.lineEndAngle=function(){return Hx(r())},delete t.lineX1,t.lineInnerRadius=function(){return Hx(i())},delete t.lineY0,t.lineOuterRadius=function(){return Hx(a())},delete t.lineY1,t.curve=function(t){return arguments.length?e(Wx(t)):e()._curve},t},qx=function(t,e){return[(e=+e)*Math.cos(t-=Math.PI/2),e*Math.sin(t)]},Xx=Array.prototype.slice;function Zx(t){return t.source}function Jx(t){return t.target}function Kx(t){var e=Zx,n=Jx,r=Fx,i=Px,a=null;function o(){var o,s=Xx.call(arguments),c=e.apply(this,s),u=n.apply(this,s);if(a||(a=o=Ui()),t(a,+r.apply(this,(s[0]=c,s)),+i.apply(this,s),+r.apply(this,(s[0]=u,s)),+i.apply(this,s)),o)return a=null,o+""||null}return o.source=function(t){return arguments.length?(e=t,o):e},o.target=function(t){return arguments.length?(n=t,o):n},o.x=function(t){return arguments.length?(r="function"==typeof t?t:fx(+t),o):r},o.y=function(t){return arguments.length?(i="function"==typeof t?t:fx(+t),o):i},o.context=function(t){return arguments.length?(a=null==t?null:t,o):a},o}function Qx(t,e,n,r,i){t.moveTo(e,n),t.bezierCurveTo(e=(e+r)/2,n,e,i,r,i)}function t_(t,e,n,r,i){t.moveTo(e,n),t.bezierCurveTo(e,n=(n+i)/2,r,n,r,i)}function e_(t,e,n,r,i){var a=qx(e,n),o=qx(e,n=(n+i)/2),s=qx(r,n),c=qx(r,i);t.moveTo(a[0],a[1]),t.bezierCurveTo(o[0],o[1],s[0],s[1],c[0],c[1])}function n_(){return Kx(Qx)}function r_(){return Kx(t_)}function i_(){var t=Kx(e_);return t.angle=t.x,delete t.x,t.radius=t.y,delete t.y,t}var a_={draw:function(t,e){var n=Math.sqrt(e/xx);t.moveTo(n,0),t.arc(0,0,n,0,kx)}},o_={draw:function(t,e){var n=Math.sqrt(e/5)/2;t.moveTo(-3*n,-n),t.lineTo(-n,-n),t.lineTo(-n,-3*n),t.lineTo(n,-3*n),t.lineTo(n,-n),t.lineTo(3*n,-n),t.lineTo(3*n,n),t.lineTo(n,n),t.lineTo(n,3*n),t.lineTo(-n,3*n),t.lineTo(-n,n),t.lineTo(-3*n,n),t.closePath()}},s_=Math.sqrt(1/3),c_=2*s_,u_={draw:function(t,e){var n=Math.sqrt(e/c_),r=n*s_;t.moveTo(0,-n),t.lineTo(r,0),t.lineTo(0,n),t.lineTo(-r,0),t.closePath()}},l_=Math.sin(xx/10)/Math.sin(7*xx/10),h_=Math.sin(kx/10)*l_,f_=-Math.cos(kx/10)*l_,d_={draw:function(t,e){var n=Math.sqrt(.8908130915292852*e),r=h_*n,i=f_*n;t.moveTo(0,-n),t.lineTo(r,i);for(var a=1;a<5;++a){var o=kx*a/5,s=Math.cos(o),c=Math.sin(o);t.lineTo(c*n,-s*n),t.lineTo(s*r-c*i,c*r+s*i)}t.closePath()}},p_={draw:function(t,e){var n=Math.sqrt(e),r=-n/2;t.rect(r,r,n,n)}},g_=Math.sqrt(3),y_={draw:function(t,e){var n=-Math.sqrt(e/(3*g_));t.moveTo(0,2*n),t.lineTo(-g_*n,-n),t.lineTo(g_*n,-n),t.closePath()}},v_=Math.sqrt(3)/2,m_=1/Math.sqrt(12),b_=3*(m_/2+1),x_={draw:function(t,e){var n=Math.sqrt(e/b_),r=n/2,i=n*m_,a=r,o=n*m_+n,s=-a,c=o;t.moveTo(r,i),t.lineTo(a,o),t.lineTo(s,c),t.lineTo(-.5*r-v_*i,v_*r+-.5*i),t.lineTo(-.5*a-v_*o,v_*a+-.5*o),t.lineTo(-.5*s-v_*c,v_*s+-.5*c),t.lineTo(-.5*r+v_*i,-.5*i-v_*r),t.lineTo(-.5*a+v_*o,-.5*o-v_*a),t.lineTo(-.5*s+v_*c,-.5*c-v_*s),t.closePath()}},__=[a_,o_,u_,p_,d_,y_,x_],k_=function(){var t=fx(a_),e=fx(64),n=null;function r(){var r;if(n||(n=r=Ui()),t.apply(this,arguments).draw(n,+e.apply(this,arguments)),r)return n=null,r+""||null}return r.type=function(e){return arguments.length?(t="function"==typeof e?e:fx(e),r):t},r.size=function(t){return arguments.length?(e="function"==typeof t?t:fx(+t),r):e},r.context=function(t){return arguments.length?(n=null==t?null:t,r):n},r},w_=function(){};function E_(t,e,n){t._context.bezierCurveTo((2*t._x0+t._x1)/3,(2*t._y0+t._y1)/3,(t._x0+2*t._x1)/3,(t._y0+2*t._y1)/3,(t._x0+4*t._x1+e)/6,(t._y0+4*t._y1+n)/6)}function T_(t){this._context=t}T_.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){switch(this._point){case 3:E_(this,this._x1,this._y1);case 2:this._context.lineTo(this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,e):this._context.moveTo(t,e);break;case 1:this._point=2;break;case 2:this._point=3,this._context.lineTo((5*this._x0+this._x1)/6,(5*this._y0+this._y1)/6);default:E_(this,t,e)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=e}};var C_=function(t){return new T_(t)};function A_(t){this._context=t}A_.prototype={areaStart:w_,areaEnd:w_,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._y0=this._y1=this._y2=this._y3=this._y4=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x2,this._y2),this._context.closePath();break;case 2:this._context.moveTo((this._x2+2*this._x3)/3,(this._y2+2*this._y3)/3),this._context.lineTo((this._x3+2*this._x2)/3,(this._y3+2*this._y2)/3),this._context.closePath();break;case 3:this.point(this._x2,this._y2),this.point(this._x3,this._y3),this.point(this._x4,this._y4)}},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1,this._x2=t,this._y2=e;break;case 1:this._point=2,this._x3=t,this._y3=e;break;case 2:this._point=3,this._x4=t,this._y4=e,this._context.moveTo((this._x0+4*this._x1+t)/6,(this._y0+4*this._y1+e)/6);break;default:E_(this,t,e)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=e}};var S_=function(t){return new A_(t)};function M_(t){this._context=t}M_.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3;var n=(this._x0+4*this._x1+t)/6,r=(this._y0+4*this._y1+e)/6;this._line?this._context.lineTo(n,r):this._context.moveTo(n,r);break;case 3:this._point=4;default:E_(this,t,e)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=e}};var O_=function(t){return new M_(t)};function D_(t,e){this._basis=new T_(t),this._beta=e}D_.prototype={lineStart:function(){this._x=[],this._y=[],this._basis.lineStart()},lineEnd:function(){var t=this._x,e=this._y,n=t.length-1;if(n>0)for(var r,i=t[0],a=e[0],o=t[n]-i,s=e[n]-a,c=-1;++c<=n;)r=c/n,this._basis.point(this._beta*t[c]+(1-this._beta)*(i+r*o),this._beta*e[c]+(1-this._beta)*(a+r*s));this._x=this._y=null,this._basis.lineEnd()},point:function(t,e){this._x.push(+t),this._y.push(+e)}};var N_=function t(e){function n(t){return 1===e?new T_(t):new D_(t,e)}return n.beta=function(e){return t(+e)},n}(.85);function B_(t,e,n){t._context.bezierCurveTo(t._x1+t._k*(t._x2-t._x0),t._y1+t._k*(t._y2-t._y0),t._x2+t._k*(t._x1-e),t._y2+t._k*(t._y1-n),t._x2,t._y2)}function L_(t,e){this._context=t,this._k=(1-e)/6}L_.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:B_(this,this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,e):this._context.moveTo(t,e);break;case 1:this._point=2,this._x1=t,this._y1=e;break;case 2:this._point=3;default:B_(this,t,e)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e}};var F_=function t(e){function n(t){return new L_(t,e)}return n.tension=function(e){return t(+e)},n}(0);function P_(t,e){this._context=t,this._k=(1-e)/6}P_.prototype={areaStart:w_,areaEnd:w_,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1,this._x3=t,this._y3=e;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=e);break;case 2:this._point=3,this._x5=t,this._y5=e;break;default:B_(this,t,e)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e}};var I_=function t(e){function n(t){return new P_(t,e)}return n.tension=function(e){return t(+e)},n}(0);function j_(t,e){this._context=t,this._k=(1-e)/6}j_.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:B_(this,t,e)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e}};var R_=function t(e){function n(t){return new j_(t,e)}return n.tension=function(e){return t(+e)},n}(0);function Y_(t,e,n){var r=t._x1,i=t._y1,a=t._x2,o=t._y2;if(t._l01_a>1e-12){var s=2*t._l01_2a+3*t._l01_a*t._l12_a+t._l12_2a,c=3*t._l01_a*(t._l01_a+t._l12_a);r=(r*s-t._x0*t._l12_2a+t._x2*t._l01_2a)/c,i=(i*s-t._y0*t._l12_2a+t._y2*t._l01_2a)/c}if(t._l23_a>1e-12){var u=2*t._l23_2a+3*t._l23_a*t._l12_a+t._l12_2a,l=3*t._l23_a*(t._l23_a+t._l12_a);a=(a*u+t._x1*t._l23_2a-e*t._l12_2a)/l,o=(o*u+t._y1*t._l23_2a-n*t._l12_2a)/l}t._context.bezierCurveTo(r,i,a,o,t._x2,t._y2)}function z_(t,e){this._context=t,this._alpha=e}z_.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:this.point(this._x2,this._y2)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){if(t=+t,e=+e,this._point){var n=this._x2-t,r=this._y2-e;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(n*n+r*r,this._alpha))}switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,e):this._context.moveTo(t,e);break;case 1:this._point=2;break;case 2:this._point=3;default:Y_(this,t,e)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e}};var U_=function t(e){function n(t){return e?new z_(t,e):new L_(t,0)}return n.alpha=function(e){return t(+e)},n}(.5);function $_(t,e){this._context=t,this._alpha=e}$_.prototype={areaStart:w_,areaEnd:w_,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,e){if(t=+t,e=+e,this._point){var n=this._x2-t,r=this._y2-e;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(n*n+r*r,this._alpha))}switch(this._point){case 0:this._point=1,this._x3=t,this._y3=e;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=e);break;case 2:this._point=3,this._x5=t,this._y5=e;break;default:Y_(this,t,e)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e}};var W_=function t(e){function n(t){return e?new $_(t,e):new P_(t,0)}return n.alpha=function(e){return t(+e)},n}(.5);function H_(t,e){this._context=t,this._alpha=e}H_.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){if(t=+t,e=+e,this._point){var n=this._x2-t,r=this._y2-e;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(n*n+r*r,this._alpha))}switch(this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:Y_(this,t,e)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e}};var V_=function t(e){function n(t){return e?new H_(t,e):new j_(t,0)}return n.alpha=function(e){return t(+e)},n}(.5);function G_(t){this._context=t}G_.prototype={areaStart:w_,areaEnd:w_,lineStart:function(){this._point=0},lineEnd:function(){this._point&&this._context.closePath()},point:function(t,e){t=+t,e=+e,this._point?this._context.lineTo(t,e):(this._point=1,this._context.moveTo(t,e))}};var q_=function(t){return new G_(t)};function X_(t){return t<0?-1:1}function Z_(t,e,n){var r=t._x1-t._x0,i=e-t._x1,a=(t._y1-t._y0)/(r||i<0&&-0),o=(n-t._y1)/(i||r<0&&-0),s=(a*i+o*r)/(r+i);return(X_(a)+X_(o))*Math.min(Math.abs(a),Math.abs(o),.5*Math.abs(s))||0}function J_(t,e){var n=t._x1-t._x0;return n?(3*(t._y1-t._y0)/n-e)/2:e}function K_(t,e,n){var r=t._x0,i=t._y0,a=t._x1,o=t._y1,s=(a-r)/3;t._context.bezierCurveTo(r+s,i+s*e,a-s,o-s*n,a,o)}function Q_(t){this._context=t}function tk(t){this._context=new ek(t)}function ek(t){this._context=t}function nk(t){return new Q_(t)}function rk(t){return new tk(t)}function ik(t){this._context=t}function ak(t){var e,n,r=t.length-1,i=new Array(r),a=new Array(r),o=new Array(r);for(i[0]=0,a[0]=2,o[0]=t[0]+2*t[1],e=1;e=0;--e)i[e]=(o[e]-i[e+1])/a[e];for(a[r-1]=(t[r]+i[r-1])/2,e=0;e=0&&(this._t=1-this._t,this._line=1-this._line)},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,e):this._context.moveTo(t,e);break;case 1:this._point=2;default:if(this._t<=0)this._context.lineTo(this._x,e),this._context.lineTo(t,e);else{var n=this._x*(1-this._t)+t*this._t;this._context.lineTo(n,this._y),this._context.lineTo(n,e)}}this._x=t,this._y=e}};var ck=function(t){return new sk(t,.5)};function uk(t){return new sk(t,0)}function lk(t){return new sk(t,1)}var hk=function(t,e){if((i=t.length)>1)for(var n,r,i,a=1,o=t[e[0]],s=o.length;a=0;)n[e]=e;return n};function dk(t,e){return t[e]}var pk=function(){var t=fx([]),e=fk,n=hk,r=dk;function i(i){var a,o,s=t.apply(this,arguments),c=i.length,u=s.length,l=new Array(u);for(a=0;a0){for(var n,r,i,a=0,o=t[0].length;a0)for(var n,r,i,a,o,s,c=0,u=t[e[0]].length;c0?(r[0]=a,r[1]=a+=i):i<0?(r[1]=o,r[0]=o+=i):(r[0]=0,r[1]=i)},vk=function(t,e){if((n=t.length)>0){for(var n,r=0,i=t[e[0]],a=i.length;r0&&(r=(n=t[e[0]]).length)>0){for(var n,r,i,a=0,o=1;oa&&(a=e,r=n);return r}var _k=function(t){var e=t.map(kk);return fk(t).sort((function(t,n){return e[t]-e[n]}))};function kk(t){for(var e,n=0,r=-1,i=t.length;++r0)){if(a/=f,f<0){if(a0){if(a>h)return;a>l&&(l=a)}if(a=r-c,f||!(a<0)){if(a/=f,f<0){if(a>h)return;a>l&&(l=a)}else if(f>0){if(a0)){if(a/=d,d<0){if(a0){if(a>h)return;a>l&&(l=a)}if(a=i-u,d||!(a<0)){if(a/=d,d<0){if(a>h)return;a>l&&(l=a)}else if(d>0){if(a0||h<1)||(l>0&&(t[0]=[c+l*f,u+l*d]),h<1&&(t[1]=[c+h*f,u+h*d]),!0)}}}}}function Uk(t,e,n,r,i){var a=t[1];if(a)return!0;var o,s,c=t[0],u=t.left,l=t.right,h=u[0],f=u[1],d=l[0],p=l[1],g=(h+d)/2,y=(f+p)/2;if(p===f){if(g=r)return;if(h>d){if(c){if(c[1]>=i)return}else c=[g,n];a=[g,i]}else{if(c){if(c[1]1)if(h>d){if(c){if(c[1]>=i)return}else c=[(n-s)/o,n];a=[(i-s)/o,i]}else{if(c){if(c[1]=r)return}else c=[e,o*e+s];a=[r,o*r+s]}else{if(c){if(c[0]=-lw)){var d=c*c+u*u,p=l*l+h*h,g=(h*d-u*p)/f,y=(c*p-l*d)/f,v=Gk.pop()||new qk;v.arc=t,v.site=i,v.x=g+o,v.y=(v.cy=y+s)+Math.sqrt(g*g+y*y),t.circle=v;for(var m=null,b=sw._;b;)if(v.yuw)s=s.L;else{if(!((i=a-iw(s,o))>uw)){r>-uw?(e=s.P,n=s):i>-uw?(e=s,n=s.N):e=n=s;break}if(!s.R){e=s;break}s=s.R}!function(t){ow[t.index]={site:t,halfedges:[]}}(t);var c=Qk(t);if(aw.insert(e,c),e||n){if(e===n)return Zk(e),n=Qk(e.site),aw.insert(c,n),c.edge=n.edge=jk(e.site,c.site),Xk(e),void Xk(n);if(n){Zk(e),Zk(n);var u=e.site,l=u[0],h=u[1],f=t[0]-l,d=t[1]-h,p=n.site,g=p[0]-l,y=p[1]-h,v=2*(f*y-d*g),m=f*f+d*d,b=g*g+y*y,x=[(y*m-d*b)/v+l,(f*b-g*m)/v+h];Yk(n.edge,u,p,x),c.edge=jk(u,t,null,x),n.edge=jk(t,p,null,x),Xk(e),Xk(n)}else c.edge=jk(e.site,c.site)}}function rw(t,e){var n=t.site,r=n[0],i=n[1],a=i-e;if(!a)return r;var o=t.P;if(!o)return-1/0;var s=(n=o.site)[0],c=n[1],u=c-e;if(!u)return s;var l=s-r,h=1/a-1/u,f=l/u;return h?(-f+Math.sqrt(f*f-2*h*(l*l/(-2*u)-c+u/2+i-a/2)))/h+r:(r+s)/2}function iw(t,e){var n=t.N;if(n)return rw(n,e);var r=t.site;return r[1]===e?r[0]:1/0}var aw,ow,sw,cw,uw=1e-6,lw=1e-12;function hw(t,e){return e[1]-t[1]||e[0]-t[0]}function fw(t,e){var n,r,i,a=t.sort(hw).pop();for(cw=[],ow=new Array(t.length),aw=new Ik,sw=new Ik;;)if(i=Vk,a&&(!i||a[1]uw||Math.abs(i[0][1]-i[1][1])>uw)||delete cw[a]}(o,s,c,u),function(t,e,n,r){var i,a,o,s,c,u,l,h,f,d,p,g,y=ow.length,v=!0;for(i=0;iuw||Math.abs(g-f)>uw)&&(c.splice(s,0,cw.push(Rk(o,d,Math.abs(p-t)uw?[t,Math.abs(h-t)uw?[Math.abs(f-r)uw?[n,Math.abs(h-n)uw?[Math.abs(f-e)=s)return null;var c=t-i.site[0],u=e-i.site[1],l=c*c+u*u;do{i=a.cells[r=o],o=null,i.halfedges.forEach((function(n){var r=a.edges[n],s=r.left;if(s!==i.site&&s||(s=r.right)){var c=t-s[0],u=e-s[1],h=c*c+u*u;hr?(r+i)/2:Math.min(0,r)||Math.max(0,i),o>a?(a+o)/2:Math.min(0,a)||Math.max(0,o))}var Aw=function(){var t,e,n=_w,r=kw,i=Cw,a=Ew,o=Tw,s=[0,1/0],c=[[-1/0,-1/0],[1/0,1/0]],u=250,l=fp,h=lt("start","zoom","end"),f=0;function d(t){t.property("__zoom",ww).on("wheel.zoom",x).on("mousedown.zoom",_).on("dblclick.zoom",k).filter(o).on("touchstart.zoom",w).on("touchmove.zoom",E).on("touchend.zoom touchcancel.zoom",T).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function p(t,e){return(e=Math.max(s[0],Math.min(s[1],e)))===t.k?t:new yw(e,t.x,t.y)}function g(t,e,n){var r=e[0]-n[0]*t.k,i=e[1]-n[1]*t.k;return r===t.x&&i===t.y?t:new yw(t.k,r,i)}function y(t){return[(+t[0][0]+ +t[1][0])/2,(+t[0][1]+ +t[1][1])/2]}function v(t,e,n){t.on("start.zoom",(function(){m(this,arguments).start()})).on("interrupt.zoom end.zoom",(function(){m(this,arguments).end()})).tween("zoom",(function(){var t=this,i=arguments,a=m(t,i),o=r.apply(t,i),s=null==n?y(o):"function"==typeof n?n.apply(t,i):n,c=Math.max(o[1][0]-o[0][0],o[1][1]-o[0][1]),u=t.__zoom,h="function"==typeof e?e.apply(t,i):e,f=l(u.invert(s).concat(c/u.k),h.invert(s).concat(c/h.k));return function(t){if(1===t)t=h;else{var e=f(t),n=c/e[2];t=new yw(n,s[0]-e[0]*n,s[1]-e[1]*n)}a.zoom(null,t)}}))}function m(t,e,n){return!n&&t.__zooming||new b(t,e)}function b(t,e){this.that=t,this.args=e,this.active=0,this.extent=r.apply(t,e),this.taps=0}function x(){if(n.apply(this,arguments)){var t=m(this,arguments),e=this.__zoom,r=Math.max(s[0],Math.min(s[1],e.k*Math.pow(2,a.apply(this,arguments)))),o=Nn(this);if(t.wheel)t.mouse[0][0]===o[0]&&t.mouse[0][1]===o[1]||(t.mouse[1]=e.invert(t.mouse[0]=o)),clearTimeout(t.wheel);else{if(e.k===r)return;t.mouse=[o,e.invert(o)],or(this),t.start()}xw(),t.wheel=setTimeout(u,150),t.zoom("mouse",i(g(p(e,r),t.mouse[0],t.mouse[1]),t.extent,c))}function u(){t.wheel=null,t.end()}}function _(){if(!e&&n.apply(this,arguments)){var t=m(this,arguments,!0),r=ke(ce.view).on("mousemove.zoom",u,!0).on("mouseup.zoom",l,!0),a=Nn(this),o=ce.clientX,s=ce.clientY;Te(ce.view),bw(),t.mouse=[a,this.__zoom.invert(a)],or(this),t.start()}function u(){if(xw(),!t.moved){var e=ce.clientX-o,n=ce.clientY-s;t.moved=e*e+n*n>f}t.zoom("mouse",i(g(t.that.__zoom,t.mouse[0]=Nn(t.that),t.mouse[1]),t.extent,c))}function l(){r.on("mousemove.zoom mouseup.zoom",null),Ce(ce.view,t.moved),xw(),t.end()}}function k(){if(n.apply(this,arguments)){var t=this.__zoom,e=Nn(this),a=t.invert(e),o=t.k*(ce.shiftKey?.5:2),s=i(g(p(t,o),e,a),r.apply(this,arguments),c);xw(),u>0?ke(this).transition().duration(u).call(v,s,e):ke(this).call(d.transform,s)}}function w(){if(n.apply(this,arguments)){var e,r,i,a,o=ce.touches,s=o.length,c=m(this,arguments,ce.changedTouches.length===s);for(bw(),r=0;rh&&S.push("'"+this.terminals_[T]+"'");O=p.showPosition?"Parse error on line "+(c+1)+":\n"+p.showPosition()+"\nExpecting "+S.join(", ")+", got '"+(this.terminals_[x]||x)+"'":"Parse error on line "+(c+1)+": Unexpected "+(x==f?"end of input":"'"+(this.terminals_[x]||x)+"'"),this.parseError(O,{text:p.match,token:this.terminals_[x]||x,line:p.yylineno,loc:v,expected:S})}if(w[0]instanceof Array&&w.length>1)throw new Error("Parse Error: multiple actions possible at state: "+k+", token: "+x);switch(w[0]){case 1:n.push(x),i.push(p.yytext),a.push(p.yylloc),n.push(w[1]),x=null,_?(x=_,_=null):(u=p.yyleng,s=p.yytext,c=p.yylineno,v=p.yylloc,l>0&&l--);break;case 2:if(C=this.productions_[w[1]][1],M.$=i[i.length-C],M._$={first_line:a[a.length-(C||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-(C||1)].first_column,last_column:a[a.length-1].last_column},m&&(M._$.range=[a[a.length-(C||1)].range[0],a[a.length-1].range[1]]),void 0!==(E=this.performAction.apply(M,[s,u,c,g.yy,w[1],i,a].concat(d))))return E;C&&(n=n.slice(0,-1*C*2),i=i.slice(0,-1*C),a=a.slice(0,-1*C)),n.push(this.productions_[w[1]][0]),i.push(M.$),a.push(M._$),A=o[n[n.length-2]][n[n.length-1]],n.push(A);break;case 3:return!0}}return!0}},M={EOF:1,parseError:function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)},setInput:function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t},unput:function(t){var e=t.length,n=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var r=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var i=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===r.length?this.yylloc.first_column:0)+r[r.length-n.length].length-n[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[i[0],i[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},less:function(t){this.unput(this.match.slice(t))},pastInput:function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"},test_match:function(t,e){var n,r,i;if(this.options.backtrack_lexer&&(i={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(i.yylloc.range=this.yylloc.range.slice(0))),(r=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=r.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:r?r[r.length-1].length-r[r.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],n=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),n)return n;if(this._backtrack){for(var a in i)this[a]=i[a];return!1}return!1},next:function(){if(this.done)return this.EOF;var t,e,n,r;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var i=this._currentRules(),a=0;ae[0].length)){if(e=n,r=a,this.options.backtrack_lexer){if(!1!==(t=this.test_match(n,i[a])))return t;if(this._backtrack){e=!1;continue}return!1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,i[r]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){var t=this.next();return t||this.lex()},begin:function(t){this.conditionStack.push(t)},popState:function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(t){return(t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"},pushState:function(t){this.begin(t)},stateStackSize:function(){return this.conditionStack.length},options:{"case-insensitive":!0},performAction:function(t,e,n,r){switch(n){case 0:return this.begin("open_directive"),56;case 1:return this.begin("type_directive"),57;case 2:return this.popState(),this.begin("arg_directive"),14;case 3:return this.popState(),this.popState(),59;case 4:return 58;case 5:return 5;case 6:case 7:case 8:case 9:case 10:break;case 11:return this.begin("ID"),16;case 12:return e.yytext=e.yytext.trim(),this.begin("ALIAS"),48;case 13:return this.popState(),this.popState(),this.begin("LINE"),18;case 14:return this.popState(),this.popState(),5;case 15:return this.begin("LINE"),27;case 16:return this.begin("LINE"),29;case 17:return this.begin("LINE"),30;case 18:return this.begin("LINE"),31;case 19:return this.begin("LINE"),36;case 20:return this.begin("LINE"),33;case 21:return this.begin("LINE"),35;case 22:return this.popState(),19;case 23:return 28;case 24:return 43;case 25:return 44;case 26:return 39;case 27:return 37;case 28:return this.begin("ID"),22;case 29:return this.begin("ID"),23;case 30:return 25;case 31:return 7;case 32:return 21;case 33:return 42;case 34:return 5;case 35:return e.yytext=e.yytext.trim(),48;case 36:return 51;case 37:return 52;case 38:return 49;case 39:return 50;case 40:return 53;case 41:return 54;case 42:return 55;case 43:return 46;case 44:return 47;case 45:return 5;case 46:return"INVALID"}},rules:[/^(?:%%\{)/i,/^(?:((?:(?!\}%%)[^:.])*))/i,/^(?::)/i,/^(?:\}%%)/i,/^(?:((?:(?!\}%%).|\n)*))/i,/^(?:[\n]+)/i,/^(?:\s+)/i,/^(?:((?!\n)\s)+)/i,/^(?:#[^\n]*)/i,/^(?:%(?!\{)[^\n]*)/i,/^(?:[^\}]%%[^\n]*)/i,/^(?:participant\b)/i,/^(?:[^\->:\n,;]+?(?=((?!\n)\s)+as(?!\n)\s|[#\n;]|$))/i,/^(?:as\b)/i,/^(?:(?:))/i,/^(?:loop\b)/i,/^(?:rect\b)/i,/^(?:opt\b)/i,/^(?:alt\b)/i,/^(?:else\b)/i,/^(?:par\b)/i,/^(?:and\b)/i,/^(?:(?:[:]?(?:no)?wrap)?[^#\n;]*)/i,/^(?:end\b)/i,/^(?:left of\b)/i,/^(?:right of\b)/i,/^(?:over\b)/i,/^(?:note\b)/i,/^(?:activate\b)/i,/^(?:deactivate\b)/i,/^(?:title\b)/i,/^(?:sequenceDiagram\b)/i,/^(?:autonumber\b)/i,/^(?:,)/i,/^(?:;)/i,/^(?:[^\+\->:\n,;]+((?!(-x|--x))[\-]*[^\+\->:\n,;]+)*)/i,/^(?:->>)/i,/^(?:-->>)/i,/^(?:->)/i,/^(?:-->)/i,/^(?:-[x])/i,/^(?:--[x])/i,/^(?::(?:(?:no)?wrap)?[^#\n;]+)/i,/^(?:\+)/i,/^(?:-)/i,/^(?:$)/i,/^(?:.)/i],conditions:{open_directive:{rules:[1,8],inclusive:!1},type_directive:{rules:[2,3,8],inclusive:!1},arg_directive:{rules:[3,4,8],inclusive:!1},ID:{rules:[7,8,12],inclusive:!1},ALIAS:{rules:[7,8,13,14],inclusive:!1},LINE:{rules:[7,8,22],inclusive:!1},INITIAL:{rules:[0,5,6,8,9,10,11,15,16,17,18,19,20,21,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46],inclusive:!0}}};function O(){this.yy={}}return S.lexer=M,O.prototype=S,S.Parser=O,new O}();e.parser=i,e.Parser=i.Parser,e.parse=function(){return i.parse.apply(i,arguments)},e.main=function(r){r[1]||(console.log("Usage: "+r[0]+" FILE"),t.exit(1));var i=n(19).readFileSync(n(20).normalize(r[1]),"utf8");return e.parser.parse(i)},n.c[n.s]===r&&e.main(t.argv.slice(1))}).call(this,n(14),n(7)(t))},function(t,e,n){var r=n(198);t.exports={Graph:r.Graph,json:n(301),alg:n(302),version:r.version}},function(t,e,n){var r;try{r={cloneDeep:n(313),constant:n(86),defaults:n(154),each:n(87),filter:n(128),find:n(314),flatten:n(156),forEach:n(126),forIn:n(319),has:n(93),isUndefined:n(139),last:n(320),map:n(140),mapValues:n(321),max:n(322),merge:n(324),min:n(329),minBy:n(330),now:n(331),pick:n(161),range:n(162),reduce:n(142),sortBy:n(338),uniqueId:n(163),values:n(147),zipObject:n(343)}}catch(t){}r||(r=window._),t.exports=r},function(t,e){var n=Array.isArray;t.exports=n},function(t,e,n){ +/** + * @license + * Copyright (c) 2012-2013 Chris Pettitt + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +t.exports={graphlib:n(311),dagre:n(153),intersect:n(368),render:n(370),util:n(12),version:n(382)}},function(t,e){t.exports=function(t){return t.webpackPolyfill||(t.deprecate=function(){},t.paths=[],t.children||(t.children=[]),Object.defineProperty(t,"loaded",{enumerable:!0,get:function(){return t.l}}),Object.defineProperty(t,"id",{enumerable:!0,get:function(){return t.i}}),t.webpackPolyfill=1),t}},function(t,e,n){"use strict";var r=n(4),i=n(17).Graph;function a(t,e,n,i){var a;do{a=r.uniqueId(i)}while(t.hasNode(a));return n.dummy=e,t.setNode(a,n),a}function o(t){return r.max(r.map(t.nodes(),(function(e){var n=t.node(e).rank;if(!r.isUndefined(n))return n})))}t.exports={addDummyNode:a,simplify:function(t){var e=(new i).setGraph(t.graph());return r.forEach(t.nodes(),(function(n){e.setNode(n,t.node(n))})),r.forEach(t.edges(),(function(n){var r=e.edge(n.v,n.w)||{weight:0,minlen:1},i=t.edge(n);e.setEdge(n.v,n.w,{weight:r.weight+i.weight,minlen:Math.max(r.minlen,i.minlen)})})),e},asNonCompoundGraph:function(t){var e=new i({multigraph:t.isMultigraph()}).setGraph(t.graph());return r.forEach(t.nodes(),(function(n){t.children(n).length||e.setNode(n,t.node(n))})),r.forEach(t.edges(),(function(n){e.setEdge(n,t.edge(n))})),e},successorWeights:function(t){var e=r.map(t.nodes(),(function(e){var n={};return r.forEach(t.outEdges(e),(function(e){n[e.w]=(n[e.w]||0)+t.edge(e).weight})),n}));return r.zipObject(t.nodes(),e)},predecessorWeights:function(t){var e=r.map(t.nodes(),(function(e){var n={};return r.forEach(t.inEdges(e),(function(e){n[e.v]=(n[e.v]||0)+t.edge(e).weight})),n}));return r.zipObject(t.nodes(),e)},intersectRect:function(t,e){var n,r,i=t.x,a=t.y,o=e.x-i,s=e.y-a,c=t.width/2,u=t.height/2;if(!o&&!s)throw new Error("Not possible to find intersection inside of the rectangle");Math.abs(s)*c>Math.abs(o)*u?(s<0&&(u=-u),n=u*o/s,r=u):(o<0&&(c=-c),n=c,r=c*s/o);return{x:i+n,y:a+r}},buildLayerMatrix:function(t){var e=r.map(r.range(o(t)+1),(function(){return[]}));return r.forEach(t.nodes(),(function(n){var i=t.node(n),a=i.rank;r.isUndefined(a)||(e[a][i.order]=n)})),e},normalizeRanks:function(t){var e=r.min(r.map(t.nodes(),(function(e){return t.node(e).rank})));r.forEach(t.nodes(),(function(n){var i=t.node(n);r.has(i,"rank")&&(i.rank-=e)}))},removeEmptyRanks:function(t){var e=r.min(r.map(t.nodes(),(function(e){return t.node(e).rank}))),n=[];r.forEach(t.nodes(),(function(r){var i=t.node(r).rank-e;n[i]||(n[i]=[]),n[i].push(r)}));var i=0,a=t.graph().nodeRankFactor;r.forEach(n,(function(e,n){r.isUndefined(e)&&n%a!=0?--i:i&&r.forEach(e,(function(e){t.node(e).rank+=i}))}))},addBorderNode:function(t,e,n,r){var i={width:0,height:0};arguments.length>=4&&(i.rank=n,i.order=r);return a(t,"border",i,e)},maxRank:o,partition:function(t,e){var n={lhs:[],rhs:[]};return r.forEach(t,(function(t){e(t)?n.lhs.push(t):n.rhs.push(t)})),n},time:function(t,e){var n=r.now();try{return e()}finally{console.log(t+" time: "+(r.now()-n)+"ms")}},notime:function(t,e){return e()}}},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=n(173),i=n(174),a=n(175),o={channel:r.default,lang:i.default,unit:a.default};e.default=o},function(t,e,n){var r;try{r={clone:n(199),constant:n(86),each:n(87),filter:n(128),has:n(93),isArray:n(5),isEmpty:n(276),isFunction:n(37),isUndefined:n(139),keys:n(30),map:n(140),reduce:n(142),size:n(279),transform:n(285),union:n(286),values:n(147)}}catch(t){}r||(r=window._),t.exports=r},function(t,e){t.exports=function(t){var e=typeof t;return null!=t&&("object"==e||"function"==e)}},function(t,e,n){var r=n(43);t.exports={isSubgraph:function(t,e){return!!t.children(e).length},edgeToId:function(t){return a(t.v)+":"+a(t.w)+":"+a(t.name)},applyStyle:function(t,e){e&&t.attr("style",e)},applyClass:function(t,e,n){e&&t.attr("class",e).attr("class",n+" "+t.attr("class"))},applyTransition:function(t,e){var n=e.graph();if(r.isPlainObject(n)){var i=n.transition;if(r.isFunction(i))return i(t)}return t}};var i=/:/g;function a(t){return t?String(t).replace(i,"\\:"):""}},function(t,e,n){(function(t,r){var i=function(){var t=function(t,e,n,r){for(n=n||{},r=t.length;r--;n[t[r]]=e);return n},e=[1,7],n=[1,6],r=[1,14],i=[1,25],a=[1,28],o=[1,26],s=[1,27],c=[1,29],u=[1,30],l=[1,31],h=[1,32],f=[1,34],d=[1,35],p=[1,36],g=[10,19],y=[1,48],v=[1,49],m=[1,50],b=[1,51],x=[1,52],_=[1,53],k=[10,19,25,32,33,41,44,45,46,47,48,49,54,56],w=[10,19,23,25,32,33,37,41,44,45,46,47,48,49,54,56,71,72,73],E=[10,13,17,19],T=[41,71,72,73],C=[41,48,49,71,72,73],A=[41,44,45,46,47,71,72,73],S=[10,19,25],M=[1,85],O={trace:function(){},yy:{},symbols_:{error:2,start:3,mermaidDoc:4,directive:5,graphConfig:6,openDirective:7,typeDirective:8,closeDirective:9,NEWLINE:10,":":11,argDirective:12,open_directive:13,type_directive:14,arg_directive:15,close_directive:16,CLASS_DIAGRAM:17,statements:18,EOF:19,statement:20,className:21,alphaNumToken:22,GENERICTYPE:23,relationStatement:24,LABEL:25,classStatement:26,methodStatement:27,annotationStatement:28,clickStatement:29,cssClassStatement:30,CLASS:31,STYLE_SEPARATOR:32,STRUCT_START:33,members:34,STRUCT_STOP:35,ANNOTATION_START:36,ANNOTATION_END:37,MEMBER:38,SEPARATOR:39,relation:40,STR:41,relationType:42,lineType:43,AGGREGATION:44,EXTENSION:45,COMPOSITION:46,DEPENDENCY:47,LINE:48,DOTTED_LINE:49,CALLBACK:50,LINK:51,LINK_TARGET:52,CLICK:53,CALLBACK_NAME:54,CALLBACK_ARGS:55,HREF:56,CSSCLASS:57,commentToken:58,textToken:59,graphCodeTokens:60,textNoTagsToken:61,TAGSTART:62,TAGEND:63,"==":64,"--":65,PCT:66,DEFAULT:67,SPACE:68,MINUS:69,keywords:70,UNICODE_TEXT:71,NUM:72,ALPHA:73,$accept:0,$end:1},terminals_:{2:"error",10:"NEWLINE",11:":",13:"open_directive",14:"type_directive",15:"arg_directive",16:"close_directive",17:"CLASS_DIAGRAM",19:"EOF",23:"GENERICTYPE",25:"LABEL",31:"CLASS",32:"STYLE_SEPARATOR",33:"STRUCT_START",35:"STRUCT_STOP",36:"ANNOTATION_START",37:"ANNOTATION_END",38:"MEMBER",39:"SEPARATOR",41:"STR",44:"AGGREGATION",45:"EXTENSION",46:"COMPOSITION",47:"DEPENDENCY",48:"LINE",49:"DOTTED_LINE",50:"CALLBACK",51:"LINK",52:"LINK_TARGET",53:"CLICK",54:"CALLBACK_NAME",55:"CALLBACK_ARGS",56:"HREF",57:"CSSCLASS",60:"graphCodeTokens",62:"TAGSTART",63:"TAGEND",64:"==",65:"--",66:"PCT",67:"DEFAULT",68:"SPACE",69:"MINUS",70:"keywords",71:"UNICODE_TEXT",72:"NUM",73:"ALPHA"},productions_:[0,[3,1],[3,2],[4,1],[5,4],[5,6],[7,1],[8,1],[12,1],[9,1],[6,4],[18,1],[18,2],[18,3],[21,1],[21,2],[21,3],[21,2],[20,1],[20,2],[20,1],[20,1],[20,1],[20,1],[20,1],[20,1],[26,2],[26,4],[26,5],[26,7],[28,4],[34,1],[34,2],[27,1],[27,2],[27,1],[27,1],[24,3],[24,4],[24,4],[24,5],[40,3],[40,2],[40,2],[40,1],[42,1],[42,1],[42,1],[42,1],[43,1],[43,1],[29,3],[29,4],[29,3],[29,4],[29,4],[29,5],[29,3],[29,4],[29,4],[29,5],[29,3],[29,4],[29,4],[29,5],[30,3],[58,1],[58,1],[59,1],[59,1],[59,1],[59,1],[59,1],[59,1],[59,1],[61,1],[61,1],[61,1],[61,1],[22,1],[22,1],[22,1]],performAction:function(t,e,n,r,i,a,o){var s=a.length-1;switch(i){case 6:r.parseDirective("%%{","open_directive");break;case 7:r.parseDirective(a[s],"type_directive");break;case 8:a[s]=a[s].trim().replace(/'/g,'"'),r.parseDirective(a[s],"arg_directive");break;case 9:r.parseDirective("}%%","close_directive","class");break;case 14:this.$=a[s];break;case 15:this.$=a[s-1]+a[s];break;case 16:this.$=a[s-2]+"~"+a[s-1]+a[s];break;case 17:this.$=a[s-1]+"~"+a[s];break;case 18:r.addRelation(a[s]);break;case 19:a[s-1].title=r.cleanupLabel(a[s]),r.addRelation(a[s-1]);break;case 26:r.addClass(a[s]);break;case 27:r.addClass(a[s-2]),r.setCssClass(a[s-2],a[s]);break;case 28:r.addClass(a[s-3]),r.addMembers(a[s-3],a[s-1]);break;case 29:r.addClass(a[s-5]),r.setCssClass(a[s-5],a[s-3]),r.addMembers(a[s-5],a[s-1]);break;case 30:r.addAnnotation(a[s],a[s-2]);break;case 31:this.$=[a[s]];break;case 32:a[s].push(a[s-1]),this.$=a[s];break;case 33:break;case 34:r.addMember(a[s-1],r.cleanupLabel(a[s]));break;case 35:case 36:break;case 37:this.$={id1:a[s-2],id2:a[s],relation:a[s-1],relationTitle1:"none",relationTitle2:"none"};break;case 38:this.$={id1:a[s-3],id2:a[s],relation:a[s-1],relationTitle1:a[s-2],relationTitle2:"none"};break;case 39:this.$={id1:a[s-3],id2:a[s],relation:a[s-2],relationTitle1:"none",relationTitle2:a[s-1]};break;case 40:this.$={id1:a[s-4],id2:a[s],relation:a[s-2],relationTitle1:a[s-3],relationTitle2:a[s-1]};break;case 41:this.$={type1:a[s-2],type2:a[s],lineType:a[s-1]};break;case 42:this.$={type1:"none",type2:a[s],lineType:a[s-1]};break;case 43:this.$={type1:a[s-1],type2:"none",lineType:a[s]};break;case 44:this.$={type1:"none",type2:"none",lineType:a[s]};break;case 45:this.$=r.relationType.AGGREGATION;break;case 46:this.$=r.relationType.EXTENSION;break;case 47:this.$=r.relationType.COMPOSITION;break;case 48:this.$=r.relationType.DEPENDENCY;break;case 49:this.$=r.lineType.LINE;break;case 50:this.$=r.lineType.DOTTED_LINE;break;case 51:case 57:this.$=a[s-2],r.setClickEvent(a[s-1],a[s]);break;case 52:case 58:this.$=a[s-3],r.setClickEvent(a[s-2],a[s-1]),r.setTooltip(a[s-2],a[s]);break;case 53:case 61:this.$=a[s-2],r.setLink(a[s-1],a[s]);break;case 54:this.$=a[s-3],r.setLink(a[s-2],a[s-1],a[s]);break;case 55:case 63:this.$=a[s-3],r.setLink(a[s-2],a[s-1]),r.setTooltip(a[s-2],a[s]);break;case 56:case 64:this.$=a[s-4],r.setLink(a[s-3],a[s-2],a[s]),r.setTooltip(a[s-3],a[s-1]);break;case 59:this.$=a[s-3],r.setClickEvent(a[s-2],a[s-1],a[s]);break;case 60:this.$=a[s-4],r.setClickEvent(a[s-3],a[s-2],a[s-1]),r.setTooltip(a[s-3],a[s]);break;case 62:this.$=a[s-3],r.setLink(a[s-2],a[s-1],a[s]);break;case 65:r.setCssClass(a[s-1],a[s])}},table:[{3:1,4:2,5:3,6:4,7:5,13:e,17:n},{1:[3]},{1:[2,1]},{3:8,4:2,5:3,6:4,7:5,13:e,17:n},{1:[2,3]},{8:9,14:[1,10]},{10:[1,11]},{14:[2,6]},{1:[2,2]},{9:12,11:[1,13],16:r},t([11,16],[2,7]),{5:23,7:5,13:e,18:15,20:16,21:24,22:33,24:17,26:18,27:19,28:20,29:21,30:22,31:i,36:a,38:o,39:s,50:c,51:u,53:l,57:h,71:f,72:d,73:p},{10:[1,37]},{12:38,15:[1,39]},{10:[2,9]},{19:[1,40]},{10:[1,41],19:[2,11]},t(g,[2,18],{25:[1,42]}),t(g,[2,20]),t(g,[2,21]),t(g,[2,22]),t(g,[2,23]),t(g,[2,24]),t(g,[2,25]),t(g,[2,33],{40:43,42:46,43:47,25:[1,45],41:[1,44],44:y,45:v,46:m,47:b,48:x,49:_}),{21:54,22:33,71:f,72:d,73:p},t(g,[2,35]),t(g,[2,36]),{22:55,71:f,72:d,73:p},{21:56,22:33,71:f,72:d,73:p},{21:57,22:33,71:f,72:d,73:p},{21:58,22:33,71:f,72:d,73:p},{41:[1,59]},t(k,[2,14],{22:33,21:60,23:[1,61],71:f,72:d,73:p}),t(w,[2,79]),t(w,[2,80]),t(w,[2,81]),t(E,[2,4]),{9:62,16:r},{16:[2,8]},{1:[2,10]},{5:23,7:5,13:e,18:63,19:[2,12],20:16,21:24,22:33,24:17,26:18,27:19,28:20,29:21,30:22,31:i,36:a,38:o,39:s,50:c,51:u,53:l,57:h,71:f,72:d,73:p},t(g,[2,19]),{21:64,22:33,41:[1,65],71:f,72:d,73:p},{40:66,42:46,43:47,44:y,45:v,46:m,47:b,48:x,49:_},t(g,[2,34]),{43:67,48:x,49:_},t(T,[2,44],{42:68,44:y,45:v,46:m,47:b}),t(C,[2,45]),t(C,[2,46]),t(C,[2,47]),t(C,[2,48]),t(A,[2,49]),t(A,[2,50]),t(g,[2,26],{32:[1,69],33:[1,70]}),{37:[1,71]},{41:[1,72]},{41:[1,73]},{54:[1,74],56:[1,75]},{22:76,71:f,72:d,73:p},t(k,[2,15]),t(k,[2,17],{22:33,21:77,71:f,72:d,73:p}),{10:[1,78]},{19:[2,13]},t(S,[2,37]),{21:79,22:33,71:f,72:d,73:p},{21:80,22:33,41:[1,81],71:f,72:d,73:p},t(T,[2,43],{42:82,44:y,45:v,46:m,47:b}),t(T,[2,42]),{22:83,71:f,72:d,73:p},{34:84,38:M},{21:86,22:33,71:f,72:d,73:p},t(g,[2,51],{41:[1,87]}),t(g,[2,53],{41:[1,89],52:[1,88]}),t(g,[2,57],{41:[1,90],55:[1,91]}),t(g,[2,61],{41:[1,93],52:[1,92]}),t(g,[2,65]),t(k,[2,16]),t(E,[2,5]),t(S,[2,39]),t(S,[2,38]),{21:94,22:33,71:f,72:d,73:p},t(T,[2,41]),t(g,[2,27],{33:[1,95]}),{35:[1,96]},{34:97,35:[2,31],38:M},t(g,[2,30]),t(g,[2,52]),t(g,[2,54]),t(g,[2,55],{52:[1,98]}),t(g,[2,58]),t(g,[2,59],{41:[1,99]}),t(g,[2,62]),t(g,[2,63],{52:[1,100]}),t(S,[2,40]),{34:101,38:M},t(g,[2,28]),{35:[2,32]},t(g,[2,56]),t(g,[2,60]),t(g,[2,64]),{35:[1,102]},t(g,[2,29])],defaultActions:{2:[2,1],4:[2,3],7:[2,6],8:[2,2],14:[2,9],39:[2,8],40:[2,10],63:[2,13],97:[2,32]},parseError:function(t,e){if(!e.recoverable){var n=new Error(t);throw n.hash=e,n}this.trace(t)},parse:function(t){var e=this,n=[0],r=[],i=[null],a=[],o=this.table,s="",c=0,u=0,l=0,h=2,f=1,d=a.slice.call(arguments,1),p=Object.create(this.lexer),g={yy:{}};for(var y in this.yy)Object.prototype.hasOwnProperty.call(this.yy,y)&&(g.yy[y]=this.yy[y]);p.setInput(t,g.yy),g.yy.lexer=p,g.yy.parser=this,void 0===p.yylloc&&(p.yylloc={});var v=p.yylloc;a.push(v);var m=p.options&&p.options.ranges;function b(){var t;return"number"!=typeof(t=r.pop()||p.lex()||f)&&(t instanceof Array&&(t=(r=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof g.yy.parseError?this.parseError=g.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;for(var x,_,k,w,E,T,C,A,S,M={};;){if(k=n[n.length-1],this.defaultActions[k]?w=this.defaultActions[k]:(null==x&&(x=b()),w=o[k]&&o[k][x]),void 0===w||!w.length||!w[0]){var O="";for(T in S=[],o[k])this.terminals_[T]&&T>h&&S.push("'"+this.terminals_[T]+"'");O=p.showPosition?"Parse error on line "+(c+1)+":\n"+p.showPosition()+"\nExpecting "+S.join(", ")+", got '"+(this.terminals_[x]||x)+"'":"Parse error on line "+(c+1)+": Unexpected "+(x==f?"end of input":"'"+(this.terminals_[x]||x)+"'"),this.parseError(O,{text:p.match,token:this.terminals_[x]||x,line:p.yylineno,loc:v,expected:S})}if(w[0]instanceof Array&&w.length>1)throw new Error("Parse Error: multiple actions possible at state: "+k+", token: "+x);switch(w[0]){case 1:n.push(x),i.push(p.yytext),a.push(p.yylloc),n.push(w[1]),x=null,_?(x=_,_=null):(u=p.yyleng,s=p.yytext,c=p.yylineno,v=p.yylloc,l>0&&l--);break;case 2:if(C=this.productions_[w[1]][1],M.$=i[i.length-C],M._$={first_line:a[a.length-(C||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-(C||1)].first_column,last_column:a[a.length-1].last_column},m&&(M._$.range=[a[a.length-(C||1)].range[0],a[a.length-1].range[1]]),void 0!==(E=this.performAction.apply(M,[s,u,c,g.yy,w[1],i,a].concat(d))))return E;C&&(n=n.slice(0,-1*C*2),i=i.slice(0,-1*C),a=a.slice(0,-1*C)),n.push(this.productions_[w[1]][0]),i.push(M.$),a.push(M._$),A=o[n[n.length-2]][n[n.length-1]],n.push(A);break;case 3:return!0}}return!0}},D={EOF:1,parseError:function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)},setInput:function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t},unput:function(t){var e=t.length,n=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var r=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var i=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===r.length?this.yylloc.first_column:0)+r[r.length-n.length].length-n[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[i[0],i[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},less:function(t){this.unput(this.match.slice(t))},pastInput:function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"},test_match:function(t,e){var n,r,i;if(this.options.backtrack_lexer&&(i={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(i.yylloc.range=this.yylloc.range.slice(0))),(r=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=r.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:r?r[r.length-1].length-r[r.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],n=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),n)return n;if(this._backtrack){for(var a in i)this[a]=i[a];return!1}return!1},next:function(){if(this.done)return this.EOF;var t,e,n,r;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var i=this._currentRules(),a=0;ae[0].length)){if(e=n,r=a,this.options.backtrack_lexer){if(!1!==(t=this.test_match(n,i[a])))return t;if(this._backtrack){e=!1;continue}return!1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,i[r]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){var t=this.next();return t||this.lex()},begin:function(t){this.conditionStack.push(t)},popState:function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(t){return(t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"},pushState:function(t){this.begin(t)},stateStackSize:function(){return this.conditionStack.length},options:{},performAction:function(t,e,n,r){switch(n){case 0:return this.begin("open_directive"),13;case 1:return this.begin("type_directive"),14;case 2:return this.popState(),this.begin("arg_directive"),11;case 3:return this.popState(),this.popState(),16;case 4:return 15;case 5:case 6:break;case 7:return 10;case 8:break;case 9:case 10:return 17;case 11:return this.begin("struct"),33;case 12:return"EOF_IN_STRUCT";case 13:return"OPEN_IN_STRUCT";case 14:return this.popState(),35;case 15:break;case 16:return"MEMBER";case 17:return 31;case 18:return 57;case 19:return 50;case 20:return 51;case 21:return 53;case 22:return 36;case 23:return 37;case 24:this.begin("generic");break;case 25:this.popState();break;case 26:return"GENERICTYPE";case 27:this.begin("string");break;case 28:this.popState();break;case 29:return"STR";case 30:this.begin("href");break;case 31:this.popState();break;case 32:return 56;case 33:this.begin("callback_name");break;case 34:this.popState();break;case 35:this.popState(),this.begin("callback_args");break;case 36:return 54;case 37:this.popState();break;case 38:return 55;case 39:case 40:case 41:case 42:return 52;case 43:case 44:return 45;case 45:case 46:return 47;case 47:return 46;case 48:return 44;case 49:return 48;case 50:return 49;case 51:return 25;case 52:return 32;case 53:return 69;case 54:return"DOT";case 55:return"PLUS";case 56:return 66;case 57:case 58:return"EQUALS";case 59:return 73;case 60:return"PUNCTUATION";case 61:return 72;case 62:return 71;case 63:return 68;case 64:return 19}},rules:[/^(?:%%\{)/,/^(?:((?:(?!\}%%)[^:.])*))/,/^(?::)/,/^(?:\}%%)/,/^(?:((?:(?!\}%%).|\n)*))/,/^(?:%%(?!\{)*[^\n]*(\r?\n?)+)/,/^(?:%%[^\n]*(\r?\n)*)/,/^(?:(\r?\n)+)/,/^(?:\s+)/,/^(?:classDiagram-v2\b)/,/^(?:classDiagram\b)/,/^(?:[{])/,/^(?:$)/,/^(?:[{])/,/^(?:[}])/,/^(?:[\n])/,/^(?:[^{}\n]*)/,/^(?:class\b)/,/^(?:cssClass\b)/,/^(?:callback\b)/,/^(?:link\b)/,/^(?:click\b)/,/^(?:<<)/,/^(?:>>)/,/^(?:[~])/,/^(?:[~])/,/^(?:[^~]*)/,/^(?:["])/,/^(?:["])/,/^(?:[^"]*)/,/^(?:href[\s]+["])/,/^(?:["])/,/^(?:[^"]*)/,/^(?:call[\s]+)/,/^(?:\([\s]*\))/,/^(?:\()/,/^(?:[^(]*)/,/^(?:\))/,/^(?:[^)]*)/,/^(?:_self\b)/,/^(?:_blank\b)/,/^(?:_parent\b)/,/^(?:_top\b)/,/^(?:\s*<\|)/,/^(?:\s*\|>)/,/^(?:\s*>)/,/^(?:\s*<)/,/^(?:\s*\*)/,/^(?:\s*o\b)/,/^(?:--)/,/^(?:\.\.)/,/^(?::{1}[^:\n;]+)/,/^(?::{3})/,/^(?:-)/,/^(?:\.)/,/^(?:\+)/,/^(?:%)/,/^(?:=)/,/^(?:=)/,/^(?:\w+)/,/^(?:[!"#$%&'*+,-.`?\\/])/,/^(?:[0-9]+)/,/^(?:[\u00AA\u00B5\u00BA\u00C0-\u00D6\u00D8-\u00F6]|[\u00F8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377]|[\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5]|[\u03F7-\u0481\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA]|[\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE]|[\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA]|[\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0]|[\u08A2-\u08AC\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0977]|[\u0979-\u097F\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2]|[\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A]|[\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39]|[\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8]|[\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C]|[\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C]|[\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99]|[\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0]|[\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D]|[\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3]|[\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10]|[\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1]|[\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81]|[\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3]|[\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6]|[\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A]|[\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081]|[\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D]|[\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0]|[\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310]|[\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C]|[\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u1700-\u170C\u170E-\u1711]|[\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7]|[\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191C]|[\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16]|[\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF]|[\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC]|[\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D]|[\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D]|[\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3]|[\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F]|[\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128]|[\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184]|[\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3]|[\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6]|[\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE]|[\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C]|[\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D]|[\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC]|[\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B]|[\uA640-\uA66E\uA67F-\uA697\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788]|[\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA801\uA803-\uA805]|[\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB]|[\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uAA00-\uAA28]|[\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA80-\uAAAF\uAAB1\uAAB5]|[\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4]|[\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E]|[\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D]|[\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36]|[\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D]|[\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC]|[\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF]|[\uFFD2-\uFFD7\uFFDA-\uFFDC])/,/^(?:\s)/,/^(?:$)/],conditions:{arg_directive:{rules:[3,4],inclusive:!1},type_directive:{rules:[2,3],inclusive:!1},open_directive:{rules:[1],inclusive:!1},callback_args:{rules:[37,38],inclusive:!1},callback_name:{rules:[34,35,36],inclusive:!1},href:{rules:[31,32],inclusive:!1},struct:{rules:[12,13,14,15,16],inclusive:!1},generic:{rules:[25,26],inclusive:!1},string:{rules:[28,29],inclusive:!1},INITIAL:{rules:[0,5,6,7,8,9,10,11,17,18,19,20,21,22,23,24,27,30,33,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64],inclusive:!0}}};function N(){this.yy={}}return O.lexer=D,N.prototype=O,O.Parser=N,new N}();e.parser=i,e.Parser=i.Parser,e.parse=function(){return i.parse.apply(i,arguments)},e.main=function(r){r[1]||(console.log("Usage: "+r[0]+" FILE"),t.exit(1));var i=n(19).readFileSync(n(20).normalize(r[1]),"utf8");return e.parser.parse(i)},n.c[n.s]===r&&e.main(t.argv.slice(1))}).call(this,n(14),n(7)(t))},function(t,e){var n,r,i=t.exports={};function a(){throw new Error("setTimeout has not been defined")}function o(){throw new Error("clearTimeout has not been defined")}function s(t){if(n===setTimeout)return setTimeout(t,0);if((n===a||!n)&&setTimeout)return n=setTimeout,setTimeout(t,0);try{return n(t,0)}catch(e){try{return n.call(null,t,0)}catch(e){return n.call(this,t,0)}}}!function(){try{n="function"==typeof setTimeout?setTimeout:a}catch(t){n=a}try{r="function"==typeof clearTimeout?clearTimeout:o}catch(t){r=o}}();var c,u=[],l=!1,h=-1;function f(){l&&c&&(l=!1,c.length?u=c.concat(u):h=-1,u.length&&d())}function d(){if(!l){var t=s(f);l=!0;for(var e=u.length;e;){for(c=u,u=[];++h1)for(var n=1;n=0;r--){var i=t[r];"."===i?t.splice(r,1):".."===i?(t.splice(r,1),n++):n&&(t.splice(r,1),n--)}if(e)for(;n--;n)t.unshift("..");return t}function r(t,e){if(t.filter)return t.filter(e);for(var n=[],r=0;r=-1&&!i;a--){var o=a>=0?arguments[a]:t.cwd();if("string"!=typeof o)throw new TypeError("Arguments to path.resolve must be strings");o&&(e=o+"/"+e,i="/"===o.charAt(0))}return(i?"/":"")+(e=n(r(e.split("/"),(function(t){return!!t})),!i).join("/"))||"."},e.normalize=function(t){var a=e.isAbsolute(t),o="/"===i(t,-1);return(t=n(r(t.split("/"),(function(t){return!!t})),!a).join("/"))||a||(t="."),t&&o&&(t+="/"),(a?"/":"")+t},e.isAbsolute=function(t){return"/"===t.charAt(0)},e.join=function(){var t=Array.prototype.slice.call(arguments,0);return e.normalize(r(t,(function(t,e){if("string"!=typeof t)throw new TypeError("Arguments to path.join must be strings");return t})).join("/"))},e.relative=function(t,n){function r(t){for(var e=0;e=0&&""===t[n];n--);return e>n?[]:t.slice(e,n-e+1)}t=e.resolve(t).substr(1),n=e.resolve(n).substr(1);for(var i=r(t.split("/")),a=r(n.split("/")),o=Math.min(i.length,a.length),s=o,c=0;c=1;--a)if(47===(e=t.charCodeAt(a))){if(!i){r=a;break}}else i=!1;return-1===r?n?"/":".":n&&1===r?"/":t.slice(0,r)},e.basename=function(t,e){var n=function(t){"string"!=typeof t&&(t+="");var e,n=0,r=-1,i=!0;for(e=t.length-1;e>=0;--e)if(47===t.charCodeAt(e)){if(!i){n=e+1;break}}else-1===r&&(i=!1,r=e+1);return-1===r?"":t.slice(n,r)}(t);return e&&n.substr(-1*e.length)===e&&(n=n.substr(0,n.length-e.length)),n},e.extname=function(t){"string"!=typeof t&&(t+="");for(var e=-1,n=0,r=-1,i=!0,a=0,o=t.length-1;o>=0;--o){var s=t.charCodeAt(o);if(47!==s)-1===r&&(i=!1,r=o+1),46===s?-1===e?e=o:1!==a&&(a=1):-1!==e&&(a=-1);else if(!i){n=o+1;break}}return-1===e||-1===r||0===a||1===a&&e===r-1&&e===n+1?"":t.slice(e,r)};var i="b"==="ab".substr(-1)?function(t,e,n){return t.substr(e,n)}:function(t,e,n){return e<0&&(e=t.length+e),t.substr(e,n)}}).call(this,n(14))},function(t,e){t.exports=function(t){return null!=t&&"object"==typeof t}},function(t,e,n){(function(t,r){var i=function(){var t=function(t,e,n,r){for(n=n||{},r=t.length;r--;n[t[r]]=e);return n},e=[1,2],n=[1,3],r=[1,5],i=[1,7],a=[2,5],o=[1,15],s=[1,17],c=[1,19],u=[1,20],l=[1,21],h=[1,22],f=[1,28],d=[1,23],p=[1,24],g=[1,25],y=[1,26],v=[1,29],m=[1,32],b=[1,4,5,14,15,17,19,20,22,23,24,25,26,36,39],x=[1,4,5,12,13,14,15,17,19,20,22,23,24,25,26,36,39],_=[1,4,5,7,14,15,17,19,20,22,23,24,25,26,36,39],k=[4,5,14,15,17,19,20,22,23,24,25,26,36,39],w={trace:function(){},yy:{},symbols_:{error:2,start:3,SPACE:4,NL:5,directive:6,SD:7,document:8,line:9,statement:10,idStatement:11,DESCR:12,"--\x3e":13,HIDE_EMPTY:14,scale:15,WIDTH:16,COMPOSIT_STATE:17,STRUCT_START:18,STRUCT_STOP:19,STATE_DESCR:20,AS:21,ID:22,FORK:23,JOIN:24,CONCURRENT:25,note:26,notePosition:27,NOTE_TEXT:28,openDirective:29,typeDirective:30,closeDirective:31,":":32,argDirective:33,eol:34,";":35,EDGE_STATE:36,left_of:37,right_of:38,open_directive:39,type_directive:40,arg_directive:41,close_directive:42,$accept:0,$end:1},terminals_:{2:"error",4:"SPACE",5:"NL",7:"SD",12:"DESCR",13:"--\x3e",14:"HIDE_EMPTY",15:"scale",16:"WIDTH",17:"COMPOSIT_STATE",18:"STRUCT_START",19:"STRUCT_STOP",20:"STATE_DESCR",21:"AS",22:"ID",23:"FORK",24:"JOIN",25:"CONCURRENT",26:"note",28:"NOTE_TEXT",32:":",35:";",36:"EDGE_STATE",37:"left_of",38:"right_of",39:"open_directive",40:"type_directive",41:"arg_directive",42:"close_directive"},productions_:[0,[3,2],[3,2],[3,2],[3,2],[8,0],[8,2],[9,2],[9,1],[9,1],[10,1],[10,2],[10,3],[10,4],[10,1],[10,2],[10,1],[10,4],[10,3],[10,6],[10,1],[10,1],[10,1],[10,4],[10,4],[10,1],[6,3],[6,5],[34,1],[34,1],[11,1],[11,1],[27,1],[27,1],[29,1],[30,1],[33,1],[31,1]],performAction:function(t,e,n,r,i,a,o){var s=a.length-1;switch(i){case 4:return r.setRootDoc(a[s]),a[s];case 5:this.$=[];break;case 6:"nl"!=a[s]&&(a[s-1].push(a[s]),this.$=a[s-1]);break;case 7:case 8:this.$=a[s];break;case 9:this.$="nl";break;case 10:this.$={stmt:"state",id:a[s],type:"default",description:""};break;case 11:this.$={stmt:"state",id:a[s-1],type:"default",description:r.trimColon(a[s])};break;case 12:this.$={stmt:"relation",state1:{stmt:"state",id:a[s-2],type:"default",description:""},state2:{stmt:"state",id:a[s],type:"default",description:""}};break;case 13:this.$={stmt:"relation",state1:{stmt:"state",id:a[s-3],type:"default",description:""},state2:{stmt:"state",id:a[s-1],type:"default",description:""},description:a[s].substr(1).trim()};break;case 17:this.$={stmt:"state",id:a[s-3],type:"default",description:"",doc:a[s-1]};break;case 18:var c=a[s],u=a[s-2].trim();if(a[s].match(":")){var l=a[s].split(":");c=l[0],u=[u,l[1]]}this.$={stmt:"state",id:c,type:"default",description:u};break;case 19:this.$={stmt:"state",id:a[s-3],type:"default",description:a[s-5],doc:a[s-1]};break;case 20:this.$={stmt:"state",id:a[s],type:"fork"};break;case 21:this.$={stmt:"state",id:a[s],type:"join"};break;case 22:this.$={stmt:"state",id:r.getDividerId(),type:"divider"};break;case 23:this.$={stmt:"state",id:a[s-1].trim(),note:{position:a[s-2].trim(),text:a[s].trim()}};break;case 30:case 31:this.$=a[s];break;case 34:r.parseDirective("%%{","open_directive");break;case 35:r.parseDirective(a[s],"type_directive");break;case 36:a[s]=a[s].trim().replace(/'/g,'"'),r.parseDirective(a[s],"arg_directive");break;case 37:r.parseDirective("}%%","close_directive","state")}},table:[{3:1,4:e,5:n,6:4,7:r,29:6,39:i},{1:[3]},{3:8,4:e,5:n,6:4,7:r,29:6,39:i},{3:9,4:e,5:n,6:4,7:r,29:6,39:i},{3:10,4:e,5:n,6:4,7:r,29:6,39:i},t([1,4,5,14,15,17,20,22,23,24,25,26,36,39],a,{8:11}),{30:12,40:[1,13]},{40:[2,34]},{1:[2,1]},{1:[2,2]},{1:[2,3]},{1:[2,4],4:o,5:s,6:27,9:14,10:16,11:18,14:c,15:u,17:l,20:h,22:f,23:d,24:p,25:g,26:y,29:6,36:v,39:i},{31:30,32:[1,31],42:m},t([32,42],[2,35]),t(b,[2,6]),{6:27,10:33,11:18,14:c,15:u,17:l,20:h,22:f,23:d,24:p,25:g,26:y,29:6,36:v,39:i},t(b,[2,8]),t(b,[2,9]),t(b,[2,10],{12:[1,34],13:[1,35]}),t(b,[2,14]),{16:[1,36]},t(b,[2,16],{18:[1,37]}),{21:[1,38]},t(b,[2,20]),t(b,[2,21]),t(b,[2,22]),{27:39,28:[1,40],37:[1,41],38:[1,42]},t(b,[2,25]),t(x,[2,30]),t(x,[2,31]),t(_,[2,26]),{33:43,41:[1,44]},t(_,[2,37]),t(b,[2,7]),t(b,[2,11]),{11:45,22:f,36:v},t(b,[2,15]),t(k,a,{8:46}),{22:[1,47]},{22:[1,48]},{21:[1,49]},{22:[2,32]},{22:[2,33]},{31:50,42:m},{42:[2,36]},t(b,[2,12],{12:[1,51]}),{4:o,5:s,6:27,9:14,10:16,11:18,14:c,15:u,17:l,19:[1,52],20:h,22:f,23:d,24:p,25:g,26:y,29:6,36:v,39:i},t(b,[2,18],{18:[1,53]}),{28:[1,54]},{22:[1,55]},t(_,[2,27]),t(b,[2,13]),t(b,[2,17]),t(k,a,{8:56}),t(b,[2,23]),t(b,[2,24]),{4:o,5:s,6:27,9:14,10:16,11:18,14:c,15:u,17:l,19:[1,57],20:h,22:f,23:d,24:p,25:g,26:y,29:6,36:v,39:i},t(b,[2,19])],defaultActions:{7:[2,34],8:[2,1],9:[2,2],10:[2,3],41:[2,32],42:[2,33],44:[2,36]},parseError:function(t,e){if(!e.recoverable){var n=new Error(t);throw n.hash=e,n}this.trace(t)},parse:function(t){var e=this,n=[0],r=[],i=[null],a=[],o=this.table,s="",c=0,u=0,l=0,h=2,f=1,d=a.slice.call(arguments,1),p=Object.create(this.lexer),g={yy:{}};for(var y in this.yy)Object.prototype.hasOwnProperty.call(this.yy,y)&&(g.yy[y]=this.yy[y]);p.setInput(t,g.yy),g.yy.lexer=p,g.yy.parser=this,void 0===p.yylloc&&(p.yylloc={});var v=p.yylloc;a.push(v);var m=p.options&&p.options.ranges;function b(){var t;return"number"!=typeof(t=r.pop()||p.lex()||f)&&(t instanceof Array&&(t=(r=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof g.yy.parseError?this.parseError=g.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;for(var x,_,k,w,E,T,C,A,S,M={};;){if(k=n[n.length-1],this.defaultActions[k]?w=this.defaultActions[k]:(null==x&&(x=b()),w=o[k]&&o[k][x]),void 0===w||!w.length||!w[0]){var O="";for(T in S=[],o[k])this.terminals_[T]&&T>h&&S.push("'"+this.terminals_[T]+"'");O=p.showPosition?"Parse error on line "+(c+1)+":\n"+p.showPosition()+"\nExpecting "+S.join(", ")+", got '"+(this.terminals_[x]||x)+"'":"Parse error on line "+(c+1)+": Unexpected "+(x==f?"end of input":"'"+(this.terminals_[x]||x)+"'"),this.parseError(O,{text:p.match,token:this.terminals_[x]||x,line:p.yylineno,loc:v,expected:S})}if(w[0]instanceof Array&&w.length>1)throw new Error("Parse Error: multiple actions possible at state: "+k+", token: "+x);switch(w[0]){case 1:n.push(x),i.push(p.yytext),a.push(p.yylloc),n.push(w[1]),x=null,_?(x=_,_=null):(u=p.yyleng,s=p.yytext,c=p.yylineno,v=p.yylloc,l>0&&l--);break;case 2:if(C=this.productions_[w[1]][1],M.$=i[i.length-C],M._$={first_line:a[a.length-(C||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-(C||1)].first_column,last_column:a[a.length-1].last_column},m&&(M._$.range=[a[a.length-(C||1)].range[0],a[a.length-1].range[1]]),void 0!==(E=this.performAction.apply(M,[s,u,c,g.yy,w[1],i,a].concat(d))))return E;C&&(n=n.slice(0,-1*C*2),i=i.slice(0,-1*C),a=a.slice(0,-1*C)),n.push(this.productions_[w[1]][0]),i.push(M.$),a.push(M._$),A=o[n[n.length-2]][n[n.length-1]],n.push(A);break;case 3:return!0}}return!0}},E={EOF:1,parseError:function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)},setInput:function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t},unput:function(t){var e=t.length,n=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var r=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var i=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===r.length?this.yylloc.first_column:0)+r[r.length-n.length].length-n[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[i[0],i[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},less:function(t){this.unput(this.match.slice(t))},pastInput:function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"},test_match:function(t,e){var n,r,i;if(this.options.backtrack_lexer&&(i={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(i.yylloc.range=this.yylloc.range.slice(0))),(r=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=r.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:r?r[r.length-1].length-r[r.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],n=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),n)return n;if(this._backtrack){for(var a in i)this[a]=i[a];return!1}return!1},next:function(){if(this.done)return this.EOF;var t,e,n,r;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var i=this._currentRules(),a=0;ae[0].length)){if(e=n,r=a,this.options.backtrack_lexer){if(!1!==(t=this.test_match(n,i[a])))return t;if(this._backtrack){e=!1;continue}return!1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,i[r]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){var t=this.next();return t||this.lex()},begin:function(t){this.conditionStack.push(t)},popState:function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(t){return(t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"},pushState:function(t){this.begin(t)},stateStackSize:function(){return this.conditionStack.length},options:{"case-insensitive":!0},performAction:function(t,e,n,r){switch(n){case 0:return this.begin("open_directive"),39;case 1:return this.begin("type_directive"),40;case 2:return this.popState(),this.begin("arg_directive"),32;case 3:return this.popState(),this.popState(),42;case 4:return 41;case 5:break;case 6:console.log("Crap after close");break;case 7:return 5;case 8:case 9:case 10:case 11:break;case 12:return this.pushState("SCALE"),15;case 13:return 16;case 14:this.popState();break;case 15:this.pushState("STATE");break;case 16:return this.popState(),e.yytext=e.yytext.slice(0,-8).trim(),23;case 17:return this.popState(),e.yytext=e.yytext.slice(0,-8).trim(),24;case 18:return this.popState(),e.yytext=e.yytext.slice(0,-8).trim(),23;case 19:return this.popState(),e.yytext=e.yytext.slice(0,-8).trim(),24;case 20:this.begin("STATE_STRING");break;case 21:return this.popState(),this.pushState("STATE_ID"),"AS";case 22:return this.popState(),"ID";case 23:this.popState();break;case 24:return"STATE_DESCR";case 25:return 17;case 26:this.popState();break;case 27:return this.popState(),this.pushState("struct"),18;case 28:return this.popState(),19;case 29:break;case 30:return this.begin("NOTE"),26;case 31:return this.popState(),this.pushState("NOTE_ID"),37;case 32:return this.popState(),this.pushState("NOTE_ID"),38;case 33:this.popState(),this.pushState("FLOATING_NOTE");break;case 34:return this.popState(),this.pushState("FLOATING_NOTE_ID"),"AS";case 35:break;case 36:return"NOTE_TEXT";case 37:return this.popState(),"ID";case 38:return this.popState(),this.pushState("NOTE_TEXT"),22;case 39:return this.popState(),e.yytext=e.yytext.substr(2).trim(),28;case 40:return this.popState(),e.yytext=e.yytext.slice(0,-8).trim(),28;case 41:case 42:return 7;case 43:return 14;case 44:return 36;case 45:return 22;case 46:return e.yytext=e.yytext.trim(),12;case 47:return 13;case 48:return 25;case 49:return 5;case 50:return"INVALID"}},rules:[/^(?:%%\{)/i,/^(?:((?:(?!\}%%)[^:.])*))/i,/^(?::)/i,/^(?:\}%%)/i,/^(?:((?:(?!\}%%).|\n)*))/i,/^(?:%%(?!\{)[^\n]*)/i,/^(?:[^\}]%%[^\n]*)/i,/^(?:[\n]+)/i,/^(?:[\s]+)/i,/^(?:((?!\n)\s)+)/i,/^(?:#[^\n]*)/i,/^(?:%[^\n]*)/i,/^(?:scale\s+)/i,/^(?:\d+)/i,/^(?:\s+width\b)/i,/^(?:state\s+)/i,/^(?:.*<>)/i,/^(?:.*<>)/i,/^(?:.*\[\[fork\]\])/i,/^(?:.*\[\[join\]\])/i,/^(?:["])/i,/^(?:\s*as\s+)/i,/^(?:[^\n\{]*)/i,/^(?:["])/i,/^(?:[^"]*)/i,/^(?:[^\n\s\{]+)/i,/^(?:\n)/i,/^(?:\{)/i,/^(?:\})/i,/^(?:[\n])/i,/^(?:note\s+)/i,/^(?:left of\b)/i,/^(?:right of\b)/i,/^(?:")/i,/^(?:\s*as\s*)/i,/^(?:["])/i,/^(?:[^"]*)/i,/^(?:[^\n]*)/i,/^(?:\s*[^:\n\s\-]+)/i,/^(?:\s*:[^:\n;]+)/i,/^(?:[\s\S]*?end note\b)/i,/^(?:stateDiagram\s+)/i,/^(?:stateDiagram-v2\s+)/i,/^(?:hide empty description\b)/i,/^(?:\[\*\])/i,/^(?:[^:\n\s\-\{]+)/i,/^(?:\s*:[^:\n;]+)/i,/^(?:-->)/i,/^(?:--)/i,/^(?:$)/i,/^(?:.)/i],conditions:{LINE:{rules:[9,10],inclusive:!1},close_directive:{rules:[9,10],inclusive:!1},arg_directive:{rules:[3,4,9,10],inclusive:!1},type_directive:{rules:[2,3,9,10],inclusive:!1},open_directive:{rules:[1,9,10],inclusive:!1},struct:{rules:[9,10,15,28,29,30,44,45,46,47,48],inclusive:!1},FLOATING_NOTE_ID:{rules:[37],inclusive:!1},FLOATING_NOTE:{rules:[34,35,36],inclusive:!1},NOTE_TEXT:{rules:[39,40],inclusive:!1},NOTE_ID:{rules:[38],inclusive:!1},NOTE:{rules:[31,32,33],inclusive:!1},SCALE:{rules:[13,14],inclusive:!1},ALIAS:{rules:[],inclusive:!1},STATE_ID:{rules:[22],inclusive:!1},STATE_STRING:{rules:[23,24],inclusive:!1},FORK_STATE:{rules:[],inclusive:!1},STATE:{rules:[9,10,16,17,18,19,20,21,25,26,27],inclusive:!1},ID:{rules:[9,10],inclusive:!1},INITIAL:{rules:[0,5,6,7,8,10,11,12,15,27,30,41,42,43,44,45,46,47,49,50],inclusive:!0}}};function T(){this.yy={}}return w.lexer=E,T.prototype=w,w.Parser=T,new T}();e.parser=i,e.Parser=i.Parser,e.parse=function(){return i.parse.apply(i,arguments)},e.main=function(r){r[1]||(console.log("Usage: "+r[0]+" FILE"),t.exit(1));var i=n(19).readFileSync(n(20).normalize(r[1]),"utf8");return e.parser.parse(i)},n.c[n.s]===r&&e.main(t.argv.slice(1))}).call(this,n(14),n(7)(t))},function(t,e,n){(function(t){t.exports=function(){"use strict";var e,r;function i(){return e.apply(null,arguments)}function a(t){return t instanceof Array||"[object Array]"===Object.prototype.toString.call(t)}function o(t){return null!=t&&"[object Object]"===Object.prototype.toString.call(t)}function s(t){return void 0===t}function c(t){return"number"==typeof t||"[object Number]"===Object.prototype.toString.call(t)}function u(t){return t instanceof Date||"[object Date]"===Object.prototype.toString.call(t)}function l(t,e){var n,r=[];for(n=0;n>>0,r=0;ryt(t)?(a=t+1,s-yt(t)):(a=t,s),{year:a,dayOfYear:o}}function Ft(t,e,n){var r,i,a=Bt(t.year(),e,n),o=Math.floor((t.dayOfYear()-a-1)/7)+1;return o<1?r=o+Pt(i=t.year()-1,e,n):o>Pt(t.year(),e,n)?(r=o-Pt(t.year(),e,n),i=t.year()+1):(i=t.year(),r=o),{week:r,year:i}}function Pt(t,e,n){var r=Bt(t,e,n),i=Bt(t+1,e,n);return(yt(t)-r+i)/7}function It(t,e){return t.slice(e,7).concat(t.slice(0,e))}W("w",["ww",2],"wo","week"),W("W",["WW",2],"Wo","isoWeek"),L("week","w"),L("isoWeek","W"),j("week",5),j("isoWeek",5),lt("w",K),lt("ww",K,q),lt("W",K),lt("WW",K,q),gt(["w","ww","W","WW"],(function(t,e,n,r){e[r.substr(0,1)]=w(t)})),W("d",0,"do","day"),W("dd",0,0,(function(t){return this.localeData().weekdaysMin(this,t)})),W("ddd",0,0,(function(t){return this.localeData().weekdaysShort(this,t)})),W("dddd",0,0,(function(t){return this.localeData().weekdays(this,t)})),W("e",0,0,"weekday"),W("E",0,0,"isoWeekday"),L("day","d"),L("weekday","e"),L("isoWeekday","E"),j("day",11),j("weekday",11),j("isoWeekday",11),lt("d",K),lt("e",K),lt("E",K),lt("dd",(function(t,e){return e.weekdaysMinRegex(t)})),lt("ddd",(function(t,e){return e.weekdaysShortRegex(t)})),lt("dddd",(function(t,e){return e.weekdaysRegex(t)})),gt(["dd","ddd","dddd"],(function(t,e,n,r){var i=n._locale.weekdaysParse(t,r,n._strict);null!=i?e.d=i:p(n).invalidWeekday=t})),gt(["d","e","E"],(function(t,e,n,r){e[r]=w(t)}));var jt="Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),Rt="Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),Yt="Su_Mo_Tu_We_Th_Fr_Sa".split("_"),zt=ct,Ut=ct,$t=ct;function Wt(){function t(t,e){return e.length-t.length}var e,n,r,i,a,o=[],s=[],c=[],u=[];for(e=0;e<7;e++)n=d([2e3,1]).day(e),r=this.weekdaysMin(n,""),i=this.weekdaysShort(n,""),a=this.weekdays(n,""),o.push(r),s.push(i),c.push(a),u.push(r),u.push(i),u.push(a);for(o.sort(t),s.sort(t),c.sort(t),u.sort(t),e=0;e<7;e++)s[e]=ft(s[e]),c[e]=ft(c[e]),u[e]=ft(u[e]);this._weekdaysRegex=new RegExp("^("+u.join("|")+")","i"),this._weekdaysShortRegex=this._weekdaysRegex,this._weekdaysMinRegex=this._weekdaysRegex,this._weekdaysStrictRegex=new RegExp("^("+c.join("|")+")","i"),this._weekdaysShortStrictRegex=new RegExp("^("+s.join("|")+")","i"),this._weekdaysMinStrictRegex=new RegExp("^("+o.join("|")+")","i")}function Ht(){return this.hours()%12||12}function Vt(t,e){W(t,0,0,(function(){return this.localeData().meridiem(this.hours(),this.minutes(),e)}))}function Gt(t,e){return e._meridiemParse}W("H",["HH",2],0,"hour"),W("h",["hh",2],0,Ht),W("k",["kk",2],0,(function(){return this.hours()||24})),W("hmm",0,0,(function(){return""+Ht.apply(this)+R(this.minutes(),2)})),W("hmmss",0,0,(function(){return""+Ht.apply(this)+R(this.minutes(),2)+R(this.seconds(),2)})),W("Hmm",0,0,(function(){return""+this.hours()+R(this.minutes(),2)})),W("Hmmss",0,0,(function(){return""+this.hours()+R(this.minutes(),2)+R(this.seconds(),2)})),Vt("a",!0),Vt("A",!1),L("hour","h"),j("hour",13),lt("a",Gt),lt("A",Gt),lt("H",K),lt("h",K),lt("k",K),lt("HH",K,q),lt("hh",K,q),lt("kk",K,q),lt("hmm",Q),lt("hmmss",tt),lt("Hmm",Q),lt("Hmmss",tt),pt(["H","HH"],3),pt(["k","kk"],(function(t,e,n){var r=w(t);e[3]=24===r?0:r})),pt(["a","A"],(function(t,e,n){n._isPm=n._locale.isPM(t),n._meridiem=t})),pt(["h","hh"],(function(t,e,n){e[3]=w(t),p(n).bigHour=!0})),pt("hmm",(function(t,e,n){var r=t.length-2;e[3]=w(t.substr(0,r)),e[4]=w(t.substr(r)),p(n).bigHour=!0})),pt("hmmss",(function(t,e,n){var r=t.length-4,i=t.length-2;e[3]=w(t.substr(0,r)),e[4]=w(t.substr(r,2)),e[5]=w(t.substr(i)),p(n).bigHour=!0})),pt("Hmm",(function(t,e,n){var r=t.length-2;e[3]=w(t.substr(0,r)),e[4]=w(t.substr(r))})),pt("Hmmss",(function(t,e,n){var r=t.length-4,i=t.length-2;e[3]=w(t.substr(0,r)),e[4]=w(t.substr(r,2)),e[5]=w(t.substr(i))}));var qt,Xt=xt("Hours",!0),Zt={calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},longDateFormat:{LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"},invalidDate:"Invalid date",ordinal:"%d",dayOfMonthOrdinalParse:/\d{1,2}/,relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},months:Tt,monthsShort:Ct,week:{dow:0,doy:6},weekdays:jt,weekdaysMin:Yt,weekdaysShort:Rt,meridiemParse:/[ap]\.?m?\.?/i},Jt={},Kt={};function Qt(t){return t?t.toLowerCase().replace("_","-"):t}function te(e){var r=null;if(!Jt[e]&&void 0!==t&&t&&t.exports)try{r=qt._abbr,n(171)("./"+e),ee(r)}catch(e){}return Jt[e]}function ee(t,e){var n;return t&&((n=s(e)?re(t):ne(t,e))?qt=n:"undefined"!=typeof console&&console.warn&&console.warn("Locale "+t+" not found. Did you forget to load it?")),qt._abbr}function ne(t,e){if(null===e)return delete Jt[t],null;var n,r=Zt;if(e.abbr=t,null!=Jt[t])M("defineLocaleOverride","use moment.updateLocale(localeName, config) to change an existing locale. moment.defineLocale(localeName, config) should only be used for creating a new locale See http://momentjs.com/guides/#/warnings/define-locale/ for more info."),r=Jt[t]._config;else if(null!=e.parentLocale)if(null!=Jt[e.parentLocale])r=Jt[e.parentLocale]._config;else{if(null==(n=te(e.parentLocale)))return Kt[e.parentLocale]||(Kt[e.parentLocale]=[]),Kt[e.parentLocale].push({name:t,config:e}),null;r=n._config}return Jt[t]=new N(D(r,e)),Kt[t]&&Kt[t].forEach((function(t){ne(t.name,t.config)})),ee(t),Jt[t]}function re(t){var e;if(t&&t._locale&&t._locale._abbr&&(t=t._locale._abbr),!t)return qt;if(!a(t)){if(e=te(t))return e;t=[t]}return function(t){for(var e,n,r,i,a=0;a=e&&E(i,n,!0)>=e-1)break;e--}a++}return qt}(t)}function ie(t){var e,n=t._a;return n&&-2===p(t).overflow&&(e=n[1]<0||11wt(n[0],n[1])?2:n[3]<0||24Pt(n,a,o)?p(t)._overflowWeeks=!0:null!=c?p(t)._overflowWeekday=!0:(s=Lt(n,r,i,a,o),t._a[0]=s.year,t._dayOfYear=s.dayOfYear)}(t),null!=t._dayOfYear&&(o=ae(t._a[0],r[0]),(t._dayOfYear>yt(o)||0===t._dayOfYear)&&(p(t)._overflowDayOfYear=!0),n=Nt(o,0,t._dayOfYear),t._a[1]=n.getUTCMonth(),t._a[2]=n.getUTCDate()),e=0;e<3&&null==t._a[e];++e)t._a[e]=s[e]=r[e];for(;e<7;e++)t._a[e]=s[e]=null==t._a[e]?2===e?1:0:t._a[e];24===t._a[3]&&0===t._a[4]&&0===t._a[5]&&0===t._a[6]&&(t._nextDay=!0,t._a[3]=0),t._d=(t._useUTC?Nt:function(t,e,n,r,i,a,o){var s;return t<100&&0<=t?(s=new Date(t+400,e,n,r,i,a,o),isFinite(s.getFullYear())&&s.setFullYear(t)):s=new Date(t,e,n,r,i,a,o),s}).apply(null,s),a=t._useUTC?t._d.getUTCDay():t._d.getDay(),null!=t._tzm&&t._d.setUTCMinutes(t._d.getUTCMinutes()-t._tzm),t._nextDay&&(t._a[3]=24),t._w&&void 0!==t._w.d&&t._w.d!==a&&(p(t).weekdayMismatch=!0)}}var se=/^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,ce=/^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,ue=/Z|[+-]\d\d(?::?\d\d)?/,le=[["YYYYYY-MM-DD",/[+-]\d{6}-\d\d-\d\d/],["YYYY-MM-DD",/\d{4}-\d\d-\d\d/],["GGGG-[W]WW-E",/\d{4}-W\d\d-\d/],["GGGG-[W]WW",/\d{4}-W\d\d/,!1],["YYYY-DDD",/\d{4}-\d{3}/],["YYYY-MM",/\d{4}-\d\d/,!1],["YYYYYYMMDD",/[+-]\d{10}/],["YYYYMMDD",/\d{8}/],["GGGG[W]WWE",/\d{4}W\d{3}/],["GGGG[W]WW",/\d{4}W\d{2}/,!1],["YYYYDDD",/\d{7}/]],he=[["HH:mm:ss.SSSS",/\d\d:\d\d:\d\d\.\d+/],["HH:mm:ss,SSSS",/\d\d:\d\d:\d\d,\d+/],["HH:mm:ss",/\d\d:\d\d:\d\d/],["HH:mm",/\d\d:\d\d/],["HHmmss.SSSS",/\d\d\d\d\d\d\.\d+/],["HHmmss,SSSS",/\d\d\d\d\d\d,\d+/],["HHmmss",/\d\d\d\d\d\d/],["HHmm",/\d\d\d\d/],["HH",/\d\d/]],fe=/^\/?Date\((\-?\d+)/i;function de(t){var e,n,r,i,a,o,s=t._i,c=se.exec(s)||ce.exec(s);if(c){for(p(t).iso=!0,e=0,n=le.length;en.valueOf():n.valueOf()this.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()},on.isLocal=function(){return!!this.isValid()&&!this._isUTC},on.isUtcOffset=function(){return!!this.isValid()&&this._isUTC},on.isUtc=Be,on.isUTC=Be,on.zoneAbbr=function(){return this._isUTC?"UTC":""},on.zoneName=function(){return this._isUTC?"Coordinated Universal Time":""},on.dates=C("dates accessor is deprecated. Use date instead.",Qe),on.months=C("months accessor is deprecated. Use month instead",St),on.years=C("years accessor is deprecated. Use year instead",bt),on.zone=C("moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/",(function(t,e){return null!=t?("string"!=typeof t&&(t=-t),this.utcOffset(t,e),this):-this.utcOffset()})),on.isDSTShifted=C("isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information",(function(){if(!s(this._isDSTShifted))return this._isDSTShifted;var t={};if(m(t,this),(t=me(t))._a){var e=t._isUTC?d(t._a):xe(t._a);this._isDSTShifted=this.isValid()&&0h&&S.push("'"+this.terminals_[T]+"'");O=p.showPosition?"Parse error on line "+(c+1)+":\n"+p.showPosition()+"\nExpecting "+S.join(", ")+", got '"+(this.terminals_[x]||x)+"'":"Parse error on line "+(c+1)+": Unexpected "+(x==f?"end of input":"'"+(this.terminals_[x]||x)+"'"),this.parseError(O,{text:p.match,token:this.terminals_[x]||x,line:p.yylineno,loc:v,expected:S})}if(w[0]instanceof Array&&w.length>1)throw new Error("Parse Error: multiple actions possible at state: "+k+", token: "+x);switch(w[0]){case 1:n.push(x),i.push(p.yytext),a.push(p.yylloc),n.push(w[1]),x=null,_?(x=_,_=null):(u=p.yyleng,s=p.yytext,c=p.yylineno,v=p.yylloc,l>0&&l--);break;case 2:if(C=this.productions_[w[1]][1],M.$=i[i.length-C],M._$={first_line:a[a.length-(C||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-(C||1)].first_column,last_column:a[a.length-1].last_column},m&&(M._$.range=[a[a.length-(C||1)].range[0],a[a.length-1].range[1]]),void 0!==(E=this.performAction.apply(M,[s,u,c,g.yy,w[1],i,a].concat(d))))return E;C&&(n=n.slice(0,-1*C*2),i=i.slice(0,-1*C),a=a.slice(0,-1*C)),n.push(this.productions_[w[1]][0]),i.push(M.$),a.push(M._$),A=o[n[n.length-2]][n[n.length-1]],n.push(A);break;case 3:return!0}}return!0}},qt={EOF:1,parseError:function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)},setInput:function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t},unput:function(t){var e=t.length,n=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var r=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var i=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===r.length?this.yylloc.first_column:0)+r[r.length-n.length].length-n[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[i[0],i[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},less:function(t){this.unput(this.match.slice(t))},pastInput:function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"},test_match:function(t,e){var n,r,i;if(this.options.backtrack_lexer&&(i={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(i.yylloc.range=this.yylloc.range.slice(0))),(r=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=r.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:r?r[r.length-1].length-r[r.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],n=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),n)return n;if(this._backtrack){for(var a in i)this[a]=i[a];return!1}return!1},next:function(){if(this.done)return this.EOF;var t,e,n,r;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var i=this._currentRules(),a=0;ae[0].length)){if(e=n,r=a,this.options.backtrack_lexer){if(!1!==(t=this.test_match(n,i[a])))return t;if(this._backtrack){e=!1;continue}return!1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,i[r]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){var t=this.next();return t||this.lex()},begin:function(t){this.conditionStack.push(t)},popState:function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(t){return(t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"},pushState:function(t){this.begin(t)},stateStackSize:function(){return this.conditionStack.length},options:{},performAction:function(t,e,n,r){switch(n){case 0:return this.begin("open_directive"),12;case 1:return this.begin("type_directive"),13;case 2:return this.popState(),this.begin("arg_directive"),10;case 3:return this.popState(),this.popState(),15;case 4:return 14;case 5:case 6:break;case 7:this.begin("string");break;case 8:this.popState();break;case 9:return"STR";case 10:return 75;case 11:return 84;case 12:return 76;case 13:return 93;case 14:return 77;case 15:return 78;case 16:this.begin("href");break;case 17:this.popState();break;case 18:return 89;case 19:this.begin("callbackname");break;case 20:this.popState();break;case 21:this.popState(),this.begin("callbackargs");break;case 22:return 87;case 23:this.popState();break;case 24:return 88;case 25:this.begin("click");break;case 26:this.popState();break;case 27:return 79;case 28:case 29:return t.lex.firstGraph()&&this.begin("dir"),24;case 30:return 38;case 31:return 42;case 32:case 33:case 34:case 35:return 90;case 36:return this.popState(),25;case 37:case 38:case 39:case 40:case 41:case 42:case 43:case 44:case 45:case 46:return this.popState(),26;case 47:return 94;case 48:return 102;case 49:return 47;case 50:return 99;case 51:return 46;case 52:return 20;case 53:return 95;case 54:return 113;case 55:case 56:case 57:return 70;case 58:case 59:case 60:return 69;case 61:return 51;case 62:return 52;case 63:return 53;case 64:return 54;case 65:return 55;case 66:return 56;case 67:return 57;case 68:return 58;case 69:return 100;case 70:return 103;case 71:return 114;case 72:return 111;case 73:return 104;case 74:case 75:return 112;case 76:return 105;case 77:return 61;case 78:return 81;case 79:return"SEP";case 80:return 80;case 81:return 98;case 82:return 63;case 83:return 62;case 84:return 65;case 85:return 64;case 86:return 109;case 87:return 110;case 88:return 71;case 89:return 49;case 90:return 50;case 91:return 40;case 92:return 41;case 93:return 59;case 94:return 60;case 95:return 120;case 96:return 21;case 97:return 22;case 98:return 23}},rules:[/^(?:%%\{)/,/^(?:((?:(?!\}%%)[^:.])*))/,/^(?::)/,/^(?:\}%%)/,/^(?:((?:(?!\}%%).|\n)*))/,/^(?:%%(?!\{)[^\n]*)/,/^(?:[^\}]%%[^\n]*)/,/^(?:["])/,/^(?:["])/,/^(?:[^"]*)/,/^(?:style\b)/,/^(?:default\b)/,/^(?:linkStyle\b)/,/^(?:interpolate\b)/,/^(?:classDef\b)/,/^(?:class\b)/,/^(?:href[\s]+["])/,/^(?:["])/,/^(?:[^"]*)/,/^(?:call[\s]+)/,/^(?:\([\s]*\))/,/^(?:\()/,/^(?:[^(]*)/,/^(?:\))/,/^(?:[^)]*)/,/^(?:click[\s]+)/,/^(?:[\s\n])/,/^(?:[^\s\n]*)/,/^(?:graph\b)/,/^(?:flowchart\b)/,/^(?:subgraph\b)/,/^(?:end\b\s*)/,/^(?:_self\b)/,/^(?:_blank\b)/,/^(?:_parent\b)/,/^(?:_top\b)/,/^(?:(\r?\n)*\s*\n)/,/^(?:\s*LR\b)/,/^(?:\s*RL\b)/,/^(?:\s*TB\b)/,/^(?:\s*BT\b)/,/^(?:\s*TD\b)/,/^(?:\s*BR\b)/,/^(?:\s*<)/,/^(?:\s*>)/,/^(?:\s*\^)/,/^(?:\s*v\b)/,/^(?:[0-9]+)/,/^(?:#)/,/^(?::::)/,/^(?::)/,/^(?:&)/,/^(?:;)/,/^(?:,)/,/^(?:\*)/,/^(?:\s*[xo<]?--+[-xo>]\s*)/,/^(?:\s*[xo<]?==+[=xo>]\s*)/,/^(?:\s*[xo<]?-?\.+-[xo>]?\s*)/,/^(?:\s*[xo<]?--\s*)/,/^(?:\s*[xo<]?==\s*)/,/^(?:\s*[xo<]?-\.\s*)/,/^(?:\(-)/,/^(?:-\))/,/^(?:\(\[)/,/^(?:\]\))/,/^(?:\[\[)/,/^(?:\]\])/,/^(?:\[\()/,/^(?:\)\])/,/^(?:-)/,/^(?:\.)/,/^(?:[\_])/,/^(?:\+)/,/^(?:%)/,/^(?:=)/,/^(?:=)/,/^(?:<)/,/^(?:>)/,/^(?:\^)/,/^(?:\\\|)/,/^(?:v\b)/,/^(?:[A-Za-z]+)/,/^(?:\\\])/,/^(?:\[\/)/,/^(?:\/\])/,/^(?:\[\\)/,/^(?:[!"#$%&'*+,-.`?\\_/])/,/^(?:[\u00AA\u00B5\u00BA\u00C0-\u00D6\u00D8-\u00F6]|[\u00F8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377]|[\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5]|[\u03F7-\u0481\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA]|[\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE]|[\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA]|[\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0]|[\u08A2-\u08AC\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0977]|[\u0979-\u097F\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2]|[\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A]|[\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39]|[\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8]|[\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C]|[\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C]|[\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99]|[\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0]|[\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D]|[\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3]|[\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10]|[\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1]|[\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81]|[\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3]|[\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6]|[\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A]|[\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081]|[\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D]|[\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0]|[\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310]|[\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C]|[\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u1700-\u170C\u170E-\u1711]|[\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7]|[\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191C]|[\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16]|[\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF]|[\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC]|[\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D]|[\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D]|[\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3]|[\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F]|[\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128]|[\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184]|[\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3]|[\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6]|[\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE]|[\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C]|[\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D]|[\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC]|[\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B]|[\uA640-\uA66E\uA67F-\uA697\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788]|[\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA801\uA803-\uA805]|[\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB]|[\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uAA00-\uAA28]|[\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA80-\uAAAF\uAAB1\uAAB5]|[\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4]|[\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E]|[\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D]|[\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36]|[\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D]|[\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC]|[\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF]|[\uFFD2-\uFFD7\uFFDA-\uFFDC])/,/^(?:\|)/,/^(?:\()/,/^(?:\))/,/^(?:\[)/,/^(?:\])/,/^(?:\{)/,/^(?:\})/,/^(?:")/,/^(?:(\r?\n)+)/,/^(?:\s)/,/^(?:$)/],conditions:{close_directive:{rules:[],inclusive:!1},arg_directive:{rules:[3,4],inclusive:!1},type_directive:{rules:[2,3],inclusive:!1},open_directive:{rules:[1],inclusive:!1},callbackargs:{rules:[23,24],inclusive:!1},callbackname:{rules:[20,21,22],inclusive:!1},href:{rules:[17,18],inclusive:!1},click:{rules:[26,27],inclusive:!1},vertex:{rules:[],inclusive:!1},dir:{rules:[36,37,38,39,40,41,42,43,44,45,46],inclusive:!1},string:{rules:[8,9],inclusive:!1},INITIAL:{rules:[0,5,6,7,10,11,12,13,14,15,16,19,25,28,29,30,31,32,33,34,35,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98],inclusive:!0}}};function Xt(){this.yy={}}return Gt.lexer=qt,Xt.prototype=Gt,Gt.Parser=Xt,new Xt}();e.parser=i,e.Parser=i.Parser,e.parse=function(){return i.parse.apply(i,arguments)},e.main=function(r){r[1]||(console.log("Usage: "+r[0]+" FILE"),t.exit(1));var i=n(19).readFileSync(n(20).normalize(r[1]),"utf8");return e.parser.parse(i)},n.c[n.s]===r&&e.main(t.argv.slice(1))}).call(this,n(14),n(7)(t))},function(t,e,n){(function(t,r){var i=function(){var t=function(t,e,n,r){for(n=n||{},r=t.length;r--;n[t[r]]=e);return n},e=[1,3],n=[1,5],r=[7,9,11,12,13,14,15,16,17,18,20,27,32],i=[1,15],a=[1,16],o=[1,17],s=[1,18],c=[1,19],u=[1,20],l=[1,21],h=[1,23],f=[1,25],d=[1,28],p=[5,7,9,11,12,13,14,15,16,17,18,20,27,32],g={trace:function(){},yy:{},symbols_:{error:2,start:3,directive:4,gantt:5,document:6,EOF:7,line:8,SPACE:9,statement:10,NL:11,dateFormat:12,inclusiveEndDates:13,axisFormat:14,excludes:15,todayMarker:16,title:17,section:18,clickStatement:19,taskTxt:20,taskData:21,openDirective:22,typeDirective:23,closeDirective:24,":":25,argDirective:26,click:27,callbackname:28,callbackargs:29,href:30,clickStatementDebug:31,open_directive:32,type_directive:33,arg_directive:34,close_directive:35,$accept:0,$end:1},terminals_:{2:"error",5:"gantt",7:"EOF",9:"SPACE",11:"NL",12:"dateFormat",13:"inclusiveEndDates",14:"axisFormat",15:"excludes",16:"todayMarker",17:"title",18:"section",20:"taskTxt",21:"taskData",25:":",27:"click",28:"callbackname",29:"callbackargs",30:"href",32:"open_directive",33:"type_directive",34:"arg_directive",35:"close_directive"},productions_:[0,[3,2],[3,3],[6,0],[6,2],[8,2],[8,1],[8,1],[8,1],[10,1],[10,1],[10,1],[10,1],[10,1],[10,1],[10,1],[10,1],[10,2],[10,1],[4,4],[4,6],[19,2],[19,3],[19,3],[19,4],[19,3],[19,4],[19,2],[31,2],[31,3],[31,3],[31,4],[31,3],[31,4],[31,2],[22,1],[23,1],[26,1],[24,1]],performAction:function(t,e,n,r,i,a,o){var s=a.length-1;switch(i){case 2:return a[s-1];case 3:this.$=[];break;case 4:a[s-1].push(a[s]),this.$=a[s-1];break;case 5:case 6:this.$=a[s];break;case 7:case 8:this.$=[];break;case 9:r.setDateFormat(a[s].substr(11)),this.$=a[s].substr(11);break;case 10:r.enableInclusiveEndDates(),this.$=a[s].substr(18);break;case 11:r.setAxisFormat(a[s].substr(11)),this.$=a[s].substr(11);break;case 12:r.setExcludes(a[s].substr(9)),this.$=a[s].substr(9);break;case 13:r.setTodayMarker(a[s].substr(12)),this.$=a[s].substr(12);break;case 14:r.setTitle(a[s].substr(6)),this.$=a[s].substr(6);break;case 15:r.addSection(a[s].substr(8)),this.$=a[s].substr(8);break;case 17:r.addTask(a[s-1],a[s]),this.$="task";break;case 21:this.$=a[s-1],r.setClickEvent(a[s-1],a[s],null);break;case 22:this.$=a[s-2],r.setClickEvent(a[s-2],a[s-1],a[s]);break;case 23:this.$=a[s-2],r.setClickEvent(a[s-2],a[s-1],null),r.setLink(a[s-2],a[s]);break;case 24:this.$=a[s-3],r.setClickEvent(a[s-3],a[s-2],a[s-1]),r.setLink(a[s-3],a[s]);break;case 25:this.$=a[s-2],r.setClickEvent(a[s-2],a[s],null),r.setLink(a[s-2],a[s-1]);break;case 26:this.$=a[s-3],r.setClickEvent(a[s-3],a[s-1],a[s]),r.setLink(a[s-3],a[s-2]);break;case 27:this.$=a[s-1],r.setLink(a[s-1],a[s]);break;case 28:case 34:this.$=a[s-1]+" "+a[s];break;case 29:case 30:case 32:this.$=a[s-2]+" "+a[s-1]+" "+a[s];break;case 31:case 33:this.$=a[s-3]+" "+a[s-2]+" "+a[s-1]+" "+a[s];break;case 35:r.parseDirective("%%{","open_directive");break;case 36:r.parseDirective(a[s],"type_directive");break;case 37:a[s]=a[s].trim().replace(/'/g,'"'),r.parseDirective(a[s],"arg_directive");break;case 38:r.parseDirective("}%%","close_directive","gantt")}},table:[{3:1,4:2,5:e,22:4,32:n},{1:[3]},{3:6,4:2,5:e,22:4,32:n},t(r,[2,3],{6:7}),{23:8,33:[1,9]},{33:[2,35]},{1:[2,1]},{4:24,7:[1,10],8:11,9:[1,12],10:13,11:[1,14],12:i,13:a,14:o,15:s,16:c,17:u,18:l,19:22,20:h,22:4,27:f,32:n},{24:26,25:[1,27],35:d},t([25,35],[2,36]),t(r,[2,8],{1:[2,2]}),t(r,[2,4]),{4:24,10:29,12:i,13:a,14:o,15:s,16:c,17:u,18:l,19:22,20:h,22:4,27:f,32:n},t(r,[2,6]),t(r,[2,7]),t(r,[2,9]),t(r,[2,10]),t(r,[2,11]),t(r,[2,12]),t(r,[2,13]),t(r,[2,14]),t(r,[2,15]),t(r,[2,16]),{21:[1,30]},t(r,[2,18]),{28:[1,31],30:[1,32]},{11:[1,33]},{26:34,34:[1,35]},{11:[2,38]},t(r,[2,5]),t(r,[2,17]),t(r,[2,21],{29:[1,36],30:[1,37]}),t(r,[2,27],{28:[1,38]}),t(p,[2,19]),{24:39,35:d},{35:[2,37]},t(r,[2,22],{30:[1,40]}),t(r,[2,23]),t(r,[2,25],{29:[1,41]}),{11:[1,42]},t(r,[2,24]),t(r,[2,26]),t(p,[2,20])],defaultActions:{5:[2,35],6:[2,1],28:[2,38],35:[2,37]},parseError:function(t,e){if(!e.recoverable){var n=new Error(t);throw n.hash=e,n}this.trace(t)},parse:function(t){var e=this,n=[0],r=[],i=[null],a=[],o=this.table,s="",c=0,u=0,l=0,h=2,f=1,d=a.slice.call(arguments,1),p=Object.create(this.lexer),g={yy:{}};for(var y in this.yy)Object.prototype.hasOwnProperty.call(this.yy,y)&&(g.yy[y]=this.yy[y]);p.setInput(t,g.yy),g.yy.lexer=p,g.yy.parser=this,void 0===p.yylloc&&(p.yylloc={});var v=p.yylloc;a.push(v);var m=p.options&&p.options.ranges;function b(){var t;return"number"!=typeof(t=r.pop()||p.lex()||f)&&(t instanceof Array&&(t=(r=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof g.yy.parseError?this.parseError=g.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;for(var x,_,k,w,E,T,C,A,S,M={};;){if(k=n[n.length-1],this.defaultActions[k]?w=this.defaultActions[k]:(null==x&&(x=b()),w=o[k]&&o[k][x]),void 0===w||!w.length||!w[0]){var O="";for(T in S=[],o[k])this.terminals_[T]&&T>h&&S.push("'"+this.terminals_[T]+"'");O=p.showPosition?"Parse error on line "+(c+1)+":\n"+p.showPosition()+"\nExpecting "+S.join(", ")+", got '"+(this.terminals_[x]||x)+"'":"Parse error on line "+(c+1)+": Unexpected "+(x==f?"end of input":"'"+(this.terminals_[x]||x)+"'"),this.parseError(O,{text:p.match,token:this.terminals_[x]||x,line:p.yylineno,loc:v,expected:S})}if(w[0]instanceof Array&&w.length>1)throw new Error("Parse Error: multiple actions possible at state: "+k+", token: "+x);switch(w[0]){case 1:n.push(x),i.push(p.yytext),a.push(p.yylloc),n.push(w[1]),x=null,_?(x=_,_=null):(u=p.yyleng,s=p.yytext,c=p.yylineno,v=p.yylloc,l>0&&l--);break;case 2:if(C=this.productions_[w[1]][1],M.$=i[i.length-C],M._$={first_line:a[a.length-(C||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-(C||1)].first_column,last_column:a[a.length-1].last_column},m&&(M._$.range=[a[a.length-(C||1)].range[0],a[a.length-1].range[1]]),void 0!==(E=this.performAction.apply(M,[s,u,c,g.yy,w[1],i,a].concat(d))))return E;C&&(n=n.slice(0,-1*C*2),i=i.slice(0,-1*C),a=a.slice(0,-1*C)),n.push(this.productions_[w[1]][0]),i.push(M.$),a.push(M._$),A=o[n[n.length-2]][n[n.length-1]],n.push(A);break;case 3:return!0}}return!0}},y={EOF:1,parseError:function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)},setInput:function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t},unput:function(t){var e=t.length,n=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var r=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var i=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===r.length?this.yylloc.first_column:0)+r[r.length-n.length].length-n[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[i[0],i[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},less:function(t){this.unput(this.match.slice(t))},pastInput:function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"},test_match:function(t,e){var n,r,i;if(this.options.backtrack_lexer&&(i={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(i.yylloc.range=this.yylloc.range.slice(0))),(r=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=r.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:r?r[r.length-1].length-r[r.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],n=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),n)return n;if(this._backtrack){for(var a in i)this[a]=i[a];return!1}return!1},next:function(){if(this.done)return this.EOF;var t,e,n,r;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var i=this._currentRules(),a=0;ae[0].length)){if(e=n,r=a,this.options.backtrack_lexer){if(!1!==(t=this.test_match(n,i[a])))return t;if(this._backtrack){e=!1;continue}return!1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,i[r]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){var t=this.next();return t||this.lex()},begin:function(t){this.conditionStack.push(t)},popState:function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(t){return(t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"},pushState:function(t){this.begin(t)},stateStackSize:function(){return this.conditionStack.length},options:{"case-insensitive":!0},performAction:function(t,e,n,r){switch(n){case 0:return this.begin("open_directive"),32;case 1:return this.begin("type_directive"),33;case 2:return this.popState(),this.begin("arg_directive"),25;case 3:return this.popState(),this.popState(),35;case 4:return 34;case 5:case 6:case 7:break;case 8:return 11;case 9:case 10:case 11:break;case 12:this.begin("href");break;case 13:this.popState();break;case 14:return 30;case 15:this.begin("callbackname");break;case 16:this.popState();break;case 17:this.popState(),this.begin("callbackargs");break;case 18:return 28;case 19:this.popState();break;case 20:return 29;case 21:this.begin("click");break;case 22:this.popState();break;case 23:return 27;case 24:return 5;case 25:return 12;case 26:return 13;case 27:return 14;case 28:return 15;case 29:return 16;case 30:return"date";case 31:return 17;case 32:return 18;case 33:return 20;case 34:return 21;case 35:return 25;case 36:return 7;case 37:return"INVALID"}},rules:[/^(?:%%\{)/i,/^(?:((?:(?!\}%%)[^:.])*))/i,/^(?::)/i,/^(?:\}%%)/i,/^(?:((?:(?!\}%%).|\n)*))/i,/^(?:%%(?!\{)*[^\n]*)/i,/^(?:[^\}]%%*[^\n]*)/i,/^(?:%%*[^\n]*[\n]*)/i,/^(?:[\n]+)/i,/^(?:\s+)/i,/^(?:#[^\n]*)/i,/^(?:%[^\n]*)/i,/^(?:href[\s]+["])/i,/^(?:["])/i,/^(?:[^"]*)/i,/^(?:call[\s]+)/i,/^(?:\([\s]*\))/i,/^(?:\()/i,/^(?:[^(]*)/i,/^(?:\))/i,/^(?:[^)]*)/i,/^(?:click[\s]+)/i,/^(?:[\s\n])/i,/^(?:[^\s\n]*)/i,/^(?:gantt\b)/i,/^(?:dateFormat\s[^#\n;]+)/i,/^(?:inclusiveEndDates\b)/i,/^(?:axisFormat\s[^#\n;]+)/i,/^(?:excludes\s[^#\n;]+)/i,/^(?:todayMarker\s[^\n;]+)/i,/^(?:\d\d\d\d-\d\d-\d\d\b)/i,/^(?:title\s[^#\n;]+)/i,/^(?:section\s[^#:\n;]+)/i,/^(?:[^#:\n;]+)/i,/^(?::[^#\n;]+)/i,/^(?::)/i,/^(?:$)/i,/^(?:.)/i],conditions:{close_directive:{rules:[],inclusive:!1},arg_directive:{rules:[3,4],inclusive:!1},type_directive:{rules:[2,3],inclusive:!1},open_directive:{rules:[1],inclusive:!1},callbackargs:{rules:[19,20],inclusive:!1},callbackname:{rules:[16,17,18],inclusive:!1},href:{rules:[13,14],inclusive:!1},click:{rules:[22,23],inclusive:!1},INITIAL:{rules:[0,5,6,7,8,9,10,11,12,15,21,24,25,26,27,28,29,30,31,32,33,34,35,36,37],inclusive:!0}}};function v(){this.yy={}}return g.lexer=y,v.prototype=g,g.Parser=v,new v}();e.parser=i,e.Parser=i.Parser,e.parse=function(){return i.parse.apply(i,arguments)},e.main=function(r){r[1]||(console.log("Usage: "+r[0]+" FILE"),t.exit(1));var i=n(19).readFileSync(n(20).normalize(r[1]),"utf8");return e.parser.parse(i)},n.c[n.s]===r&&e.main(t.argv.slice(1))}).call(this,n(14),n(7)(t))},function(t,e,n){(function(t,r){var i=function(){var t=function(t,e,n,r){for(n=n||{},r=t.length;r--;n[t[r]]=e);return n},e=[1,2],n=[1,5],r=[6,9,11,17,18,19,21],i=[1,15],a=[1,16],o=[1,17],s=[1,21],c=[4,6,9,11,17,18,19,21],u={trace:function(){},yy:{},symbols_:{error:2,start:3,journey:4,document:5,EOF:6,directive:7,line:8,SPACE:9,statement:10,NEWLINE:11,openDirective:12,typeDirective:13,closeDirective:14,":":15,argDirective:16,title:17,section:18,taskName:19,taskData:20,open_directive:21,type_directive:22,arg_directive:23,close_directive:24,$accept:0,$end:1},terminals_:{2:"error",4:"journey",6:"EOF",9:"SPACE",11:"NEWLINE",15:":",17:"title",18:"section",19:"taskName",20:"taskData",21:"open_directive",22:"type_directive",23:"arg_directive",24:"close_directive"},productions_:[0,[3,3],[3,2],[5,0],[5,2],[8,2],[8,1],[8,1],[8,1],[7,4],[7,6],[10,1],[10,1],[10,2],[10,1],[12,1],[13,1],[16,1],[14,1]],performAction:function(t,e,n,r,i,a,o){var s=a.length-1;switch(i){case 1:return a[s-1];case 3:this.$=[];break;case 4:a[s-1].push(a[s]),this.$=a[s-1];break;case 5:case 6:this.$=a[s];break;case 7:case 8:this.$=[];break;case 11:r.setTitle(a[s].substr(6)),this.$=a[s].substr(6);break;case 12:r.addSection(a[s].substr(8)),this.$=a[s].substr(8);break;case 13:r.addTask(a[s-1],a[s]),this.$="task";break;case 15:r.parseDirective("%%{","open_directive");break;case 16:r.parseDirective(a[s],"type_directive");break;case 17:a[s]=a[s].trim().replace(/'/g,'"'),r.parseDirective(a[s],"arg_directive");break;case 18:r.parseDirective("}%%","close_directive","journey")}},table:[{3:1,4:e,7:3,12:4,21:n},{1:[3]},t(r,[2,3],{5:6}),{3:7,4:e,7:3,12:4,21:n},{13:8,22:[1,9]},{22:[2,15]},{6:[1,10],7:18,8:11,9:[1,12],10:13,11:[1,14],12:4,17:i,18:a,19:o,21:n},{1:[2,2]},{14:19,15:[1,20],24:s},t([15,24],[2,16]),t(r,[2,8],{1:[2,1]}),t(r,[2,4]),{7:18,10:22,12:4,17:i,18:a,19:o,21:n},t(r,[2,6]),t(r,[2,7]),t(r,[2,11]),t(r,[2,12]),{20:[1,23]},t(r,[2,14]),{11:[1,24]},{16:25,23:[1,26]},{11:[2,18]},t(r,[2,5]),t(r,[2,13]),t(c,[2,9]),{14:27,24:s},{24:[2,17]},{11:[1,28]},t(c,[2,10])],defaultActions:{5:[2,15],7:[2,2],21:[2,18],26:[2,17]},parseError:function(t,e){if(!e.recoverable){var n=new Error(t);throw n.hash=e,n}this.trace(t)},parse:function(t){var e=this,n=[0],r=[],i=[null],a=[],o=this.table,s="",c=0,u=0,l=0,h=2,f=1,d=a.slice.call(arguments,1),p=Object.create(this.lexer),g={yy:{}};for(var y in this.yy)Object.prototype.hasOwnProperty.call(this.yy,y)&&(g.yy[y]=this.yy[y]);p.setInput(t,g.yy),g.yy.lexer=p,g.yy.parser=this,void 0===p.yylloc&&(p.yylloc={});var v=p.yylloc;a.push(v);var m=p.options&&p.options.ranges;function b(){var t;return"number"!=typeof(t=r.pop()||p.lex()||f)&&(t instanceof Array&&(t=(r=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof g.yy.parseError?this.parseError=g.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;for(var x,_,k,w,E,T,C,A,S,M={};;){if(k=n[n.length-1],this.defaultActions[k]?w=this.defaultActions[k]:(null==x&&(x=b()),w=o[k]&&o[k][x]),void 0===w||!w.length||!w[0]){var O="";for(T in S=[],o[k])this.terminals_[T]&&T>h&&S.push("'"+this.terminals_[T]+"'");O=p.showPosition?"Parse error on line "+(c+1)+":\n"+p.showPosition()+"\nExpecting "+S.join(", ")+", got '"+(this.terminals_[x]||x)+"'":"Parse error on line "+(c+1)+": Unexpected "+(x==f?"end of input":"'"+(this.terminals_[x]||x)+"'"),this.parseError(O,{text:p.match,token:this.terminals_[x]||x,line:p.yylineno,loc:v,expected:S})}if(w[0]instanceof Array&&w.length>1)throw new Error("Parse Error: multiple actions possible at state: "+k+", token: "+x);switch(w[0]){case 1:n.push(x),i.push(p.yytext),a.push(p.yylloc),n.push(w[1]),x=null,_?(x=_,_=null):(u=p.yyleng,s=p.yytext,c=p.yylineno,v=p.yylloc,l>0&&l--);break;case 2:if(C=this.productions_[w[1]][1],M.$=i[i.length-C],M._$={first_line:a[a.length-(C||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-(C||1)].first_column,last_column:a[a.length-1].last_column},m&&(M._$.range=[a[a.length-(C||1)].range[0],a[a.length-1].range[1]]),void 0!==(E=this.performAction.apply(M,[s,u,c,g.yy,w[1],i,a].concat(d))))return E;C&&(n=n.slice(0,-1*C*2),i=i.slice(0,-1*C),a=a.slice(0,-1*C)),n.push(this.productions_[w[1]][0]),i.push(M.$),a.push(M._$),A=o[n[n.length-2]][n[n.length-1]],n.push(A);break;case 3:return!0}}return!0}},l={EOF:1,parseError:function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)},setInput:function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t},unput:function(t){var e=t.length,n=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var r=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var i=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===r.length?this.yylloc.first_column:0)+r[r.length-n.length].length-n[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[i[0],i[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},less:function(t){this.unput(this.match.slice(t))},pastInput:function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"},test_match:function(t,e){var n,r,i;if(this.options.backtrack_lexer&&(i={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(i.yylloc.range=this.yylloc.range.slice(0))),(r=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=r.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:r?r[r.length-1].length-r[r.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],n=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),n)return n;if(this._backtrack){for(var a in i)this[a]=i[a];return!1}return!1},next:function(){if(this.done)return this.EOF;var t,e,n,r;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var i=this._currentRules(),a=0;ae[0].length)){if(e=n,r=a,this.options.backtrack_lexer){if(!1!==(t=this.test_match(n,i[a])))return t;if(this._backtrack){e=!1;continue}return!1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,i[r]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){var t=this.next();return t||this.lex()},begin:function(t){this.conditionStack.push(t)},popState:function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(t){return(t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"},pushState:function(t){this.begin(t)},stateStackSize:function(){return this.conditionStack.length},options:{"case-insensitive":!0},performAction:function(t,e,n,r){switch(n){case 0:return this.begin("open_directive"),21;case 1:return this.begin("type_directive"),22;case 2:return this.popState(),this.begin("arg_directive"),15;case 3:return this.popState(),this.popState(),24;case 4:return 23;case 5:case 6:break;case 7:return 11;case 8:case 9:break;case 10:return 4;case 11:return 17;case 12:return 18;case 13:return 19;case 14:return 20;case 15:return 15;case 16:return 6;case 17:return"INVALID"}},rules:[/^(?:%%\{)/i,/^(?:((?:(?!\}%%)[^:.])*))/i,/^(?::)/i,/^(?:\}%%)/i,/^(?:((?:(?!\}%%).|\n)*))/i,/^(?:%(?!\{)[^\n]*)/i,/^(?:[^\}]%%[^\n]*)/i,/^(?:[\n]+)/i,/^(?:\s+)/i,/^(?:#[^\n]*)/i,/^(?:journey\b)/i,/^(?:title\s[^#\n;]+)/i,/^(?:section\s[^#:\n;]+)/i,/^(?:[^#:\n;]+)/i,/^(?::[^#\n;]+)/i,/^(?::)/i,/^(?:$)/i,/^(?:.)/i],conditions:{open_directive:{rules:[1],inclusive:!1},type_directive:{rules:[2,3],inclusive:!1},arg_directive:{rules:[3,4],inclusive:!1},INITIAL:{rules:[0,5,6,7,8,9,10,11,12,13,14,15,16,17],inclusive:!0}}};function h(){this.yy={}}return u.lexer=l,h.prototype=u,u.Parser=h,new h}();e.parser=i,e.Parser=i.Parser,e.parse=function(){return i.parse.apply(i,arguments)},e.main=function(r){r[1]||(console.log("Usage: "+r[0]+" FILE"),t.exit(1));var i=n(19).readFileSync(n(20).normalize(r[1]),"utf8");return e.parser.parse(i)},n.c[n.s]===r&&e.main(t.argv.slice(1))}).call(this,n(14),n(7)(t))},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=n(9),i=n(15);e.default=function(t,e){return r.default.lang.round(i.default.parse(t)[e])}},function(t,e,n){var r=n(112),i=n(82),a=n(24);t.exports=function(t){return a(t)?r(t):i(t)}},function(t,e,n){var r;if(!r)try{r=n(0)}catch(t){}r||(r=window.d3),t.exports=r},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=n(9),i=n(15);e.default=function(t,e,n){var a=i.default.parse(t),o=a[e],s=r.default.channel.clamp[e](o+n);return o!==s&&(a[e]=s),i.default.stringify(a)}},function(t,e,n){var r=n(210),i=n(216);t.exports=function(t,e){var n=i(t,e);return r(n)?n:void 0}},function(t,e,n){var r=n(38),i=n(212),a=n(213),o=r?r.toStringTag:void 0;t.exports=function(t){return null==t?void 0===t?"[object Undefined]":"[object Null]":o&&o in Object(t)?i(t):a(t)}},function(t,e){t.exports=function(t){return t}},function(t,e){t.exports=function(t,e){return t===e||t!=t&&e!=e}},function(t,e,n){var r=n(34),i=n(11);t.exports=function(t){if(!i(t))return!1;var e=r(t);return"[object Function]"==e||"[object GeneratorFunction]"==e||"[object AsyncFunction]"==e||"[object Proxy]"==e}},function(t,e,n){var r=n(16).Symbol;t.exports=r},function(t,e,n){(function(t){var r=n(16),i=n(232),a=e&&!e.nodeType&&e,o=a&&"object"==typeof t&&t&&!t.nodeType&&t,s=o&&o.exports===a?r.Buffer:void 0,c=(s?s.isBuffer:void 0)||i;t.exports=c}).call(this,n(7)(t))},function(t,e,n){var r=n(112),i=n(236),a=n(24);t.exports=function(t){return a(t)?r(t,!0):i(t)}},function(t,e,n){var r=n(241),i=n(77),a=n(242),o=n(121),s=n(243),c=n(34),u=n(110),l=u(r),h=u(i),f=u(a),d=u(o),p=u(s),g=c;(r&&"[object DataView]"!=g(new r(new ArrayBuffer(1)))||i&&"[object Map]"!=g(new i)||a&&"[object Promise]"!=g(a.resolve())||o&&"[object Set]"!=g(new o)||s&&"[object WeakMap]"!=g(new s))&&(g=function(t){var e=c(t),n="[object Object]"==e?t.constructor:void 0,r=n?u(n):"";if(r)switch(r){case l:return"[object DataView]";case h:return"[object Map]";case f:return"[object Promise]";case d:return"[object Set]";case p:return"[object WeakMap]"}return e}),t.exports=g},function(t,e,n){var r=n(34),i=n(21);t.exports=function(t){return"symbol"==typeof t||i(t)&&"[object Symbol]"==r(t)}},function(t,e,n){var r;try{r={defaults:n(154),each:n(87),isFunction:n(37),isPlainObject:n(158),pick:n(161),has:n(93),range:n(162),uniqueId:n(163)}}catch(t){}r||(r=window._),t.exports=r},function(t){t.exports=JSON.parse('{"name":"mermaid","version":"8.8.4","description":"Markdownish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.","main":"dist/mermaid.core.js","keywords":["diagram","markdown","flowchart","sequence diagram","gantt","class diagram","git graph"],"scripts":{"build:development":"webpack --progress --colors","build:production":"yarn build:development -p --config webpack.config.prod.babel.js","build":"yarn build:development && yarn build:production","postbuild":"documentation build src/mermaidAPI.js src/config.js --shallow -f md --markdown-toc false > docs/Setup.md","build:watch":"yarn build --watch","minify":"minify ./dist/mermaid.js > ./dist/mermaid.min.js","release":"yarn build","lint":"eslint src","e2e:depr":"yarn lint && jest e2e --config e2e/jest.config.js","cypress":"percy exec -- cypress run","e2e":"start-server-and-test dev http://localhost:9000/ cypress","e2e-upd":"yarn lint && jest e2e -u --config e2e/jest.config.js","dev":"webpack-dev-server --config webpack.config.e2e.js","test":"yarn lint && jest src/.*","test:watch":"jest --watch src","prepublishOnly":"yarn build && yarn test","prepare":"yarn build"},"repository":{"type":"git","url":"https://github.com/knsv/mermaid"},"author":"Knut Sveidqvist","license":"MIT","standard":{"ignore":["**/parser/*.js","dist/**/*.js","cypress/**/*.js"],"globals":["page"]},"dependencies":{"@braintree/sanitize-url":"^3.1.0","d3":"^5.7.0","dagre":"^0.8.4","dagre-d3":"^0.6.4","entity-decode":"^2.0.2","graphlib":"^2.1.7","he":"^1.2.0","khroma":"^1.1.0","minify":"^4.1.1","moment-mini":"^2.22.1","stylis":"^3.5.2"},"devDependencies":{"@babel/core":"^7.2.2","@babel/preset-env":"^7.8.4","@babel/register":"^7.0.0","@percy/cypress":"*","babel-core":"7.0.0-bridge.0","babel-eslint":"^10.1.0","babel-jest":"^24.9.0","babel-loader":"^8.0.4","coveralls":"^3.0.2","css-loader":"^2.0.1","css-to-string-loader":"^0.1.3","cypress":"4.0.1","documentation":"^12.0.1","eslint":"^6.3.0","eslint-config-prettier":"^6.3.0","eslint-plugin-prettier":"^3.1.0","husky":"^1.2.1","identity-obj-proxy":"^3.0.0","jest":"^24.9.0","jison":"^0.4.18","moment":"^2.23.0","node-sass":"^4.12.0","prettier":"^1.18.2","puppeteer":"^1.17.0","sass-loader":"^7.1.0","start-server-and-test":"^1.10.6","terser-webpack-plugin":"^2.2.2","webpack":"^4.41.2","webpack-bundle-analyzer":"^3.7.0","webpack-cli":"^3.1.2","webpack-dev-server":"^3.4.1","webpack-node-externals":"^1.7.2","yarn-upgrade-all":"^0.5.0"},"files":["dist"],"yarn-upgrade-all":{"ignore":["babel-core"]},"sideEffects":["**/*.css","**/*.scss"],"husky":{"hooks":{"pre-push":"yarn test"}}}')},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=new(n(176).default)({r:0,g:0,b:0,a:0},"transparent");e.default=r},function(t,e,n){var r=n(58),i=n(59);t.exports=function(t,e,n,a){var o=!n;n||(n={});for(var s=-1,c=e.length;++s-1&&t%1==0&&t-1}(s)?s:(n=s.match(a))?(e=n[0],r.test(e)?"about:blank":s):"about:blank"}}},function(t,e,n){(function(t,r){var i=function(){var t=function(t,e,n,r){for(n=n||{},r=t.length;r--;n[t[r]]=e);return n},e=[2,3],n=[1,7],r=[7,12,15,17,19,20,21],i=[7,11,12,15,17,19,20,21],a=[2,20],o=[1,32],s={trace:function(){},yy:{},symbols_:{error:2,start:3,GG:4,":":5,document:6,EOF:7,DIR:8,options:9,body:10,OPT:11,NL:12,line:13,statement:14,COMMIT:15,commit_arg:16,BRANCH:17,ID:18,CHECKOUT:19,MERGE:20,RESET:21,reset_arg:22,STR:23,HEAD:24,reset_parents:25,CARET:26,$accept:0,$end:1},terminals_:{2:"error",4:"GG",5:":",7:"EOF",8:"DIR",11:"OPT",12:"NL",15:"COMMIT",17:"BRANCH",18:"ID",19:"CHECKOUT",20:"MERGE",21:"RESET",23:"STR",24:"HEAD",26:"CARET"},productions_:[0,[3,4],[3,5],[6,0],[6,2],[9,2],[9,1],[10,0],[10,2],[13,2],[13,1],[14,2],[14,2],[14,2],[14,2],[14,2],[16,0],[16,1],[22,2],[22,2],[25,0],[25,2]],performAction:function(t,e,n,r,i,a,o){var s=a.length-1;switch(i){case 1:return a[s-1];case 2:return r.setDirection(a[s-3]),a[s-1];case 4:r.setOptions(a[s-1]),this.$=a[s];break;case 5:a[s-1]+=a[s],this.$=a[s-1];break;case 7:this.$=[];break;case 8:a[s-1].push(a[s]),this.$=a[s-1];break;case 9:this.$=a[s-1];break;case 11:r.commit(a[s]);break;case 12:r.branch(a[s]);break;case 13:r.checkout(a[s]);break;case 14:r.merge(a[s]);break;case 15:r.reset(a[s]);break;case 16:this.$="";break;case 17:this.$=a[s];break;case 18:this.$=a[s-1]+":"+a[s];break;case 19:this.$=a[s-1]+":"+r.count,r.count=0;break;case 20:r.count=0;break;case 21:r.count+=1}},table:[{3:1,4:[1,2]},{1:[3]},{5:[1,3],8:[1,4]},{6:5,7:e,9:6,12:n},{5:[1,8]},{7:[1,9]},t(r,[2,7],{10:10,11:[1,11]}),t(i,[2,6]),{6:12,7:e,9:6,12:n},{1:[2,1]},{7:[2,4],12:[1,15],13:13,14:14,15:[1,16],17:[1,17],19:[1,18],20:[1,19],21:[1,20]},t(i,[2,5]),{7:[1,21]},t(r,[2,8]),{12:[1,22]},t(r,[2,10]),{12:[2,16],16:23,23:[1,24]},{18:[1,25]},{18:[1,26]},{18:[1,27]},{18:[1,30],22:28,24:[1,29]},{1:[2,2]},t(r,[2,9]),{12:[2,11]},{12:[2,17]},{12:[2,12]},{12:[2,13]},{12:[2,14]},{12:[2,15]},{12:a,25:31,26:o},{12:a,25:33,26:o},{12:[2,18]},{12:a,25:34,26:o},{12:[2,19]},{12:[2,21]}],defaultActions:{9:[2,1],21:[2,2],23:[2,11],24:[2,17],25:[2,12],26:[2,13],27:[2,14],28:[2,15],31:[2,18],33:[2,19],34:[2,21]},parseError:function(t,e){if(!e.recoverable){var n=new Error(t);throw n.hash=e,n}this.trace(t)},parse:function(t){var e=this,n=[0],r=[],i=[null],a=[],o=this.table,s="",c=0,u=0,l=0,h=2,f=1,d=a.slice.call(arguments,1),p=Object.create(this.lexer),g={yy:{}};for(var y in this.yy)Object.prototype.hasOwnProperty.call(this.yy,y)&&(g.yy[y]=this.yy[y]);p.setInput(t,g.yy),g.yy.lexer=p,g.yy.parser=this,void 0===p.yylloc&&(p.yylloc={});var v=p.yylloc;a.push(v);var m=p.options&&p.options.ranges;function b(){var t;return"number"!=typeof(t=r.pop()||p.lex()||f)&&(t instanceof Array&&(t=(r=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof g.yy.parseError?this.parseError=g.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;for(var x,_,k,w,E,T,C,A,S,M={};;){if(k=n[n.length-1],this.defaultActions[k]?w=this.defaultActions[k]:(null==x&&(x=b()),w=o[k]&&o[k][x]),void 0===w||!w.length||!w[0]){var O="";for(T in S=[],o[k])this.terminals_[T]&&T>h&&S.push("'"+this.terminals_[T]+"'");O=p.showPosition?"Parse error on line "+(c+1)+":\n"+p.showPosition()+"\nExpecting "+S.join(", ")+", got '"+(this.terminals_[x]||x)+"'":"Parse error on line "+(c+1)+": Unexpected "+(x==f?"end of input":"'"+(this.terminals_[x]||x)+"'"),this.parseError(O,{text:p.match,token:this.terminals_[x]||x,line:p.yylineno,loc:v,expected:S})}if(w[0]instanceof Array&&w.length>1)throw new Error("Parse Error: multiple actions possible at state: "+k+", token: "+x);switch(w[0]){case 1:n.push(x),i.push(p.yytext),a.push(p.yylloc),n.push(w[1]),x=null,_?(x=_,_=null):(u=p.yyleng,s=p.yytext,c=p.yylineno,v=p.yylloc,l>0&&l--);break;case 2:if(C=this.productions_[w[1]][1],M.$=i[i.length-C],M._$={first_line:a[a.length-(C||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-(C||1)].first_column,last_column:a[a.length-1].last_column},m&&(M._$.range=[a[a.length-(C||1)].range[0],a[a.length-1].range[1]]),void 0!==(E=this.performAction.apply(M,[s,u,c,g.yy,w[1],i,a].concat(d))))return E;C&&(n=n.slice(0,-1*C*2),i=i.slice(0,-1*C),a=a.slice(0,-1*C)),n.push(this.productions_[w[1]][0]),i.push(M.$),a.push(M._$),A=o[n[n.length-2]][n[n.length-1]],n.push(A);break;case 3:return!0}}return!0}},c={EOF:1,parseError:function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)},setInput:function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t},unput:function(t){var e=t.length,n=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var r=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var i=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===r.length?this.yylloc.first_column:0)+r[r.length-n.length].length-n[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[i[0],i[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},less:function(t){this.unput(this.match.slice(t))},pastInput:function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"},test_match:function(t,e){var n,r,i;if(this.options.backtrack_lexer&&(i={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(i.yylloc.range=this.yylloc.range.slice(0))),(r=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=r.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:r?r[r.length-1].length-r[r.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],n=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),n)return n;if(this._backtrack){for(var a in i)this[a]=i[a];return!1}return!1},next:function(){if(this.done)return this.EOF;var t,e,n,r;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var i=this._currentRules(),a=0;ae[0].length)){if(e=n,r=a,this.options.backtrack_lexer){if(!1!==(t=this.test_match(n,i[a])))return t;if(this._backtrack){e=!1;continue}return!1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,i[r]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){var t=this.next();return t||this.lex()},begin:function(t){this.conditionStack.push(t)},popState:function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(t){return(t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"},pushState:function(t){this.begin(t)},stateStackSize:function(){return this.conditionStack.length},options:{"case-insensitive":!0},performAction:function(t,e,n,r){switch(n){case 0:return 12;case 1:case 2:case 3:break;case 4:return 4;case 5:return 15;case 6:return 17;case 7:return 20;case 8:return 21;case 9:return 19;case 10:case 11:return 8;case 12:return 5;case 13:return 26;case 14:this.begin("options");break;case 15:this.popState();break;case 16:return 11;case 17:this.begin("string");break;case 18:this.popState();break;case 19:return 23;case 20:return 18;case 21:return 7}},rules:[/^(?:(\r?\n)+)/i,/^(?:\s+)/i,/^(?:#[^\n]*)/i,/^(?:%[^\n]*)/i,/^(?:gitGraph\b)/i,/^(?:commit\b)/i,/^(?:branch\b)/i,/^(?:merge\b)/i,/^(?:reset\b)/i,/^(?:checkout\b)/i,/^(?:LR\b)/i,/^(?:BT\b)/i,/^(?::)/i,/^(?:\^)/i,/^(?:options\r?\n)/i,/^(?:end\r?\n)/i,/^(?:[^\n]+\r?\n)/i,/^(?:["])/i,/^(?:["])/i,/^(?:[^"]*)/i,/^(?:[a-zA-Z][-_\.a-zA-Z0-9]*[-_a-zA-Z0-9])/i,/^(?:$)/i],conditions:{options:{rules:[15,16],inclusive:!1},string:{rules:[18,19],inclusive:!1},INITIAL:{rules:[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,17,20,21],inclusive:!0}}};function u(){this.yy={}}return s.lexer=c,u.prototype=s,s.Parser=u,new u}();e.parser=i,e.Parser=i.Parser,e.parse=function(){return i.parse.apply(i,arguments)},e.main=function(r){r[1]||(console.log("Usage: "+r[0]+" FILE"),t.exit(1));var i=n(19).readFileSync(n(20).normalize(r[1]),"utf8");return e.parser.parse(i)},n.c[n.s]===r&&e.main(t.argv.slice(1))}).call(this,n(14),n(7)(t))},function(t,e,n){(function(t,r){var i=function(){var t=function(t,e,n,r){for(n=n||{},r=t.length;r--;n[t[r]]=e);return n},e=[6,9,10],n={trace:function(){},yy:{},symbols_:{error:2,start:3,info:4,document:5,EOF:6,line:7,statement:8,NL:9,showInfo:10,$accept:0,$end:1},terminals_:{2:"error",4:"info",6:"EOF",9:"NL",10:"showInfo"},productions_:[0,[3,3],[5,0],[5,2],[7,1],[7,1],[8,1]],performAction:function(t,e,n,r,i,a,o){a.length;switch(i){case 1:return r;case 4:break;case 6:r.setInfo(!0)}},table:[{3:1,4:[1,2]},{1:[3]},t(e,[2,2],{5:3}),{6:[1,4],7:5,8:6,9:[1,7],10:[1,8]},{1:[2,1]},t(e,[2,3]),t(e,[2,4]),t(e,[2,5]),t(e,[2,6])],defaultActions:{4:[2,1]},parseError:function(t,e){if(!e.recoverable){var n=new Error(t);throw n.hash=e,n}this.trace(t)},parse:function(t){var e=this,n=[0],r=[],i=[null],a=[],o=this.table,s="",c=0,u=0,l=0,h=2,f=1,d=a.slice.call(arguments,1),p=Object.create(this.lexer),g={yy:{}};for(var y in this.yy)Object.prototype.hasOwnProperty.call(this.yy,y)&&(g.yy[y]=this.yy[y]);p.setInput(t,g.yy),g.yy.lexer=p,g.yy.parser=this,void 0===p.yylloc&&(p.yylloc={});var v=p.yylloc;a.push(v);var m=p.options&&p.options.ranges;function b(){var t;return"number"!=typeof(t=r.pop()||p.lex()||f)&&(t instanceof Array&&(t=(r=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof g.yy.parseError?this.parseError=g.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;for(var x,_,k,w,E,T,C,A,S,M={};;){if(k=n[n.length-1],this.defaultActions[k]?w=this.defaultActions[k]:(null==x&&(x=b()),w=o[k]&&o[k][x]),void 0===w||!w.length||!w[0]){var O="";for(T in S=[],o[k])this.terminals_[T]&&T>h&&S.push("'"+this.terminals_[T]+"'");O=p.showPosition?"Parse error on line "+(c+1)+":\n"+p.showPosition()+"\nExpecting "+S.join(", ")+", got '"+(this.terminals_[x]||x)+"'":"Parse error on line "+(c+1)+": Unexpected "+(x==f?"end of input":"'"+(this.terminals_[x]||x)+"'"),this.parseError(O,{text:p.match,token:this.terminals_[x]||x,line:p.yylineno,loc:v,expected:S})}if(w[0]instanceof Array&&w.length>1)throw new Error("Parse Error: multiple actions possible at state: "+k+", token: "+x);switch(w[0]){case 1:n.push(x),i.push(p.yytext),a.push(p.yylloc),n.push(w[1]),x=null,_?(x=_,_=null):(u=p.yyleng,s=p.yytext,c=p.yylineno,v=p.yylloc,l>0&&l--);break;case 2:if(C=this.productions_[w[1]][1],M.$=i[i.length-C],M._$={first_line:a[a.length-(C||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-(C||1)].first_column,last_column:a[a.length-1].last_column},m&&(M._$.range=[a[a.length-(C||1)].range[0],a[a.length-1].range[1]]),void 0!==(E=this.performAction.apply(M,[s,u,c,g.yy,w[1],i,a].concat(d))))return E;C&&(n=n.slice(0,-1*C*2),i=i.slice(0,-1*C),a=a.slice(0,-1*C)),n.push(this.productions_[w[1]][0]),i.push(M.$),a.push(M._$),A=o[n[n.length-2]][n[n.length-1]],n.push(A);break;case 3:return!0}}return!0}},r={EOF:1,parseError:function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)},setInput:function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t},unput:function(t){var e=t.length,n=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var r=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var i=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===r.length?this.yylloc.first_column:0)+r[r.length-n.length].length-n[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[i[0],i[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},less:function(t){this.unput(this.match.slice(t))},pastInput:function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"},test_match:function(t,e){var n,r,i;if(this.options.backtrack_lexer&&(i={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(i.yylloc.range=this.yylloc.range.slice(0))),(r=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=r.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:r?r[r.length-1].length-r[r.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],n=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),n)return n;if(this._backtrack){for(var a in i)this[a]=i[a];return!1}return!1},next:function(){if(this.done)return this.EOF;var t,e,n,r;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var i=this._currentRules(),a=0;ae[0].length)){if(e=n,r=a,this.options.backtrack_lexer){if(!1!==(t=this.test_match(n,i[a])))return t;if(this._backtrack){e=!1;continue}return!1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,i[r]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){var t=this.next();return t||this.lex()},begin:function(t){this.conditionStack.push(t)},popState:function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(t){return(t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"},pushState:function(t){this.begin(t)},stateStackSize:function(){return this.conditionStack.length},options:{"case-insensitive":!0},performAction:function(t,e,n,r){switch(n){case 0:return 4;case 1:return 9;case 2:return"space";case 3:return 10;case 4:return 6;case 5:return"TXT"}},rules:[/^(?:info\b)/i,/^(?:[\s\n\r]+)/i,/^(?:[\s]+)/i,/^(?:showInfo\b)/i,/^(?:$)/i,/^(?:.)/i],conditions:{INITIAL:{rules:[0,1,2,3,4,5],inclusive:!0}}};function i(){this.yy={}}return n.lexer=r,i.prototype=n,n.Parser=i,new i}();e.parser=i,e.Parser=i.Parser,e.parse=function(){return i.parse.apply(i,arguments)},e.main=function(r){r[1]||(console.log("Usage: "+r[0]+" FILE"),t.exit(1));var i=n(19).readFileSync(n(20).normalize(r[1]),"utf8");return e.parser.parse(i)},n.c[n.s]===r&&e.main(t.argv.slice(1))}).call(this,n(14),n(7)(t))},function(t,e,n){(function(t,r){var i=function(){var t=function(t,e,n,r){for(n=n||{},r=t.length;r--;n[t[r]]=e);return n},e=[1,4],n=[1,5],r=[1,6],i=[1,7],a=[1,9],o=[1,10,12,19,20,21,22],s=[1,6,10,12,19,20,21,22],c=[19,20,21],u=[1,22],l=[6,19,20,21,22],h={trace:function(){},yy:{},symbols_:{error:2,start:3,eol:4,directive:5,PIE:6,document:7,line:8,statement:9,txt:10,value:11,title:12,title_value:13,openDirective:14,typeDirective:15,closeDirective:16,":":17,argDirective:18,NEWLINE:19,";":20,EOF:21,open_directive:22,type_directive:23,arg_directive:24,close_directive:25,$accept:0,$end:1},terminals_:{2:"error",6:"PIE",10:"txt",11:"value",12:"title",13:"title_value",17:":",19:"NEWLINE",20:";",21:"EOF",22:"open_directive",23:"type_directive",24:"arg_directive",25:"close_directive"},productions_:[0,[3,2],[3,2],[3,2],[7,0],[7,2],[8,2],[9,0],[9,2],[9,2],[9,1],[5,3],[5,5],[4,1],[4,1],[4,1],[14,1],[15,1],[18,1],[16,1]],performAction:function(t,e,n,r,i,a,o){var s=a.length-1;switch(i){case 6:this.$=a[s-1];break;case 8:r.addSection(a[s-1],r.cleanupValue(a[s]));break;case 9:this.$=a[s].trim(),r.setTitle(this.$);break;case 16:r.parseDirective("%%{","open_directive");break;case 17:r.parseDirective(a[s],"type_directive");break;case 18:a[s]=a[s].trim().replace(/'/g,'"'),r.parseDirective(a[s],"arg_directive");break;case 19:r.parseDirective("}%%","close_directive","pie")}},table:[{3:1,4:2,5:3,6:e,14:8,19:n,20:r,21:i,22:a},{1:[3]},{3:10,4:2,5:3,6:e,14:8,19:n,20:r,21:i,22:a},{3:11,4:2,5:3,6:e,14:8,19:n,20:r,21:i,22:a},t(o,[2,4],{7:12}),t(s,[2,13]),t(s,[2,14]),t(s,[2,15]),{15:13,23:[1,14]},{23:[2,16]},{1:[2,1]},{1:[2,2]},t(c,[2,7],{14:8,8:15,9:16,5:19,1:[2,3],10:[1,17],12:[1,18],22:a}),{16:20,17:[1,21],25:u},t([17,25],[2,17]),t(o,[2,5]),{4:23,19:n,20:r,21:i},{11:[1,24]},{13:[1,25]},t(c,[2,10]),t(l,[2,11]),{18:26,24:[1,27]},t(l,[2,19]),t(o,[2,6]),t(c,[2,8]),t(c,[2,9]),{16:28,25:u},{25:[2,18]},t(l,[2,12])],defaultActions:{9:[2,16],10:[2,1],11:[2,2],27:[2,18]},parseError:function(t,e){if(!e.recoverable){var n=new Error(t);throw n.hash=e,n}this.trace(t)},parse:function(t){var e=this,n=[0],r=[],i=[null],a=[],o=this.table,s="",c=0,u=0,l=0,h=2,f=1,d=a.slice.call(arguments,1),p=Object.create(this.lexer),g={yy:{}};for(var y in this.yy)Object.prototype.hasOwnProperty.call(this.yy,y)&&(g.yy[y]=this.yy[y]);p.setInput(t,g.yy),g.yy.lexer=p,g.yy.parser=this,void 0===p.yylloc&&(p.yylloc={});var v=p.yylloc;a.push(v);var m=p.options&&p.options.ranges;function b(){var t;return"number"!=typeof(t=r.pop()||p.lex()||f)&&(t instanceof Array&&(t=(r=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof g.yy.parseError?this.parseError=g.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;for(var x,_,k,w,E,T,C,A,S,M={};;){if(k=n[n.length-1],this.defaultActions[k]?w=this.defaultActions[k]:(null==x&&(x=b()),w=o[k]&&o[k][x]),void 0===w||!w.length||!w[0]){var O="";for(T in S=[],o[k])this.terminals_[T]&&T>h&&S.push("'"+this.terminals_[T]+"'");O=p.showPosition?"Parse error on line "+(c+1)+":\n"+p.showPosition()+"\nExpecting "+S.join(", ")+", got '"+(this.terminals_[x]||x)+"'":"Parse error on line "+(c+1)+": Unexpected "+(x==f?"end of input":"'"+(this.terminals_[x]||x)+"'"),this.parseError(O,{text:p.match,token:this.terminals_[x]||x,line:p.yylineno,loc:v,expected:S})}if(w[0]instanceof Array&&w.length>1)throw new Error("Parse Error: multiple actions possible at state: "+k+", token: "+x);switch(w[0]){case 1:n.push(x),i.push(p.yytext),a.push(p.yylloc),n.push(w[1]),x=null,_?(x=_,_=null):(u=p.yyleng,s=p.yytext,c=p.yylineno,v=p.yylloc,l>0&&l--);break;case 2:if(C=this.productions_[w[1]][1],M.$=i[i.length-C],M._$={first_line:a[a.length-(C||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-(C||1)].first_column,last_column:a[a.length-1].last_column},m&&(M._$.range=[a[a.length-(C||1)].range[0],a[a.length-1].range[1]]),void 0!==(E=this.performAction.apply(M,[s,u,c,g.yy,w[1],i,a].concat(d))))return E;C&&(n=n.slice(0,-1*C*2),i=i.slice(0,-1*C),a=a.slice(0,-1*C)),n.push(this.productions_[w[1]][0]),i.push(M.$),a.push(M._$),A=o[n[n.length-2]][n[n.length-1]],n.push(A);break;case 3:return!0}}return!0}},f={EOF:1,parseError:function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)},setInput:function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t},unput:function(t){var e=t.length,n=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var r=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var i=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===r.length?this.yylloc.first_column:0)+r[r.length-n.length].length-n[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[i[0],i[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},less:function(t){this.unput(this.match.slice(t))},pastInput:function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"},test_match:function(t,e){var n,r,i;if(this.options.backtrack_lexer&&(i={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(i.yylloc.range=this.yylloc.range.slice(0))),(r=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=r.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:r?r[r.length-1].length-r[r.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],n=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),n)return n;if(this._backtrack){for(var a in i)this[a]=i[a];return!1}return!1},next:function(){if(this.done)return this.EOF;var t,e,n,r;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var i=this._currentRules(),a=0;ae[0].length)){if(e=n,r=a,this.options.backtrack_lexer){if(!1!==(t=this.test_match(n,i[a])))return t;if(this._backtrack){e=!1;continue}return!1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,i[r]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){var t=this.next();return t||this.lex()},begin:function(t){this.conditionStack.push(t)},popState:function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(t){return(t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"},pushState:function(t){this.begin(t)},stateStackSize:function(){return this.conditionStack.length},options:{"case-insensitive":!0},performAction:function(t,e,n,r){switch(n){case 0:return this.begin("open_directive"),22;case 1:return this.begin("type_directive"),23;case 2:return this.popState(),this.begin("arg_directive"),17;case 3:return this.popState(),this.popState(),25;case 4:return 24;case 5:case 6:break;case 7:return 19;case 8:case 9:break;case 10:return this.begin("title"),12;case 11:return this.popState(),"title_value";case 12:this.begin("string");break;case 13:this.popState();break;case 14:return"txt";case 15:return 6;case 16:return"value";case 17:return 21}},rules:[/^(?:%%\{)/i,/^(?:((?:(?!\}%%)[^:.])*))/i,/^(?::)/i,/^(?:\}%%)/i,/^(?:((?:(?!\}%%).|\n)*))/i,/^(?:%%(?!\{)[^\n]*)/i,/^(?:[^\}]%%[^\n]*)/i,/^(?:[\n\r]+)/i,/^(?:%%[^\n]*)/i,/^(?:[\s]+)/i,/^(?:title\b)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:["])/i,/^(?:["])/i,/^(?:[^"]*)/i,/^(?:pie\b)/i,/^(?::[\s]*[\d]+(?:\.[\d]+)?)/i,/^(?:$)/i],conditions:{close_directive:{rules:[],inclusive:!1},arg_directive:{rules:[3,4],inclusive:!1},type_directive:{rules:[2,3],inclusive:!1},open_directive:{rules:[1],inclusive:!1},title:{rules:[11],inclusive:!1},string:{rules:[13,14],inclusive:!1},INITIAL:{rules:[0,5,6,7,8,9,10,12,15,16,17],inclusive:!0}}};function d(){this.yy={}}return h.lexer=f,d.prototype=h,h.Parser=d,new d}();e.parser=i,e.Parser=i.Parser,e.parse=function(){return i.parse.apply(i,arguments)},e.main=function(r){r[1]||(console.log("Usage: "+r[0]+" FILE"),t.exit(1));var i=n(19).readFileSync(n(20).normalize(r[1]),"utf8");return e.parser.parse(i)},n.c[n.s]===r&&e.main(t.argv.slice(1))}).call(this,n(14),n(7)(t))},function(t,e,n){(function(t,r){var i=function(){var t=function(t,e,n,r){for(n=n||{},r=t.length;r--;n[t[r]]=e);return n},e=[1,2],n=[1,5],r=[6,9,11,23,37],i=[1,17],a=[1,20],o=[1,25],s=[1,26],c=[1,27],u=[1,28],l=[1,37],h=[23,34,35],f=[4,6,9,11,23,37],d=[30,31,32,33],p=[22,27],g={trace:function(){},yy:{},symbols_:{error:2,start:3,ER_DIAGRAM:4,document:5,EOF:6,directive:7,line:8,SPACE:9,statement:10,NEWLINE:11,openDirective:12,typeDirective:13,closeDirective:14,":":15,argDirective:16,entityName:17,relSpec:18,role:19,BLOCK_START:20,attributes:21,BLOCK_STOP:22,ALPHANUM:23,attribute:24,attributeType:25,attributeName:26,ATTRIBUTE_WORD:27,cardinality:28,relType:29,ZERO_OR_ONE:30,ZERO_OR_MORE:31,ONE_OR_MORE:32,ONLY_ONE:33,NON_IDENTIFYING:34,IDENTIFYING:35,WORD:36,open_directive:37,type_directive:38,arg_directive:39,close_directive:40,$accept:0,$end:1},terminals_:{2:"error",4:"ER_DIAGRAM",6:"EOF",9:"SPACE",11:"NEWLINE",15:":",20:"BLOCK_START",22:"BLOCK_STOP",23:"ALPHANUM",27:"ATTRIBUTE_WORD",30:"ZERO_OR_ONE",31:"ZERO_OR_MORE",32:"ONE_OR_MORE",33:"ONLY_ONE",34:"NON_IDENTIFYING",35:"IDENTIFYING",36:"WORD",37:"open_directive",38:"type_directive",39:"arg_directive",40:"close_directive"},productions_:[0,[3,3],[3,2],[5,0],[5,2],[8,2],[8,1],[8,1],[8,1],[7,4],[7,6],[10,1],[10,5],[10,4],[10,3],[10,1],[17,1],[21,1],[21,2],[24,2],[25,1],[26,1],[18,3],[28,1],[28,1],[28,1],[28,1],[29,1],[29,1],[19,1],[19,1],[12,1],[13,1],[16,1],[14,1]],performAction:function(t,e,n,r,i,a,o){var s=a.length-1;switch(i){case 1:break;case 3:this.$=[];break;case 4:a[s-1].push(a[s]),this.$=a[s-1];break;case 5:case 6:this.$=a[s];break;case 7:case 8:this.$=[];break;case 12:r.addEntity(a[s-4]),r.addEntity(a[s-2]),r.addRelationship(a[s-4],a[s],a[s-2],a[s-3]);break;case 13:r.addEntity(a[s-3]),r.addAttributes(a[s-3],a[s-1]);break;case 14:r.addEntity(a[s-2]);break;case 15:r.addEntity(a[s]);break;case 16:this.$=a[s];break;case 17:this.$=[a[s]];break;case 18:a[s].push(a[s-1]),this.$=a[s];break;case 19:this.$={attributeType:a[s-1],attributeName:a[s]};break;case 20:case 21:this.$=a[s];break;case 22:this.$={cardA:a[s],relType:a[s-1],cardB:a[s-2]};break;case 23:this.$=r.Cardinality.ZERO_OR_ONE;break;case 24:this.$=r.Cardinality.ZERO_OR_MORE;break;case 25:this.$=r.Cardinality.ONE_OR_MORE;break;case 26:this.$=r.Cardinality.ONLY_ONE;break;case 27:this.$=r.Identification.NON_IDENTIFYING;break;case 28:this.$=r.Identification.IDENTIFYING;break;case 29:this.$=a[s].replace(/"/g,"");break;case 30:this.$=a[s];break;case 31:r.parseDirective("%%{","open_directive");break;case 32:r.parseDirective(a[s],"type_directive");break;case 33:a[s]=a[s].trim().replace(/'/g,'"'),r.parseDirective(a[s],"arg_directive");break;case 34:r.parseDirective("}%%","close_directive","er")}},table:[{3:1,4:e,7:3,12:4,37:n},{1:[3]},t(r,[2,3],{5:6}),{3:7,4:e,7:3,12:4,37:n},{13:8,38:[1,9]},{38:[2,31]},{6:[1,10],7:15,8:11,9:[1,12],10:13,11:[1,14],12:4,17:16,23:i,37:n},{1:[2,2]},{14:18,15:[1,19],40:a},t([15,40],[2,32]),t(r,[2,8],{1:[2,1]}),t(r,[2,4]),{7:15,10:21,12:4,17:16,23:i,37:n},t(r,[2,6]),t(r,[2,7]),t(r,[2,11]),t(r,[2,15],{18:22,28:24,20:[1,23],30:o,31:s,32:c,33:u}),t([6,9,11,15,20,23,30,31,32,33,37],[2,16]),{11:[1,29]},{16:30,39:[1,31]},{11:[2,34]},t(r,[2,5]),{17:32,23:i},{21:33,22:[1,34],24:35,25:36,27:l},{29:38,34:[1,39],35:[1,40]},t(h,[2,23]),t(h,[2,24]),t(h,[2,25]),t(h,[2,26]),t(f,[2,9]),{14:41,40:a},{40:[2,33]},{15:[1,42]},{22:[1,43]},t(r,[2,14]),{21:44,22:[2,17],24:35,25:36,27:l},{26:45,27:[1,46]},{27:[2,20]},{28:47,30:o,31:s,32:c,33:u},t(d,[2,27]),t(d,[2,28]),{11:[1,48]},{19:49,23:[1,51],36:[1,50]},t(r,[2,13]),{22:[2,18]},t(p,[2,19]),t(p,[2,21]),{23:[2,22]},t(f,[2,10]),t(r,[2,12]),t(r,[2,29]),t(r,[2,30])],defaultActions:{5:[2,31],7:[2,2],20:[2,34],31:[2,33],37:[2,20],44:[2,18],47:[2,22]},parseError:function(t,e){if(!e.recoverable){var n=new Error(t);throw n.hash=e,n}this.trace(t)},parse:function(t){var e=this,n=[0],r=[],i=[null],a=[],o=this.table,s="",c=0,u=0,l=0,h=2,f=1,d=a.slice.call(arguments,1),p=Object.create(this.lexer),g={yy:{}};for(var y in this.yy)Object.prototype.hasOwnProperty.call(this.yy,y)&&(g.yy[y]=this.yy[y]);p.setInput(t,g.yy),g.yy.lexer=p,g.yy.parser=this,void 0===p.yylloc&&(p.yylloc={});var v=p.yylloc;a.push(v);var m=p.options&&p.options.ranges;function b(){var t;return"number"!=typeof(t=r.pop()||p.lex()||f)&&(t instanceof Array&&(t=(r=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof g.yy.parseError?this.parseError=g.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;for(var x,_,k,w,E,T,C,A,S,M={};;){if(k=n[n.length-1],this.defaultActions[k]?w=this.defaultActions[k]:(null==x&&(x=b()),w=o[k]&&o[k][x]),void 0===w||!w.length||!w[0]){var O="";for(T in S=[],o[k])this.terminals_[T]&&T>h&&S.push("'"+this.terminals_[T]+"'");O=p.showPosition?"Parse error on line "+(c+1)+":\n"+p.showPosition()+"\nExpecting "+S.join(", ")+", got '"+(this.terminals_[x]||x)+"'":"Parse error on line "+(c+1)+": Unexpected "+(x==f?"end of input":"'"+(this.terminals_[x]||x)+"'"),this.parseError(O,{text:p.match,token:this.terminals_[x]||x,line:p.yylineno,loc:v,expected:S})}if(w[0]instanceof Array&&w.length>1)throw new Error("Parse Error: multiple actions possible at state: "+k+", token: "+x);switch(w[0]){case 1:n.push(x),i.push(p.yytext),a.push(p.yylloc),n.push(w[1]),x=null,_?(x=_,_=null):(u=p.yyleng,s=p.yytext,c=p.yylineno,v=p.yylloc,l>0&&l--);break;case 2:if(C=this.productions_[w[1]][1],M.$=i[i.length-C],M._$={first_line:a[a.length-(C||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-(C||1)].first_column,last_column:a[a.length-1].last_column},m&&(M._$.range=[a[a.length-(C||1)].range[0],a[a.length-1].range[1]]),void 0!==(E=this.performAction.apply(M,[s,u,c,g.yy,w[1],i,a].concat(d))))return E;C&&(n=n.slice(0,-1*C*2),i=i.slice(0,-1*C),a=a.slice(0,-1*C)),n.push(this.productions_[w[1]][0]),i.push(M.$),a.push(M._$),A=o[n[n.length-2]][n[n.length-1]],n.push(A);break;case 3:return!0}}return!0}},y={EOF:1,parseError:function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)},setInput:function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t},unput:function(t){var e=t.length,n=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var r=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var i=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===r.length?this.yylloc.first_column:0)+r[r.length-n.length].length-n[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[i[0],i[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},less:function(t){this.unput(this.match.slice(t))},pastInput:function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"},test_match:function(t,e){var n,r,i;if(this.options.backtrack_lexer&&(i={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(i.yylloc.range=this.yylloc.range.slice(0))),(r=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=r.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:r?r[r.length-1].length-r[r.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],n=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),n)return n;if(this._backtrack){for(var a in i)this[a]=i[a];return!1}return!1},next:function(){if(this.done)return this.EOF;var t,e,n,r;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var i=this._currentRules(),a=0;ae[0].length)){if(e=n,r=a,this.options.backtrack_lexer){if(!1!==(t=this.test_match(n,i[a])))return t;if(this._backtrack){e=!1;continue}return!1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,i[r]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){var t=this.next();return t||this.lex()},begin:function(t){this.conditionStack.push(t)},popState:function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(t){return(t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"},pushState:function(t){this.begin(t)},stateStackSize:function(){return this.conditionStack.length},options:{"case-insensitive":!0},performAction:function(t,e,n,r){switch(n){case 0:return this.begin("open_directive"),37;case 1:return this.begin("type_directive"),38;case 2:return this.popState(),this.begin("arg_directive"),15;case 3:return this.popState(),this.popState(),40;case 4:return 39;case 5:case 6:break;case 7:return 11;case 8:break;case 9:return 9;case 10:return 36;case 11:return 4;case 12:return this.begin("block"),20;case 13:break;case 14:return 27;case 15:break;case 16:return this.popState(),22;case 17:return e.yytext[0];case 18:return 30;case 19:return 31;case 20:return 32;case 21:return 33;case 22:return 30;case 23:return 31;case 24:return 32;case 25:return 34;case 26:return 35;case 27:case 28:return 34;case 29:return 23;case 30:return e.yytext[0];case 31:return 6}},rules:[/^(?:%%\{)/i,/^(?:((?:(?!\}%%)[^:.])*))/i,/^(?::)/i,/^(?:\}%%)/i,/^(?:((?:(?!\}%%).|\n)*))/i,/^(?:%(?!\{)[^\n]*)/i,/^(?:[^\}]%%[^\n]*)/i,/^(?:[\n]+)/i,/^(?:\s+)/i,/^(?:[\s]+)/i,/^(?:"[^"]*")/i,/^(?:erDiagram\b)/i,/^(?:\{)/i,/^(?:\s+)/i,/^(?:[A-Za-z][A-Za-z0-9\-_]*)/i,/^(?:[\n]+)/i,/^(?:\})/i,/^(?:.)/i,/^(?:\|o\b)/i,/^(?:\}o\b)/i,/^(?:\}\|)/i,/^(?:\|\|)/i,/^(?:o\|)/i,/^(?:o\{)/i,/^(?:\|\{)/i,/^(?:\.\.)/i,/^(?:--)/i,/^(?:\.-)/i,/^(?:-\.)/i,/^(?:[A-Za-z][A-Za-z0-9\-_]*)/i,/^(?:.)/i,/^(?:$)/i],conditions:{open_directive:{rules:[1],inclusive:!1},type_directive:{rules:[2,3],inclusive:!1},arg_directive:{rules:[3,4],inclusive:!1},block:{rules:[13,14,15,16,17],inclusive:!1},INITIAL:{rules:[0,5,6,7,8,9,10,11,12,18,19,20,21,22,23,24,25,26,27,28,29,30,31],inclusive:!0}}};function v(){this.yy={}}return g.lexer=y,v.prototype=g,g.Parser=v,new v}();e.parser=i,e.Parser=i.Parser,e.parse=function(){return i.parse.apply(i,arguments)},e.main=function(r){r[1]||(console.log("Usage: "+r[0]+" FILE"),t.exit(1));var i=n(19).readFileSync(n(20).normalize(r[1]),"utf8");return e.parser.parse(i)},n.c[n.s]===r&&e.main(t.argv.slice(1))}).call(this,n(14),n(7)(t))},function(t,e,n){"use strict";var r;Object.defineProperty(e,"__esModule",{value:!0}),function(t){t[t.ALL=0]="ALL",t[t.RGB=1]="RGB",t[t.HSL=2]="HSL"}(r||(r={})),e.TYPE=r},function(t,e,n){"use strict";var r=n(10);t.exports=i;function i(t){this._isDirected=!r.has(t,"directed")||t.directed,this._isMultigraph=!!r.has(t,"multigraph")&&t.multigraph,this._isCompound=!!r.has(t,"compound")&&t.compound,this._label=void 0,this._defaultNodeLabelFn=r.constant(void 0),this._defaultEdgeLabelFn=r.constant(void 0),this._nodes={},this._isCompound&&(this._parent={},this._children={},this._children["\0"]={}),this._in={},this._preds={},this._out={},this._sucs={},this._edgeObjs={},this._edgeLabels={}}function a(t,e){t[e]?t[e]++:t[e]=1}function o(t,e){--t[e]||delete t[e]}function s(t,e,n,i){var a=""+e,o=""+n;if(!t&&a>o){var s=a;a=o,o=s}return a+""+o+""+(r.isUndefined(i)?"\0":i)}function c(t,e,n,r){var i=""+e,a=""+n;if(!t&&i>a){var o=i;i=a,a=o}var s={v:i,w:a};return r&&(s.name=r),s}function u(t,e){return s(t,e.v,e.w,e.name)}i.prototype._nodeCount=0,i.prototype._edgeCount=0,i.prototype.isDirected=function(){return this._isDirected},i.prototype.isMultigraph=function(){return this._isMultigraph},i.prototype.isCompound=function(){return this._isCompound},i.prototype.setGraph=function(t){return this._label=t,this},i.prototype.graph=function(){return this._label},i.prototype.setDefaultNodeLabel=function(t){return r.isFunction(t)||(t=r.constant(t)),this._defaultNodeLabelFn=t,this},i.prototype.nodeCount=function(){return this._nodeCount},i.prototype.nodes=function(){return r.keys(this._nodes)},i.prototype.sources=function(){var t=this;return r.filter(this.nodes(),(function(e){return r.isEmpty(t._in[e])}))},i.prototype.sinks=function(){var t=this;return r.filter(this.nodes(),(function(e){return r.isEmpty(t._out[e])}))},i.prototype.setNodes=function(t,e){var n=arguments,i=this;return r.each(t,(function(t){n.length>1?i.setNode(t,e):i.setNode(t)})),this},i.prototype.setNode=function(t,e){return r.has(this._nodes,t)?(arguments.length>1&&(this._nodes[t]=e),this):(this._nodes[t]=arguments.length>1?e:this._defaultNodeLabelFn(t),this._isCompound&&(this._parent[t]="\0",this._children[t]={},this._children["\0"][t]=!0),this._in[t]={},this._preds[t]={},this._out[t]={},this._sucs[t]={},++this._nodeCount,this)},i.prototype.node=function(t){return this._nodes[t]},i.prototype.hasNode=function(t){return r.has(this._nodes,t)},i.prototype.removeNode=function(t){var e=this;if(r.has(this._nodes,t)){var n=function(t){e.removeEdge(e._edgeObjs[t])};delete this._nodes[t],this._isCompound&&(this._removeFromParentsChildList(t),delete this._parent[t],r.each(this.children(t),(function(t){e.setParent(t)})),delete this._children[t]),r.each(r.keys(this._in[t]),n),delete this._in[t],delete this._preds[t],r.each(r.keys(this._out[t]),n),delete this._out[t],delete this._sucs[t],--this._nodeCount}return this},i.prototype.setParent=function(t,e){if(!this._isCompound)throw new Error("Cannot set parent in a non-compound graph");if(r.isUndefined(e))e="\0";else{for(var n=e+="";!r.isUndefined(n);n=this.parent(n))if(n===t)throw new Error("Setting "+e+" as parent of "+t+" would create a cycle");this.setNode(e)}return this.setNode(t),this._removeFromParentsChildList(t),this._parent[t]=e,this._children[e][t]=!0,this},i.prototype._removeFromParentsChildList=function(t){delete this._children[this._parent[t]][t]},i.prototype.parent=function(t){if(this._isCompound){var e=this._parent[t];if("\0"!==e)return e}},i.prototype.children=function(t){if(r.isUndefined(t)&&(t="\0"),this._isCompound){var e=this._children[t];if(e)return r.keys(e)}else{if("\0"===t)return this.nodes();if(this.hasNode(t))return[]}},i.prototype.predecessors=function(t){var e=this._preds[t];if(e)return r.keys(e)},i.prototype.successors=function(t){var e=this._sucs[t];if(e)return r.keys(e)},i.prototype.neighbors=function(t){var e=this.predecessors(t);if(e)return r.union(e,this.successors(t))},i.prototype.isLeaf=function(t){return 0===(this.isDirected()?this.successors(t):this.neighbors(t)).length},i.prototype.filterNodes=function(t){var e=new this.constructor({directed:this._isDirected,multigraph:this._isMultigraph,compound:this._isCompound});e.setGraph(this.graph());var n=this;r.each(this._nodes,(function(n,r){t(r)&&e.setNode(r,n)})),r.each(this._edgeObjs,(function(t){e.hasNode(t.v)&&e.hasNode(t.w)&&e.setEdge(t,n.edge(t))}));var i={};return this._isCompound&&r.each(e.nodes(),(function(t){e.setParent(t,function t(r){var a=n.parent(r);return void 0===a||e.hasNode(a)?(i[r]=a,a):a in i?i[a]:t(a)}(t))})),e},i.prototype.setDefaultEdgeLabel=function(t){return r.isFunction(t)||(t=r.constant(t)),this._defaultEdgeLabelFn=t,this},i.prototype.edgeCount=function(){return this._edgeCount},i.prototype.edges=function(){return r.values(this._edgeObjs)},i.prototype.setPath=function(t,e){var n=this,i=arguments;return r.reduce(t,(function(t,r){return i.length>1?n.setEdge(t,r,e):n.setEdge(t,r),r})),this},i.prototype.setEdge=function(){var t,e,n,i,o=!1,u=arguments[0];"object"==typeof u&&null!==u&&"v"in u?(t=u.v,e=u.w,n=u.name,2===arguments.length&&(i=arguments[1],o=!0)):(t=u,e=arguments[1],n=arguments[3],arguments.length>2&&(i=arguments[2],o=!0)),t=""+t,e=""+e,r.isUndefined(n)||(n=""+n);var l=s(this._isDirected,t,e,n);if(r.has(this._edgeLabels,l))return o&&(this._edgeLabels[l]=i),this;if(!r.isUndefined(n)&&!this._isMultigraph)throw new Error("Cannot set a named edge when isMultigraph = false");this.setNode(t),this.setNode(e),this._edgeLabels[l]=o?i:this._defaultEdgeLabelFn(t,e,n);var h=c(this._isDirected,t,e,n);return t=h.v,e=h.w,Object.freeze(h),this._edgeObjs[l]=h,a(this._preds[e],t),a(this._sucs[t],e),this._in[e][l]=h,this._out[t][l]=h,this._edgeCount++,this},i.prototype.edge=function(t,e,n){var r=1===arguments.length?u(this._isDirected,arguments[0]):s(this._isDirected,t,e,n);return this._edgeLabels[r]},i.prototype.hasEdge=function(t,e,n){var i=1===arguments.length?u(this._isDirected,arguments[0]):s(this._isDirected,t,e,n);return r.has(this._edgeLabels,i)},i.prototype.removeEdge=function(t,e,n){var r=1===arguments.length?u(this._isDirected,arguments[0]):s(this._isDirected,t,e,n),i=this._edgeObjs[r];return i&&(t=i.v,e=i.w,delete this._edgeLabels[r],delete this._edgeObjs[r],o(this._preds[e],t),o(this._sucs[t],e),delete this._in[e][r],delete this._out[t][r],this._edgeCount--),this},i.prototype.inEdges=function(t,e){var n=this._in[t];if(n){var i=r.values(n);return e?r.filter(i,(function(t){return t.v===e})):i}},i.prototype.outEdges=function(t,e){var n=this._out[t];if(n){var i=r.values(n);return e?r.filter(i,(function(t){return t.w===e})):i}},i.prototype.nodeEdges=function(t,e){var n=this.inEdges(t,e);if(n)return n.concat(this.outEdges(t,e))}},function(t,e,n){var r=n(33)(n(16),"Map");t.exports=r},function(t,e,n){var r=n(217),i=n(224),a=n(226),o=n(227),s=n(228);function c(t){var e=-1,n=null==t?0:t.length;for(this.clear();++e-1&&t%1==0&&t<=9007199254740991}},function(t,e,n){(function(t){var r=n(109),i=e&&!e.nodeType&&e,a=i&&"object"==typeof t&&t&&!t.nodeType&&t,o=a&&a.exports===i&&r.process,s=function(){try{var t=a&&a.require&&a.require("util").types;return t||o&&o.binding&&o.binding("util")}catch(t){}}();t.exports=s}).call(this,n(7)(t))},function(t,e,n){var r=n(62),i=n(234),a=Object.prototype.hasOwnProperty;t.exports=function(t){if(!r(t))return i(t);var e=[];for(var n in Object(t))a.call(t,n)&&"constructor"!=n&&e.push(n);return e}},function(t,e,n){var r=n(116),i=n(117),a=Object.prototype.propertyIsEnumerable,o=Object.getOwnPropertySymbols,s=o?function(t){return null==t?[]:(t=Object(t),r(o(t),(function(e){return a.call(t,e)})))}:i;t.exports=s},function(t,e){t.exports=function(t,e){for(var n=-1,r=e.length,i=t.length;++n0&&a(l)?n>1?t(l,n-1,a,o,s):r(s,l):o||(s[s.length]=l)}return s}},function(t,e,n){var r=n(42);t.exports=function(t,e,n){for(var i=-1,a=t.length;++i4,u=c?1:17,l=c?8:4,h=s?0:-1,f=c?255:15;return i.default.set({r:(r>>l*(h+3)&f)*u,g:(r>>l*(h+2)&f)*u,b:(r>>l*(h+1)&f)*u,a:s?(r&f)*u/255:1},t)}}},stringify:function(t){return t.a<1?"#"+a.DEC2HEX[Math.round(t.r)]+a.DEC2HEX[Math.round(t.g)]+a.DEC2HEX[Math.round(t.b)]+r.default.unit.frac2hex(t.a):"#"+a.DEC2HEX[Math.round(t.r)]+a.DEC2HEX[Math.round(t.g)]+a.DEC2HEX[Math.round(t.b)]}};e.default=o},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=n(9),i=n(45),a=n(15);e.default=function(t,e,n,o){void 0===o&&(o=1);var s=i.default.set({h:r.default.channel.clamp.h(t),s:r.default.channel.clamp.s(e),l:r.default.channel.clamp.l(n),a:r.default.channel.clamp.a(o)});return a.default.stringify(s)}},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=n(29);e.default=function(t){return r.default(t,"a")}},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=n(9),i=n(15);e.default=function(t){var e=i.default.parse(t),n=e.r,a=e.g,o=e.b,s=.2126*r.default.channel.toLinear(n)+.7152*r.default.channel.toLinear(a)+.0722*r.default.channel.toLinear(o);return r.default.lang.round(s)}},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=n(102);e.default=function(t){return r.default(t)>=.5}},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=n(32);e.default=function(t,e){return r.default(t,"a",e)}},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=n(32);e.default=function(t,e){return r.default(t,"a",-e)}},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=n(15),i=n(52);e.default=function(t,e){var n=r.default.parse(t),a={};for(var o in e)e[o]&&(a[o]=n[o]+e[o]);return i.default(t,a)}},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=n(15),i=n(51);e.default=function(t,e,n){void 0===n&&(n=50);var a=r.default.parse(t),o=a.r,s=a.g,c=a.b,u=a.a,l=r.default.parse(e),h=l.r,f=l.g,d=l.b,p=l.a,g=n/100,y=2*g-1,v=u-p,m=((y*v==-1?y:(y+v)/(1+y*v))+1)/2,b=1-m,x=o*m+h*b,_=s*m+f*b,k=c*m+d*b,w=u*g+p*(1-g);return i.default(x,_,k,w)}},function(t,e,n){var r=n(53),i=n(79),a=n(58),o=n(229),s=n(235),c=n(114),u=n(115),l=n(238),h=n(239),f=n(119),d=n(240),p=n(41),g=n(244),y=n(245),v=n(124),m=n(5),b=n(39),x=n(249),_=n(11),k=n(251),w=n(30),E={};E["[object Arguments]"]=E["[object Array]"]=E["[object ArrayBuffer]"]=E["[object DataView]"]=E["[object Boolean]"]=E["[object Date]"]=E["[object Float32Array]"]=E["[object Float64Array]"]=E["[object Int8Array]"]=E["[object Int16Array]"]=E["[object Int32Array]"]=E["[object Map]"]=E["[object Number]"]=E["[object Object]"]=E["[object RegExp]"]=E["[object Set]"]=E["[object String]"]=E["[object Symbol]"]=E["[object Uint8Array]"]=E["[object Uint8ClampedArray]"]=E["[object Uint16Array]"]=E["[object Uint32Array]"]=!0,E["[object Error]"]=E["[object Function]"]=E["[object WeakMap]"]=!1,t.exports=function t(e,n,T,C,A,S){var M,O=1&n,D=2&n,N=4&n;if(T&&(M=A?T(e,C,A,S):T(e)),void 0!==M)return M;if(!_(e))return e;var B=m(e);if(B){if(M=g(e),!O)return u(e,M)}else{var L=p(e),F="[object Function]"==L||"[object GeneratorFunction]"==L;if(b(e))return c(e,O);if("[object Object]"==L||"[object Arguments]"==L||F&&!A){if(M=D||F?{}:v(e),!O)return D?h(e,s(M,e)):l(e,o(M,e))}else{if(!E[L])return A?e:{};M=y(e,L,O)}}S||(S=new r);var P=S.get(e);if(P)return P;S.set(e,M),k(e)?e.forEach((function(r){M.add(t(r,n,T,r,e,S))})):x(e)&&e.forEach((function(r,i){M.set(i,t(r,n,T,i,e,S))}));var I=N?D?d:f:D?keysIn:w,j=B?void 0:I(e);return i(j||e,(function(r,i){j&&(r=e[i=r]),a(M,i,t(r,n,T,i,e,S))})),M}},function(t,e,n){(function(e){var n="object"==typeof e&&e&&e.Object===Object&&e;t.exports=n}).call(this,n(211))},function(t,e){var n=Function.prototype.toString;t.exports=function(t){if(null!=t){try{return n.call(t)}catch(t){}try{return t+""}catch(t){}}return""}},function(t,e,n){var r=n(33),i=function(){try{var t=r(Object,"defineProperty");return t({},"",{}),t}catch(t){}}();t.exports=i},function(t,e,n){var r=n(230),i=n(47),a=n(5),o=n(39),s=n(60),c=n(48),u=Object.prototype.hasOwnProperty;t.exports=function(t,e){var n=a(t),l=!n&&i(t),h=!n&&!l&&o(t),f=!n&&!l&&!h&&c(t),d=n||l||h||f,p=d?r(t.length,String):[],g=p.length;for(var y in t)!e&&!u.call(t,y)||d&&("length"==y||h&&("offset"==y||"parent"==y)||f&&("buffer"==y||"byteLength"==y||"byteOffset"==y)||s(y,g))||p.push(y);return p}},function(t,e){t.exports=function(t,e){return function(n){return t(e(n))}}},function(t,e,n){(function(t){var r=n(16),i=e&&!e.nodeType&&e,a=i&&"object"==typeof t&&t&&!t.nodeType&&t,o=a&&a.exports===i?r.Buffer:void 0,s=o?o.allocUnsafe:void 0;t.exports=function(t,e){if(e)return t.slice();var n=t.length,r=s?s(n):new t.constructor(n);return t.copy(r),r}}).call(this,n(7)(t))},function(t,e){t.exports=function(t,e){var n=-1,r=t.length;for(e||(e=Array(r));++nl))return!1;var f=c.get(t);if(f&&c.get(e))return f==e;var d=-1,p=!0,g=2&n?new r:void 0;for(c.set(t,e),c.set(e,t);++d0&&(a=c.removeMin(),(o=s[a]).distance!==Number.POSITIVE_INFINITY);)r(a).forEach(u);return s}(t,String(e),n||a,r||function(e){return t.outEdges(e)})};var a=r.constant(1)},function(t,e,n){var r=n(10);function i(){this._arr=[],this._keyIndices={}}t.exports=i,i.prototype.size=function(){return this._arr.length},i.prototype.keys=function(){return this._arr.map((function(t){return t.key}))},i.prototype.has=function(t){return r.has(this._keyIndices,t)},i.prototype.priority=function(t){var e=this._keyIndices[t];if(void 0!==e)return this._arr[e].priority},i.prototype.min=function(){if(0===this.size())throw new Error("Queue underflow");return this._arr[0].key},i.prototype.add=function(t,e){var n=this._keyIndices;if(t=String(t),!r.has(n,t)){var i=this._arr,a=i.length;return n[t]=a,i.push({key:t,priority:e}),this._decrease(a),!0}return!1},i.prototype.removeMin=function(){this._swap(0,this._arr.length-1);var t=this._arr.pop();return delete this._keyIndices[t.key],this._heapify(0),t.key},i.prototype.decrease=function(t,e){var n=this._keyIndices[t];if(e>this._arr[n].priority)throw new Error("New priority is greater than current priority. Key: "+t+" Old: "+this._arr[n].priority+" New: "+e);this._arr[n].priority=e,this._decrease(n)},i.prototype._heapify=function(t){var e=this._arr,n=2*t,r=n+1,i=t;n>1].priority2?e[2]:void 0;for(u&&a(e[0],e[1],u)&&(r=1);++n1&&o.sort((function(t,e){var r=t.x-n.x,i=t.y-n.y,a=Math.sqrt(r*r+i*i),o=e.x-n.x,s=e.y-n.y,c=Math.sqrt(o*o+s*s);return aMath.abs(o)*u?(s<0&&(u=-u),n=0===s?0:u*o/s,r=u):(o<0&&(c=-c),n=c,r=0===o?0:c*s/o);return{x:i+n,y:a+r}}},function(t,e,n){t.exports=function t(e){"use strict";var n=/^\0+/g,r=/[\0\r\f]/g,i=/: */g,a=/zoo|gra/,o=/([,: ])(transform)/g,s=/,+\s*(?![^(]*[)])/g,c=/ +\s*(?![^(]*[)])/g,u=/ *[\0] */g,l=/,\r+?/g,h=/([\t\r\n ])*\f?&/g,f=/:global\(((?:[^\(\)\[\]]*|\[.*\]|\([^\(\)]*\))*)\)/g,d=/\W+/g,p=/@(k\w+)\s*(\S*)\s*/,g=/::(place)/g,y=/:(read-only)/g,v=/\s+(?=[{\];=:>])/g,m=/([[}=:>])\s+/g,b=/(\{[^{]+?);(?=\})/g,x=/\s{2,}/g,_=/([^\(])(:+) */g,k=/[svh]\w+-[tblr]{2}/,w=/\(\s*(.*)\s*\)/g,E=/([\s\S]*?);/g,T=/-self|flex-/g,C=/[^]*?(:[rp][el]a[\w-]+)[^]*/,A=/stretch|:\s*\w+\-(?:conte|avail)/,S=/([^-])(image-set\()/,M="-webkit-",O="-moz-",D="-ms-",N=1,B=1,L=0,F=1,P=1,I=1,j=0,R=0,Y=0,z=[],U=[],$=0,W=null,H=0,V=1,G="",q="",X="";function Z(t,e,i,a,o){for(var s,c,l=0,h=0,f=0,d=0,v=0,m=0,b=0,x=0,k=0,E=0,T=0,C=0,A=0,S=0,O=0,D=0,j=0,U=0,W=0,K=i.length,it=K-1,at="",ot="",st="",ct="",ut="",lt="";O0&&(ot=ot.replace(r,"")),ot.trim().length>0)){switch(b){case 32:case 9:case 59:case 13:case 10:break;default:ot+=i.charAt(O)}b=59}if(1===j)switch(b){case 123:case 125:case 59:case 34:case 39:case 40:case 41:case 44:j=0;case 9:case 13:case 10:case 32:break;default:for(j=0,W=O,v=b,O--,b=59;W0&&(++O,b=v);case 123:W=K}}switch(b){case 123:for(v=(ot=ot.trim()).charCodeAt(0),T=1,W=++O;O0&&(ot=ot.replace(r,"")),m=ot.charCodeAt(1)){case 100:case 109:case 115:case 45:s=e;break;default:s=z}if(W=(st=Z(e,s,st,m,o+1)).length,Y>0&&0===W&&(W=ot.length),$>0&&(c=nt(3,st,s=J(z,ot,U),e,B,N,W,m,o,a),ot=s.join(""),void 0!==c&&0===(W=(st=c.trim()).length)&&(m=0,st="")),W>0)switch(m){case 115:ot=ot.replace(w,et);case 100:case 109:case 45:st=ot+"{"+st+"}";break;case 107:st=(ot=ot.replace(p,"$1 $2"+(V>0?G:"")))+"{"+st+"}",st=1===P||2===P&&tt("@"+st,3)?"@"+M+st+"@"+st:"@"+st;break;default:st=ot+st,112===a&&(ct+=st,st="")}else st="";break;default:st=Z(e,J(e,ot,U),st,a,o+1)}ut+=st,C=0,j=0,S=0,D=0,U=0,A=0,ot="",st="",b=i.charCodeAt(++O);break;case 125:case 59:if((W=(ot=(D>0?ot.replace(r,""):ot).trim()).length)>1)switch(0===S&&(45===(v=ot.charCodeAt(0))||v>96&&v<123)&&(W=(ot=ot.replace(" ",":")).length),$>0&&void 0!==(c=nt(1,ot,e,t,B,N,ct.length,a,o,a))&&0===(W=(ot=c.trim()).length)&&(ot="\0\0"),v=ot.charCodeAt(0),m=ot.charCodeAt(1),v){case 0:break;case 64:if(105===m||99===m){lt+=ot+i.charAt(O);break}default:if(58===ot.charCodeAt(W-1))break;ct+=Q(ot,v,m,ot.charCodeAt(2))}C=0,j=0,S=0,D=0,U=0,ot="",b=i.charCodeAt(++O)}}switch(b){case 13:case 10:if(h+d+f+l+R===0)switch(E){case 41:case 39:case 34:case 64:case 126:case 62:case 42:case 43:case 47:case 45:case 58:case 44:case 59:case 123:case 125:break;default:S>0&&(j=1)}47===h?h=0:F+C===0&&107!==a&&ot.length>0&&(D=1,ot+="\0"),$*H>0&&nt(0,ot,e,t,B,N,ct.length,a,o,a),N=1,B++;break;case 59:case 125:if(h+d+f+l===0){N++;break}default:switch(N++,at=i.charAt(O),b){case 9:case 32:if(d+l+h===0)switch(x){case 44:case 58:case 9:case 32:at="";break;default:32!==b&&(at=" ")}break;case 0:at="\\0";break;case 12:at="\\f";break;case 11:at="\\v";break;case 38:d+h+l===0&&F>0&&(U=1,D=1,at="\f"+at);break;case 108:if(d+h+l+L===0&&S>0)switch(O-S){case 2:112===x&&58===i.charCodeAt(O-3)&&(L=x);case 8:111===k&&(L=k)}break;case 58:d+h+l===0&&(S=O);break;case 44:h+f+d+l===0&&(D=1,at+="\r");break;case 34:case 39:0===h&&(d=d===b?0:0===d?b:d);break;case 91:d+h+f===0&&l++;break;case 93:d+h+f===0&&l--;break;case 41:d+h+l===0&&f--;break;case 40:if(d+h+l===0){if(0===C)switch(2*x+3*k){case 533:break;default:T=0,C=1}f++}break;case 64:h+f+d+l+S+A===0&&(A=1);break;case 42:case 47:if(d+l+f>0)break;switch(h){case 0:switch(2*b+3*i.charCodeAt(O+1)){case 235:h=47;break;case 220:W=O,h=42}break;case 42:47===b&&42===x&&W+2!==O&&(33===i.charCodeAt(W+2)&&(ct+=i.substring(W,O+1)),at="",h=0)}}if(0===h){if(F+d+l+A===0&&107!==a&&59!==b)switch(b){case 44:case 126:case 62:case 43:case 41:case 40:if(0===C){switch(x){case 9:case 32:case 10:case 13:at+="\0";break;default:at="\0"+at+(44===b?"":"\0")}D=1}else switch(b){case 40:S+7===O&&108===x&&(S=0),C=++T;break;case 41:0==(C=--T)&&(D=1,at+="\0")}break;case 9:case 32:switch(x){case 0:case 123:case 125:case 59:case 44:case 12:case 9:case 32:case 10:case 13:break;default:0===C&&(D=1,at+="\0")}}ot+=at,32!==b&&9!==b&&(E=b)}}k=x,x=b,O++}if(W=ct.length,Y>0&&0===W&&0===ut.length&&0===e[0].length==0&&(109!==a||1===e.length&&(F>0?q:X)===e[0])&&(W=e.join(",").length+2),W>0){if(s=0===F&&107!==a?function(t){for(var e,n,i=0,a=t.length,o=Array(a);i1)){if(f=c.charCodeAt(c.length-1),d=n.charCodeAt(0),e="",0!==l)switch(f){case 42:case 126:case 62:case 43:case 32:case 40:break;default:e=" "}switch(d){case 38:n=e+q;case 126:case 62:case 43:case 32:case 41:case 40:break;case 91:n=e+n+q;break;case 58:switch(2*n.charCodeAt(1)+3*n.charCodeAt(2)){case 530:if(I>0){n=e+n.substring(8,h-1);break}default:(l<1||s[l-1].length<1)&&(n=e+q+n)}break;case 44:e="";default:n=h>1&&n.indexOf(":")>0?e+n.replace(_,"$1"+q+"$2"):e+n+q}c+=n}o[i]=c.replace(r,"").trim()}return o}(e):e,$>0&&void 0!==(c=nt(2,ct,s,t,B,N,W,a,o,a))&&0===(ct=c).length)return lt+ct+ut;if(ct=s.join(",")+"{"+ct+"}",P*L!=0){switch(2!==P||tt(ct,2)||(L=0),L){case 111:ct=ct.replace(y,":-moz-$1")+ct;break;case 112:ct=ct.replace(g,"::-webkit-input-$1")+ct.replace(g,"::-moz-$1")+ct.replace(g,":-ms-input-$1")+ct}L=0}}return lt+ct+ut}function J(t,e,n){var r=e.trim().split(l),i=r,a=r.length,o=t.length;switch(o){case 0:case 1:for(var s=0,c=0===o?"":t[0]+" ";s0&&F>0)return i.replace(f,"$1").replace(h,"$1"+X);break;default:return t.trim()+i.replace(h,"$1"+t.trim())}default:if(n*F>0&&i.indexOf("\f")>0)return i.replace(h,(58===t.charCodeAt(0)?"":"$1")+t.trim())}return t+i}function Q(t,e,n,r){var u,l=0,h=t+";",f=2*e+3*n+4*r;if(944===f)return function(t){var e=t.length,n=t.indexOf(":",9)+1,r=t.substring(0,n).trim(),i=t.substring(n,e-1).trim();switch(t.charCodeAt(9)*V){case 0:break;case 45:if(110!==t.charCodeAt(10))break;default:var a=i.split((i="",s)),o=0;for(n=0,e=a.length;o64&&h<90||h>96&&h<123||95===h||45===h&&45!==u.charCodeAt(1)))switch(isNaN(parseFloat(u))+(-1!==u.indexOf("("))){case 1:switch(u){case"infinite":case"alternate":case"backwards":case"running":case"normal":case"forwards":case"both":case"none":case"linear":case"ease":case"ease-in":case"ease-out":case"ease-in-out":case"paused":case"reverse":case"alternate-reverse":case"inherit":case"initial":case"unset":case"step-start":case"step-end":break;default:u+=G}}l[n++]=u}i+=(0===o?"":",")+l.join(" ")}}return i=r+i+";",1===P||2===P&&tt(i,1)?M+i+i:i}(h);if(0===P||2===P&&!tt(h,1))return h;switch(f){case 1015:return 97===h.charCodeAt(10)?M+h+h:h;case 951:return 116===h.charCodeAt(3)?M+h+h:h;case 963:return 110===h.charCodeAt(5)?M+h+h:h;case 1009:if(100!==h.charCodeAt(4))break;case 969:case 942:return M+h+h;case 978:return M+h+O+h+h;case 1019:case 983:return M+h+O+h+D+h+h;case 883:return 45===h.charCodeAt(8)?M+h+h:h.indexOf("image-set(",11)>0?h.replace(S,"$1-webkit-$2")+h:h;case 932:if(45===h.charCodeAt(4))switch(h.charCodeAt(5)){case 103:return M+"box-"+h.replace("-grow","")+M+h+D+h.replace("grow","positive")+h;case 115:return M+h+D+h.replace("shrink","negative")+h;case 98:return M+h+D+h.replace("basis","preferred-size")+h}return M+h+D+h+h;case 964:return M+h+D+"flex-"+h+h;case 1023:if(99!==h.charCodeAt(8))break;return u=h.substring(h.indexOf(":",15)).replace("flex-","").replace("space-between","justify"),M+"box-pack"+u+M+h+D+"flex-pack"+u+h;case 1005:return a.test(h)?h.replace(i,":"+M)+h.replace(i,":"+O)+h:h;case 1e3:switch(l=(u=h.substring(13).trim()).indexOf("-")+1,u.charCodeAt(0)+u.charCodeAt(l)){case 226:u=h.replace(k,"tb");break;case 232:u=h.replace(k,"tb-rl");break;case 220:u=h.replace(k,"lr");break;default:return h}return M+h+D+u+h;case 1017:if(-1===h.indexOf("sticky",9))return h;case 975:switch(l=(h=t).length-10,f=(u=(33===h.charCodeAt(l)?h.substring(0,l):h).substring(t.indexOf(":",7)+1).trim()).charCodeAt(0)+(0|u.charCodeAt(7))){case 203:if(u.charCodeAt(8)<111)break;case 115:h=h.replace(u,M+u)+";"+h;break;case 207:case 102:h=h.replace(u,M+(f>102?"inline-":"")+"box")+";"+h.replace(u,M+u)+";"+h.replace(u,D+u+"box")+";"+h}return h+";";case 938:if(45===h.charCodeAt(5))switch(h.charCodeAt(6)){case 105:return u=h.replace("-items",""),M+h+M+"box-"+u+D+"flex-"+u+h;case 115:return M+h+D+"flex-item-"+h.replace(T,"")+h;default:return M+h+D+"flex-line-pack"+h.replace("align-content","").replace(T,"")+h}break;case 973:case 989:if(45!==h.charCodeAt(3)||122===h.charCodeAt(4))break;case 931:case 953:if(!0===A.test(t))return 115===(u=t.substring(t.indexOf(":")+1)).charCodeAt(0)?Q(t.replace("stretch","fill-available"),e,n,r).replace(":fill-available",":stretch"):h.replace(u,M+u)+h.replace(u,O+u.replace("fill-",""))+h;break;case 962:if(h=M+h+(102===h.charCodeAt(5)?D+h:"")+h,n+r===211&&105===h.charCodeAt(13)&&h.indexOf("transform",10)>0)return h.substring(0,h.indexOf(";",27)+1).replace(o,"$1-webkit-$2")+h}return h}function tt(t,e){var n=t.indexOf(1===e?":":"{"),r=t.substring(0,3!==e?n:10),i=t.substring(n+1,t.length-1);return W(2!==e?r:r.replace(C,"$1"),i,e)}function et(t,e){var n=Q(e,e.charCodeAt(0),e.charCodeAt(1),e.charCodeAt(2));return n!==e+";"?n.replace(E," or ($1)").substring(4):"("+e+")"}function nt(t,e,n,r,i,a,o,s,c,u){for(var l,h=0,f=e;h<$;++h)switch(l=U[h].call(at,t,f,n,r,i,a,o,s,c,u)){case void 0:case!1:case!0:case null:break;default:f=l}if(f!==e)return f}function rt(t,e,n,r){for(var i=e+1;i0&&(G=i.replace(d,91===a?"":"-")),a=1,1===F?X=i:q=i;var o,s=[X];$>0&&void 0!==(o=nt(-1,n,s,s,B,N,0,0,0,0))&&"string"==typeof o&&(n=o);var c=Z(z,s,n,0,0);return $>0&&void 0!==(o=nt(-2,c,s,s,B,N,c.length,0,0,0))&&"string"!=typeof(c=o)&&(a=0),G="",X="",q="",L=0,B=1,N=1,j*a==0?c:function(t){return t.replace(r,"").replace(v,"").replace(m,"$1").replace(b,"$1").replace(x," ")}(c)}return at.use=function t(e){switch(e){case void 0:case null:$=U.length=0;break;default:if("function"==typeof e)U[$++]=e;else if("object"==typeof e)for(var n=0,r=e.length;n=255?255:t<0?0:t},g:function(t){return t>=255?255:t<0?0:t},b:function(t){return t>=255?255:t<0?0:t},h:function(t){return t%360},s:function(t){return t>=100?100:t<0?0:t},l:function(t){return t>=100?100:t<0?0:t},a:function(t){return t>=1?1:t<0?0:t}},toLinear:function(t){var e=t/255;return t>.03928?Math.pow((e+.055)/1.055,2.4):e/12.92},hue2rgb:function(t,e,n){return n<0&&(n+=1),n>1&&(n-=1),n<1/6?t+6*(e-t)*n:n<.5?e:n<2/3?t+(e-t)*(2/3-n)*6:t},hsl2rgb:function(t,e){var n=t.h,i=t.s,a=t.l;if(100===i)return 2.55*a;n/=360,i/=100;var o=(a/=100)<.5?a*(1+i):a+i-a*i,s=2*a-o;switch(e){case"r":return 255*r.hue2rgb(s,o,n+1/3);case"g":return 255*r.hue2rgb(s,o,n);case"b":return 255*r.hue2rgb(s,o,n-1/3)}},rgb2hsl:function(t,e){var n=t.r,r=t.g,i=t.b;n/=255,r/=255,i/=255;var a=Math.max(n,r,i),o=Math.min(n,r,i),s=(a+o)/2;if("l"===e)return 100*s;if(a===o)return 0;var c=a-o;if("s"===e)return 100*(s>.5?c/(2-a-o):c/(a+o));switch(a){case n:return 60*((r-i)/c+(r1?e:"0"+e},dec2hex:function(t){var e=Math.round(t).toString(16);return e.length>1?e:"0"+e}};e.default=r},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=n(9),i=n(75),a=n(177),o=function(){function t(t,e){this.color=e,this.changed=!1,this.data=t,this.type=new a.default}return t.prototype.set=function(t,e){return this.color=e,this.changed=!1,this.data=t,this.type.type=i.TYPE.ALL,this},t.prototype._ensureHSL=function(){void 0===this.data.h&&(this.data.h=r.default.channel.rgb2hsl(this.data,"h")),void 0===this.data.s&&(this.data.s=r.default.channel.rgb2hsl(this.data,"s")),void 0===this.data.l&&(this.data.l=r.default.channel.rgb2hsl(this.data,"l"))},t.prototype._ensureRGB=function(){void 0===this.data.r&&(this.data.r=r.default.channel.hsl2rgb(this.data,"r")),void 0===this.data.g&&(this.data.g=r.default.channel.hsl2rgb(this.data,"g")),void 0===this.data.b&&(this.data.b=r.default.channel.hsl2rgb(this.data,"b"))},Object.defineProperty(t.prototype,"r",{get:function(){return this.type.is(i.TYPE.HSL)||void 0===this.data.r?(this._ensureHSL(),r.default.channel.hsl2rgb(this.data,"r")):this.data.r},set:function(t){this.type.set(i.TYPE.RGB),this.changed=!0,this.data.r=t},enumerable:!0,configurable:!0}),Object.defineProperty(t.prototype,"g",{get:function(){return this.type.is(i.TYPE.HSL)||void 0===this.data.g?(this._ensureHSL(),r.default.channel.hsl2rgb(this.data,"g")):this.data.g},set:function(t){this.type.set(i.TYPE.RGB),this.changed=!0,this.data.g=t},enumerable:!0,configurable:!0}),Object.defineProperty(t.prototype,"b",{get:function(){return this.type.is(i.TYPE.HSL)||void 0===this.data.b?(this._ensureHSL(),r.default.channel.hsl2rgb(this.data,"b")):this.data.b},set:function(t){this.type.set(i.TYPE.RGB),this.changed=!0,this.data.b=t},enumerable:!0,configurable:!0}),Object.defineProperty(t.prototype,"h",{get:function(){return this.type.is(i.TYPE.RGB)||void 0===this.data.h?(this._ensureRGB(),r.default.channel.rgb2hsl(this.data,"h")):this.data.h},set:function(t){this.type.set(i.TYPE.HSL),this.changed=!0,this.data.h=t},enumerable:!0,configurable:!0}),Object.defineProperty(t.prototype,"s",{get:function(){return this.type.is(i.TYPE.RGB)||void 0===this.data.s?(this._ensureRGB(),r.default.channel.rgb2hsl(this.data,"s")):this.data.s},set:function(t){this.type.set(i.TYPE.HSL),this.changed=!0,this.data.s=t},enumerable:!0,configurable:!0}),Object.defineProperty(t.prototype,"l",{get:function(){return this.type.is(i.TYPE.RGB)||void 0===this.data.l?(this._ensureRGB(),r.default.channel.rgb2hsl(this.data,"l")):this.data.l},set:function(t){this.type.set(i.TYPE.HSL),this.changed=!0,this.data.l=t},enumerable:!0,configurable:!0}),Object.defineProperty(t.prototype,"a",{get:function(){return this.data.a},set:function(t){this.changed=!0,this.data.a=t},enumerable:!0,configurable:!0}),t}();e.default=o},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=n(75),i=function(){function t(){this.type=r.TYPE.ALL}return t.prototype.get=function(){return this.type},t.prototype.set=function(t){if(this.type&&this.type!==t)throw new Error("Cannot change both RGB and HSL channels at the same time");this.type=t},t.prototype.reset=function(){this.type=r.TYPE.ALL},t.prototype.is=function(t){return this.type===t},t}();e.default=i},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=n(9),i={};e.DEC2HEX=i;for(var a=0;a<=255;a++)i[a]=r.default.unit.dec2hex(a)},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=n(99),i={colors:{aliceblue:"#f0f8ff",antiquewhite:"#faebd7",aqua:"#00ffff",aquamarine:"#7fffd4",azure:"#f0ffff",beige:"#f5f5dc",bisque:"#ffe4c4",black:"#000000",blanchedalmond:"#ffebcd",blue:"#0000ff",blueviolet:"#8a2be2",brown:"#a52a2a",burlywood:"#deb887",cadetblue:"#5f9ea0",chartreuse:"#7fff00",chocolate:"#d2691e",coral:"#ff7f50",cornflowerblue:"#6495ed",cornsilk:"#fff8dc",crimson:"#dc143c",cyanaqua:"#00ffff",darkblue:"#00008b",darkcyan:"#008b8b",darkgoldenrod:"#b8860b",darkgray:"#a9a9a9",darkgreen:"#006400",darkgrey:"#a9a9a9",darkkhaki:"#bdb76b",darkmagenta:"#8b008b",darkolivegreen:"#556b2f",darkorange:"#ff8c00",darkorchid:"#9932cc",darkred:"#8b0000",darksalmon:"#e9967a",darkseagreen:"#8fbc8f",darkslateblue:"#483d8b",darkslategray:"#2f4f4f",darkslategrey:"#2f4f4f",darkturquoise:"#00ced1",darkviolet:"#9400d3",deeppink:"#ff1493",deepskyblue:"#00bfff",dimgray:"#696969",dimgrey:"#696969",dodgerblue:"#1e90ff",firebrick:"#b22222",floralwhite:"#fffaf0",forestgreen:"#228b22",fuchsia:"#ff00ff",gainsboro:"#dcdcdc",ghostwhite:"#f8f8ff",gold:"#ffd700",goldenrod:"#daa520",gray:"#808080",green:"#008000",greenyellow:"#adff2f",grey:"#808080",honeydew:"#f0fff0",hotpink:"#ff69b4",indianred:"#cd5c5c",indigo:"#4b0082",ivory:"#fffff0",khaki:"#f0e68c",lavender:"#e6e6fa",lavenderblush:"#fff0f5",lawngreen:"#7cfc00",lemonchiffon:"#fffacd",lightblue:"#add8e6",lightcoral:"#f08080",lightcyan:"#e0ffff",lightgoldenrodyellow:"#fafad2",lightgray:"#d3d3d3",lightgreen:"#90ee90",lightgrey:"#d3d3d3",lightpink:"#ffb6c1",lightsalmon:"#ffa07a",lightseagreen:"#20b2aa",lightskyblue:"#87cefa",lightslategray:"#778899",lightslategrey:"#778899",lightsteelblue:"#b0c4de",lightyellow:"#ffffe0",lime:"#00ff00",limegreen:"#32cd32",linen:"#faf0e6",magenta:"#ff00ff",maroon:"#800000",mediumaquamarine:"#66cdaa",mediumblue:"#0000cd",mediumorchid:"#ba55d3",mediumpurple:"#9370db",mediumseagreen:"#3cb371",mediumslateblue:"#7b68ee",mediumspringgreen:"#00fa9a",mediumturquoise:"#48d1cc",mediumvioletred:"#c71585",midnightblue:"#191970",mintcream:"#f5fffa",mistyrose:"#ffe4e1",moccasin:"#ffe4b5",navajowhite:"#ffdead",navy:"#000080",oldlace:"#fdf5e6",olive:"#808000",olivedrab:"#6b8e23",orange:"#ffa500",orangered:"#ff4500",orchid:"#da70d6",palegoldenrod:"#eee8aa",palegreen:"#98fb98",paleturquoise:"#afeeee",palevioletred:"#db7093",papayawhip:"#ffefd5",peachpuff:"#ffdab9",peru:"#cd853f",pink:"#ffc0cb",plum:"#dda0dd",powderblue:"#b0e0e6",purple:"#800080",rebeccapurple:"#663399",red:"#ff0000",rosybrown:"#bc8f8f",royalblue:"#4169e1",saddlebrown:"#8b4513",salmon:"#fa8072",sandybrown:"#f4a460",seagreen:"#2e8b57",seashell:"#fff5ee",sienna:"#a0522d",silver:"#c0c0c0",skyblue:"#87ceeb",slateblue:"#6a5acd",slategray:"#708090",slategrey:"#708090",snow:"#fffafa",springgreen:"#00ff7f",tan:"#d2b48c",teal:"#008080",thistle:"#d8bfd8",transparent:"#00000000",turquoise:"#40e0d0",violet:"#ee82ee",wheat:"#f5deb3",white:"#ffffff",whitesmoke:"#f5f5f5",yellow:"#ffff00",yellowgreen:"#9acd32"},parse:function(t){t=t.toLowerCase();var e=i.colors[t];if(e)return r.default.parse(e)},stringify:function(t){var e=r.default.stringify(t);for(var n in i.colors)if(i.colors[n]===e)return n}};e.default=i},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=n(9),i=n(45),a={re:/^rgba?\(\s*?(-?(?:\d+(?:\.\d+)?|(?:\.\d+))(?:e\d+)?(%?))\s*?(?:,|\s)\s*?(-?(?:\d+(?:\.\d+)?|(?:\.\d+))(?:e\d+)?(%?))\s*?(?:,|\s)\s*?(-?(?:\d+(?:\.\d+)?|(?:\.\d+))(?:e\d+)?(%?))(?:\s*?(?:,|\/)\s*?\+?(-?(?:\d+(?:\.\d+)?|(?:\.\d+))(?:e\d+)?(%?)))?\s*?\)$/i,parse:function(t){var e=t.charCodeAt(0);if(114===e||82===e){var n=t.match(a.re);if(n){var o=n[1],s=n[2],c=n[3],u=n[4],l=n[5],h=n[6],f=n[7],d=n[8];return i.default.set({r:r.default.channel.clamp.r(s?2.55*parseFloat(o):parseFloat(o)),g:r.default.channel.clamp.g(u?2.55*parseFloat(c):parseFloat(c)),b:r.default.channel.clamp.b(h?2.55*parseFloat(l):parseFloat(l)),a:f?r.default.channel.clamp.a(d?parseFloat(f)/100:parseFloat(f)):1},t)}}},stringify:function(t){return t.a<1?"rgba("+r.default.lang.round(t.r)+", "+r.default.lang.round(t.g)+", "+r.default.lang.round(t.b)+", "+r.default.lang.round(t.a)+")":"rgb("+r.default.lang.round(t.r)+", "+r.default.lang.round(t.g)+", "+r.default.lang.round(t.b)+")"}};e.default=a},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=n(9),i=n(45),a={re:/^hsla?\(\s*?(-?(?:\d+(?:\.\d+)?|(?:\.\d+))(?:e-?\d+)?(?:deg|grad|rad|turn)?)\s*?(?:,|\s)\s*?(-?(?:\d+(?:\.\d+)?|(?:\.\d+))(?:e-?\d+)?%)\s*?(?:,|\s)\s*?(-?(?:\d+(?:\.\d+)?|(?:\.\d+))(?:e-?\d+)?%)(?:\s*?(?:,|\/)\s*?\+?(-?(?:\d+(?:\.\d+)?|(?:\.\d+))(?:e-?\d+)?(%)?))?\s*?\)$/i,hueRe:/^(.+?)(deg|grad|rad|turn)$/i,_hue2deg:function(t){var e=t.match(a.hueRe);if(e){var n=e[1];switch(e[2]){case"grad":return r.default.channel.clamp.h(.9*parseFloat(n));case"rad":return r.default.channel.clamp.h(180*parseFloat(n)/Math.PI);case"turn":return r.default.channel.clamp.h(360*parseFloat(n))}}return r.default.channel.clamp.h(parseFloat(t))},parse:function(t){var e=t.charCodeAt(0);if(104===e||72===e){var n=t.match(a.re);if(n){var o=n[1],s=n[2],c=n[3],u=n[4],l=n[5];return i.default.set({h:a._hue2deg(o),s:r.default.channel.clamp.s(parseFloat(s)),l:r.default.channel.clamp.l(parseFloat(c)),a:u?r.default.channel.clamp.a(l?parseFloat(u)/100:parseFloat(u)):1},t)}}},stringify:function(t){return t.a<1?"hsla("+r.default.lang.round(t.h)+", "+r.default.lang.round(t.s)+"%, "+r.default.lang.round(t.l)+"%, "+t.a+")":"hsl("+r.default.lang.round(t.h)+", "+r.default.lang.round(t.s)+"%, "+r.default.lang.round(t.l)+"%)"}};e.default=a},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=n(29);e.default=function(t){return r.default(t,"r")}},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=n(29);e.default=function(t){return r.default(t,"g")}},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=n(29);e.default=function(t){return r.default(t,"b")}},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=n(29);e.default=function(t){return r.default(t,"h")}},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=n(29);e.default=function(t){return r.default(t,"s")}},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=n(29);e.default=function(t){return r.default(t,"l")}},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=n(103);e.default=function(t){return!r.default(t)}},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=n(15);e.default=function(t){try{return r.default.parse(t),!0}catch(t){return!1}}},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=n(32);e.default=function(t,e){return r.default(t,"s",e)}},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=n(32);e.default=function(t,e){return r.default(t,"s",-e)}},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=n(32);e.default=function(t,e){return r.default(t,"l",e)}},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=n(32);e.default=function(t,e){return r.default(t,"l",-e)}},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=n(32);e.default=function(t){return r.default(t,"h",180)}},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=n(52);e.default=function(t){return r.default(t,{s:0})}},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=n(15),i=n(107);e.default=function(t,e){void 0===e&&(e=100);var n=r.default.parse(t);return n.r=255-n.r,n.g=255-n.g,n.b=255-n.b,i.default(n,t,e)}},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=n(9),i=n(15),a=n(106);e.default=function(t,e){var n,o,s,c=i.default.parse(t),u={};for(var l in e)u[l]=(n=c[l],o=e[l],s=r.default.channel.max[l],o>0?(s-n)*o/100:n*o/100);return a.default(t,u)}},function(t,e,n){t.exports={Graph:n(76),version:n(300)}},function(t,e,n){var r=n(108);t.exports=function(t){return r(t,4)}},function(t,e){t.exports=function(){this.__data__=[],this.size=0}},function(t,e,n){var r=n(55),i=Array.prototype.splice;t.exports=function(t){var e=this.__data__,n=r(e,t);return!(n<0)&&(n==e.length-1?e.pop():i.call(e,n,1),--this.size,!0)}},function(t,e,n){var r=n(55);t.exports=function(t){var e=this.__data__,n=r(e,t);return n<0?void 0:e[n][1]}},function(t,e,n){var r=n(55);t.exports=function(t){return r(this.__data__,t)>-1}},function(t,e,n){var r=n(55);t.exports=function(t,e){var n=this.__data__,i=r(n,t);return i<0?(++this.size,n.push([t,e])):n[i][1]=e,this}},function(t,e,n){var r=n(54);t.exports=function(){this.__data__=new r,this.size=0}},function(t,e){t.exports=function(t){var e=this.__data__,n=e.delete(t);return this.size=e.size,n}},function(t,e){t.exports=function(t){return this.__data__.get(t)}},function(t,e){t.exports=function(t){return this.__data__.has(t)}},function(t,e,n){var r=n(54),i=n(77),a=n(78);t.exports=function(t,e){var n=this.__data__;if(n instanceof r){var o=n.__data__;if(!i||o.length<199)return o.push([t,e]),this.size=++n.size,this;n=this.__data__=new a(o)}return n.set(t,e),this.size=n.size,this}},function(t,e,n){var r=n(37),i=n(214),a=n(11),o=n(110),s=/^\[object .+?Constructor\]$/,c=Function.prototype,u=Object.prototype,l=c.toString,h=u.hasOwnProperty,f=RegExp("^"+l.call(h).replace(/[\\^$.*+?()[\]{}|]/g,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$");t.exports=function(t){return!(!a(t)||i(t))&&(r(t)?f:s).test(o(t))}},function(t,e){var n;n=function(){return this}();try{n=n||new Function("return this")()}catch(t){"object"==typeof window&&(n=window)}t.exports=n},function(t,e,n){var r=n(38),i=Object.prototype,a=i.hasOwnProperty,o=i.toString,s=r?r.toStringTag:void 0;t.exports=function(t){var e=a.call(t,s),n=t[s];try{t[s]=void 0;var r=!0}catch(t){}var i=o.call(t);return r&&(e?t[s]=n:delete t[s]),i}},function(t,e){var n=Object.prototype.toString;t.exports=function(t){return n.call(t)}},function(t,e,n){var r,i=n(215),a=(r=/[^.]+$/.exec(i&&i.keys&&i.keys.IE_PROTO||""))?"Symbol(src)_1."+r:"";t.exports=function(t){return!!a&&a in t}},function(t,e,n){var r=n(16)["__core-js_shared__"];t.exports=r},function(t,e){t.exports=function(t,e){return null==t?void 0:t[e]}},function(t,e,n){var r=n(218),i=n(54),a=n(77);t.exports=function(){this.size=0,this.__data__={hash:new r,map:new(a||i),string:new r}}},function(t,e,n){var r=n(219),i=n(220),a=n(221),o=n(222),s=n(223);function c(t){var e=-1,n=null==t?0:t.length;for(this.clear();++e0){if(++e>=800)return arguments[0]}else e=0;return t.apply(void 0,arguments)}}},function(t,e,n){var r=n(131),i=n(292),a=n(296),o=n(132),s=n(297),c=n(90);t.exports=function(t,e,n){var u=-1,l=i,h=t.length,f=!0,d=[],p=d;if(n)f=!1,l=a;else if(h>=200){var g=e?null:s(t);if(g)return c(g);f=!1,l=o,p=new r}else p=e?[]:d;t:for(;++u-1}},function(t,e,n){var r=n(145),i=n(294),a=n(295);t.exports=function(t,e,n){return e==e?a(t,e,n):r(t,i,n)}},function(t,e){t.exports=function(t){return t!=t}},function(t,e){t.exports=function(t,e,n){for(var r=n-1,i=t.length;++r1||1===e.length&&t.hasEdge(e[0],e[0])}))}},function(t,e,n){var r=n(10);t.exports=function(t,e,n){return function(t,e,n){var r={},i=t.nodes();return i.forEach((function(t){r[t]={},r[t][t]={distance:0},i.forEach((function(e){t!==e&&(r[t][e]={distance:Number.POSITIVE_INFINITY})})),n(t).forEach((function(n){var i=n.v===t?n.w:n.v,a=e(n);r[t][i]={distance:a,predecessor:t}}))})),i.forEach((function(t){var e=r[t];i.forEach((function(n){var a=r[n];i.forEach((function(n){var r=a[t],i=e[n],o=a[n],s=r.distance+i.distance;s0;){if(n=c.removeMin(),r.has(s,n))o.setEdge(n,s[n]);else{if(l)throw new Error("Input graph is not connected: "+t);l=!0}t.nodeEdges(n).forEach(u)}return o}},function(t,e,n){var r;try{r=n(3)}catch(t){}r||(r=window.graphlib),t.exports=r},function(t,e,n){"use strict";var r=n(4),i=n(345),a=n(348),o=n(349),s=n(8).normalizeRanks,c=n(351),u=n(8).removeEmptyRanks,l=n(352),h=n(353),f=n(354),d=n(355),p=n(364),g=n(8),y=n(17).Graph;t.exports=function(t,e){var n=e&&e.debugTiming?g.time:g.notime;n("layout",(function(){var e=n(" buildLayoutGraph",(function(){return function(t){var e=new y({multigraph:!0,compound:!0}),n=C(t.graph());return e.setGraph(r.merge({},m,T(n,v),r.pick(n,b))),r.forEach(t.nodes(),(function(n){var i=C(t.node(n));e.setNode(n,r.defaults(T(i,x),_)),e.setParent(n,t.parent(n))})),r.forEach(t.edges(),(function(n){var i=C(t.edge(n));e.setEdge(n,r.merge({},w,T(i,k),r.pick(i,E)))})),e}(t)}));n(" runLayout",(function(){!function(t,e){e(" makeSpaceForEdgeLabels",(function(){!function(t){var e=t.graph();e.ranksep/=2,r.forEach(t.edges(),(function(n){var r=t.edge(n);r.minlen*=2,"c"!==r.labelpos.toLowerCase()&&("TB"===e.rankdir||"BT"===e.rankdir?r.width+=r.labeloffset:r.height+=r.labeloffset)}))}(t)})),e(" removeSelfEdges",(function(){!function(t){r.forEach(t.edges(),(function(e){if(e.v===e.w){var n=t.node(e.v);n.selfEdges||(n.selfEdges=[]),n.selfEdges.push({e:e,label:t.edge(e)}),t.removeEdge(e)}}))}(t)})),e(" acyclic",(function(){i.run(t)})),e(" nestingGraph.run",(function(){l.run(t)})),e(" rank",(function(){o(g.asNonCompoundGraph(t))})),e(" injectEdgeLabelProxies",(function(){!function(t){r.forEach(t.edges(),(function(e){var n=t.edge(e);if(n.width&&n.height){var r=t.node(e.v),i={rank:(t.node(e.w).rank-r.rank)/2+r.rank,e:e};g.addDummyNode(t,"edge-proxy",i,"_ep")}}))}(t)})),e(" removeEmptyRanks",(function(){u(t)})),e(" nestingGraph.cleanup",(function(){l.cleanup(t)})),e(" normalizeRanks",(function(){s(t)})),e(" assignRankMinMax",(function(){!function(t){var e=0;r.forEach(t.nodes(),(function(n){var i=t.node(n);i.borderTop&&(i.minRank=t.node(i.borderTop).rank,i.maxRank=t.node(i.borderBottom).rank,e=r.max(e,i.maxRank))})),t.graph().maxRank=e}(t)})),e(" removeEdgeLabelProxies",(function(){!function(t){r.forEach(t.nodes(),(function(e){var n=t.node(e);"edge-proxy"===n.dummy&&(t.edge(n.e).labelRank=n.rank,t.removeNode(e))}))}(t)})),e(" normalize.run",(function(){a.run(t)})),e(" parentDummyChains",(function(){c(t)})),e(" addBorderSegments",(function(){h(t)})),e(" order",(function(){d(t)})),e(" insertSelfEdges",(function(){!function(t){var e=g.buildLayerMatrix(t);r.forEach(e,(function(e){var n=0;r.forEach(e,(function(e,i){var a=t.node(e);a.order=i+n,r.forEach(a.selfEdges,(function(e){g.addDummyNode(t,"selfedge",{width:e.label.width,height:e.label.height,rank:a.rank,order:i+ ++n,e:e.e,label:e.label},"_se")})),delete a.selfEdges}))}))}(t)})),e(" adjustCoordinateSystem",(function(){f.adjust(t)})),e(" position",(function(){p(t)})),e(" positionSelfEdges",(function(){!function(t){r.forEach(t.nodes(),(function(e){var n=t.node(e);if("selfedge"===n.dummy){var r=t.node(n.e.v),i=r.x+r.width/2,a=r.y,o=n.x-i,s=r.height/2;t.setEdge(n.e,n.label),t.removeNode(e),n.label.points=[{x:i+2*o/3,y:a-s},{x:i+5*o/6,y:a-s},{x:i+o,y:a},{x:i+5*o/6,y:a+s},{x:i+2*o/3,y:a+s}],n.label.x=n.x,n.label.y=n.y}}))}(t)})),e(" removeBorderNodes",(function(){!function(t){r.forEach(t.nodes(),(function(e){if(t.children(e).length){var n=t.node(e),i=t.node(n.borderTop),a=t.node(n.borderBottom),o=t.node(r.last(n.borderLeft)),s=t.node(r.last(n.borderRight));n.width=Math.abs(s.x-o.x),n.height=Math.abs(a.y-i.y),n.x=o.x+n.width/2,n.y=i.y+n.height/2}})),r.forEach(t.nodes(),(function(e){"border"===t.node(e).dummy&&t.removeNode(e)}))}(t)})),e(" normalize.undo",(function(){a.undo(t)})),e(" fixupEdgeLabelCoords",(function(){!function(t){r.forEach(t.edges(),(function(e){var n=t.edge(e);if(r.has(n,"x"))switch("l"!==n.labelpos&&"r"!==n.labelpos||(n.width-=n.labeloffset),n.labelpos){case"l":n.x-=n.width/2+n.labeloffset;break;case"r":n.x+=n.width/2+n.labeloffset}}))}(t)})),e(" undoCoordinateSystem",(function(){f.undo(t)})),e(" translateGraph",(function(){!function(t){var e=Number.POSITIVE_INFINITY,n=0,i=Number.POSITIVE_INFINITY,a=0,o=t.graph(),s=o.marginx||0,c=o.marginy||0;function u(t){var r=t.x,o=t.y,s=t.width,c=t.height;e=Math.min(e,r-s/2),n=Math.max(n,r+s/2),i=Math.min(i,o-c/2),a=Math.max(a,o+c/2)}r.forEach(t.nodes(),(function(e){u(t.node(e))})),r.forEach(t.edges(),(function(e){var n=t.edge(e);r.has(n,"x")&&u(n)})),e-=s,i-=c,r.forEach(t.nodes(),(function(n){var r=t.node(n);r.x-=e,r.y-=i})),r.forEach(t.edges(),(function(n){var a=t.edge(n);r.forEach(a.points,(function(t){t.x-=e,t.y-=i})),r.has(a,"x")&&(a.x-=e),r.has(a,"y")&&(a.y-=i)})),o.width=n-e+s,o.height=a-i+c}(t)})),e(" assignNodeIntersects",(function(){!function(t){r.forEach(t.edges(),(function(e){var n,r,i=t.edge(e),a=t.node(e.v),o=t.node(e.w);i.points?(n=i.points[0],r=i.points[i.points.length-1]):(i.points=[],n=o,r=a),i.points.unshift(g.intersectRect(a,n)),i.points.push(g.intersectRect(o,r))}))}(t)})),e(" reversePoints",(function(){!function(t){r.forEach(t.edges(),(function(e){var n=t.edge(e);n.reversed&&n.points.reverse()}))}(t)})),e(" acyclic.undo",(function(){i.undo(t)}))}(e,n)})),n(" updateInputGraph",(function(){!function(t,e){r.forEach(t.nodes(),(function(n){var r=t.node(n),i=e.node(n);r&&(r.x=i.x,r.y=i.y,e.children(n).length&&(r.width=i.width,r.height=i.height))})),r.forEach(t.edges(),(function(n){var i=t.edge(n),a=e.edge(n);i.points=a.points,r.has(a,"x")&&(i.x=a.x,i.y=a.y)})),t.graph().width=e.graph().width,t.graph().height=e.graph().height}(t,e)}))}))};var v=["nodesep","edgesep","ranksep","marginx","marginy"],m={ranksep:50,edgesep:20,nodesep:50,rankdir:"tb"},b=["acyclicer","ranker","rankdir","align"],x=["width","height"],_={width:0,height:0},k=["minlen","weight","width","height","labeloffset"],w={minlen:1,weight:1,width:0,height:0,labeloffset:10,labelpos:"r"},E=["labelpos"];function T(t,e){return r.mapValues(r.pick(t,e),Number)}function C(t){var e={};return r.forEach(t,(function(t,n){e[n.toLowerCase()]=t})),e}},function(t,e,n){var r=n(108);t.exports=function(t){return r(t,5)}},function(t,e,n){var r=n(315)(n(316));t.exports=r},function(t,e,n){var r=n(25),i=n(24),a=n(30);t.exports=function(t){return function(e,n,o){var s=Object(e);if(!i(e)){var c=r(n,3);e=a(e),n=function(t){return c(s[t],t,s)}}var u=t(e,n,o);return u>-1?s[c?e[u]:u]:void 0}}},function(t,e,n){var r=n(145),i=n(25),a=n(317),o=Math.max;t.exports=function(t,e,n){var s=null==t?0:t.length;if(!s)return-1;var c=null==n?0:a(n);return c<0&&(c=o(s+c,0)),r(t,i(e,3),c)}},function(t,e,n){var r=n(155);t.exports=function(t){var e=r(t),n=e%1;return e==e?n?e-n:e:0}},function(t,e,n){var r=n(11),i=n(42),a=/^\s+|\s+$/g,o=/^[-+]0x[0-9a-f]+$/i,s=/^0b[01]+$/i,c=/^0o[0-7]+$/i,u=parseInt;t.exports=function(t){if("number"==typeof t)return t;if(i(t))return NaN;if(r(t)){var e="function"==typeof t.valueOf?t.valueOf():t;t=r(e)?e+"":e}if("string"!=typeof t)return 0===t?t:+t;t=t.replace(a,"");var n=s.test(t);return n||c.test(t)?u(t.slice(2),n?2:8):o.test(t)?NaN:+t}},function(t,e,n){var r=n(89),i=n(127),a=n(40);t.exports=function(t,e){return null==t?t:r(t,i(e),a)}},function(t,e){t.exports=function(t){var e=null==t?0:t.length;return e?t[e-1]:void 0}},function(t,e,n){var r=n(59),i=n(88),a=n(25);t.exports=function(t,e){var n={};return e=a(e,3),i(t,(function(t,i,a){r(n,i,e(t,i,a))})),n}},function(t,e,n){var r=n(95),i=n(323),a=n(35);t.exports=function(t){return t&&t.length?r(t,a,i):void 0}},function(t,e){t.exports=function(t,e){return t>e}},function(t,e,n){var r=n(325),i=n(328)((function(t,e,n){r(t,e,n)}));t.exports=i},function(t,e,n){var r=n(53),i=n(157),a=n(89),o=n(326),s=n(11),c=n(40),u=n(159);t.exports=function t(e,n,l,h,f){e!==n&&a(n,(function(a,c){if(f||(f=new r),s(a))o(e,n,c,l,t,h,f);else{var d=h?h(u(e,c),a,c+"",e,n,f):void 0;void 0===d&&(d=a),i(e,c,d)}}),c)}},function(t,e,n){var r=n(157),i=n(114),a=n(123),o=n(115),s=n(124),c=n(47),u=n(5),l=n(146),h=n(39),f=n(37),d=n(11),p=n(158),g=n(48),y=n(159),v=n(327);t.exports=function(t,e,n,m,b,x,_){var k=y(t,n),w=y(e,n),E=_.get(w);if(E)r(t,n,E);else{var T=x?x(k,w,n+"",t,e,_):void 0,C=void 0===T;if(C){var A=u(w),S=!A&&h(w),M=!A&&!S&&g(w);T=w,A||S||M?u(k)?T=k:l(k)?T=o(k):S?(C=!1,T=i(w,!0)):M?(C=!1,T=a(w,!0)):T=[]:p(w)||c(w)?(T=k,c(k)?T=v(k):d(k)&&!f(k)||(T=s(w))):C=!1}C&&(_.set(w,T),b(T,w,m,x,_),_.delete(w)),r(t,n,T)}}},function(t,e,n){var r=n(46),i=n(40);t.exports=function(t){return r(t,i(t))}},function(t,e,n){var r=n(67),i=n(68);t.exports=function(t){return r((function(e,n){var r=-1,a=n.length,o=a>1?n[a-1]:void 0,s=a>2?n[2]:void 0;for(o=t.length>3&&"function"==typeof o?(a--,o):void 0,s&&i(n[0],n[1],s)&&(o=a<3?void 0:o,a=1),e=Object(e);++r1&&o(t,e[0],e[1])?e=[]:n>2&&o(e[0],e[1],e[2])&&(e=[e[0]]),i(t,r(e,1),[])}));t.exports=s},function(t,e,n){var r=n(66),i=n(25),a=n(141),o=n(340),s=n(61),c=n(341),u=n(35);t.exports=function(t,e,n){var l=-1;e=r(e.length?e:[u],s(i));var h=a(t,(function(t,n,i){return{criteria:r(e,(function(e){return e(t)})),index:++l,value:t}}));return o(h,(function(t,e){return c(t,e,n)}))}},function(t,e){t.exports=function(t,e){var n=t.length;for(t.sort(e);n--;)t[n]=t[n].value;return t}},function(t,e,n){var r=n(342);t.exports=function(t,e,n){for(var i=-1,a=t.criteria,o=e.criteria,s=a.length,c=n.length;++i=c?u:u*("desc"==n[i]?-1:1)}return t.index-e.index}},function(t,e,n){var r=n(42);t.exports=function(t,e){if(t!==e){var n=void 0!==t,i=null===t,a=t==t,o=r(t),s=void 0!==e,c=null===e,u=e==e,l=r(e);if(!c&&!l&&!o&&t>e||o&&s&&u&&!c&&!l||i&&s&&u||!n&&u||!a)return 1;if(!i&&!o&&!l&&t0;--c)if(r=e[c].dequeue()){i=i.concat(s(t,e,n,r,!0));break}}return i}(n.graph,n.buckets,n.zeroIdx);return r.flatten(r.map(u,(function(e){return t.outEdges(e.v,e.w)})),!0)};var o=r.constant(1);function s(t,e,n,i,a){var o=a?[]:void 0;return r.forEach(t.inEdges(i.v),(function(r){var i=t.edge(r),s=t.node(r.v);a&&o.push({v:r.v,w:r.w}),s.out-=i,c(e,n,s)})),r.forEach(t.outEdges(i.v),(function(r){var i=t.edge(r),a=r.w,o=t.node(a);o.in-=i,c(e,n,o)})),t.removeNode(i.v),o}function c(t,e,n){n.out?n.in?t[n.out-n.in+e].enqueue(n):t[t.length-1].enqueue(n):t[0].enqueue(n)}},function(t,e){function n(){var t={};t._next=t._prev=t,this._sentinel=t}function r(t){t._prev._next=t._next,t._next._prev=t._prev,delete t._next,delete t._prev}function i(t,e){if("_next"!==t&&"_prev"!==t)return e}t.exports=n,n.prototype.dequeue=function(){var t=this._sentinel,e=t._prev;if(e!==t)return r(e),e},n.prototype.enqueue=function(t){var e=this._sentinel;t._prev&&t._next&&r(t),t._next=e._next,e._next._prev=t,e._next=t,t._prev=e},n.prototype.toString=function(){for(var t=[],e=this._sentinel,n=e._prev;n!==e;)t.push(JSON.stringify(n,i)),n=n._prev;return"["+t.join(", ")+"]"}},function(t,e,n){"use strict";var r=n(4),i=n(8);t.exports={run:function(t){t.graph().dummyChains=[],r.forEach(t.edges(),(function(e){!function(t,e){var n,r,a,o=e.v,s=t.node(o).rank,c=e.w,u=t.node(c).rank,l=e.name,h=t.edge(e),f=h.labelRank;if(u===s+1)return;for(t.removeEdge(e),a=0,++s;sc.lim&&(u=c,l=!0);var h=r.filter(e.edges(),(function(e){return l===m(t,t.node(e.v),u)&&l!==m(t,t.node(e.w),u)}));return r.minBy(h,(function(t){return a(e,t)}))}function v(t,e,n,i){var a=n.v,o=n.w;t.removeEdge(a,o),t.setEdge(i.v,i.w,{}),d(t),h(t,e),function(t,e){var n=r.find(t.nodes(),(function(t){return!e.node(t).parent})),i=s(t,n);i=i.slice(1),r.forEach(i,(function(n){var r=t.node(n).parent,i=e.edge(n,r),a=!1;i||(i=e.edge(r,n),a=!0),e.node(n).rank=e.node(r).rank+(a?i.minlen:-i.minlen)}))}(t,e)}function m(t,e,n){return n.low<=e.lim&&e.lim<=n.lim}t.exports=l,l.initLowLimValues=d,l.initCutValues=h,l.calcCutValue=f,l.leaveEdge=g,l.enterEdge=y,l.exchangeEdges=v},function(t,e,n){var r=n(4);t.exports=function(t){var e=function(t){var e={},n=0;function i(a){var o=n;r.forEach(t.children(a),i),e[a]={low:o,lim:n++}}return r.forEach(t.children(),i),e}(t);r.forEach(t.graph().dummyChains,(function(n){for(var r=t.node(n),i=r.edgeObj,a=function(t,e,n,r){var i,a,o=[],s=[],c=Math.min(e[n].low,e[r].low),u=Math.max(e[n].lim,e[r].lim);i=n;do{i=t.parent(i),o.push(i)}while(i&&(e[i].low>c||u>e[i].lim));a=i,i=r;for(;(i=t.parent(i))!==a;)s.push(i);return{path:o.concat(s.reverse()),lca:a}}(t,e,i.v,i.w),o=a.path,s=a.lca,c=0,u=o[c],l=!0;n!==i.w;){if(r=t.node(n),l){for(;(u=o[c])!==s&&t.node(u).maxRank=2),s=l.buildLayerMatrix(t);var y=a(t,s);y0;)e%2&&(n+=c[e+1]),c[e=e-1>>1]+=t.weight;u+=t.weight*n}))),u}t.exports=function(t,e){for(var n=0,r=1;r=t.barycenter)&&function(t,e){var n=0,r=0;t.weight&&(n+=t.barycenter*t.weight,r+=t.weight);e.weight&&(n+=e.barycenter*e.weight,r+=e.weight);t.vs=e.vs.concat(t.vs),t.barycenter=n/r,t.weight=r,t.i=Math.min(e.i,t.i),e.merged=!0}(t,e)}}function i(e){return function(n){n.in.push(e),0==--n.indegree&&t.push(n)}}for(;t.length;){var a=t.pop();e.push(a),r.forEach(a.in.reverse(),n(a)),r.forEach(a.out,i(a))}return r.map(r.filter(e,(function(t){return!t.merged})),(function(t){return r.pick(t,["vs","i","barycenter","weight"])}))}(r.filter(n,(function(t){return!t.indegree})))}},function(t,e,n){var r=n(4),i=n(8);function a(t,e,n){for(var i;e.length&&(i=r.last(e)).i<=n;)e.pop(),t.push(i.vs),n++;return n}t.exports=function(t,e){var n=i.partition(t,(function(t){return r.has(t,"barycenter")})),o=n.lhs,s=r.sortBy(n.rhs,(function(t){return-t.i})),c=[],u=0,l=0,h=0;o.sort((f=!!e,function(t,e){return t.barycentere.barycenter?1:f?e.i-t.i:t.i-e.i})),h=a(c,s,h),r.forEach(o,(function(t){h+=t.vs.length,c.push(t.vs),u+=t.barycenter*t.weight,l+=t.weight,h=a(c,s,h)}));var f;var d={vs:r.flatten(c,!0)};l&&(d.barycenter=u/l,d.weight=l);return d}},function(t,e,n){var r=n(4),i=n(17).Graph;t.exports=function(t,e,n){var a=function(t){var e;for(;t.hasNode(e=r.uniqueId("_root")););return e}(t),o=new i({compound:!0}).setGraph({root:a}).setDefaultNodeLabel((function(e){return t.node(e)}));return r.forEach(t.nodes(),(function(i){var s=t.node(i),c=t.parent(i);(s.rank===e||s.minRank<=e&&e<=s.maxRank)&&(o.setNode(i),o.setParent(i,c||a),r.forEach(t[n](i),(function(e){var n=e.v===i?e.w:e.v,a=o.edge(n,i),s=r.isUndefined(a)?0:a.weight;o.setEdge(n,i,{weight:t.edge(e).weight+s})})),r.has(s,"minRank")&&o.setNode(i,{borderLeft:s.borderLeft[e],borderRight:s.borderRight[e]}))})),o}},function(t,e,n){var r=n(4);t.exports=function(t,e,n){var i,a={};r.forEach(n,(function(n){for(var r,o,s=t.parent(n);s;){if((r=t.parent(s))?(o=a[r],a[r]=s):(o=i,i=s),o&&o!==s)return void e.setEdge(o,s);s=r}}))}},function(t,e,n){"use strict";var r=n(4),i=n(8),a=n(365).positionX;t.exports=function(t){(function(t){var e=i.buildLayerMatrix(t),n=t.graph().ranksep,a=0;r.forEach(e,(function(e){var i=r.max(r.map(e,(function(e){return t.node(e).height})));r.forEach(e,(function(e){t.node(e).y=a+i/2})),a+=i+n}))})(t=i.asNonCompoundGraph(t)),r.forEach(a(t),(function(e,n){t.node(n).x=e}))}},function(t,e,n){"use strict";var r=n(4),i=n(17).Graph,a=n(8);function o(t,e){var n={};return r.reduce(e,(function(e,i){var a=0,o=0,s=e.length,u=r.last(i);return r.forEach(i,(function(e,l){var h=function(t,e){if(t.node(e).dummy)return r.find(t.predecessors(e),(function(e){return t.node(e).dummy}))}(t,e),f=h?t.node(h).order:s;(h||e===u)&&(r.forEach(i.slice(o,l+1),(function(e){r.forEach(t.predecessors(e),(function(r){var i=t.node(r),o=i.order;!(os)&&c(n,e,u)}))}))}return r.reduce(e,(function(e,n){var a,o=-1,s=0;return r.forEach(n,(function(r,c){if("border"===t.node(r).dummy){var u=t.predecessors(r);u.length&&(a=t.node(u[0]).order,i(n,s,c,o,a),s=c,o=a)}i(n,s,n.length,a,e.length)})),n})),n}function c(t,e,n){if(e>n){var r=e;e=n,n=r}var i=t[e];i||(t[e]=i={}),i[n]=!0}function u(t,e,n){if(e>n){var i=e;e=n,n=i}return r.has(t[e],n)}function l(t,e,n,i){var a={},o={},s={};return r.forEach(e,(function(t){r.forEach(t,(function(t,e){a[t]=t,o[t]=t,s[t]=e}))})),r.forEach(e,(function(t){var e=-1;r.forEach(t,(function(t){var c=i(t);if(c.length)for(var l=((c=r.sortBy(c,(function(t){return s[t]}))).length-1)/2,h=Math.floor(l),f=Math.ceil(l);h<=f;++h){var d=c[h];o[t]===t&&e0}t.exports=function(t,e,r,i){var a,o,s,c,u,l,h,f,d,p,g,y,v;if(a=e.y-t.y,s=t.x-e.x,u=e.x*t.y-t.x*e.y,d=a*r.x+s*r.y+u,p=a*i.x+s*i.y+u,0!==d&&0!==p&&n(d,p))return;if(o=i.y-r.y,c=r.x-i.x,l=i.x*r.y-r.x*i.y,h=o*t.x+c*t.y+l,f=o*e.x+c*e.y+l,0!==h&&0!==f&&n(h,f))return;if(0===(g=a*c-o*s))return;return y=Math.abs(g/2),{x:(v=s*l-c*u)<0?(v-y)/g:(v+y)/g,y:(v=o*u-a*l)<0?(v-y)/g:(v+y)/g}}},function(t,e,n){var r=n(43),i=n(31),a=n(153).layout;t.exports=function(){var t=n(371),e=n(374),i=n(375),u=n(376),l=n(377),h=n(378),f=n(379),d=n(380),p=n(381),g=function(n,g){!function(t){t.nodes().forEach((function(e){var n=t.node(e);r.has(n,"label")||t.children(e).length||(n.label=e),r.has(n,"paddingX")&&r.defaults(n,{paddingLeft:n.paddingX,paddingRight:n.paddingX}),r.has(n,"paddingY")&&r.defaults(n,{paddingTop:n.paddingY,paddingBottom:n.paddingY}),r.has(n,"padding")&&r.defaults(n,{paddingLeft:n.padding,paddingRight:n.padding,paddingTop:n.padding,paddingBottom:n.padding}),r.defaults(n,o),r.each(["paddingLeft","paddingRight","paddingTop","paddingBottom"],(function(t){n[t]=Number(n[t])})),r.has(n,"width")&&(n._prevWidth=n.width),r.has(n,"height")&&(n._prevHeight=n.height)})),t.edges().forEach((function(e){var n=t.edge(e);r.has(n,"label")||(n.label=""),r.defaults(n,s)}))}(g);var y=c(n,"output"),v=c(y,"clusters"),m=c(y,"edgePaths"),b=i(c(y,"edgeLabels"),g),x=t(c(y,"nodes"),g,d);a(g),l(x,g),h(b,g),u(m,g,p);var _=e(v,g);f(_,g),function(t){r.each(t.nodes(),(function(e){var n=t.node(e);r.has(n,"_prevWidth")?n.width=n._prevWidth:delete n.width,r.has(n,"_prevHeight")?n.height=n._prevHeight:delete n.height,delete n._prevWidth,delete n._prevHeight}))}(g)};return g.createNodes=function(e){return arguments.length?(t=e,g):t},g.createClusters=function(t){return arguments.length?(e=t,g):e},g.createEdgeLabels=function(t){return arguments.length?(i=t,g):i},g.createEdgePaths=function(t){return arguments.length?(u=t,g):u},g.shapes=function(t){return arguments.length?(d=t,g):d},g.arrows=function(t){return arguments.length?(p=t,g):p},g};var o={paddingLeft:10,paddingRight:10,paddingTop:10,paddingBottom:10,rx:0,ry:0,shape:"rect"},s={arrowhead:"normal",curve:i.curveLinear};function c(t,e){var n=t.select("g."+e);return n.empty()&&(n=t.append("g").attr("class",e)),n}},function(t,e,n){"use strict";var r=n(43),i=n(97),a=n(12),o=n(31);t.exports=function(t,e,n){var s,c=e.nodes().filter((function(t){return!a.isSubgraph(e,t)})),u=t.selectAll("g.node").data(c,(function(t){return t})).classed("update",!0);u.exit().remove(),u.enter().append("g").attr("class","node").style("opacity",0),(u=t.selectAll("g.node")).each((function(t){var s=e.node(t),c=o.select(this);a.applyClass(c,s.class,(c.classed("update")?"update ":"")+"node"),c.select("g.label").remove();var u=c.append("g").attr("class","label"),l=i(u,s),h=n[s.shape],f=r.pick(l.node().getBBox(),"width","height");s.elem=this,s.id&&c.attr("id",s.id),s.labelId&&u.attr("id",s.labelId),r.has(s,"width")&&(f.width=s.width),r.has(s,"height")&&(f.height=s.height),f.width+=s.paddingLeft+s.paddingRight,f.height+=s.paddingTop+s.paddingBottom,u.attr("transform","translate("+(s.paddingLeft-s.paddingRight)/2+","+(s.paddingTop-s.paddingBottom)/2+")");var d=o.select(this);d.select(".label-container").remove();var p=h(d,f,s).classed("label-container",!0);a.applyStyle(p,s.style);var g=p.node().getBBox();s.width=g.width,s.height=g.height})),s=u.exit?u.exit():u.selectAll(null);return a.applyTransition(s,e).style("opacity",0).remove(),u}},function(t,e,n){var r=n(12);t.exports=function(t,e){for(var n=t.append("text"),i=function(t){for(var e,n="",r=!1,i=0;i0&&void 0!==arguments[0]?arguments[0]:"fatal";isNaN(t)&&(t=t.toLowerCase(),void 0!==s[t]&&(t=s[t])),c.trace=function(){},c.debug=function(){},c.info=function(){},c.warn=function(){},c.error=function(){},c.fatal=function(){},t<=s.fatal&&(c.fatal=console.error?console.error.bind(console,l("FATAL"),"color: orange"):console.log.bind(console,"",l("FATAL"))),t<=s.error&&(c.error=console.error?console.error.bind(console,l("ERROR"),"color: orange"):console.log.bind(console,"",l("ERROR"))),t<=s.warn&&(c.warn=console.warn?console.warn.bind(console,l("WARN"),"color: orange"):console.log.bind(console,"",l("WARN"))),t<=s.info&&(c.info=console.info?console.info.bind(console,l("INFO"),"color: lightblue"):console.log.bind(console,"",l("INFO"))),t<=s.debug&&(c.debug=console.debug?console.debug.bind(console,l("DEBUG"),"color: lightgreen"):console.log.bind(console,"",l("DEBUG")))},l=function(t){var e=o()().format("ss.SSS");return"%c".concat(e," : ").concat(t," : ")},h=n(169),f=n.n(h),d=n(0),p=n(44),g=n(70),y=function(t){for(var e="",n=0;n>=0;){if(!((n=t.indexOf("=0)){e+=t,n=-1;break}e+=t.substr(0,n),(n=(t=t.substr(n+1)).indexOf("<\/script>"))>=0&&(n+=9,t=t.substr(n))}return e},v=//gi,m=function(t){return t.replace(v,"#br#")},b=function(t){return t.replace(/#br#/g,"
")},x={getRows:function(t){if(!t)return 1;var e=m(t);return(e=e.replace(/\\n/g,"#br#")).split("#br#")},sanitizeText:function(t,e){var n=t,r=!0;if(!e.flowchart||!1!==e.flowchart.htmlLabels&&"false"!==e.flowchart.htmlLabels||(r=!1),r){var i=e.securityLevel;"antiscript"===i?n=y(n):"loose"!==i&&(n=(n=(n=m(n)).replace(//g,">")).replace(/=/g,"="),n=b(n))}return n},hasBreaks:function(t){return//gi.test(t)},splitBreaks:function(t){return t.split(//gi)},lineBreakRegex:v,removeScript:y};function _(t,e){for(var n=0;n1&&void 0!==arguments[1]?arguments[1]:null;try{var n=new RegExp("[%]{2}(?![{]".concat(C.source,")(?=[}][%]{2}).*\n"),"ig");t=t.trim().replace(n,"").replace(/'/gm,'"'),c.debug("Detecting diagram directive".concat(null!==e?" type:"+e:""," based on the text:").concat(t));for(var r,i=[];null!==(r=T.exec(t));)if(r.index===T.lastIndex&&T.lastIndex++,r&&!e||e&&r[1]&&r[1].match(e)||e&&r[2]&&r[2].match(e)){var a=r[1]?r[1]:r[2],o=r[3]?r[3].trim():r[4]?JSON.parse(r[4].trim()):null;i.push({type:a,args:o})}return 0===i.length&&i.push({type:t,args:null}),1===i.length?i[0]:i}catch(n){return c.error("ERROR: ".concat(n.message," - Unable to parse directive").concat(null!==e?" type:"+e:""," based on the text:").concat(t)),{type:null,args:null}}},M=function(t){return t=t.replace(T,"").replace(A,"\n"),c.debug("Detecting diagram type based on the text "+t),t.match(/^\s*sequenceDiagram/)?"sequence":t.match(/^\s*gantt/)?"gantt":t.match(/^\s*classDiagram-v2/)?"classDiagram":t.match(/^\s*classDiagram/)?"class":t.match(/^\s*stateDiagram-v2/)?"stateDiagram":t.match(/^\s*stateDiagram/)?"state":t.match(/^\s*gitGraph/)?"git":t.match(/^\s*flowchart/)?"flowchart-v2":t.match(/^\s*info/)?"info":t.match(/^\s*pie/)?"pie":t.match(/^\s*erDiagram/)?"er":t.match(/^\s*journey/)?"journey":"flowchart"},O=function(t,e){var n={};return function(){for(var r=arguments.length,i=new Array(r),a=0;a"},n),x.lineBreakRegex.test(t))return t;var r=t.split(" "),i=[],a="";return r.forEach((function(t,o){var s=z("".concat(t," "),n),c=z(a,n);if(s>e){var u=Y(t,e,"-",n),l=u.hyphenatedStrings,h=u.remainingWord;i.push.apply(i,[a].concat(w(l))),a=h}else c+s>=e?(i.push(a),a=t):a=[a,t].filter(Boolean).join(" ");o+1===r.length&&i.push(a)})),i.filter((function(t){return""!==t})).join(n.joinWith)}),(function(t,e,n){return"".concat(t,"-").concat(e,"-").concat(n.fontSize,"-").concat(n.fontWeight,"-").concat(n.fontFamily,"-").concat(n.joinWith)})),Y=O((function(t,e){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"-",r=arguments.length>3?arguments[3]:void 0;r=Object.assign({fontSize:12,fontWeight:400,fontFamily:"Arial",margin:0},r);var i=t.split(""),a=[],o="";return i.forEach((function(t,s){var c="".concat(o).concat(t);if(z(c,r)>=e){var u=s+1,l=i.length===u,h="".concat(c).concat(n);a.push(l?c:h),o=""}else o=c})),{hyphenatedStrings:a,remainingWord:o}}),(function(t,e){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"-",r=arguments.length>3?arguments[3]:void 0;return"".concat(t,"-").concat(e,"-").concat(n,"-").concat(r.fontSize,"-").concat(r.fontWeight,"-").concat(r.fontFamily)})),z=function(t,e){return e=Object.assign({fontSize:12,fontWeight:400,fontFamily:"Arial"},e),U(t,e).width},U=O((function(t,e){var n=e=Object.assign({fontSize:12,fontWeight:400,fontFamily:"Arial"},e),r=n.fontSize,i=n.fontFamily,a=n.fontWeight;if(!t)return{width:0,height:0};var o=["sans-serif",i],s=t.split(x.lineBreakRegex),c=[],u=Object(d.select)("body");if(!u.remove)return{width:0,height:0,lineHeight:0};for(var l=u.append("svg"),h=0,f=o;hc[1].height&&c[0].width>c[1].width&&c[0].lineHeight>c[1].lineHeight?0:1]}),(function(t,e){return"".concat(t,"-").concat(e.fontSize,"-").concat(e.fontWeight,"-").concat(e.fontFamily)})),$=function(t,e,n){var r=new Map;return r.set("height",t),n?(r.set("width","100%"),r.set("style","max-width: ".concat(e,"px;"))):r.set("width",e),r},W=function(t,e,n,r){!function(t,e){var n=!0,r=!1,i=void 0;try{for(var a,o=e[Symbol.iterator]();!(n=(a=o.next()).done);n=!0){var s=a.value;t.attr(s[0],s[1])}}catch(t){r=!0,i=t}finally{try{n||null==o.return||o.return()}finally{if(r)throw i}}}(t,$(e,n,r))},H={assignWithDepth:I,wrapLabel:R,calculateTextHeight:function(t,e){return e=Object.assign({fontSize:12,fontWeight:400,fontFamily:"Arial",margin:15},e),U(t,e).height},calculateTextWidth:z,calculateTextDimensions:U,calculateSvgSizeAttrs:$,configureSvgSize:W,detectInit:function(t){var e=S(t,/(?:init\b)|(?:initialize\b)/),n={};if(Array.isArray(e)){var r=e.map((function(t){return t.args}));n=I(n,w(r))}else n=e.args;if(n){var i=M(t);["config"].forEach((function(t){void 0!==n[t]&&("flowchart-v2"===i&&(i="flowchart"),n[i]=n[t],delete n[t])}))}return n},detectDirective:S,detectType:M,isSubstringInArray:function(t,e){for(var n=0;n=1&&(i={x:t.x,y:t.y}),a>0&&a<1&&(i={x:(1-a)*e.x+a*t.x,y:(1-a)*e.y+a*t.y})}}e=t})),i}(t)},calcCardinalityPosition:function(t,e,n){var r;c.info("our points",e),e[0]!==n&&(e=e.reverse()),e.forEach((function(t){N(t,r),r=t}));var i,a=25;r=void 0,e.forEach((function(t){if(r&&!i){var e=N(t,r);if(e=1&&(i={x:t.x,y:t.y}),n>0&&n<1&&(i={x:(1-n)*r.x+n*t.x,y:(1-n)*r.y+n*t.y})}}r=t}));var o=t?10:5,s=Math.atan2(e[0].y-i.y,e[0].x-i.x),u={x:0,y:0};return u.x=Math.sin(s)*o+(e[0].x+i.x)/2,u.y=-Math.cos(s)*o+(e[0].y+i.y)/2,u},calcTerminalLabelPosition:function(t,e,n){var r,i=JSON.parse(JSON.stringify(n));c.info("our points",i),"start_left"!==e&&"start_right"!==e&&(i=i.reverse()),i.forEach((function(t){N(t,r),r=t}));var a,o=25;r=void 0,i.forEach((function(t){if(r&&!a){var e=N(t,r);if(e=1&&(a={x:t.x,y:t.y}),n>0&&n<1&&(a={x:(1-n)*r.x+n*t.x,y:(1-n)*r.y+n*t.y})}}r=t}));var s=10,u=Math.atan2(i[0].y-a.y,i[0].x-a.x),l={x:0,y:0};return l.x=Math.sin(u)*s+(i[0].x+a.x)/2,l.y=-Math.cos(u)*s+(i[0].y+a.y)/2,"start_left"===e&&(l.x=Math.sin(u+Math.PI)*s+(i[0].x+a.x)/2,l.y=-Math.cos(u+Math.PI)*s+(i[0].y+a.y)/2),"end_right"===e&&(l.x=Math.sin(u-Math.PI)*s+(i[0].x+a.x)/2-5,l.y=-Math.cos(u-Math.PI)*s+(i[0].y+a.y)/2-5),"end_left"===e&&(l.x=Math.sin(u)*s+(i[0].x+a.x)/2-5,l.y=-Math.cos(u)*s+(i[0].y+a.y)/2-5),l},formatUrl:function(t,e){var n=t.trim();if(n)return"loose"!==e.securityLevel?Object(g.sanitizeUrl)(n):n},getStylesFromArray:B,generateId:F,random:P,memoize:O,runFunc:function(t){for(var e,n=t.split("."),r=n.length-1,i=n[r],a=window,o=0;o1?s-1:0),u=1;u=0&&(n=!0)})),n},qt=function(t,e){var n=[];return t.nodes.forEach((function(r,i){Gt(e,r)||n.push(t.nodes[i])})),{nodes:n}},Xt={parseDirective:function(t,e,n){Go.parseDirective(this,t,e,n)},defaultConfig:function(){return gt.flowchart},addVertex:function(t,e,n,r,i){var a,o=t;void 0!==o&&0!==o.trim().length&&(void 0===Dt[o]&&(Dt[o]={id:o,domId:"flowchart-"+o+"-"+Mt,styles:[],classes:[]}),Mt++,void 0!==e?(Ot=_t(),'"'===(a=x.sanitizeText(e.trim(),Ot))[0]&&'"'===a[a.length-1]&&(a=a.substring(1,a.length-1)),Dt[o].text=a):void 0===Dt[o].text&&(Dt[o].text=t),void 0!==n&&(Dt[o].type=n),null!=r&&r.forEach((function(t){Dt[o].styles.push(t)})),null!=i&&i.forEach((function(t){Dt[o].classes.push(t)})))},lookUpDomId:Yt,addLink:function(t,e,n,r){var i,a;for(i=0;i/)&&(At="LR"),At.match(/.*v/)&&(At="TB")},setClass:Ut,setTooltip:function(t,e){t.split(",").forEach((function(t){void 0!==e&&(Pt["gen-1"===St?Yt(t):t]=x.sanitizeText(e,Ot))}))},getTooltip:function(t){return Pt[t]},setClickEvent:function(t,e,n){t.split(",").forEach((function(t){!function(t,e,n){var r=Yt(t);if("loose"===_t().securityLevel&&void 0!==e){var i=[];if("string"==typeof n){i=n.split(/,(?=(?:(?:[^"]*"){2})*[^"]*$)/);for(var a=0;a=0)&&s.push(t))})),"gen-1"===St){c.warn("LOOKING UP");for(var l=0;l0&&function t(e,n){var r=Lt[n].nodes;if(!((Ht+=1)>2e3)){if(Vt[Ht]=n,Lt[n].id===e)return{result:!0,count:0};for(var i=0,a=1;i=0){var s=t(e,o);if(s.result)return{result:!0,count:a+s.count};a+=s.count}i+=1}return{result:!1,count:a}}}("none",Lt.length-1)},getSubGraphs:function(){return Lt},destructLink:function(t,e){var n,r=function(t){var e=t.trim(),n=e.slice(0,-1),r="arrow_open";switch(e.slice(-1)){case"x":r="arrow_cross","x"===e[0]&&(r="double_"+r,n=n.slice(1));break;case">":r="arrow_point","<"===e[0]&&(r="double_"+r,n=n.slice(1));break;case"o":r="arrow_circle","o"===e[0]&&(r="double_"+r,n=n.slice(1))}var i="normal",a=n.length-1;"="===n[0]&&(i="thick");var o=function(t,e){for(var n=e.length,r=0,i=0;in.height/2-a)){var o=a*a*(1-r*r/(i*i));0!=o&&(o=Math.sqrt(o)),o=a-o,t.y-n.y>0&&(o=-o),e.y+=o}return e},c}function de(t,e,n,r){return t.insert("polygon",":first-child").attr("points",r.map((function(t){return t.x+","+t.y})).join(" ")).attr("transform","translate("+-e/2+","+n/2+")")}var pe={addToRender:function(t){t.shapes().question=ne,t.shapes().hexagon=re,t.shapes().stadium=le,t.shapes().subroutine=he,t.shapes().cylinder=fe,t.shapes().rect_left_inv_arrow=ie,t.shapes().lean_right=ae,t.shapes().lean_left=oe,t.shapes().trapezoid=se,t.shapes().inv_trapezoid=ce,t.shapes().rect_right_inv_arrow=ue},addToRenderV2:function(t){t({question:ne}),t({hexagon:re}),t({stadium:le}),t({subroutine:he}),t({cylinder:fe}),t({rect_left_inv_arrow:ie}),t({lean_right:ae}),t({lean_left:oe}),t({trapezoid:se}),t({inv_trapezoid:ce}),t({rect_right_inv_arrow:ue})}},ge={},ye=function(t,e,n){var r=Object(d.select)('[id="'.concat(n,'"]'));Object.keys(t).forEach((function(n){var i=t[n],a="default";i.classes.length>0&&(a=i.classes.join(" "));var o,s=B(i.styles),u=void 0!==i.text?i.text:i.id;if(_t().flowchart.htmlLabels){var l={label:u.replace(/fa[lrsb]?:fa-[\w-]+/g,(function(t){return"")}))};(o=ee()(r,l).node()).parentNode.removeChild(o)}else{var h=document.createElementNS("http://www.w3.org/2000/svg","text");h.setAttribute("style",s.labelStyle.replace("color:","fill:"));for(var f=u.split(x.lineBreakRegex),d=0;d').concat(a.text.replace(/fa[lrsb]?:fa-[\w-]+/g,(function(t){return"")})),"")):(u.labelType="text",u.label=a.text.replace(x.lineBreakRegex,"\n"),void 0===a.style&&(u.style=u.style||"stroke: #333; stroke-width: 1.5px;fill:none"),u.labelStyle=u.labelStyle.replace("color:","fill:"))),u.id=o,u.class=s+" "+c,u.minlen=a.length||1,e.setEdge(Xt.lookUpDomId(a.start),Xt.lookUpDomId(a.end),u,i)}))},me=function(t){for(var e=Object.keys(t),n=0;n=0;h--)i=l[h],Xt.addVertex(i.id,i.title,"group",void 0,i.classes);var f=Xt.getVertices();c.warn("Get vertices",f);var p=Xt.getEdges(),g=0;for(g=l.length-1;g>=0;g--){i=l[g],Object(d.selectAll)("cluster").append("text");for(var y=0;y"),c.info("vertexText"+i),function(t){var e,n,r=Object(d.select)(document.createElementNS("http://www.w3.org/2000/svg","foreignObject")),i=r.append("xhtml:div"),a=t.label,o=t.isNode?"nodeLabel":"edgeLabel";return i.html(''+a+""),e=i,(n=t.labelStyle)&&e.attr("style",n),i.style("display","inline-block"),i.style("white-space","nowrap"),i.attr("xmlns","http://www.w3.org/1999/xhtml"),r.node()}({isNode:r,label:i.replace(/fa[lrsb]?:fa-[\w-]+/g,(function(t){return"")})),labelStyle:e.replace("fill:","color:")});var a=document.createElementNS("http://www.w3.org/2000/svg","text");a.setAttribute("style",e.replace("color:","fill:"));var o=[];o="string"==typeof i?i.split(/\\n|\n|/gi):Array.isArray(i)?i:[];for(var s=0;s0)t(a,n,r,i);else{var o=n.node(a);c.info("cp ",a," to ",i," with parent ",e),r.setNode(a,o),i!==n.parent(a)&&(c.warn("Setting parent",a,n.parent(a)),r.setParent(a,n.parent(a))),e!==i&&a!==e?(c.debug("Setting parent",a,e),r.setParent(a,e)):(c.info("In copy ",e,"root",i,"data",n.node(e),i),c.debug("Not Setting parent for node=",a,"cluster!==rootId",e!==i,"node!==clusterId",a!==e));var s=n.edges(a);c.debug("Copying Edges",s),s.forEach((function(t){c.info("Edge",t);var a=n.edge(t.v,t.w,t.name);c.info("Edge data",a,i);try{!function(t,e){return c.info("Decendants of ",e," is ",Oe[e]),c.info("Edge is ",t),t.v!==e&&(t.w!==e&&(Oe[e]?(c.info("Here "),Oe[e].indexOf(t.v)>=0||(!!Ne(t.v,e)||(!!Ne(t.w,e)||Oe[e].indexOf(t.w)>=0))):(c.debug("Tilt, ",e,",not in decendants"),!1)))}(t,i)?c.info("Skipping copy of edge ",t.v,"--\x3e",t.w," rootId: ",i," clusterId:",e):(c.info("Copying as ",t.v,t.w,a,t.name),r.setEdge(t.v,t.w,a,t.name),c.info("newGraph edges ",r.edges(),r.edge(r.edges()[0])))}catch(t){c.error(t)}}))}c.debug("Removing node",a),n.removeNode(a)}))},Le=function t(e,n){c.trace("Searching",e);var r=n.children(e);if(c.trace("Searching children of id ",e,r),r.length<1)return c.trace("This is a valid node",e),e;for(var i=0;i ",a),a}},Fe=function(t){return Me[t]&&Me[t].externalConnections&&Me[t]?Me[t].id:t},Pe=function(t,e){!t||e>10?c.debug("Opting out, no graph "):(c.debug("Opting in, graph "),t.nodes().forEach((function(e){t.children(e).length>0&&(c.warn("Cluster identified",e," Replacement id in edges: ",Le(e,t)),Oe[e]=function t(e,n){for(var r=n.children(e),i=[].concat(r),a=0;a0?(c.debug("Cluster identified",e,Oe),r.forEach((function(t){t.v!==e&&t.w!==e&&(Ne(t.v,e)^Ne(t.w,e)&&(c.warn("Edge: ",t," leaves cluster ",e),c.warn("Decendants of XXX ",e,": ",Oe[e]),Me[e].externalConnections=!0))}))):c.debug("Not a cluster ",e,Oe)})),t.edges().forEach((function(e){var n=t.edge(e);c.warn("Edge "+e.v+" -> "+e.w+": "+JSON.stringify(e)),c.warn("Edge "+e.v+" -> "+e.w+": "+JSON.stringify(t.edge(e)));var r=e.v,i=e.w;c.warn("Fix XXX",Me,"ids:",e.v,e.w,"Translateing: ",Me[e.v]," --- ",Me[e.w]),(Me[e.v]||Me[e.w])&&(c.warn("Fixing and trixing - removing XXX",e.v,e.w,e.name),r=Fe(e.v),i=Fe(e.w),t.removeEdge(e.v,e.w,e.name),r!==e.v&&(n.fromCluster=e.v),i!==e.w&&(n.toCluster=e.w),c.warn("Fix Replacing with XXX",r,i,e.name),t.setEdge(r,i,n,e.name))})),c.warn("Adjusted Graph",G.a.json.write(t)),Ie(t,0),c.trace(Me))},Ie=function t(e,n){if(c.warn("extractor - ",n,G.a.json.write(e),e.children("D")),n>10)c.error("Bailing out");else{for(var r=e.nodes(),i=!1,a=0;a0}if(i){c.debug("Nodes = ",r,n);for(var u=0;u0){c.warn("Cluster without external connections, without a parent and with children",l,n);var h=e.graph(),f=new G.a.Graph({multigraph:!0,compound:!0}).setGraph({rankdir:"TB"===h.rankdir?"LR":"TB",nodesep:50,ranksep:50,marginx:8,marginy:8}).setDefaultEdgeLabel((function(){return{}}));c.warn("Old graph before copy",G.a.json.write(e)),Be(l,e,f,l),e.setNode(l,{clusterNode:!0,id:l,clusterData:Me[l].clusterData,labelText:Me[l].labelText,graph:f}),c.warn("New graph after copy node: (",l,")",G.a.json.write(f)),c.debug("Old graph after copy",G.a.json.write(e))}else c.warn("Cluster ** ",l," **not meeting the criteria !externalConnections:",!Me[l].externalConnections," no parent: ",!e.parent(l)," children ",e.children(l)&&e.children(l).length>0,e.children("D"),n),c.debug(Me);else c.debug("Not a cluster",l,n)}r=e.nodes(),c.warn("New list of nodes",r);for(var d=0;d0}var $e=function(t,e,n,r){var i,a,o,s,c,u,l,h,f,d,p,g,y;if(i=e.y-t.y,o=t.x-e.x,c=e.x*t.y-t.x*e.y,f=i*n.x+o*n.y+c,d=i*r.x+o*r.y+c,!(0!==f&&0!==d&&Ue(f,d)||(a=r.y-n.y,s=n.x-r.x,u=r.x*n.y-n.x*r.y,l=a*t.x+s*t.y+u,h=a*e.x+s*e.y+u,0!==l&&0!==h&&Ue(l,h)||0==(p=i*s-a*o))))return g=Math.abs(p/2),{x:(y=o*u-s*c)<0?(y-g)/p:(y+g)/p,y:(y=a*c-i*u)<0?(y-g)/p:(y+g)/p}},We=function(t,e,n){var r=t.x,i=t.y,a=[],o=Number.POSITIVE_INFINITY,s=Number.POSITIVE_INFINITY;"function"==typeof e.forEach?e.forEach((function(t){o=Math.min(o,t.x),s=Math.min(s,t.y)})):(o=Math.min(o,e.x),s=Math.min(s,e.y));for(var c=r-t.width/2-o,u=i-t.height/2-s,l=0;l1&&a.sort((function(t,e){var r=t.x-n.x,i=t.y-n.y,a=Math.sqrt(r*r+i*i),o=e.x-n.x,s=e.y-n.y,c=Math.sqrt(o*o+s*s);return aMath.abs(o)*u?(s<0&&(u=-u),n=0===s?0:u*o/s,r=u):(o<0&&(c=-c),n=c,r=0===o?0:c*s/o),{x:i+n,y:a+r}},Ve={node:n.n(Re).a,circle:ze,ellipse:Ye,polygon:We,rect:He},Ge=function(t,e){var n=Ce(t,e,"node "+e.classes,!0),r=n.shapeSvg,i=n.bbox,a=n.halfPadding;c.info("Classes = ",e.classes);var o=r.insert("rect",":first-child");return o.attr("rx",e.rx).attr("ry",e.ry).attr("x",-i.width/2-a).attr("y",-i.height/2-a).attr("width",i.width+e.padding).attr("height",i.height+e.padding),Ae(e,o),e.intersect=function(t){return Ve.rect(e,t)},r};function qe(t){return function(t){if(Array.isArray(t)){for(var e=0,n=new Array(t.length);e0){var r=t.split("~");n=r[0],e=r[1]}return{className:n,type:e}},tn=function(t){var e=Qe(t);void 0===Ze[e.className]&&(Ze[e.className]={id:e.className,type:e.type,cssClasses:[],methods:[],members:[],annotations:[],domId:"classid-"+e.className+"-"+Je},Je++)},en=function(t){for(var e=Object.keys(Ze),n=0;n>")?r.annotations.push(i.substring(2,i.length-2)):i.indexOf(")")>0?r.methods.push(i):i&&r.members.push(i)}},rn=function(t,e){t.split(",").forEach((function(t){var n=t;t[0].match(/\d/)&&(n="classid-"+n),void 0!==Ze[n]&&Ze[n].cssClasses.push(e)}))},an=function(t,e,n){var r=_t(),i=t,a=en(i);if("loose"===r.securityLevel&&void 0!==e&&void 0!==Ze[i]){var o=[];if("string"==typeof n){o=n.split(/,(?=(?:(?:[^"]*"){2})*[^"]*$)/);for(var s=0;s1&&a>i&&a<=t.length){var o="",s="",c=t.substring(0,1);c.match(/\w/)?s=t.substring(0,i).trim():(c.match(/\+|-|~|#/)&&(o=c),s=t.substring(1,i).trim());var u=t.substring(i+1,a),l=t.substring(a+1,1);n=yn(l),e=o+s+"("+gn(u.trim())+")",a<"".length&&""!==(r=t.substring(a+2).trim())&&(r=" : "+gn(r))}else e=gn(t);return{displayText:e,cssStyle:n}},pn=function(t,e,n,r){var i=ln(e),a=t.append("tspan").attr("x",r.padding).text(i.displayText);""!==i.cssStyle&&a.attr("style",i.cssStyle),n||a.attr("dy",r.textHeight)},gn=function t(e){var n=e;return-1!=e.indexOf("~")?t(n=(n=n.replace("~","<")).replace("~",">")):n},yn=function(t){switch(t){case"*":return"font-style:italic;";case"$":return"text-decoration:underline;";default:return""}},vn=function(t,e,n){c.info("Rendering class "+e);var r,i=e.id,a={id:i,label:e.id,width:0,height:0},o=t.append("g").attr("id",en(i)).attr("class","classGroup");r=e.link?o.append("svg:a").attr("xlink:href",e.link).attr("target",e.linkTarget).append("text").attr("y",n.textHeight+n.padding).attr("x",0):o.append("text").attr("y",n.textHeight+n.padding).attr("x",0);var s=!0;e.annotations.forEach((function(t){var e=r.append("tspan").text("«"+t+"»");s||e.attr("dy",n.textHeight),s=!1}));var u=e.id;void 0!==e.type&&""!==e.type&&(u+="<"+e.type+">");var l=r.append("tspan").text(u).attr("class","title");s||l.attr("dy",n.textHeight);var h=r.node().getBBox().height,f=o.append("line").attr("x1",0).attr("y1",n.padding+h+n.dividerMargin/2).attr("y2",n.padding+h+n.dividerMargin/2),d=o.append("text").attr("x",n.padding).attr("y",h+n.dividerMargin+n.textHeight).attr("fill","white").attr("class","classText");s=!0,e.members.forEach((function(t){pn(d,t,s,n),s=!1}));var p=d.node().getBBox(),g=o.append("line").attr("x1",0).attr("y1",n.padding+h+n.dividerMargin+p.height).attr("y2",n.padding+h+n.dividerMargin+p.height),y=o.append("text").attr("x",n.padding).attr("y",h+2*n.dividerMargin+p.height+n.textHeight).attr("fill","white").attr("class","classText");s=!0,e.methods.forEach((function(t){pn(y,t,s,n),s=!1}));var v=o.node().getBBox(),m=" ";e.cssClasses.length>0&&(m+=e.cssClasses.join(" "));var b=o.insert("rect",":first-child").attr("x",0).attr("y",0).attr("width",v.width+2*n.padding).attr("height",v.height+n.padding+.5*n.dividerMargin).attr("class",m).node().getBBox().width;return r.node().childNodes.forEach((function(t){t.setAttribute("x",(b-t.getBBox().width)/2)})),e.tooltip&&r.insert("title").text(e.tooltip),f.attr("x2",b),g.attr("x2",b),a.width=b,a.height=v.height+n.padding+.5*n.dividerMargin,a},mn=function(t,e,n,r){var i=function(t){switch(t){case on.AGGREGATION:return"aggregation";case on.EXTENSION:return"extension";case on.COMPOSITION:return"composition";case on.DEPENDENCY:return"dependency"}};e.points=e.points.filter((function(t){return!Number.isNaN(t.y)}));var a,o,s=e.points,u=Object(d.line)().x((function(t){return t.x})).y((function(t){return t.y})).curve(d.curveBasis),l=t.append("path").attr("d",u(s)).attr("id","edge"+un).attr("class","relation"),h="";r.arrowMarkerAbsolute&&(h=(h=(h=window.location.protocol+"//"+window.location.host+window.location.pathname+window.location.search).replace(/\(/g,"\\(")).replace(/\)/g,"\\)")),1==n.relation.lineType&&l.attr("class","relation dashed-line"),"none"!==n.relation.type1&&l.attr("marker-start","url("+h+"#"+i(n.relation.type1)+"Start)"),"none"!==n.relation.type2&&l.attr("marker-end","url("+h+"#"+i(n.relation.type2)+"End)");var f,p,g,y,v=e.points.length,m=H.calcLabelPosition(e.points);if(a=m.x,o=m.y,v%2!=0&&v>1){var b=H.calcCardinalityPosition("none"!==n.relation.type1,e.points,e.points[0]),x=H.calcCardinalityPosition("none"!==n.relation.type2,e.points,e.points[v-1]);c.debug("cardinality_1_point "+JSON.stringify(b)),c.debug("cardinality_2_point "+JSON.stringify(x)),f=b.x,p=b.y,g=x.x,y=x.y}if(void 0!==n.title){var _=t.append("g").attr("class","classLabel"),k=_.append("text").attr("class","label").attr("x",a).attr("y",o).attr("fill","red").attr("text-anchor","middle").text(n.title);window.label=k;var w=k.node().getBBox();_.insert("rect",":first-child").attr("class","box").attr("x",w.x-r.padding/2).attr("y",w.y-r.padding/2).attr("width",w.width+r.padding).attr("height",w.height+r.padding)}(c.info("Rendering relation "+JSON.stringify(n)),void 0!==n.relationTitle1&&"none"!==n.relationTitle1)&&t.append("g").attr("class","cardinality").append("text").attr("class","type1").attr("x",f).attr("y",p).attr("fill","black").attr("font-size","6").text(n.relationTitle1);void 0!==n.relationTitle2&&"none"!==n.relationTitle2&&t.append("g").attr("class","cardinality").append("text").attr("class","type2").attr("x",g).attr("y",y).attr("fill","black").attr("font-size","6").text(n.relationTitle2);un++},bn=function(t,e,n){var r=t.insert("g").attr("class","node default").attr("id",e.domId||e.id),i=70,a=10;"LR"===n&&(i=10,a=70);var o=r.append("rect").style("stroke","black").style("fill","black").attr("x",-1*i/2).attr("y",-1*a/2).attr("width",i).attr("height",a).attr("class","fork-join");return Ae(e,o),e.height=e.height+e.padding/2,e.width=e.width+e.padding/2,e.intersect=function(t){return Ve.rect(e,t)},r},xn={question:function(t,e){var n=Ce(t,e,void 0,!0),r=n.shapeSvg,i=n.bbox,a=i.width+e.padding+(i.height+e.padding),o=[{x:a/2,y:0},{x:a,y:-a/2},{x:a/2,y:-a},{x:0,y:-a/2}];c.info("Question main (Circle)");var s=Se(r,a,a,o);return Ae(e,s),e.intersect=function(t){return c.warn("Intersect called"),Ve.polygon(e,o,t)},r},rect:function(t,e){var n=Ce(t,e,"node "+e.classes,!0),r=n.shapeSvg,i=n.bbox,a=n.halfPadding;c.trace("Classes = ",e.classes);var o=r.insert("rect",":first-child");return o.attr("class","basic label-container").attr("style",e.style).attr("rx",e.rx).attr("ry",e.ry).attr("x",-i.width/2-a).attr("y",-i.height/2-a).attr("width",i.width+e.padding).attr("height",i.height+e.padding),Ae(e,o),e.intersect=function(t){return Ve.rect(e,t)},r},rectWithTitle:function(t,e){var n;n=e.classes?"node "+e.classes:"node default";var r=t.insert("g").attr("class",n).attr("id",e.domId||e.id),i=r.insert("rect",":first-child"),a=r.insert("line"),o=r.insert("g").attr("class","label"),s=e.labelText.flat();c.info("Label text",s[0]);var u,l=o.node().appendChild(Te(s[0],e.labelStyle,!0,!0));if(_t().flowchart.htmlLabels){var h=l.children[0],f=Object(d.select)(l);u=h.getBoundingClientRect(),f.attr("width",u.width),f.attr("height",u.height)}c.info("Text 2",s);var p=s.slice(1,s.length),g=l.getBBox(),y=o.node().appendChild(Te(p.join("
"),e.labelStyle,!0,!0));if(_t().flowchart.htmlLabels){var v=y.children[0],m=Object(d.select)(y);u=v.getBoundingClientRect(),m.attr("width",u.width),m.attr("height",u.height)}var b=e.padding/2;return Object(d.select)(y).attr("transform","translate( "+(u.width>g.width?0:(g.width-u.width)/2)+", "+(g.height+b+5)+")"),Object(d.select)(l).attr("transform","translate( "+(u.widthe.height/2-s)){var i=s*s*(1-r*r/(o*o));0!=i&&(i=Math.sqrt(i)),i=s-i,t.y-e.y>0&&(i=-i),n.y+=i}return n},r},start:function(t,e){var n=t.insert("g").attr("class","node default").attr("id",e.domId||e.id),r=n.insert("circle",":first-child");return r.attr("class","state-start").attr("r",7).attr("width",14).attr("height",14),Ae(e,r),e.intersect=function(t){return Ve.circle(e,7,t)},n},end:function(t,e){var n=t.insert("g").attr("class","node default").attr("id",e.domId||e.id),r=n.insert("circle",":first-child"),i=n.insert("circle",":first-child");return i.attr("class","state-start").attr("r",7).attr("width",14).attr("height",14),r.attr("class","state-end").attr("r",5).attr("width",10).attr("height",10),Ae(e,i),e.intersect=function(t){return Ve.circle(e,7,t)},n},note:Ge,subroutine:function(t,e){var n=Ce(t,e,void 0,!0),r=n.shapeSvg,i=n.bbox,a=i.width+e.padding,o=i.height+e.padding,s=Se(r,a,o,[{x:0,y:0},{x:a,y:0},{x:a,y:-o},{x:0,y:-o},{x:0,y:0},{x:-8,y:0},{x:a+8,y:0},{x:a+8,y:-o},{x:-8,y:-o},{x:-8,y:0}]);return Ae(e,s),e.intersect=function(t){return Ve.polygon(e,t)},r},fork:bn,join:bn,class_box:function(t,e){var n,r=e.padding/2;n=e.classes?"node "+e.classes:"node default";var i=t.insert("g").attr("class",n).attr("id",e.domId||e.id),a=i.insert("rect",":first-child"),o=i.insert("line"),s=i.insert("line"),c=0,u=4,l=i.insert("g").attr("class","label"),h=0,f=e.classData.annotations&&e.classData.annotations[0],p=e.classData.annotations[0]?"«"+e.classData.annotations[0]+"»":"",g=l.node().appendChild(Te(p,e.labelStyle,!0,!0)),y=g.getBBox();if(_t().flowchart.htmlLabels){var v=g.children[0],m=Object(d.select)(g);y=v.getBoundingClientRect(),m.attr("width",y.width),m.attr("height",y.height)}e.classData.annotations[0]&&(u+=y.height+4,c+=y.width);var b=e.classData.id;void 0!==e.classData.type&&""!==e.classData.type&&(b+="<"+e.classData.type+">");var x=l.node().appendChild(Te(b,e.labelStyle,!0,!0));Object(d.select)(x).attr("class","classTitle");var _=x.getBBox();if(_t().flowchart.htmlLabels){var k=x.children[0],w=Object(d.select)(x);_=k.getBoundingClientRect(),w.attr("width",_.width),w.attr("height",_.height)}u+=_.height+4,_.width>c&&(c=_.width);var E=[];e.classData.members.forEach((function(t){var n=ln(t).displayText,r=l.node().appendChild(Te(n,e.labelStyle,!0,!0)),i=r.getBBox();if(_t().flowchart.htmlLabels){var a=r.children[0],o=Object(d.select)(r);i=a.getBoundingClientRect(),o.attr("width",i.width),o.attr("height",i.height)}i.width>c&&(c=i.width),u+=i.height+4,E.push(r)})),u+=8;var T=[];if(e.classData.methods.forEach((function(t){var n=ln(t).displayText,r=l.node().appendChild(Te(n,e.labelStyle,!0,!0)),i=r.getBBox();if(_t().flowchart.htmlLabels){var a=r.children[0],o=Object(d.select)(r);i=a.getBoundingClientRect(),o.attr("width",i.width),o.attr("height",i.height)}i.width>c&&(c=i.width),u+=i.height+4,T.push(r)})),u+=8,f){var C=(c-y.width)/2;Object(d.select)(g).attr("transform","translate( "+(-1*c/2+C)+", "+-1*u/2+")"),h=y.height+4}var A=(c-_.width)/2;return Object(d.select)(x).attr("transform","translate( "+(-1*c/2+A)+", "+(-1*u/2+h)+")"),h+=_.height+4,o.attr("class","divider").attr("x1",-c/2-r).attr("x2",c/2+r).attr("y1",-u/2-r+8+h).attr("y2",-u/2-r+8+h),h+=8,E.forEach((function(t){Object(d.select)(t).attr("transform","translate( "+-c/2+", "+(-1*u/2+h+4)+")"),h+=_.height+4})),h+=8,s.attr("class","divider").attr("x1",-c/2-r).attr("x2",c/2+r).attr("y1",-u/2-r+8+h).attr("y2",-u/2-r+8+h),h+=8,T.forEach((function(t){Object(d.select)(t).attr("transform","translate( "+-c/2+", "+(-1*u/2+h)+")"),h+=_.height+4})),a.attr("class","outer title-state").attr("x",-c/2-r).attr("y",-u/2-r).attr("width",c+e.padding).attr("height",u+e.padding),Ae(e,a),e.intersect=function(t){return Ve.rect(e,t)},i}},_n={},kn=function(t){var e=_n[t.id];c.trace("Transforming node",t,"translate("+(t.x-t.width/2-5)+", "+(t.y-t.height/2-5)+")");t.clusterNode?e.attr("transform","translate("+(t.x-t.width/2-8)+", "+(t.y-t.height/2-8)+")"):e.attr("transform","translate("+t.x+", "+t.y+")")},wn={rect:function(t,e){c.trace("Creating subgraph rect for ",e.id,e);var n=t.insert("g").attr("class","cluster"+(e.class?" "+e.class:"")).attr("id",e.id),r=n.insert("rect",":first-child"),i=n.insert("g").attr("class","cluster-label"),a=i.node().appendChild(Te(e.labelText,e.labelStyle,void 0,!0)),o=a.getBBox();if(_t().flowchart.htmlLabels){var s=a.children[0],u=Object(d.select)(a);o=s.getBoundingClientRect(),u.attr("width",o.width),u.attr("height",o.height)}var l=0*e.padding,h=l/2;c.trace("Data ",e,JSON.stringify(e)),r.attr("style",e.style).attr("rx",e.rx).attr("ry",e.ry).attr("x",e.x-e.width/2-h).attr("y",e.y-e.height/2-h).attr("width",e.width+l).attr("height",e.height+l),i.attr("transform","translate("+(e.x-o.width/2)+", "+(e.y-e.height/2+e.padding/3)+")");var f=r.node().getBBox();return e.width=f.width,e.height=f.height,e.intersect=function(t){return He(e,t)},n},roundedWithTitle:function(t,e){var n=t.insert("g").attr("class",e.classes).attr("id",e.id),r=n.insert("rect",":first-child"),i=n.insert("g").attr("class","cluster-label"),a=n.append("rect"),o=i.node().appendChild(Te(e.labelText,e.labelStyle,void 0,!0)),s=o.getBBox();if(_t().flowchart.htmlLabels){var c=o.children[0],u=Object(d.select)(o);s=c.getBoundingClientRect(),u.attr("width",s.width),u.attr("height",s.height)}s=o.getBBox();var l=0*e.padding,h=l/2;r.attr("class","outer").attr("x",e.x-e.width/2-h).attr("y",e.y-e.height/2-h).attr("width",e.width+l).attr("height",e.height+l),a.attr("class","inner").attr("x",e.x-e.width/2-h).attr("y",e.y-e.height/2-h+s.height-1).attr("width",e.width+l).attr("height",e.height+l-s.height-3),i.attr("transform","translate("+(e.x-s.width/2)+", "+(e.y-e.height/2-e.padding/3+(_t().flowchart.htmlLabels?5:3))+")");var f=r.node().getBBox();return e.width=f.width,e.height=f.height,e.intersect=function(t){return He(e,t)},n},noteGroup:function(t,e){var n=t.insert("g").attr("class","note-cluster").attr("id",e.id),r=n.insert("rect",":first-child"),i=0*e.padding,a=i/2;r.attr("rx",e.rx).attr("ry",e.ry).attr("x",e.x-e.width/2-a).attr("y",e.y-e.height/2-a).attr("width",e.width+i).attr("height",e.height+i).attr("fill","none");var o=r.node().getBBox();return e.width=o.width,e.height=o.height,e.intersect=function(t){return He(e,t)},n},divider:function(t,e){var n=t.insert("g").attr("class",e.classes).attr("id",e.id),r=n.insert("rect",":first-child"),i=0*e.padding,a=i/2;r.attr("class","divider").attr("x",e.x-e.width/2-a).attr("y",e.y-e.height/2).attr("width",e.width+i).attr("height",e.height+i);var o=r.node().getBBox();return e.width=o.width,e.height=o.height,e.intersect=function(t){return He(e,t)},n}},En={},Tn={},Cn={},An=function(t,e){var n=t.x,r=t.y,i=Math.abs(e.x-n),a=Math.abs(e.y-r),o=t.width/2,s=t.height/2;return i>=o||a>=s},Sn=function(t,e,n){c.warn("intersection calc o:",e," i:",n,t);var r=t.x,i=t.y,a=Math.abs(r-n.x),o=t.width/2,s=n.xMath.abs(r-e.x)*u){var y=n.y0&&c.info("Recursive edges",n.edge(n.edges()[0]));var s=o.insert("g").attr("class","clusters"),u=o.insert("g").attr("class","edgePaths"),l=o.insert("g").attr("class","edgeLabels"),h=o.insert("g").attr("class","nodes");return n.nodes().forEach((function(e){var o=n.node(e);if(void 0!==i){var s=JSON.parse(JSON.stringify(i.clusterData));c.info("Setting data for cluster XXX (",e,") ",s,i),n.setNode(i.id,s),n.parent(e)||(c.warn("Setting parent",e,i.id),n.setParent(e,i.id,s))}if(c.info("(Insert) Node XXX"+e+": "+JSON.stringify(n.node(e))),o&&o.clusterNode){c.info("Cluster identified",e,o,n.node(e));var u=t(h,o.graph,r,n.node(e));Ae(o,u),function(t,e){_n[e.id]=t}(u,o),c.warn("Recursive render complete",u,o)}else n.children(e).length>0?(c.info("Cluster - the non recursive path XXX",e,o.id,o,n),c.info(Le(o.id,n)),Me[o.id]={id:Le(o.id,n),node:o}):(c.info("Node - the non recursive path",e,o.id,o),function(t,e,n){var r,i;e.link?(r=t.insert("svg:a").attr("xlink:href",e.link).attr("target",e.linkTarget||"_blank"),i=xn[e.shape](r,e,n)):r=i=xn[e.shape](t,e,n),e.tooltip&&i.attr("title",e.tooltip),e.class&&i.attr("class","node default "+e.class),_n[e.id]=r,e.haveCallback&&_n[e.id].attr("class",_n[e.id].attr("class")+" clickable")}(h,n.node(e),a))})),n.edges().forEach((function(t){var e=n.edge(t.v,t.w,t.name);c.info("Edge "+t.v+" -> "+t.w+": "+JSON.stringify(t)),c.info("Edge "+t.v+" -> "+t.w+": ",t," ",JSON.stringify(n.edge(t))),c.info("Fix",Me,"ids:",t.v,t.w,"Translateing: ",Me[t.v],Me[t.w]),function(t,e){var n=Te(e.label,e.labelStyle),r=t.insert("g").attr("class","edgeLabel"),i=r.insert("g").attr("class","label");i.node().appendChild(n);var a=n.getBBox();if(_t().flowchart.htmlLabels){var o=n.children[0],s=Object(d.select)(n);a=o.getBoundingClientRect(),s.attr("width",a.width),s.attr("height",a.height)}if(i.attr("transform","translate("+-a.width/2+", "+-a.height/2+")"),Tn[e.id]=r,e.width=a.width,e.height=a.height,e.startLabelLeft){var c=Te(e.startLabelLeft,e.labelStyle),u=t.insert("g").attr("class","edgeTerminals"),l=u.insert("g").attr("class","inner");l.node().appendChild(c);var h=c.getBBox();l.attr("transform","translate("+-h.width/2+", "+-h.height/2+")"),Cn[e.id]||(Cn[e.id]={}),Cn[e.id].startLeft=u}if(e.startLabelRight){var f=Te(e.startLabelRight,e.labelStyle),p=t.insert("g").attr("class","edgeTerminals"),g=p.insert("g").attr("class","inner");p.node().appendChild(f),g.node().appendChild(f);var y=f.getBBox();g.attr("transform","translate("+-y.width/2+", "+-y.height/2+")"),Cn[e.id]||(Cn[e.id]={}),Cn[e.id].startRight=p}if(e.endLabelLeft){var v=Te(e.endLabelLeft,e.labelStyle),m=t.insert("g").attr("class","edgeTerminals"),b=m.insert("g").attr("class","inner");b.node().appendChild(v);var x=v.getBBox();b.attr("transform","translate("+-x.width/2+", "+-x.height/2+")"),m.node().appendChild(v),Cn[e.id]||(Cn[e.id]={}),Cn[e.id].endLeft=m}if(e.endLabelRight){var _=Te(e.endLabelRight,e.labelStyle),k=t.insert("g").attr("class","edgeTerminals"),w=k.insert("g").attr("class","inner");w.node().appendChild(_);var E=_.getBBox();w.attr("transform","translate("+-E.width/2+", "+-E.height/2+")"),k.node().appendChild(_),Cn[e.id]||(Cn[e.id]={}),Cn[e.id].endRight=k}}(l,e)})),n.edges().forEach((function(t){c.info("Edge "+t.v+" -> "+t.w+": "+JSON.stringify(t))})),c.info("#############################################"),c.info("### Layout ###"),c.info("#############################################"),c.info(n),ke.a.layout(n),c.info("Graph after layout:",G.a.json.write(n)),je(n).forEach((function(t){var e=n.node(t);c.info("Position "+t+": "+JSON.stringify(n.node(t))),c.info("Position "+t+": ("+e.x,","+e.y,") width: ",e.width," height: ",e.height),e&&e.clusterNode?kn(e):n.children(t).length>0?(!function(t,e){c.trace("Inserting cluster");var n=e.shape||"rect";En[e.id]=wn[n](t,e)}(s,e),Me[e.id].node=e):kn(e)})),n.edges().forEach((function(t){var e=n.edge(t);c.info("Edge "+t.v+" -> "+t.w+": "+JSON.stringify(e),e);var i=function(t,e,n,r,i,a){var o=n.points,s=!1,u=a.node(e.v),l=a.node(e.w);if(l.intersect&&u.intersect&&((o=o.slice(1,n.points.length-1)).unshift(u.intersect(o[0])),c.info("Last point",o[o.length-1],l,l.intersect(o[o.length-1])),o.push(l.intersect(o[o.length-1]))),n.toCluster){var h;c.trace("edge",n),c.trace("to cluster",r[n.toCluster]),o=[];var f=!1;n.points.forEach((function(t){var e=r[n.toCluster].node;if(An(e,t)||f)f||o.push(t);else{c.trace("inside",n.toCluster,t,h);var i=Sn(e,h,t),a=!1;o.forEach((function(t){a=a||t.x===i.x&&t.y===i.y})),o.find((function(t){return t.x===i.x&&t.y===i.y}))?c.warn("no intersect",i,o):o.push(i),f=!0}h=t})),s=!0}if(n.fromCluster){c.trace("edge",n),c.warn("from cluster",r[n.fromCluster]);for(var p,g=[],y=!1,v=o.length-1;v>=0;v--){var m=o[v],b=r[n.fromCluster].node;if(An(b,m)||y)c.trace("Outside point",m),y||g.unshift(m);else{c.warn("inside",n.fromCluster,m,b);var x=Sn(b,p,m);g.unshift(x),y=!0}p=m}o=g,s=!0}var _,k=o.filter((function(t){return!Number.isNaN(t.y)})),w=Object(d.line)().x((function(t){return t.x})).y((function(t){return t.y})).curve(d.curveBasis);switch(n.thickness){case"normal":_="edge-thickness-normal";break;case"thick":_="edge-thickness-thick";break;default:_=""}switch(n.pattern){case"solid":_+=" edge-pattern-solid";break;case"dotted":_+=" edge-pattern-dotted";break;case"dashed":_+=" edge-pattern-dashed"}var E=t.append("path").attr("d",w(k)).attr("id",n.id).attr("class"," "+_+(n.classes?" "+n.classes:"")).attr("style",n.style),T="";switch(_t().state.arrowMarkerAbsolute&&(T=(T=(T=window.location.protocol+"//"+window.location.host+window.location.pathname+window.location.search).replace(/\(/g,"\\(")).replace(/\)/g,"\\)")),c.info("arrowTypeStart",n.arrowTypeStart),c.info("arrowTypeEnd",n.arrowTypeEnd),n.arrowTypeStart){case"arrow_cross":E.attr("marker-start","url("+T+"#"+i+"-crossStart)");break;case"arrow_point":E.attr("marker-start","url("+T+"#"+i+"-pointStart)");break;case"arrow_barb":E.attr("marker-start","url("+T+"#"+i+"-barbStart)");break;case"arrow_circle":E.attr("marker-start","url("+T+"#"+i+"-circleStart)");break;case"aggregation":E.attr("marker-start","url("+T+"#"+i+"-aggregationStart)");break;case"extension":E.attr("marker-start","url("+T+"#"+i+"-extensionStart)");break;case"composition":E.attr("marker-start","url("+T+"#"+i+"-compositionStart)");break;case"dependency":E.attr("marker-start","url("+T+"#"+i+"-dependencyStart)")}switch(n.arrowTypeEnd){case"arrow_cross":E.attr("marker-end","url("+T+"#"+i+"-crossEnd)");break;case"arrow_point":E.attr("marker-end","url("+T+"#"+i+"-pointEnd)");break;case"arrow_barb":E.attr("marker-end","url("+T+"#"+i+"-barbEnd)");break;case"arrow_circle":E.attr("marker-end","url("+T+"#"+i+"-circleEnd)");break;case"aggregation":E.attr("marker-end","url("+T+"#"+i+"-aggregationEnd)");break;case"extension":E.attr("marker-end","url("+T+"#"+i+"-extensionEnd)");break;case"composition":E.attr("marker-end","url("+T+"#"+i+"-compositionEnd)");break;case"dependency":E.attr("marker-end","url("+T+"#"+i+"-dependencyEnd)")}var C={};return s&&(C.updatedPath=o),C.originalPath=n.points,C}(u,t,e,Me,r,n);!function(t,e){c.info("Moving label",t.id,t.label,Tn[t.id]);var n=e.updatedPath?e.updatedPath:e.originalPath;if(t.label){var r=Tn[t.id],i=t.x,a=t.y;if(n){var o=H.calcLabelPosition(n);c.info("Moving label from (",i,",",a,") to (",o.x,",",o.y,")")}r.attr("transform","translate("+i+", "+a+")")}if(t.startLabelLeft){var s=Cn[t.id].startLeft,u=t.x,l=t.y;if(n){var h=H.calcTerminalLabelPosition(0,"start_left",n);u=h.x,l=h.y}s.attr("transform","translate("+u+", "+l+")")}if(t.startLabelRight){var f=Cn[t.id].startRight,d=t.x,p=t.y;if(n){var g=H.calcTerminalLabelPosition(0,"start_right",n);d=g.x,p=g.y}f.attr("transform","translate("+d+", "+p+")")}if(t.endLabelLeft){var y=Cn[t.id].endLeft,v=t.x,m=t.y;if(n){var b=H.calcTerminalLabelPosition(0,"end_left",n);v=b.x,m=b.y}y.attr("transform","translate("+v+", "+m+")")}if(t.endLabelRight){var x=Cn[t.id].endRight,_=t.x,k=t.y;if(n){var w=H.calcTerminalLabelPosition(0,"end_right",n);_=w.x,k=w.y}x.attr("transform","translate("+_+", "+k+")")}}(e,i)})),o},On=function(t,e,n,r,i){Ee(t,n,r,i),_n={},Tn={},Cn={},En={},Oe={},De={},Me={},c.warn("Graph at first:",G.a.json.write(e)),Pe(e),c.warn("Graph after:",G.a.json.write(e)),Mn(t,e,r)},Dn={},Nn=function(t,e,n){var r=Object(d.select)('[id="'.concat(n,'"]'));Object.keys(t).forEach((function(n){var i=t[n],a="default";i.classes.length>0&&(a=i.classes.join(" "));var o,s=B(i.styles),u=void 0!==i.text?i.text:i.id;if(_t().flowchart.htmlLabels){var l={label:u.replace(/fa[lrsb]?:fa-[\w-]+/g,(function(t){return"")}))};(o=ee()(r,l).node()).parentNode.removeChild(o)}else{var h=document.createElementNS("http://www.w3.org/2000/svg","text");h.setAttribute("style",s.labelStyle.replace("color:","fill:"));for(var f=u.split(x.lineBreakRegex),d=0;d=0;h--)i=l[h],c.info("Subgraph - ",i),Xt.addVertex(i.id,i.title,"group",void 0,i.classes);var f=Xt.getVertices(),p=Xt.getEdges();c.info(p);var g=0;for(g=l.length-1;g>=0;g--){i=l[g],Object(d.selectAll)("cluster").append("text");for(var y=0;y0)switch(e.valign){case"top":case"start":s=function(){return Math.round(e.y+e.textMargin)};break;case"middle":case"center":s=function(){return Math.round(e.y+(n+r+e.textMargin)/2)};break;case"bottom":case"end":s=function(){return Math.round(e.y+(n+r+2*e.textMargin)-e.textMargin)}}if(void 0!==e.anchor&&void 0!==e.textMargin&&void 0!==e.width)switch(e.anchor){case"left":case"start":e.x=Math.round(e.x+e.textMargin),e.anchor="start",e.dominantBaseline="text-after-edge",e.alignmentBaseline="middle";break;case"middle":case"center":e.x=Math.round(e.x+e.width/2),e.anchor="middle",e.dominantBaseline="middle",e.alignmentBaseline="middle";break;case"right":case"end":e.x=Math.round(e.x+e.width-e.textMargin),e.anchor="end",e.dominantBaseline="text-before-edge",e.alignmentBaseline="middle"}for(var c=0;c0&&(r+=(l._groups||l)[0][0].getBBox().height,n=r),a.push(l)}return a},jn=function(t,e){var n,r,i,a,o,s=t.append("polygon");return s.attr("points",(n=e.x,r=e.y,i=e.width,a=e.height,n+","+r+" "+(n+i)+","+r+" "+(n+i)+","+(r+a-(o=7))+" "+(n+i-1.2*o)+","+(r+a)+" "+n+","+(r+a))),s.attr("class","labelBox"),e.y=e.y+e.height/2,In(t,e),s},Rn=-1,Yn=function(){return{x:0,y:0,fill:void 0,anchor:void 0,style:"#666",width:void 0,height:void 0,textMargin:0,rx:0,ry:0,tspan:!0,valign:void 0}},zn=function(){return{x:0,y:0,fill:"#EDF2AE",stroke:"#666",width:100,anchor:"start",height:100,rx:0,ry:0}},Un=function(){function t(t,e,n,i,a,o,s){r(e.append("text").attr("x",n+a/2).attr("y",i+o/2+5).style("text-anchor","middle").text(t),s)}function e(t,e,n,i,a,o,s,c){for(var u=c.actorFontSize,l=c.actorFontFamily,h=c.actorFontWeight,f=t.split(x.lineBreakRegex),d=0;d2&&void 0!==arguments[2]?arguments[2]:{text:void 0,wrap:void 0},r=arguments.length>3?arguments[3]:void 0;if(r===ir.ACTIVE_END){var i=er(t.actor);if(i<1){var a=new Error("Trying to inactivate an inactive participant ("+t.actor+")");throw a.hash={text:"->>-",token:"->>-",line:"1",loc:{first_line:1,last_line:1,first_column:1,last_column:1},expected:["'ACTIVE_PARTICIPANT'"]},a}}return qn.push({from:t,to:e,message:n.text,wrap:void 0===n.wrap&&rr()||!!n.wrap,type:r}),!0},rr=function(){return Qn},ir={SOLID:0,DOTTED:1,NOTE:2,SOLID_CROSS:3,DOTTED_CROSS:4,SOLID_OPEN:5,DOTTED_OPEN:6,LOOP_START:10,LOOP_END:11,ALT_START:12,ALT_ELSE:13,ALT_END:14,OPT_START:15,OPT_END:16,ACTIVE_START:17,ACTIVE_END:18,PAR_START:19,PAR_AND:20,PAR_END:21,RECT_START:22,RECT_END:23},ar=function(t,e,n){var r={actor:t,placement:e,message:n.text,wrap:void 0===n.wrap&&rr()||!!n.wrap},i=[].concat(t,t);Xn.push(r),qn.push({from:i[0],to:i[1],message:n.text,wrap:void 0===n.wrap&&rr()||!!n.wrap,type:ir.NOTE,placement:e})},or=function(t){Zn=t.text,Jn=void 0===t.wrap&&rr()||!!t.wrap},sr={addActor:tr,addMessage:function(t,e,n,r){qn.push({from:t,to:e,message:n.text,wrap:void 0===n.wrap&&rr()||!!n.wrap,answer:r})},addSignal:nr,autoWrap:rr,setWrap:function(t){Qn=t},enableSequenceNumbers:function(){Kn=!0},showSequenceNumbers:function(){return Kn},getMessages:function(){return qn},getActors:function(){return Gn},getActor:function(t){return Gn[t]},getActorKeys:function(){return Object.keys(Gn)},getTitle:function(){return Zn},parseDirective:function(t,e,n){Go.parseDirective(this,t,e,n)},getConfig:function(){return _t().sequence},getTitleWrapped:function(){return Jn},clear:function(){Gn={},qn=[]},parseMessage:function(t){var e=t.trim(),n={text:e.replace(/^[:]?(?:no)?wrap:/,"").trim(),wrap:null!==e.match(/^[:]?wrap:/)||null===e.match(/^[:]?nowrap:/)&&void 0};return c.debug("parseMessage:",n),n},LINETYPE:ir,ARROWTYPE:{FILLED:0,OPEN:1},PLACEMENT:{LEFTOF:0,RIGHTOF:1,OVER:2},addNote:ar,setTitle:or,apply:function t(e){if(e instanceof Array)e.forEach((function(e){t(e)}));else switch(e.type){case"addActor":tr(e.actor,e.actor,e.description);break;case"activeStart":case"activeEnd":nr(e.actor,void 0,void 0,e.signalType);break;case"addNote":ar(e.actor,e.placement,e.text);break;case"addMessage":nr(e.from,e.to,e.msg,e.signalType);break;case"loopStart":nr(void 0,void 0,e.loopText,e.signalType);break;case"loopEnd":nr(void 0,void 0,void 0,e.signalType);break;case"rectStart":nr(void 0,void 0,e.color,e.signalType);break;case"rectEnd":nr(void 0,void 0,void 0,e.signalType);break;case"optStart":nr(void 0,void 0,e.optText,e.signalType);break;case"optEnd":nr(void 0,void 0,void 0,e.signalType);break;case"altStart":case"else":nr(void 0,void 0,e.altText,e.signalType);break;case"altEnd":nr(void 0,void 0,void 0,e.signalType);break;case"setTitle":or(e.text);break;case"parStart":case"and":nr(void 0,void 0,e.parText,e.signalType);break;case"parEnd":nr(void 0,void 0,void 0,e.signalType)}}};Wn.parser.yy=sr;var cr={},ur={data:{startx:void 0,stopx:void 0,starty:void 0,stopy:void 0},verticalPos:0,sequenceItems:[],activations:[],models:{getHeight:function(){return Math.max.apply(null,0===this.actors.length?[0]:this.actors.map((function(t){return t.height||0})))+(0===this.loops.length?0:this.loops.map((function(t){return t.height||0})).reduce((function(t,e){return t+e})))+(0===this.messages.length?0:this.messages.map((function(t){return t.height||0})).reduce((function(t,e){return t+e})))+(0===this.notes.length?0:this.notes.map((function(t){return t.height||0})).reduce((function(t,e){return t+e})))},clear:function(){this.actors=[],this.loops=[],this.messages=[],this.notes=[]},addActor:function(t){this.actors.push(t)},addLoop:function(t){this.loops.push(t)},addMessage:function(t){this.messages.push(t)},addNote:function(t){this.notes.push(t)},lastActor:function(){return this.actors[this.actors.length-1]},lastLoop:function(){return this.loops[this.loops.length-1]},lastMessage:function(){return this.messages[this.messages.length-1]},lastNote:function(){return this.notes[this.notes.length-1]},actors:[],loops:[],messages:[],notes:[]},init:function(){this.sequenceItems=[],this.activations=[],this.models.clear(),this.data={startx:void 0,stopx:void 0,starty:void 0,stopy:void 0},this.verticalPos=0,pr(Wn.parser.yy.getConfig())},updateVal:function(t,e,n,r){void 0===t[e]?t[e]=n:t[e]=r(n,t[e])},updateBounds:function(t,e,n,r){var i=this,a=0;function o(o){return function(s){a++;var c=i.sequenceItems.length-a+1;i.updateVal(s,"starty",e-c*cr.boxMargin,Math.min),i.updateVal(s,"stopy",r+c*cr.boxMargin,Math.max),i.updateVal(ur.data,"startx",t-c*cr.boxMargin,Math.min),i.updateVal(ur.data,"stopx",n+c*cr.boxMargin,Math.max),"activation"!==o&&(i.updateVal(s,"startx",t-c*cr.boxMargin,Math.min),i.updateVal(s,"stopx",n+c*cr.boxMargin,Math.max),i.updateVal(ur.data,"starty",e-c*cr.boxMargin,Math.min),i.updateVal(ur.data,"stopy",r+c*cr.boxMargin,Math.max))}}this.sequenceItems.forEach(o()),this.activations.forEach(o("activation"))},insert:function(t,e,n,r){var i=Math.min(t,n),a=Math.max(t,n),o=Math.min(e,r),s=Math.max(e,r);this.updateVal(ur.data,"startx",i,Math.min),this.updateVal(ur.data,"starty",o,Math.min),this.updateVal(ur.data,"stopx",a,Math.max),this.updateVal(ur.data,"stopy",s,Math.max),this.updateBounds(i,o,a,s)},newActivation:function(t,e,n){var r=n[t.from.actor],i=gr(t.from.actor).length||0,a=r.x+r.width/2+(i-1)*cr.activationWidth/2;this.activations.push({startx:a,starty:this.verticalPos+2,stopx:a+cr.activationWidth,stopy:void 0,actor:t.from.actor,anchored:$n.anchorElement(e)})},endActivation:function(t){var e=this.activations.map((function(t){return t.actor})).lastIndexOf(t.from.actor);return this.activations.splice(e,1)[0]},createLoop:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{message:void 0,wrap:!1,width:void 0},e=arguments.length>1?arguments[1]:void 0;return{startx:void 0,starty:this.verticalPos,stopx:void 0,stopy:void 0,title:t.message,wrap:t.wrap,width:t.width,height:0,fill:e}},newLoop:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{message:void 0,wrap:!1,width:void 0},e=arguments.length>1?arguments[1]:void 0;this.sequenceItems.push(this.createLoop(t,e))},endLoop:function(){return this.sequenceItems.pop()},addSectionToLoop:function(t){var e=this.sequenceItems.pop();e.sections=e.sections||[],e.sectionTitles=e.sectionTitles||[],e.sections.push({y:ur.getVerticalPos(),height:0}),e.sectionTitles.push(t),this.sequenceItems.push(e)},bumpVerticalPos:function(t){this.verticalPos=this.verticalPos+t,this.data.stopy=this.verticalPos},getVerticalPos:function(){return this.verticalPos},getBounds:function(){return{bounds:this.data,models:this.models}}},lr=function(t){return{fontFamily:t.messageFontFamily,fontSize:t.messageFontSize,fontWeight:t.messageFontWeight}},hr=function(t){return{fontFamily:t.noteFontFamily,fontSize:t.noteFontSize,fontWeight:t.noteFontWeight}},fr=function(t){return{fontFamily:t.actorFontFamily,fontSize:t.actorFontSize,fontWeight:t.actorFontWeight}},dr=function(t,e,n,r){for(var i=0,a=0,o=0;o0&&o.forEach((function(r){if(n=r,i.startx===i.stopx){var a=e[t.from],o=e[t.to];n.from=Math.min(a.x-i.width/2,a.x-a.width/2,n.from),n.to=Math.max(o.x+i.width/2,o.x+a.width/2,n.to),n.width=Math.max(n.width,Math.abs(n.to-n.from))-cr.labelBoxWidth}else n.from=Math.min(i.startx,n.from),n.to=Math.max(i.stopx,n.to),n.width=Math.max(n.width,i.width)-cr.labelBoxWidth})))})),ur.activations=[],c.debug("Loop type widths:",a),a},_r={bounds:ur,drawActors:dr,setConf:pr,draw:function(t,e){cr=_t().sequence,Wn.parser.yy.clear(),Wn.parser.yy.setWrap(cr.wrap),Wn.parser.parse(t+"\n"),ur.init(),c.debug("C:".concat(JSON.stringify(cr,null,2)));var n=Object(d.select)('[id="'.concat(e,'"]')),r=Wn.parser.yy.getActors(),i=Wn.parser.yy.getActorKeys(),a=Wn.parser.yy.getMessages(),o=Wn.parser.yy.getTitle(),s=mr(r,a);cr.height=br(r,s),dr(n,r,i,0);var u=xr(a,r,s);$n.insertArrowHead(n),$n.insertArrowCrossHead(n),$n.insertSequenceNumber(n);var l=1;a.forEach((function(t){var e,i,a;switch(t.type){case Wn.parser.yy.LINETYPE.NOTE:i=t.noteModel,function(t,e){ur.bumpVerticalPos(cr.boxMargin),e.height=cr.boxMargin,e.starty=ur.getVerticalPos();var n=$n.getNoteRect();n.x=e.startx,n.y=e.starty,n.width=e.width||cr.width,n.class="note";var r=t.append("g"),i=$n.drawRect(r,n),a=$n.getTextObj();a.x=e.startx,a.y=e.starty,a.width=n.width,a.dy="1em",a.text=e.message,a.class="noteText",a.fontFamily=cr.noteFontFamily,a.fontSize=cr.noteFontSize,a.fontWeight=cr.noteFontWeight,a.anchor=cr.noteAlign,a.textMargin=cr.noteMargin,a.valign=cr.noteAlign;var o=In(r,a),s=Math.round(o.map((function(t){return(t._groups||t)[0][0].getBBox().height})).reduce((function(t,e){return t+e})));i.attr("height",s+2*cr.noteMargin),e.height+=s+2*cr.noteMargin,ur.bumpVerticalPos(s+2*cr.noteMargin),e.stopy=e.starty+s+2*cr.noteMargin,e.stopx=e.startx+n.width,ur.insert(e.startx,e.starty,e.stopx,e.stopy),ur.models.addNote(e)}(n,i);break;case Wn.parser.yy.LINETYPE.ACTIVE_START:ur.newActivation(t,n,r);break;case Wn.parser.yy.LINETYPE.ACTIVE_END:!function(t,e){var r=ur.endActivation(t);r.starty+18>e&&(r.starty=e-6,e+=12),$n.drawActivation(n,r,e,cr,gr(t.from.actor).length),ur.insert(r.startx,e-10,r.stopx,e)}(t,ur.getVerticalPos());break;case Wn.parser.yy.LINETYPE.LOOP_START:vr(u,t,cr.boxMargin,cr.boxMargin+cr.boxTextMargin,(function(t){return ur.newLoop(t)}));break;case Wn.parser.yy.LINETYPE.LOOP_END:e=ur.endLoop(),$n.drawLoop(n,e,"loop",cr),ur.bumpVerticalPos(e.stopy-ur.getVerticalPos()),ur.models.addLoop(e);break;case Wn.parser.yy.LINETYPE.RECT_START:vr(u,t,cr.boxMargin,cr.boxMargin,(function(t){return ur.newLoop(void 0,t.message)}));break;case Wn.parser.yy.LINETYPE.RECT_END:e=ur.endLoop(),$n.drawBackgroundRect(n,e),ur.models.addLoop(e),ur.bumpVerticalPos(e.stopy-ur.getVerticalPos());break;case Wn.parser.yy.LINETYPE.OPT_START:vr(u,t,cr.boxMargin,cr.boxMargin+cr.boxTextMargin,(function(t){return ur.newLoop(t)}));break;case Wn.parser.yy.LINETYPE.OPT_END:e=ur.endLoop(),$n.drawLoop(n,e,"opt",cr),ur.bumpVerticalPos(e.stopy-ur.getVerticalPos()),ur.models.addLoop(e);break;case Wn.parser.yy.LINETYPE.ALT_START:vr(u,t,cr.boxMargin,cr.boxMargin+cr.boxTextMargin,(function(t){return ur.newLoop(t)}));break;case Wn.parser.yy.LINETYPE.ALT_ELSE:vr(u,t,cr.boxMargin+cr.boxTextMargin,cr.boxMargin,(function(t){return ur.addSectionToLoop(t)}));break;case Wn.parser.yy.LINETYPE.ALT_END:e=ur.endLoop(),$n.drawLoop(n,e,"alt",cr),ur.bumpVerticalPos(e.stopy-ur.getVerticalPos()),ur.models.addLoop(e);break;case Wn.parser.yy.LINETYPE.PAR_START:vr(u,t,cr.boxMargin,cr.boxMargin+cr.boxTextMargin,(function(t){return ur.newLoop(t)}));break;case Wn.parser.yy.LINETYPE.PAR_AND:vr(u,t,cr.boxMargin+cr.boxTextMargin,cr.boxMargin,(function(t){return ur.addSectionToLoop(t)}));break;case Wn.parser.yy.LINETYPE.PAR_END:e=ur.endLoop(),$n.drawLoop(n,e,"par",cr),ur.bumpVerticalPos(e.stopy-ur.getVerticalPos()),ur.models.addLoop(e);break;default:try{(a=t.msgModel).starty=ur.getVerticalPos(),a.sequenceIndex=l,function(t,e){ur.bumpVerticalPos(10);var n=e.startx,r=e.stopx,i=e.starty,a=e.message,o=e.type,s=e.sequenceIndex,c=x.splitBreaks(a).length,u=H.calculateTextDimensions(a,lr(cr)),l=u.height/c;e.height+=l,ur.bumpVerticalPos(l);var h=$n.getTextObj();h.x=n,h.y=i+10,h.width=r-n,h.class="messageText",h.dy="1em",h.text=a,h.fontFamily=cr.messageFontFamily,h.fontSize=cr.messageFontSize,h.fontWeight=cr.messageFontWeight,h.anchor=cr.messageAlign,h.valign=cr.messageAlign,h.textMargin=cr.wrapPadding,h.tspan=!1,In(t,h);var f,d,p=u.height-10,g=u.width;if(n===r){d=ur.getVerticalPos()+p,cr.rightAngles?f=t.append("path").attr("d","M ".concat(n,",").concat(d," H ").concat(n+Math.max(cr.width/2,g/2)," V ").concat(d+25," H ").concat(n)):(p+=cr.boxMargin,d=ur.getVerticalPos()+p,f=t.append("path").attr("d","M "+n+","+d+" C "+(n+60)+","+(d-10)+" "+(n+60)+","+(d+30)+" "+n+","+(d+20))),p+=30;var y=Math.max(g/2,cr.width/2);ur.insert(n-y,ur.getVerticalPos()-10+p,r+y,ur.getVerticalPos()+30+p)}else p+=cr.boxMargin,d=ur.getVerticalPos()+p,(f=t.append("line")).attr("x1",n),f.attr("y1",d),f.attr("x2",r),f.attr("y2",d),ur.insert(n,d-10,r,d);o===Wn.parser.yy.LINETYPE.DOTTED||o===Wn.parser.yy.LINETYPE.DOTTED_CROSS||o===Wn.parser.yy.LINETYPE.DOTTED_OPEN?(f.style("stroke-dasharray","3, 3"),f.attr("class","messageLine1")):f.attr("class","messageLine0");var v="";cr.arrowMarkerAbsolute&&(v=(v=(v=window.location.protocol+"//"+window.location.host+window.location.pathname+window.location.search).replace(/\(/g,"\\(")).replace(/\)/g,"\\)")),f.attr("stroke-width",2),f.attr("stroke","none"),f.style("fill","none"),o!==Wn.parser.yy.LINETYPE.SOLID&&o!==Wn.parser.yy.LINETYPE.DOTTED||f.attr("marker-end","url("+v+"#arrowhead)"),o!==Wn.parser.yy.LINETYPE.SOLID_CROSS&&o!==Wn.parser.yy.LINETYPE.DOTTED_CROSS||f.attr("marker-end","url("+v+"#crosshead)"),(sr.showSequenceNumbers()||cr.showSequenceNumbers)&&(f.attr("marker-start","url("+v+"#sequencenumber)"),t.append("text").attr("x",n).attr("y",d+4).attr("font-family","sans-serif").attr("font-size","12px").attr("text-anchor","middle").attr("textLength","16px").attr("class","sequenceNumber").text(s)),ur.bumpVerticalPos(p),e.height+=p,e.stopy=e.starty+e.height,ur.insert(e.fromBounds,e.starty,e.toBounds,e.stopy)}(n,a),ur.models.addMessage(a)}catch(t){c.error("error while drawing message",t)}}[Wn.parser.yy.LINETYPE.SOLID_OPEN,Wn.parser.yy.LINETYPE.DOTTED_OPEN,Wn.parser.yy.LINETYPE.SOLID,Wn.parser.yy.LINETYPE.DOTTED,Wn.parser.yy.LINETYPE.SOLID_CROSS,Wn.parser.yy.LINETYPE.DOTTED_CROSS].includes(t.type)&&l++})),cr.mirrorActors&&(ur.bumpVerticalPos(2*cr.boxMargin),dr(n,r,i,ur.getVerticalPos()));var h=ur.getBounds().bounds;c.debug("For line height fix Querying: #"+e+" .actor-line"),Object(d.selectAll)("#"+e+" .actor-line").attr("y2",h.stopy);var f=h.stopy-h.starty+2*cr.diagramMarginY;cr.mirrorActors&&(f=f-cr.boxMargin+cr.bottomMarginAdj);var p=h.stopx-h.startx+2*cr.diagramMarginX;o&&n.append("text").text(o).attr("x",(h.stopx-h.startx)/2-2*cr.diagramMarginX).attr("y",-25),W(n,f,p,cr.useMaxWidth);var g=o?40:0;n.attr("viewBox",h.startx-cr.diagramMarginX+" -"+(cr.diagramMarginY+g)+" "+p+" "+(f+g)),c.debug("models:",ur.models)}},kr=n(27),wr=n.n(kr);function Er(t){return function(t){if(Array.isArray(t)){for(var e=0,n=new Array(t.length);e=6&&n.indexOf("weekends")>=0||(n.indexOf(t.format("dddd").toLowerCase())>=0||n.indexOf(t.format(e.trim()))>=0)},Yr=function(t,e,n){if(n.length&&!t.manualEndTime){var r=o()(t.startTime,e,!0);r.add(1,"d");var i=o()(t.endTime,e,!0),a=zr(r,i,e,n);t.endTime=i.toDate(),t.renderEndTime=a}},zr=function(t,e,n,r){for(var i=!1,a=null;t<=e;)i||(a=e.toDate()),(i=Rr(t,n,r))&&e.add(1,"d"),t.add(1,"d");return a},Ur=function(t,e,n){n=n.trim();var r=/^after\s+([\d\w- ]+)/.exec(n.trim());if(null!==r){var i=null;if(r[1].split(" ").forEach((function(t){var e=Xr(t);void 0!==e&&(i?e.endTime>i.endTime&&(i=e):i=e)})),i)return i.endTime;var a=new Date;return a.setHours(0,0,0,0),a}var s=o()(n,e.trim(),!0);return s.isValid()?s.toDate():(c.debug("Invalid date:"+n),c.debug("With date format:"+e.trim()),new Date)},$r=function(t,e){if(null!==t)switch(t[2]){case"s":e.add(t[1],"seconds");break;case"m":e.add(t[1],"minutes");break;case"h":e.add(t[1],"hours");break;case"d":e.add(t[1],"days");break;case"w":e.add(t[1],"weeks")}return e.toDate()},Wr=function(t,e,n,r){r=r||!1,n=n.trim();var i=o()(n,e.trim(),!0);return i.isValid()?(r&&i.add(1,"d"),i.toDate()):$r(/^([\d]+)([wdhms])/.exec(n.trim()),o()(t))},Hr=0,Vr=function(t){return void 0===t?"task"+(Hr+=1):t},Gr=[],qr={},Xr=function(t){var e=qr[t];return Gr[e]},Zr=function(){for(var t=function(t){var e=Gr[t],n="";switch(Gr[t].raw.startTime.type){case"prevTaskEnd":var r=Xr(e.prevTaskId);e.startTime=r.endTime;break;case"getStartDate":(n=Ur(0,Ar,Gr[t].raw.startTime.startData))&&(Gr[t].startTime=n)}return Gr[t].startTime&&(Gr[t].endTime=Wr(Gr[t].startTime,Ar,Gr[t].raw.endTime.data,Ir),Gr[t].endTime&&(Gr[t].processed=!0,Gr[t].manualEndTime=o()(Gr[t].raw.endTime.data,"YYYY-MM-DD",!0).isValid(),Yr(Gr[t],Ar,Or))),Gr[t].processed},e=!0,n=0;nr?i=1:n0&&(e=t.classes.join(" "));for(var n=0,r=0;rn-e?n+a+1.5*ni.leftPadding>u?e+r-5:n+r+5:(n-e)/2+e+r})).attr("y",(function(t,r){return t.order*e+ni.barHeight/2+(ni.fontSize/2-2)+n})).attr("text-height",i).attr("class",(function(t){var e=o(t.startTime),n=o(t.endTime);t.milestone&&(n=e+i);var r=this.getBBox().width,a="";t.classes.length>0&&(a=t.classes.join(" "));for(var c=0,l=0;ln-e?n+r+1.5*ni.leftPadding>u?a+" taskTextOutsideLeft taskTextOutside"+c+" "+h:a+" taskTextOutsideRight taskTextOutside"+c+" "+h+" width-"+r:a+" taskText taskText"+c+" "+h+" width-"+r}))}(t,i,c,h,r,0,e),function(t,e){for(var n=[],r=0,i=0;i0&&a.setAttribute("dy","1em"),a.textContent=e[i],r.appendChild(a)}return r})).attr("x",10).attr("y",(function(i,a){if(!(a>0))return i[1]*t/2+e;for(var o=0;o "+t.w+": "+JSON.stringify(i.edge(t))),mn(r,i.edge(t),i.edge(t).relation,ci))}));var h=r.node().getBBox(),f=h.width+40,p=h.height+40;W(r,p,f,ci.useMaxWidth);var g="".concat(h.x-20," ").concat(h.y-20," ").concat(f," ").concat(p);c.debug("viewBox ".concat(g)),r.attr("viewBox",g)};ai.parser.yy=cn;var fi={dividerMargin:10,padding:5,textHeight:10},di=function(t){Object.keys(t).forEach((function(e){fi[e]=t[e]}))},pi=function(t,e){c.info("Drawing class"),cn.clear(),ai.parser.parse(t);var n=_t().flowchart;c.info("config:",n);var r=n.nodeSpacing||50,i=n.rankSpacing||50,a=new G.a.Graph({multigraph:!0,compound:!0}).setGraph({rankdir:"TD",nodesep:r,ranksep:i,marginx:8,marginy:8}).setDefaultEdgeLabel((function(){return{}})),o=cn.getClasses(),s=cn.getRelations();c.info(s),function(t,e){var n=Object.keys(t);c.info("keys:",n),c.info(t),n.forEach((function(n){var r=t[n],i="";r.cssClasses.length>0&&(i=i+" "+r.cssClasses.join(" "));var a={labelStyle:""},o=void 0!==r.text?r.text:r.id,s="";switch(r.type){case"class":s="class_box";break;default:s="class_box"}e.setNode(r.id,{labelStyle:a.labelStyle,shape:s,labelText:o,classData:r,rx:0,ry:0,class:i,style:a.style,id:r.id,domId:r.domId,haveCallback:r.haveCallback,link:r.link,width:"group"===r.type?500:void 0,type:r.type,padding:_t().flowchart.padding}),c.info("setNode",{labelStyle:a.labelStyle,shape:s,labelText:o,rx:0,ry:0,class:i,style:a.style,id:r.id,width:"group"===r.type?500:void 0,type:r.type,padding:_t().flowchart.padding})}))}(o,a),function(t,e){var n=0;t.forEach((function(r){n++;var i={classes:"relation"};i.pattern=1==r.relation.lineType?"dashed":"solid",i.id="id"+n,"arrow_open"===r.type?i.arrowhead="none":i.arrowhead="normal",c.info(i,r),i.startLabelRight="none"===r.relationTitle1?"":r.relationTitle1,i.endLabelLeft="none"===r.relationTitle2?"":r.relationTitle2,i.arrowTypeStart=gi(r.relation.type1),i.arrowTypeEnd=gi(r.relation.type2);var a="",o="";if(void 0!==r.style){var s=B(r.style);a=s.style,o=s.labelStyle}else a="fill:none";i.style=a,i.labelStyle=o,void 0!==r.interpolate?i.curve=D(r.interpolate,d.curveLinear):void 0!==t.defaultInterpolate?i.curve=D(t.defaultInterpolate,d.curveLinear):i.curve=D(fi.curve,d.curveLinear),r.text=r.title,void 0===r.text?void 0!==r.style&&(i.arrowheadStyle="fill: #333"):(i.arrowheadStyle="fill: #333",i.labelpos="c",_t().flowchart.htmlLabels,i.labelType="text",i.label=r.text.replace(x.lineBreakRegex,"\n"),void 0===r.style&&(i.style=i.style||"stroke: #333; stroke-width: 1.5px;fill:none"),i.labelStyle=i.labelStyle.replace("color:","fill:")),e.setEdge(r.id1,r.id2,i,n)}))}(s,a);var u=Object(d.select)('[id="'.concat(e,'"]'));u.attr("xmlns:xlink","http://www.w3.org/1999/xlink");var l=Object(d.select)("#"+e+" g");On(l,a,["aggregation","extension","composition","dependency"],"classDiagram",e);var h=u.node().getBBox(),f=h.width+16,p=h.height+16;if(c.debug("new ViewBox 0 0 ".concat(f," ").concat(p),"translate(".concat(8-a._label.marginx,", ").concat(8-a._label.marginy,")")),W(u,p,f,n.useMaxWidth),u.attr("viewBox","0 0 ".concat(f," ").concat(p)),u.select("g").attr("transform","translate(".concat(8-a._label.marginx,", ").concat(8-h.y,")")),!n.htmlLabels)for(var g=document.querySelectorAll('[id="'+e+'"] .edgeLabel .label'),y=0;y0&&o.length>0){var c={stmt:"state",id:F(),type:"divider",doc:mi(o)};i.push(mi(c)),n.doc=i}n.doc.forEach((function(e){return t(n,e,!0)}))}}({id:"root"},{id:"root",doc:bi},!0),{id:"root",doc:bi}},extract:function(t){var e;e=t.doc?t.doc:t,c.info(e),Ei(),c.info("Extract",e),e.forEach((function(t){"state"===t.stmt&&wi(t.id,t.type,t.doc,t.description,t.note),"relation"===t.stmt&&Ti(t.state1.id,t.state2.id,t.description)}))},trimColon:function(t){return t&&":"===t[0]?t.substr(1).trim():t.trim()}},Oi=n(22),Di=n.n(Oi),Ni={},Bi=function(t,e){Ni[t]=e},Li=function(t,e){var n=t.append("text").attr("x",2*_t().state.padding).attr("y",_t().state.textHeight+1.3*_t().state.padding).attr("font-size",_t().state.fontSize).attr("class","state-title").text(e.descriptions[0]).node().getBBox(),r=n.height,i=t.append("text").attr("x",_t().state.padding).attr("y",r+.4*_t().state.padding+_t().state.dividerMargin+_t().state.textHeight).attr("class","state-description"),a=!0,o=!0;e.descriptions.forEach((function(t){a||(!function(t,e,n){var r=t.append("tspan").attr("x",2*_t().state.padding).text(e);n||r.attr("dy",_t().state.textHeight)}(i,t,o),o=!1),a=!1}));var s=t.append("line").attr("x1",_t().state.padding).attr("y1",_t().state.padding+r+_t().state.dividerMargin/2).attr("y2",_t().state.padding+r+_t().state.dividerMargin/2).attr("class","descr-divider"),c=i.node().getBBox(),u=Math.max(c.width,n.width);return s.attr("x2",u+3*_t().state.padding),t.insert("rect",":first-child").attr("x",_t().state.padding).attr("y",_t().state.padding).attr("width",u+2*_t().state.padding).attr("height",c.height+r+2*_t().state.padding).attr("rx",_t().state.radius),t},Fi=function(t,e,n){var r,i=_t().state.padding,a=2*_t().state.padding,o=t.node().getBBox(),s=o.width,c=o.x,u=t.append("text").attr("x",0).attr("y",_t().state.titleShift).attr("font-size",_t().state.fontSize).attr("class","state-title").text(e.id),l=u.node().getBBox().width+a,h=Math.max(l,s);h===s&&(h+=a);var f=t.node().getBBox();e.doc,r=c-i,l>s&&(r=(s-h)/2+i),Math.abs(c-f.x)s&&(r=c-(l-s)/2);var d=1-_t().state.textHeight;return t.insert("rect",":first-child").attr("x",r).attr("y",d).attr("class",n?"alt-composit":"composit").attr("width",h).attr("height",f.height+_t().state.textHeight+_t().state.titleShift+1).attr("rx","0"),u.attr("x",r+i),l<=s&&u.attr("x",c+(h-a)/2-l/2+i),t.insert("rect",":first-child").attr("x",r).attr("y",_t().state.titleShift-_t().state.textHeight-_t().state.padding).attr("width",h).attr("height",3*_t().state.textHeight).attr("rx",_t().state.radius),t.insert("rect",":first-child").attr("x",r).attr("y",_t().state.titleShift-_t().state.textHeight-_t().state.padding).attr("width",h).attr("height",f.height+3+2*_t().state.textHeight).attr("rx",_t().state.radius),t},Pi=function(t,e){e.attr("class","state-note");var n=e.append("rect").attr("x",0).attr("y",_t().state.padding),r=function(t,e,n,r){var i=0,a=r.append("text");a.style("text-anchor","start"),a.attr("class","noteText");var o=t.replace(/\r\n/g,"
"),s=(o=o.replace(/\n/g,"
")).split(x.lineBreakRegex),c=1.25*_t().state.noteMargin,u=!0,l=!1,h=void 0;try{for(var f,d=s[Symbol.iterator]();!(u=(f=d.next()).done);u=!0){var p=f.value.trim();if(p.length>0){var g=a.append("tspan");if(g.text(p),0===c)c+=g.node().getBBox().height;i+=c,g.attr("x",e+_t().state.noteMargin),g.attr("y",n+i+1.25*_t().state.noteMargin)}}}catch(t){l=!0,h=t}finally{try{u||null==d.return||d.return()}finally{if(l)throw h}}return{textWidth:a.node().getBBox().width,textHeight:i}}(t,0,0,e.append("g")),i=r.textWidth,a=r.textHeight;return n.attr("height",a+2*_t().state.noteMargin),n.attr("width",i+2*_t().state.noteMargin),n},Ii=function(t,e){var n=e.id,r={id:n,label:e.id,width:0,height:0},i=t.append("g").attr("id",n).attr("class","stateGroup");"start"===e.type&&function(t){t.append("circle").attr("class","start-state").attr("r",_t().state.sizeUnit).attr("cx",_t().state.padding+_t().state.sizeUnit).attr("cy",_t().state.padding+_t().state.sizeUnit)}(i),"end"===e.type&&function(t){t.append("circle").attr("class","end-state-outer").attr("r",_t().state.sizeUnit+_t().state.miniPadding).attr("cx",_t().state.padding+_t().state.sizeUnit+_t().state.miniPadding).attr("cy",_t().state.padding+_t().state.sizeUnit+_t().state.miniPadding),t.append("circle").attr("class","end-state-inner").attr("r",_t().state.sizeUnit).attr("cx",_t().state.padding+_t().state.sizeUnit+2).attr("cy",_t().state.padding+_t().state.sizeUnit+2)}(i),"fork"!==e.type&&"join"!==e.type||function(t,e){var n=_t().state.forkWidth,r=_t().state.forkHeight;if(e.parentId){var i=n;n=r,r=i}t.append("rect").style("stroke","black").style("fill","black").attr("width",n).attr("height",r).attr("x",_t().state.padding).attr("y",_t().state.padding)}(i,e),"note"===e.type&&Pi(e.note.text,i),"divider"===e.type&&function(t){t.append("line").style("stroke","grey").style("stroke-dasharray","3").attr("x1",_t().state.textHeight).attr("class","divider").attr("x2",2*_t().state.textHeight).attr("y1",0).attr("y2",0)}(i),"default"===e.type&&0===e.descriptions.length&&function(t,e){var n=t.append("text").attr("x",2*_t().state.padding).attr("y",_t().state.textHeight+2*_t().state.padding).attr("font-size",_t().state.fontSize).attr("class","state-title").text(e.id),r=n.node().getBBox();t.insert("rect",":first-child").attr("x",_t().state.padding).attr("y",_t().state.padding).attr("width",r.width+2*_t().state.padding).attr("height",r.height+2*_t().state.padding).attr("rx",_t().state.radius)}(i,e),"default"===e.type&&e.descriptions.length>0&&Li(i,e);var a=i.node().getBBox();return r.width=a.width+2*_t().state.padding,r.height=a.height+2*_t().state.padding,Bi(n,r),r},ji=0;Oi.parser.yy=Mi;var Ri={},Yi=function t(e,n,r,i){var a,o=new G.a.Graph({compound:!0,multigraph:!0}),s=!0;for(a=0;a "+t.w+": "+JSON.stringify(o.edge(t))),function(t,e,n){e.points=e.points.filter((function(t){return!Number.isNaN(t.y)}));var r=e.points,i=Object(d.line)().x((function(t){return t.x})).y((function(t){return t.y})).curve(d.curveBasis),a=t.append("path").attr("d",i(r)).attr("id","edge"+ji).attr("class","transition"),o="";if(_t().state.arrowMarkerAbsolute&&(o=(o=(o=window.location.protocol+"//"+window.location.host+window.location.pathname+window.location.search).replace(/\(/g,"\\(")).replace(/\)/g,"\\)")),a.attr("marker-end","url("+o+"#"+function(t){switch(t){case Mi.relationType.AGGREGATION:return"aggregation";case Mi.relationType.EXTENSION:return"extension";case Mi.relationType.COMPOSITION:return"composition";case Mi.relationType.DEPENDENCY:return"dependency"}}(Mi.relationType.DEPENDENCY)+"End)"),void 0!==n.title){for(var s=t.append("g").attr("class","stateLabel"),u=H.calcLabelPosition(e.points),l=u.x,h=u.y,f=x.getRows(n.title),p=0,g=[],y=0,v=0,m=0;m<=f.length;m++){var b=s.append("text").attr("text-anchor","middle").text(f[m]).attr("x",l).attr("y",h+p),_=b.node().getBBox();if(y=Math.max(y,_.width),v=Math.min(v,_.x),c.info(_.x,l,h+p),0===p){var k=b.node().getBBox();p=k.height,c.info("Title height",p,h)}g.push(b)}var w=p*f.length;if(f.length>1){var E=(f.length-1)*p*.5;g.forEach((function(t,e){return t.attr("y",h+e*p-E)})),w=p*f.length}var T=s.node().getBBox();s.insert("rect",":first-child").attr("class","box").attr("x",l-y/2-_t().state.padding/2).attr("y",h-w/2-_t().state.padding/2-3.5).attr("width",y+_t().state.padding).attr("height",w+_t().state.padding),c.info(T)}ji++}(n,o.edge(t),o.edge(t).relation))})),w=k.getBBox();var E={id:r||"root",label:r||"root",width:0,height:0};return E.width=w.width+2*vi.padding,E.height=w.height+2*vi.padding,c.debug("Doc rendered",E,o),E},zi=function(){},Ui=function(t,e){vi=_t().state,Oi.parser.yy.clear(),Oi.parser.parse(t),c.debug("Rendering diagram "+t);var n=Object(d.select)("[id='".concat(e,"']"));n.append("defs").append("marker").attr("id","dependencyEnd").attr("refX",19).attr("refY",7).attr("markerWidth",20).attr("markerHeight",28).attr("orient","auto").append("path").attr("d","M 19,7 L9,13 L14,7 L9,1 Z"),new G.a.Graph({multigraph:!0,compound:!0,rankdir:"RL"}).setDefaultEdgeLabel((function(){return{}}));var r=Mi.getRootDoc();Yi(r,n,void 0,!1);var i=vi.padding,a=n.node().getBBox(),o=a.width+2*i,s=a.height+2*i;W(n,s,1.75*o,vi.useMaxWidth),n.attr("viewBox","".concat(a.x-vi.padding," ").concat(a.y-vi.padding," ")+o+" "+s)},$i={},Wi={},Hi=function(t,e,n,r){if("root"!==n.id){var i="rect";!0===n.start&&(i="start"),!1===n.start&&(i="end"),"default"!==n.type&&(i=n.type),Wi[n.id]||(Wi[n.id]={id:n.id,shape:i,description:n.id,classes:"statediagram-state"}),n.description&&(Array.isArray(Wi[n.id].description)?(Wi[n.id].shape="rectWithTitle",Wi[n.id].description.push(n.description)):Wi[n.id].description.length>0?(Wi[n.id].shape="rectWithTitle",Wi[n.id].description===n.id?Wi[n.id].description=[n.description]:Wi[n.id].description=[Wi[n.id].description,n.description]):(Wi[n.id].shape="rect",Wi[n.id].description=n.description)),!Wi[n.id].type&&n.doc&&(c.info("Setting cluser for ",n.id),Wi[n.id].type="group",Wi[n.id].shape="divider"===n.type?"divider":"roundedWithTitle",Wi[n.id].classes=Wi[n.id].classes+" "+(r?"statediagram-cluster statediagram-cluster-alt":"statediagram-cluster"));var a={labelStyle:"",shape:Wi[n.id].shape,labelText:Wi[n.id].description,classes:Wi[n.id].classes,style:"",id:n.id,domId:"state-"+n.id+"-"+Vi,type:Wi[n.id].type,padding:15};if(n.note){var o={labelStyle:"",shape:"note",labelText:n.note.text,classes:"statediagram-note",style:"",id:n.id+"----note",domId:"state-"+n.id+"----note-"+Vi,type:Wi[n.id].type,padding:15},s={labelStyle:"",shape:"noteGroup",labelText:n.note.text,classes:Wi[n.id].classes,style:"",id:n.id+"----parent",domId:"state-"+n.id+"----parent-"+Vi,type:"group",padding:0};Vi++,t.setNode(n.id+"----parent",s),t.setNode(o.id,o),t.setNode(n.id,a),t.setParent(n.id,n.id+"----parent"),t.setParent(o.id,n.id+"----parent");var u=n.id,l=o.id;"left of"===n.note.position&&(u=o.id,l=n.id),t.setEdge(u,l,{arrowhead:"none",arrowType:"",style:"fill:none",labelStyle:"",classes:"transition note-edge",arrowheadStyle:"fill: #333",labelpos:"c",labelType:"text",thickness:"normal"})}else t.setNode(n.id,a)}e&&"root"!==e.id&&(c.info("Setting node ",n.id," to be child of its parent ",e.id),t.setParent(n.id,e.id)),n.doc&&(c.info("Adding nodes children "),Gi(t,n,n.doc,!r))},Vi=0,Gi=function(t,e,n,r){Vi=0,c.trace("items",n),n.forEach((function(n){if("state"===n.stmt||"default"===n.stmt)Hi(t,e,n,r);else if("relation"===n.stmt){Hi(t,e,n.state1,r),Hi(t,e,n.state2,r);var i={id:"edge"+Vi,arrowhead:"normal",arrowTypeEnd:"arrow_barb",style:"fill:none",labelStyle:"",label:n.description,arrowheadStyle:"fill: #333",labelpos:"c",labelType:"text",thickness:"normal",classes:"transition"},a=n.state1.id,o=n.state2.id;t.setEdge(a,o,i,Vi),Vi++}}))},qi=function(t){for(var e=Object.keys(t),n=0;ne.seq?t:e}),t[0]),n="";t.forEach((function(t){n+=t===e?"\t*":"\t|"}));var r,i,a,o=[n,e.id,e.seq];for(var s in Ki)Ki[s]===e.id&&o.push(s);if(c.debug(o.join(" ")),Array.isArray(e.parent)){var u=Zi[e.parent[0]];aa(t,e,u),t.push(Zi[e.parent[1]])}else{if(null==e.parent)return;var l=Zi[e.parent];aa(t,e,l)}r=t,i=function(t){return t.id},a=Object.create(null),oa(t=r.reduce((function(t,e){var n=i(e);return a[n]||(a[n]=!0,t.push(e)),t}),[]))}var sa,ca=function(){var t=Object.keys(Zi).map((function(t){return Zi[t]}));return t.forEach((function(t){c.debug(t.id)})),t.sort((function(t,e){return e.seq-t.seq})),t},ua={setDirection:function(t){ta=t},setOptions:function(t){c.debug("options str",t),t=(t=t&&t.trim())||"{}";try{ia=JSON.parse(t)}catch(t){c.error("error while parsing gitGraph options",t.message)}},getOptions:function(){return ia},commit:function(t){var e={id:na(),message:t,seq:ea++,parent:null==Ji?null:Ji.id};Ji=e,Zi[e.id]=e,Ki[Qi]=e.id,c.debug("in pushCommit "+e.id)},branch:function(t){Ki[t]=null!=Ji?Ji.id:null,c.debug("in createBranch")},merge:function(t){var e=Zi[Ki[Qi]],n=Zi[Ki[t]];if(function(t,e){return t.seq>e.seq&&ra(e,t)}(e,n))c.debug("Already merged");else{if(ra(e,n))Ki[Qi]=Ki[t],Ji=Zi[Ki[Qi]];else{var r={id:na(),message:"merged branch "+t+" into "+Qi,seq:ea++,parent:[null==Ji?null:Ji.id,Ki[t]]};Ji=r,Zi[r.id]=r,Ki[Qi]=r.id}c.debug(Ki),c.debug("in mergeBranch")}},checkout:function(t){c.debug("in checkout");var e=Ki[Qi=t];Ji=Zi[e]},reset:function(t){c.debug("in reset",t);var e=t.split(":")[0],n=parseInt(t.split(":")[1]),r="HEAD"===e?Ji:Zi[Ki[e]];for(c.debug(r,n);n>0;)if(n--,!(r=Zi[r.parent])){var i="Critical error - unique parent commit not found during reset";throw c.error(i),i}Ji=r,Ki[Qi]=r.id},prettyPrint:function(){c.debug(Zi),oa([ca()[0]])},clear:function(){Zi={},Ki={master:Ji=null},Qi="master",ea=0},getBranchesAsObjArray:function(){var t=[];for(var e in Ki)t.push({name:e,commit:Zi[Ki[e]]});return t},getBranches:function(){return Ki},getCommits:function(){return Zi},getCommitsArray:ca,getCurrentBranch:function(){return Qi},getDirection:function(){return ta},getHead:function(){return Ji}},la=n(71),ha=n.n(la),fa={},da={nodeSpacing:150,nodeFillColor:"yellow",nodeStrokeWidth:2,nodeStrokeColor:"grey",lineStrokeWidth:4,branchOffset:50,lineColor:"grey",leftMargin:50,branchColors:["#442f74","#983351","#609732","#AA9A39"],nodeRadius:10,nodeLabel:{width:75,height:100,x:-25,y:0}},pa={};function ga(t,e,n,r){var i=D(r,d.curveBasis),a=da.branchColors[n%da.branchColors.length],o=Object(d.line)().x((function(t){return Math.round(t.x)})).y((function(t){return Math.round(t.y)})).curve(i);t.append("svg:path").attr("d",o(e)).style("stroke",a).style("stroke-width",da.lineStrokeWidth).style("fill","none")}function ya(t,e){e=e||t.node().getBBox();var n=t.node().getCTM();return{left:n.e+e.x*n.a,top:n.f+e.y*n.d,width:e.width,height:e.height}}function va(t,e,n,r,i){c.debug("svgDrawLineForCommits: ",e,n);var a=ya(t.select("#node-"+e+" circle")),o=ya(t.select("#node-"+n+" circle"));switch(r){case"LR":if(a.left-o.left>da.nodeSpacing){var s={x:a.left-da.nodeSpacing,y:o.top+o.height/2};ga(t,[s,{x:o.left+o.width,y:o.top+o.height/2}],i,"linear"),ga(t,[{x:a.left,y:a.top+a.height/2},{x:a.left-da.nodeSpacing/2,y:a.top+a.height/2},{x:a.left-da.nodeSpacing/2,y:s.y},s],i)}else ga(t,[{x:a.left,y:a.top+a.height/2},{x:a.left-da.nodeSpacing/2,y:a.top+a.height/2},{x:a.left-da.nodeSpacing/2,y:o.top+o.height/2},{x:o.left+o.width,y:o.top+o.height/2}],i);break;case"BT":if(o.top-a.top>da.nodeSpacing){var u={x:o.left+o.width/2,y:a.top+a.height+da.nodeSpacing};ga(t,[u,{x:o.left+o.width/2,y:o.top}],i,"linear"),ga(t,[{x:a.left+a.width/2,y:a.top+a.height},{x:a.left+a.width/2,y:a.top+a.height+da.nodeSpacing/2},{x:o.left+o.width/2,y:u.y-da.nodeSpacing/2},u],i)}else ga(t,[{x:a.left+a.width/2,y:a.top+a.height},{x:a.left+a.width/2,y:a.top+da.nodeSpacing/2},{x:o.left+o.width/2,y:o.top-da.nodeSpacing/2},{x:o.left+o.width/2,y:o.top}],i)}}function ma(t,e){return t.select(e).node().cloneNode(!0)}function ba(t,e,n,r){var i,a=Object.keys(fa).length;if("string"==typeof e)do{if(i=fa[e],c.debug("in renderCommitHistory",i.id,i.seq),t.select("#node-"+e).size()>0)return;t.append((function(){return ma(t,"#def-commit")})).attr("class","commit").attr("id",(function(){return"node-"+i.id})).attr("transform",(function(){switch(r){case"LR":return"translate("+(i.seq*da.nodeSpacing+da.leftMargin)+", "+sa*da.branchOffset+")";case"BT":return"translate("+(sa*da.branchOffset+da.leftMargin)+", "+(a-i.seq)*da.nodeSpacing+")"}})).attr("fill",da.nodeFillColor).attr("stroke",da.nodeStrokeColor).attr("stroke-width",da.nodeStrokeWidth);var o=void 0;for(var s in n)if(n[s].commit===i){o=n[s];break}o&&(c.debug("found branch ",o.name),t.select("#node-"+i.id+" p").append("xhtml:span").attr("class","branch-label").text(o.name+", ")),t.select("#node-"+i.id+" p").append("xhtml:span").attr("class","commit-id").text(i.id),""!==i.message&&"BT"===r&&t.select("#node-"+i.id+" p").append("xhtml:span").attr("class","commit-msg").text(", "+i.message),e=i.parent}while(e&&fa[e]);Array.isArray(e)&&(c.debug("found merge commmit",e),ba(t,e[0],n,r),sa++,ba(t,e[1],n,r),sa--)}function xa(t,e,n,r){for(r=r||0;e.seq>0&&!e.lineDrawn;)"string"==typeof e.parent?(va(t,e.id,e.parent,n,r),e.lineDrawn=!0,e=fa[e.parent]):Array.isArray(e.parent)&&(va(t,e.id,e.parent[0],n,r),va(t,e.id,e.parent[1],n,r+1),xa(t,fa[e.parent[1]],n,r+1),e.lineDrawn=!0,e=fa[e.parent[0]])}var _a,ka=function(t){pa=t},wa=function(t,e,n){try{var r=ha.a.parser;r.yy=ua,r.yy.clear(),c.debug("in gitgraph renderer",t+"\n","id:",e,n),r.parse(t+"\n"),da=Object.assign(da,pa,ua.getOptions()),c.debug("effective options",da);var i=ua.getDirection();fa=ua.getCommits();var a=ua.getBranchesAsObjArray();"BT"===i&&(da.nodeLabel.x=a.length*da.branchOffset,da.nodeLabel.width="100%",da.nodeLabel.y=-2*da.nodeRadius);var o=Object(d.select)('[id="'.concat(e,'"]'));for(var s in function(t){t.append("defs").append("g").attr("id","def-commit").append("circle").attr("r",da.nodeRadius).attr("cx",0).attr("cy",0),t.select("#def-commit").append("foreignObject").attr("width",da.nodeLabel.width).attr("height",da.nodeLabel.height).attr("x",da.nodeLabel.x).attr("y",da.nodeLabel.y).attr("class","node-label").attr("requiredFeatures","http://www.w3.org/TR/SVG11/feature#Extensibility").append("p").html("")}(o),sa=1,a){var u=a[s];ba(o,u.commit.id,a,i),xa(o,u.commit,i),sa++}o.attr("height",(function(){return"BT"===i?Object.keys(fa).length*da.nodeSpacing:(a.length+1)*da.branchOffset}))}catch(t){c.error("Error while rendering gitgraph"),c.error(t.message)}},Ea="",Ta=!1,Ca={setMessage:function(t){c.debug("Setting message to: "+t),Ea=t},getMessage:function(){return Ea},setInfo:function(t){Ta=t},getInfo:function(){return Ta}},Aa=n(72),Sa=n.n(Aa),Ma={},Oa=function(t){Object.keys(t).forEach((function(e){Ma[e]=t[e]}))},Da=function(t,e,n){try{var r=Sa.a.parser;r.yy=Ca,c.debug("Renering info diagram\n"+t),r.parse(t),c.debug("Parsed info diagram");var i=Object(d.select)("#"+e);i.append("g").append("text").attr("x",100).attr("y",40).attr("class","version").attr("font-size","32px").style("text-anchor","middle").text("v "+n),i.attr("height",100),i.attr("width",400)}catch(t){c.error("Error while rendering info diagram"),c.error(t.message)}},Na={},Ba=function(t){Object.keys(t).forEach((function(e){Na[e]=t[e]}))},La=function(t,e){try{c.debug("Renering svg for syntax error\n");var n=Object(d.select)("#"+t),r=n.append("g");r.append("path").attr("class","error-icon").attr("d","m411.313,123.313c6.25-6.25 6.25-16.375 0-22.625s-16.375-6.25-22.625,0l-32,32-9.375,9.375-20.688-20.688c-12.484-12.5-32.766-12.5-45.25,0l-16,16c-1.261,1.261-2.304,2.648-3.31,4.051-21.739-8.561-45.324-13.426-70.065-13.426-105.867,0-192,86.133-192,192s86.133,192 192,192 192-86.133 192-192c0-24.741-4.864-48.327-13.426-70.065 1.402-1.007 2.79-2.049 4.051-3.31l16-16c12.5-12.492 12.5-32.758 0-45.25l-20.688-20.688 9.375-9.375 32.001-31.999zm-219.313,100.687c-52.938,0-96,43.063-96,96 0,8.836-7.164,16-16,16s-16-7.164-16-16c0-70.578 57.422-128 128-128 8.836,0 16,7.164 16,16s-7.164,16-16,16z"),r.append("path").attr("class","error-icon").attr("d","m459.02,148.98c-6.25-6.25-16.375-6.25-22.625,0s-6.25,16.375 0,22.625l16,16c3.125,3.125 7.219,4.688 11.313,4.688 4.094,0 8.188-1.563 11.313-4.688 6.25-6.25 6.25-16.375 0-22.625l-16.001-16z"),r.append("path").attr("class","error-icon").attr("d","m340.395,75.605c3.125,3.125 7.219,4.688 11.313,4.688 4.094,0 8.188-1.563 11.313-4.688 6.25-6.25 6.25-16.375 0-22.625l-16-16c-6.25-6.25-16.375-6.25-22.625,0s-6.25,16.375 0,22.625l15.999,16z"),r.append("path").attr("class","error-icon").attr("d","m400,64c8.844,0 16-7.164 16-16v-32c0-8.836-7.156-16-16-16-8.844,0-16,7.164-16,16v32c0,8.836 7.156,16 16,16z"),r.append("path").attr("class","error-icon").attr("d","m496,96.586h-32c-8.844,0-16,7.164-16,16 0,8.836 7.156,16 16,16h32c8.844,0 16-7.164 16-16 0-8.836-7.156-16-16-16z"),r.append("path").attr("class","error-icon").attr("d","m436.98,75.605c3.125,3.125 7.219,4.688 11.313,4.688 4.094,0 8.188-1.563 11.313-4.688l32-32c6.25-6.25 6.25-16.375 0-22.625s-16.375-6.25-22.625,0l-32,32c-6.251,6.25-6.251,16.375-0.001,22.625z"),r.append("text").attr("class","error-text").attr("x",1240).attr("y",250).attr("font-size","150px").style("text-anchor","middle").text("Syntax error in graph"),r.append("text").attr("class","error-text").attr("x",1050).attr("y",400).attr("font-size","100px").style("text-anchor","middle").text("mermaid version "+e),n.attr("height",100),n.attr("width",400),n.attr("viewBox","768 0 512 512")}catch(t){c.error("Error while rendering info diagram"),c.error(t.message)}},Fa={},Pa="",Ia={parseDirective:function(t,e,n){Go.parseDirective(this,t,e,n)},getConfig:function(){return _t().pie},addSection:function(t,e){void 0===Fa[t]&&(Fa[t]=e,c.debug("Added new section :",t))},getSections:function(){return Fa},cleanupValue:function(t){return":"===t.substring(0,1)?(t=t.substring(1).trim(),Number(t.trim())):Number(t.trim())},clear:function(){Fa={},Pa=""},setTitle:function(t){Pa=t},getTitle:function(){return Pa}},ja=n(73),Ra=n.n(ja),Ya={},za=function(t){Object.keys(t).forEach((function(e){Ya[e]=t[e]}))},Ua=function(t,e){try{var n=Ra.a.parser;n.yy=Ia,c.debug("Rendering info diagram\n"+t),n.yy.clear(),n.parse(t),c.debug("Parsed info diagram");var r=document.getElementById(e);void 0===(_a=r.parentElement.offsetWidth)&&(_a=1200),void 0!==Ya.useWidth&&(_a=Ya.useWidth);var i=Object(d.select)("#"+e);W(i,450,_a,Ya.useMaxWidth),r.setAttribute("viewBox","0 0 "+_a+" 450");var a=Math.min(_a,450)/2-40,o=i.append("g").attr("transform","translate("+_a/2+",225)"),s=Ia.getSections(),u=0;Object.keys(s).forEach((function(t){u+=s[t]}));var l=Object(d.scaleOrdinal)().domain(s).range(d.schemeSet2),h=Object(d.pie)().value((function(t){return t.value}))(Object(d.entries)(s)),f=Object(d.arc)().innerRadius(0).outerRadius(a);o.selectAll("mySlices").data(h).enter().append("path").attr("d",f).attr("fill",(function(t){return l(t.data.key)})).attr("stroke","black").style("stroke-width","2px").style("opacity",.7),o.selectAll("mySlices").data(h).enter().append("text").text((function(t){return(t.data.value/u*100).toFixed(0)+"%"})).attr("transform",(function(t){return"translate("+f.centroid(t)+")"})).style("text-anchor","middle").attr("class","slice").style("font-size",17),o.append("text").text(n.yy.getTitle()).attr("x",0).attr("y",-200).attr("class","pieTitleText");var p=o.selectAll(".legend").data(l.domain()).enter().append("g").attr("class","legend").attr("transform",(function(t,e){return"translate(216,"+(22*e-22*l.domain().length/2)+")"}));p.append("rect").attr("width",18).attr("height",18).style("fill",l).style("stroke",l),p.append("text").attr("x",22).attr("y",14).text((function(t){return t}))}catch(t){c.error("Error while rendering info diagram"),c.error(t)}},$a={},Wa=[],Ha="",Va=function(t){return void 0===$a[t]&&($a[t]={attributes:[]},c.info("Added new entity :",t)),$a[t]},Ga={Cardinality:{ZERO_OR_ONE:"ZERO_OR_ONE",ZERO_OR_MORE:"ZERO_OR_MORE",ONE_OR_MORE:"ONE_OR_MORE",ONLY_ONE:"ONLY_ONE"},Identification:{NON_IDENTIFYING:"NON_IDENTIFYING",IDENTIFYING:"IDENTIFYING"},parseDirective:function(t,e,n){Go.parseDirective(this,t,e,n)},getConfig:function(){return _t().er},addEntity:Va,addAttributes:function(t,e){var n,r=Va(t);for(n=e.length-1;n>=0;n--)r.attributes.push(e[n]),c.debug("Added attribute ",e[n].attributeName)},getEntities:function(){return $a},addRelationship:function(t,e,n,r){var i={entityA:t,roleA:e,entityB:n,relSpec:r};Wa.push(i),c.debug("Added new relationship :",i)},getRelationships:function(){return Wa},clear:function(){$a={},Wa=[],Ha=""},setTitle:function(t){Ha=t},getTitle:function(){return Ha}},qa=n(74),Xa=n.n(qa),Za={ONLY_ONE_START:"ONLY_ONE_START",ONLY_ONE_END:"ONLY_ONE_END",ZERO_OR_ONE_START:"ZERO_OR_ONE_START",ZERO_OR_ONE_END:"ZERO_OR_ONE_END",ONE_OR_MORE_START:"ONE_OR_MORE_START",ONE_OR_MORE_END:"ONE_OR_MORE_END",ZERO_OR_MORE_START:"ZERO_OR_MORE_START",ZERO_OR_MORE_END:"ZERO_OR_MORE_END"},Ja=Za,Ka=function(t,e){var n;t.append("defs").append("marker").attr("id",Za.ONLY_ONE_START).attr("refX",0).attr("refY",9).attr("markerWidth",18).attr("markerHeight",18).attr("orient","auto").append("path").attr("stroke",e.stroke).attr("fill","none").attr("d","M9,0 L9,18 M15,0 L15,18"),t.append("defs").append("marker").attr("id",Za.ONLY_ONE_END).attr("refX",18).attr("refY",9).attr("markerWidth",18).attr("markerHeight",18).attr("orient","auto").append("path").attr("stroke",e.stroke).attr("fill","none").attr("d","M3,0 L3,18 M9,0 L9,18"),(n=t.append("defs").append("marker").attr("id",Za.ZERO_OR_ONE_START).attr("refX",0).attr("refY",9).attr("markerWidth",30).attr("markerHeight",18).attr("orient","auto")).append("circle").attr("stroke",e.stroke).attr("fill","white").attr("cx",21).attr("cy",9).attr("r",6),n.append("path").attr("stroke",e.stroke).attr("fill","none").attr("d","M9,0 L9,18"),(n=t.append("defs").append("marker").attr("id",Za.ZERO_OR_ONE_END).attr("refX",30).attr("refY",9).attr("markerWidth",30).attr("markerHeight",18).attr("orient","auto")).append("circle").attr("stroke",e.stroke).attr("fill","white").attr("cx",9).attr("cy",9).attr("r",6),n.append("path").attr("stroke",e.stroke).attr("fill","none").attr("d","M21,0 L21,18"),t.append("defs").append("marker").attr("id",Za.ONE_OR_MORE_START).attr("refX",18).attr("refY",18).attr("markerWidth",45).attr("markerHeight",36).attr("orient","auto").append("path").attr("stroke",e.stroke).attr("fill","none").attr("d","M0,18 Q 18,0 36,18 Q 18,36 0,18 M42,9 L42,27"),t.append("defs").append("marker").attr("id",Za.ONE_OR_MORE_END).attr("refX",27).attr("refY",18).attr("markerWidth",45).attr("markerHeight",36).attr("orient","auto").append("path").attr("stroke",e.stroke).attr("fill","none").attr("d","M3,9 L3,27 M9,18 Q27,0 45,18 Q27,36 9,18"),(n=t.append("defs").append("marker").attr("id",Za.ZERO_OR_MORE_START).attr("refX",18).attr("refY",18).attr("markerWidth",57).attr("markerHeight",36).attr("orient","auto")).append("circle").attr("stroke",e.stroke).attr("fill","white").attr("cx",48).attr("cy",18).attr("r",6),n.append("path").attr("stroke",e.stroke).attr("fill","none").attr("d","M0,18 Q18,0 36,18 Q18,36 0,18"),(n=t.append("defs").append("marker").attr("id",Za.ZERO_OR_MORE_END).attr("refX",39).attr("refY",18).attr("markerWidth",57).attr("markerHeight",36).attr("orient","auto")).append("circle").attr("stroke",e.stroke).attr("fill","white").attr("cx",9).attr("cy",18).attr("r",6),n.append("path").attr("stroke",e.stroke).attr("fill","none").attr("d","M21,18 Q39,0 57,18 Q39,36 21,18")},Qa={},to=function(t,e,n){var r;return Object.keys(e).forEach((function(i){var a=t.append("g").attr("id",i);r=void 0===r?i:r;var o="entity-"+i,s=a.append("text").attr("class","er entityLabel").attr("id",o).attr("x",0).attr("y",0).attr("dominant-baseline","middle").attr("text-anchor","middle").attr("style","font-family: "+_t().fontFamily+"; font-size: "+Qa.fontSize+"px").text(i),c=function(t,e,n){var r=Qa.entityPadding/3,i=Qa.entityPadding/3,a=.85*Qa.fontSize,o=e.node().getBBox(),s=[],c=0,u=0,l=o.height+2*r,h=1;n.forEach((function(n){var i="".concat(e.node().id,"-attr-").concat(h),o=t.append("text").attr("class","er entityLabel").attr("id","".concat(i,"-type")).attr("x",0).attr("y",0).attr("dominant-baseline","middle").attr("text-anchor","left").attr("style","font-family: "+_t().fontFamily+"; font-size: "+a+"px").text(n.attributeType),f=t.append("text").attr("class","er entityLabel").attr("id","".concat(i,"-name")).attr("x",0).attr("y",0).attr("dominant-baseline","middle").attr("text-anchor","left").attr("style","font-family: "+_t().fontFamily+"; font-size: "+a+"px").text(n.attributeName);s.push({tn:o,nn:f});var d=o.node().getBBox(),p=f.node().getBBox();c=Math.max(c,d.width),u=Math.max(u,p.width),l+=Math.max(d.height,p.height)+2*r,h+=1}));var f={width:Math.max(Qa.minEntityWidth,Math.max(o.width+2*Qa.entityPadding,c+u+4*i)),height:n.length>0?l:Math.max(Qa.minEntityHeight,o.height+2*Qa.entityPadding)},d=Math.max(0,f.width-(c+u)-4*i);if(n.length>0){e.attr("transform","translate("+f.width/2+","+(r+o.height/2)+")");var p=o.height+2*r,g="attributeBoxOdd";s.forEach((function(e){var n=p+r+Math.max(e.tn.node().getBBox().height,e.nn.node().getBBox().height)/2;e.tn.attr("transform","translate("+i+","+n+")");var a=t.insert("rect","#"+e.tn.node().id).attr("class","er ".concat(g)).attr("fill",Qa.fill).attr("fill-opacity","100%").attr("stroke",Qa.stroke).attr("x",0).attr("y",p).attr("width",c+2*i+d/2).attr("height",e.tn.node().getBBox().height+2*r);e.nn.attr("transform","translate("+(parseFloat(a.attr("width"))+i)+","+n+")"),t.insert("rect","#"+e.nn.node().id).attr("class","er ".concat(g)).attr("fill",Qa.fill).attr("fill-opacity","100%").attr("stroke",Qa.stroke).attr("x","".concat(a.attr("x")+a.attr("width"))).attr("y",p).attr("width",u+2*i+d/2).attr("height",e.nn.node().getBBox().height+2*r),p+=Math.max(e.tn.node().getBBox().height,e.nn.node().getBBox().height)+2*r,g="attributeBoxOdd"==g?"attributeBoxEven":"attributeBoxOdd"}))}else f.height=Math.max(Qa.minEntityHeight,l),e.attr("transform","translate("+f.width/2+","+f.height/2+")");return f}(a,s,e[i].attributes),u=c.width,l=c.height,h=a.insert("rect","#"+o).attr("class","er entityBox").attr("fill",Qa.fill).attr("fill-opacity","100%").attr("stroke",Qa.stroke).attr("x",0).attr("y",0).attr("width",u).attr("height",l).node().getBBox();n.setNode(i,{width:h.width,height:h.height,shape:"rect",id:i})})),r},eo=function(t){return(t.entityA+t.roleA+t.entityB).replace(/\s/g,"")},no=0,ro=function(t){for(var e=Object.keys(t),n=0;n/gi," "),r=t.append("text");r.attr("x",e.x),r.attr("y",e.y),r.attr("class","legend"),r.style("text-anchor",e.anchor),void 0!==e.class&&r.attr("class",e.class);var i=r.append("tspan");return i.attr("x",e.x+2*e.textMargin),i.text(n),r},bo=-1,xo=function(){return{x:0,y:0,width:100,anchor:"start",height:100,rx:0,ry:0}},_o=function(){function t(t,e,n,i,a,o,s,c){r(e.append("text").attr("x",n+a/2).attr("y",i+o/2+5).style("font-color",c).style("text-anchor","middle").text(t),s)}function e(t,e,n,i,a,o,s,c,u){for(var l=c.taskFontSize,h=c.taskFontFamily,f=t.split(//gi),d=0;d3?function(t){var e=Object(d.arc)().startAngle(Math.PI/2).endAngle(Math.PI/2*3).innerRadius(7.5).outerRadius(15/2.2);t.append("path").attr("class","mouth").attr("d",e).attr("transform","translate("+o.cx+","+(o.cy+2)+")")}(s):o.score<3?function(t){var e=Object(d.arc)().startAngle(3*Math.PI/2).endAngle(Math.PI/2*5).innerRadius(7.5).outerRadius(15/2.2);t.append("path").attr("class","mouth").attr("d",e).attr("transform","translate("+o.cx+","+(o.cy+7)+")")}(s):function(t){t.append("line").attr("class","mouth").attr("stroke",2).attr("x1",o.cx-5).attr("y1",o.cy+7).attr("x2",o.cx+5).attr("y2",o.cy+7).attr("class","mouth").attr("stroke-width","1px").attr("stroke","#666")}(s);var c=xo();c.x=e.x,c.y=e.y,c.fill=e.fill,c.width=n.width,c.height=n.height,c.class="task task-type-"+e.num,c.rx=3,c.ry=3,yo(i,c);var u=e.x+14;e.people.forEach((function(t){var n=e.actors[t],r={cx:u,cy:e.y,r:7,fill:n,stroke:"#000",title:t};vo(i,r),u+=10})),_o(n)(e.task,i,c.x,c.y,c.width,c.height,{class:"task"},n,e.colour)},Co=function(t){t.append("defs").append("marker").attr("id","arrowhead").attr("refX",5).attr("refY",2).attr("markerWidth",6).attr("markerHeight",4).attr("orient","auto").append("path").attr("d","M 0,0 V 4 L6,2 Z")};ao.parser.yy=go;var Ao={leftMargin:150,diagramMarginX:50,diagramMarginY:20,taskMargin:50,width:150,height:50,taskFontSize:14,taskFontFamily:'"Open-Sans", "sans-serif"',boxMargin:10,boxTextMargin:5,noteMargin:10,messageMargin:35,messageAlign:"center",bottomMarginAdj:1,activationWidth:10,textPlacement:"fo",actorColours:["#8FBC8F","#7CFC00","#00FFFF","#20B2AA","#B0E0E6","#FFFFE0"],sectionFills:["#191970","#8B008B","#4B0082","#2F4F4F","#800000","#8B4513","#00008B"],sectionColours:["#fff"]},So={};var Mo=Ao.leftMargin,Oo={data:{startx:void 0,stopx:void 0,starty:void 0,stopy:void 0},verticalPos:0,sequenceItems:[],init:function(){this.sequenceItems=[],this.data={startx:void 0,stopx:void 0,starty:void 0,stopy:void 0},this.verticalPos=0},updateVal:function(t,e,n,r){void 0===t[e]?t[e]=n:t[e]=r(n,t[e])},updateBounds:function(t,e,n,r){var i,a=this,o=0;this.sequenceItems.forEach((function(s){o++;var c=a.sequenceItems.length-o+1;a.updateVal(s,"starty",e-c*Ao.boxMargin,Math.min),a.updateVal(s,"stopy",r+c*Ao.boxMargin,Math.max),a.updateVal(Oo.data,"startx",t-c*Ao.boxMargin,Math.min),a.updateVal(Oo.data,"stopx",n+c*Ao.boxMargin,Math.max),"activation"!==i&&(a.updateVal(s,"startx",t-c*Ao.boxMargin,Math.min),a.updateVal(s,"stopx",n+c*Ao.boxMargin,Math.max),a.updateVal(Oo.data,"starty",e-c*Ao.boxMargin,Math.min),a.updateVal(Oo.data,"stopy",r+c*Ao.boxMargin,Math.max))}))},insert:function(t,e,n,r){var i=Math.min(t,n),a=Math.max(t,n),o=Math.min(e,r),s=Math.max(e,r);this.updateVal(Oo.data,"startx",i,Math.min),this.updateVal(Oo.data,"starty",o,Math.min),this.updateVal(Oo.data,"stopx",a,Math.max),this.updateVal(Oo.data,"stopy",s,Math.max),this.updateBounds(i,o,a,s)},bumpVerticalPos:function(t){this.verticalPos=this.verticalPos+t,this.data.stopy=this.verticalPos},getVerticalPos:function(){return this.verticalPos},getBounds:function(){return this.data}},Do=Ao.sectionFills,No=Ao.sectionColours,Bo=function(t,e,n){for(var r="",i=n+(2*Ao.height+Ao.diagramMarginY),a=0,o="#CCC",s="black",c=0,u=0;u tspan {\n fill: ").concat(t.actorTextColor,";\n stroke: none;\n }\n\n .actor-line {\n stroke: ").concat(t.actorLineColor,";\n }\n\n .messageLine0 {\n stroke-width: 1.5;\n stroke-dasharray: none;\n stroke: ").concat(t.signalColor,";\n }\n\n .messageLine1 {\n stroke-width: 1.5;\n stroke-dasharray: 2, 2;\n stroke: ").concat(t.signalColor,";\n }\n\n #arrowhead path {\n fill: ").concat(t.signalColor,";\n stroke: ").concat(t.signalColor,";\n }\n\n .sequenceNumber {\n fill: ").concat(t.sequenceNumberColor,";\n }\n\n #sequencenumber {\n fill: ").concat(t.signalColor,";\n }\n\n #crosshead path {\n fill: ").concat(t.signalColor,";\n stroke: ").concat(t.signalColor,";\n }\n\n .messageText {\n fill: ").concat(t.signalTextColor,";\n stroke: ").concat(t.signalTextColor,";\n }\n\n .labelBox {\n stroke: ").concat(t.labelBoxBorderColor,";\n fill: ").concat(t.labelBoxBkgColor,";\n }\n\n .labelText, .labelText > tspan {\n fill: ").concat(t.labelTextColor,";\n stroke: none;\n }\n\n .loopText, .loopText > tspan {\n fill: ").concat(t.loopTextColor,";\n stroke: none;\n }\n\n .loopLine {\n stroke-width: 2px;\n stroke-dasharray: 2, 2;\n stroke: ").concat(t.labelBoxBorderColor,";\n fill: ").concat(t.labelBoxBorderColor,";\n }\n\n .note {\n //stroke: #decc93;\n stroke: ").concat(t.noteBorderColor,";\n fill: ").concat(t.noteBkgColor,";\n }\n\n .noteText, .noteText > tspan {\n fill: ").concat(t.noteTextColor,";\n stroke: none;\n }\n\n .activation0 {\n fill: ").concat(t.activationBkgColor,";\n stroke: ").concat(t.activationBorderColor,";\n }\n\n .activation1 {\n fill: ").concat(t.activationBkgColor,";\n stroke: ").concat(t.activationBorderColor,";\n }\n\n .activation2 {\n fill: ").concat(t.activationBkgColor,";\n stroke: ").concat(t.activationBorderColor,";\n }\n")},gantt:function(t){return'\n .mermaid-main-font {\n font-family: "trebuchet ms", verdana, arial, sans-serif;\n font-family: var(--mermaid-font-family);\n }\n\n .section {\n stroke: none;\n opacity: 0.2;\n }\n\n .section0 {\n fill: '.concat(t.sectionBkgColor,";\n }\n\n .section2 {\n fill: ").concat(t.sectionBkgColor2,";\n }\n\n .section1,\n .section3 {\n fill: ").concat(t.altSectionBkgColor,";\n opacity: 0.2;\n }\n\n .sectionTitle0 {\n fill: ").concat(t.titleColor,";\n }\n\n .sectionTitle1 {\n fill: ").concat(t.titleColor,";\n }\n\n .sectionTitle2 {\n fill: ").concat(t.titleColor,";\n }\n\n .sectionTitle3 {\n fill: ").concat(t.titleColor,";\n }\n\n .sectionTitle {\n text-anchor: start;\n font-size: 11px;\n text-height: 14px;\n font-family: 'trebuchet ms', verdana, arial, sans-serif;\n font-family: var(--mermaid-font-family);\n\n }\n\n\n /* Grid and axis */\n\n .grid .tick {\n stroke: ").concat(t.gridColor,";\n opacity: 0.8;\n shape-rendering: crispEdges;\n text {\n font-family: ").concat(t.fontFamily,";\n fill: ").concat(t.textColor,";\n }\n }\n\n .grid path {\n stroke-width: 0;\n }\n\n\n /* Today line */\n\n .today {\n fill: none;\n stroke: ").concat(t.todayLineColor,";\n stroke-width: 2px;\n }\n\n\n /* Task styling */\n\n /* Default task */\n\n .task {\n stroke-width: 2;\n }\n\n .taskText {\n text-anchor: middle;\n font-family: 'trebuchet ms', verdana, arial, sans-serif;\n font-family: var(--mermaid-font-family);\n }\n\n .taskText:not([font-size]) {\n font-size: 11px;\n }\n\n .taskTextOutsideRight {\n fill: ").concat(t.taskTextDarkColor,";\n text-anchor: start;\n font-size: 11px;\n font-family: 'trebuchet ms', verdana, arial, sans-serif;\n font-family: var(--mermaid-font-family);\n\n }\n\n .taskTextOutsideLeft {\n fill: ").concat(t.taskTextDarkColor,";\n text-anchor: end;\n font-size: 11px;\n }\n\n /* Special case clickable */\n .task.clickable {\n cursor: pointer;\n }\n .taskText.clickable {\n cursor: pointer;\n fill: ").concat(t.taskTextClickableColor," !important;\n font-weight: bold;\n }\n\n .taskTextOutsideLeft.clickable {\n cursor: pointer;\n fill: ").concat(t.taskTextClickableColor," !important;\n font-weight: bold;\n }\n\n .taskTextOutsideRight.clickable {\n cursor: pointer;\n fill: ").concat(t.taskTextClickableColor," !important;\n font-weight: bold;\n }\n\n /* Specific task settings for the sections*/\n\n .taskText0,\n .taskText1,\n .taskText2,\n .taskText3 {\n fill: ").concat(t.taskTextColor,";\n }\n\n .task0,\n .task1,\n .task2,\n .task3 {\n fill: ").concat(t.taskBkgColor,";\n stroke: ").concat(t.taskBorderColor,";\n }\n\n .taskTextOutside0,\n .taskTextOutside2\n {\n fill: ").concat(t.taskTextOutsideColor,";\n }\n\n .taskTextOutside1,\n .taskTextOutside3 {\n fill: ").concat(t.taskTextOutsideColor,";\n }\n\n\n /* Active task */\n\n .active0,\n .active1,\n .active2,\n .active3 {\n fill: ").concat(t.activeTaskBkgColor,";\n stroke: ").concat(t.activeTaskBorderColor,";\n }\n\n .activeText0,\n .activeText1,\n .activeText2,\n .activeText3 {\n fill: ").concat(t.taskTextDarkColor," !important;\n }\n\n\n /* Completed task */\n\n .done0,\n .done1,\n .done2,\n .done3 {\n stroke: ").concat(t.doneTaskBorderColor,";\n fill: ").concat(t.doneTaskBkgColor,";\n stroke-width: 2;\n }\n\n .doneText0,\n .doneText1,\n .doneText2,\n .doneText3 {\n fill: ").concat(t.taskTextDarkColor," !important;\n }\n\n\n /* Tasks on the critical line */\n\n .crit0,\n .crit1,\n .crit2,\n .crit3 {\n stroke: ").concat(t.critBorderColor,";\n fill: ").concat(t.critBkgColor,";\n stroke-width: 2;\n }\n\n .activeCrit0,\n .activeCrit1,\n .activeCrit2,\n .activeCrit3 {\n stroke: ").concat(t.critBorderColor,";\n fill: ").concat(t.activeTaskBkgColor,";\n stroke-width: 2;\n }\n\n .doneCrit0,\n .doneCrit1,\n .doneCrit2,\n .doneCrit3 {\n stroke: ").concat(t.critBorderColor,";\n fill: ").concat(t.doneTaskBkgColor,";\n stroke-width: 2;\n cursor: pointer;\n shape-rendering: crispEdges;\n }\n\n .milestone {\n transform: rotate(45deg) scale(0.8,0.8);\n }\n\n .milestoneText {\n font-style: italic;\n }\n .doneCritText0,\n .doneCritText1,\n .doneCritText2,\n .doneCritText3 {\n fill: ").concat(t.taskTextDarkColor," !important;\n }\n\n .activeCritText0,\n .activeCritText1,\n .activeCritText2,\n .activeCritText3 {\n fill: ").concat(t.taskTextDarkColor," !important;\n }\n\n .titleText {\n text-anchor: middle;\n font-size: 18px;\n fill: ").concat(t.textColor," ;\n font-family: 'trebuchet ms', verdana, arial, sans-serif;\n font-family: var(--mermaid-font-family);\n }\n")},classDiagram:Po,"classDiagram-v2":Po,class:Po,stateDiagram:jo,state:jo,git:function(){return"\n .commit-id,\n .commit-msg,\n .branch-label {\n fill: lightgrey;\n color: lightgrey;\n font-family: 'trebuchet ms', verdana, arial, sans-serif;\n font-family: var(--mermaid-font-family);\n }\n"},info:function(){return""},pie:function(t){return".pieTitleText {\n text-anchor: middle;\n font-size: 25px;\n fill: ".concat(t.taskTextDarkColor,";\n font-family: ").concat(t.fontFamily,";\n }\n .slice {\n font-family: ").concat(t.fontFamily,";\n fill: ").concat(t.textColor,";\n // fill: white;\n }\n .legend text {\n fill: ").concat(t.taskTextDarkColor,";\n font-family: ").concat(t.fontFamily,";\n font-size: 17px;\n }\n")},er:function(t){return"\n .entityBox {\n fill: ".concat(t.mainBkg,";\n stroke: ").concat(t.nodeBorder,";\n }\n\n .attributeBoxOdd {\n fill: #ffffff;\n stroke: ").concat(t.nodeBorder,";\n }\n\n .attributeBoxEven {\n fill: #f2f2f2;\n stroke: ").concat(t.nodeBorder,";\n }\n\n .relationshipLabelBox {\n fill: ").concat(t.tertiaryColor,";\n opacity: 0.7;\n background-color: ").concat(t.tertiaryColor,";\n rect {\n opacity: 0.5;\n }\n }\n\n .relationshipLine {\n stroke: ").concat(t.lineColor,";\n }\n")},journey:function(t){return".label {\n font-family: 'trebuchet ms', verdana, arial, sans-serif;\n font-family: var(--mermaid-font-family);\n color: ".concat(t.textColor,";\n }\n .mouth {\n stroke: #666;\n }\n\n line {\n stroke: ").concat(t.textColor,"\n }\n\n .legend {\n fill: ").concat(t.textColor,";\n }\n\n .label text {\n fill: #333;\n }\n .label {\n color: ").concat(t.textColor,"\n }\n\n .face {\n fill: #FFF8DC;\n stroke: #999;\n }\n\n .node rect,\n .node circle,\n .node ellipse,\n .node polygon,\n .node path {\n fill: ").concat(t.mainBkg,";\n stroke: ").concat(t.nodeBorder,";\n stroke-width: 1px;\n }\n\n .node .label {\n text-align: center;\n }\n .node.clickable {\n cursor: pointer;\n }\n\n .arrowheadPath {\n fill: ").concat(t.arrowheadColor,";\n }\n\n .edgePath .path {\n stroke: ").concat(t.lineColor,";\n stroke-width: 1.5px;\n }\n\n .flowchart-link {\n stroke: ").concat(t.lineColor,";\n fill: none;\n }\n\n .edgeLabel {\n background-color: ").concat(t.edgeLabelBackground,";\n rect {\n opacity: 0.5;\n }\n text-align: center;\n }\n\n .cluster rect {\n }\n\n .cluster text {\n fill: ").concat(t.titleColor,";\n }\n\n div.mermaidTooltip {\n position: absolute;\n text-align: center;\n max-width: 200px;\n padding: 2px;\n font-family: 'trebuchet ms', verdana, arial, sans-serif;\n font-family: var(--mermaid-font-family);\n font-size: 12px;\n background: ").concat(t.tertiaryColor,";\n border: 1px solid ").concat(t.border2,";\n border-radius: 2px;\n pointer-events: none;\n z-index: 100;\n }\n\n .task-type-0, .section-type-0 {\n ").concat(t.fillType0?"fill: ".concat(t.fillType0):"",";\n }\n .task-type-1, .section-type-1 {\n ").concat(t.fillType0?"fill: ".concat(t.fillType1):"",";\n }\n .task-type-2, .section-type-2 {\n ").concat(t.fillType0?"fill: ".concat(t.fillType2):"",";\n }\n .task-type-3, .section-type-3 {\n ").concat(t.fillType0?"fill: ".concat(t.fillType3):"",";\n }\n .task-type-4, .section-type-4 {\n ").concat(t.fillType0?"fill: ".concat(t.fillType4):"",";\n }\n .task-type-5, .section-type-5 {\n ").concat(t.fillType0?"fill: ".concat(t.fillType5):"",";\n }\n .task-type-6, .section-type-6 {\n ").concat(t.fillType0?"fill: ".concat(t.fillType6):"",";\n }\n .task-type-7, .section-type-7 {\n ").concat(t.fillType0?"fill: ".concat(t.fillType7):"",";\n }\n")}},Yo=function(t,e,n){return" {\n font-family: ".concat(n.fontFamily,";\n font-size: ").concat(n.fontSize,";\n fill: ").concat(n.textColor,"\n }\n\n /* Classes common for multiple diagrams */\n\n .error-icon {\n fill: ").concat(n.errorBkgColor,";\n }\n .error-text {\n fill: ").concat(n.errorTextColor,";\n stroke: ").concat(n.errorTextColor,";\n }\n\n .edge-thickness-normal {\n stroke-width: 2px;\n }\n .edge-thickness-thick {\n stroke-width: 3.5px\n }\n .edge-pattern-solid {\n stroke-dasharray: 0;\n }\n\n .edge-pattern-dashed{\n stroke-dasharray: 3;\n }\n .edge-pattern-dotted {\n stroke-dasharray: 2;\n }\n\n .marker {\n fill: ").concat(n.lineColor,";\n }\n .marker.cross {\n stroke: ").concat(n.lineColor,";\n }\n\n svg {\n font-family: ").concat(n.fontFamily,";\n font-size: ").concat(n.fontSize,";\n }\n\n ").concat(Ro[t](n),"\n\n ").concat(e,"\n\n ").concat(t," { fill: apa;}\n")};function zo(t){return(zo="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}var Uo={},$o=function(t,e,n){switch(c.debug("Directive type=".concat(e.type," with args:"),e.args),e.type){case"init":case"initialize":["config"].forEach((function(t){void 0!==e.args[t]&&("flowchart-v2"===n&&(n="flowchart"),e.args[n]=e.args[t],delete e.args[t])})),e.args,wt(e.args);break;case"wrap":case"nowrap":t&&t.setWrap&&t.setWrap("wrap"===e.type);break;default:c.warn("Unhandled directive: source: '%%{".concat(e.type,": ").concat(JSON.stringify(e.args?e.args:{}),"}%%"),e)}};function Wo(t){ka(t.git),me(t.flowchart),Ln(t.flowchart),void 0!==t.sequenceDiagram&&_r.setConf(I(t.sequence,t.sequenceDiagram)),_r.setConf(t.sequence),ri(t.gantt),li(t.class),zi(t.state),qi(t.state),Oa(t.class),za(t.class),ro(t.er),Lo(t.journey),Ba(t.class)}function Ho(){}var Vo=Object.freeze({render:function(t,e,n,r){Et();var i=e,a=H.detectInit(i);a&&wt(a);var o=_t();if(e.length>o.maxTextSize&&(i="graph TB;a[Maximum text size in diagram exceeded];style a fill:#faa"),void 0!==r)r.innerHTML="",Object(d.select)(r).append("div").attr("id","d"+t).attr("style","font-family: "+o.fontFamily).append("svg").attr("id",t).attr("width","100%").attr("xmlns","http://www.w3.org/2000/svg").append("g");else{var s=document.getElementById(t);s&&s.remove();var u=document.querySelector("#d"+t);u&&u.remove(),Object(d.select)("body").append("div").attr("id","d"+t).append("svg").attr("id",t).attr("width","100%").attr("xmlns","http://www.w3.org/2000/svg").append("g")}window.txt=i,i=function(t){var e=t;return e=(e=(e=e.replace(/style.*:\S*#.*;/g,(function(t){return t.substring(0,t.length-1)}))).replace(/classDef.*:\S*#.*;/g,(function(t){return t.substring(0,t.length-1)}))).replace(/#\w+;/g,(function(t){var e=t.substring(1,t.length-1);return/^\+?\d+$/.test(e)?"fl°°"+e+"¶ß":"fl°"+e+"¶ß"}))}(i);var l=Object(d.select)("#d"+t).node(),h=H.detectType(i),g=l.firstChild,y=g.firstChild,v="";if(void 0!==o.themeCSS&&(v+="\n".concat(o.themeCSS)),void 0!==o.fontFamily&&(v+="\n:root { --mermaid-font-family: ".concat(o.fontFamily,"}")),void 0!==o.altFontFamily&&(v+="\n:root { --mermaid-alt-font-family: ".concat(o.altFontFamily,"}")),"flowchart"===h||"flowchart-v2"===h||"graph"===h){var m=be(i);for(var b in m)v+="\n.".concat(b," > * { ").concat(m[b].styles.join(" !important; ")," !important; }"),m[b].textStyles&&(v+="\n.".concat(b," tspan { ").concat(m[b].textStyles.join(" !important; ")," !important; }"))}var x=(new f.a)("#".concat(t),Yo(h,v,o.themeVariables)),_=document.createElement("style");_.innerHTML=x,g.insertBefore(_,y);try{switch(h){case"git":o.flowchart.arrowMarkerAbsolute=o.arrowMarkerAbsolute,ka(o.git),wa(i,t,!1);break;case"flowchart":o.flowchart.arrowMarkerAbsolute=o.arrowMarkerAbsolute,me(o.flowchart),xe(i,t,!1);break;case"flowchart-v2":o.flowchart.arrowMarkerAbsolute=o.arrowMarkerAbsolute,Ln(o.flowchart),Fn(i,t,!1);break;case"sequence":o.sequence.arrowMarkerAbsolute=o.arrowMarkerAbsolute,o.sequenceDiagram?(_r.setConf(Object.assign(o.sequence,o.sequenceDiagram)),console.error("`mermaid config.sequenceDiagram` has been renamed to `config.sequence`. Please update your mermaid config.")):_r.setConf(o.sequence),_r.draw(i,t);break;case"gantt":o.gantt.arrowMarkerAbsolute=o.arrowMarkerAbsolute,ri(o.gantt),ii(i,t);break;case"class":o.class.arrowMarkerAbsolute=o.arrowMarkerAbsolute,li(o.class),hi(i,t);break;case"classDiagram":o.class.arrowMarkerAbsolute=o.arrowMarkerAbsolute,di(o.class),pi(i,t);break;case"state":o.class.arrowMarkerAbsolute=o.arrowMarkerAbsolute,zi(o.state),Ui(i,t);break;case"stateDiagram":o.class.arrowMarkerAbsolute=o.arrowMarkerAbsolute,qi(o.state),Xi(i,t);break;case"info":o.class.arrowMarkerAbsolute=o.arrowMarkerAbsolute,Oa(o.class),Da(i,t,p.version);break;case"pie":o.class.arrowMarkerAbsolute=o.arrowMarkerAbsolute,za(o.pie),Ua(i,t,p.version);break;case"er":ro(o.er),io(i,t,p.version);break;case"journey":Lo(o.journey),Fo(i,t,p.version)}}catch(e){throw La(t,p.version),e}Object(d.select)('[id="'.concat(t,'"]')).selectAll("foreignobject > *").attr("xmlns","http://www.w3.org/1999/xhtml");var k=Object(d.select)("#d"+t).node().innerHTML;if(c.debug("cnf.arrowMarkerAbsolute",o.arrowMarkerAbsolute),o.arrowMarkerAbsolute&&"false"!==o.arrowMarkerAbsolute||(k=k.replace(/marker-end="url\(.*?#/g,'marker-end="url(#',"g")),k=function(t){var e=t;return e=(e=(e=e.replace(/fl°°/g,(function(){return"&#"}))).replace(/fl°/g,(function(){return"&"}))).replace(/¶ß/g,(function(){return";"}))}(k),void 0!==n)switch(h){case"flowchart":case"flowchart-v2":n(k,Xt.bindFunctions);break;case"gantt":n(k,Qr.bindFunctions);break;case"class":case"classDiagram":n(k,cn.bindFunctions);break;default:n(k)}else c.debug("CB = undefined!");var w=Object(d.select)("#d"+t).node();return null!==w&&"function"==typeof w.remove&&Object(d.select)("#d"+t).node().remove(),k},parse:function(t){var e=H.detectInit(t);e&&c.debug("reinit ",e);var n,r=H.detectType(t);switch(c.debug("Type "+r),r){case"git":(n=ha.a).parser.yy=ua;break;case"flowchart":case"flowchart-v2":Xt.clear(),(n=Jt.a).parser.yy=Xt;break;case"sequence":(n=Hn.a).parser.yy=sr;break;case"gantt":(n=wr.a).parser.yy=Qr;break;case"class":case"classDiagram":(n=oi.a).parser.yy=cn;break;case"state":case"stateDiagram":(n=Di.a).parser.yy=Mi;break;case"info":c.debug("info info info"),(n=Sa.a).parser.yy=Ca;break;case"pie":c.debug("pie"),(n=Ra.a).parser.yy=Ia;break;case"er":c.debug("er"),(n=Xa.a).parser.yy=Ga;break;case"journey":c.debug("Journey"),(n=oo.a).parser.yy=go}return n.parser.yy.graphType=r,n.parser.yy.parseError=function(t,e){throw{str:t,hash:e}},n.parse(t),n},parseDirective:function(t,e,n,r){try{if(void 0!==e)switch(e=e.trim(),n){case"open_directive":Uo={};break;case"type_directive":Uo.type=e.toLowerCase();break;case"arg_directive":Uo.args=JSON.parse(e);break;case"close_directive":$o(t,Uo,r),Uo=null}}catch(t){c.error("Error while rendering sequenceDiagram directive: ".concat(e," jison context: ").concat(n)),c.error(t.message)}},initialize:function(t){t&&t.fontFamily&&(t.themeVariables&&t.themeVariables.fontFamily||(t.themeVariables={fontFamily:t.fontFamily})),dt=I({},t),t&&t.theme&&ht[t.theme]?t.themeVariables=ht[t.theme].getThemeVariables(t.themeVariables):t&&(t.themeVariables=ht.default.getThemeVariables(t.themeVariables));var e="object"===zo(t)?function(t){return yt=I({},gt),yt=I(yt,t),t.theme&&(yt.themeVariables=ht[t.theme].getThemeVariables(t.themeVariables)),mt=bt(yt,vt),yt}(t):xt();Wo(e),u(e.logLevel)},reinitialize:Ho,getConfig:_t,setConfig:function(t){return I(mt,t),_t()},getSiteConfig:xt,updateSiteConfig:function(t){return yt=I(yt,t),bt(yt,vt),yt},reset:function(){Et()},globalReset:function(){Et(),Wo(_t())},defaultConfig:gt});u(_t().logLevel),Et(_t());var Go=Vo,qo=function(){Xo.startOnLoad?Go.getConfig().startOnLoad&&Xo.init():void 0===Xo.startOnLoad&&(c.debug("In start, no config"),Go.getConfig().startOnLoad&&Xo.init())};"undefined"!=typeof document&& +/*! + * Wait for document loaded before starting the execution + */ +window.addEventListener("load",(function(){qo()}),!1);var Xo={startOnLoad:!0,htmlLabels:!0,mermaidAPI:Go,parse:Go.parse,render:Go.render,init:function(){var t,e,n=this,r=Go.getConfig();arguments.length>=2?( +/*! sequence config was passed as #1 */ +void 0!==arguments[0]&&(Xo.sequenceConfig=arguments[0]),t=arguments[1]):t=arguments[0],"function"==typeof arguments[arguments.length-1]?(e=arguments[arguments.length-1],c.debug("Callback function found")):void 0!==r.mermaid&&("function"==typeof r.mermaid.callback?(e=r.mermaid.callback,c.debug("Callback function found")):c.debug("No Callback function found")),t=void 0===t?document.querySelectorAll(".mermaid"):"string"==typeof t?document.querySelectorAll(t):t instanceof window.Node?[t]:t,c.debug("Start On Load before: "+Xo.startOnLoad),void 0!==Xo.startOnLoad&&(c.debug("Start On Load inner: "+Xo.startOnLoad),Go.updateSiteConfig({startOnLoad:Xo.startOnLoad})),void 0!==Xo.ganttConfig&&Go.updateSiteConfig({gantt:Xo.ganttConfig});for(var a,o=H.initIdGeneratior(r.deterministicIds,r.deterministicIDSeed).next,s=function(r){var s=t[r]; +/*! Check if previously processed */if(s.getAttribute("data-processed"))return"continue";s.setAttribute("data-processed",!0);var u="mermaid-".concat(o());a=i(a=s.innerHTML).trim().replace(//gi,"
");var l=H.detectInit(a);l&&c.debug("Detected early reinit: ",l);try{Go.render(u,a,(function(t,n){s.innerHTML=t,void 0!==e&&e(u),n&&n(s)}),s)}catch(t){c.warn("Syntax Error rendering"),c.warn(t),n.parseError&&n.parseError(t)}},u=0;u ⚠️ Here lay dragons: this codebase is still experimental, try at your own risk! + +## About the documentation + +The two main sections of this book are: + +- [Exploration](./explore): documents the process of exploring the design and implementation space for Anoma +- [Specifications](./specs): implementation independent technical specifications + +The Anoma user guide and networks documentation can be found at . + +### The source + +This book is written using [mdBook](https://rust-lang.github.io/mdBook/) with [mdbook-mermaid](https://github.com/badboy/mdbook-mermaid) for diagrams, it currently lives in the [Anoma repo](https://github.com/anoma/anoma). + +To get started quickly, in the `docs` directory one can: + +```shell +# Install dependencies +make dev-deps + +# This will open the book in your default browser and rebuild on changes +make serve +``` + +The mermaid diagrams docs can be found at . + +[Contributions](https://github.com/anoma/anoma/issues) to the contents and the structure of this book (nothing is set in stone) should be made via pull requests. Code changes that diverge from the spec should also update this book. diff --git a/documentation/dev/src/SUMMARY.md b/documentation/dev/src/SUMMARY.md new file mode 100644 index 0000000000..f0d84c6afa --- /dev/null +++ b/documentation/dev/src/SUMMARY.md @@ -0,0 +1,63 @@ +# Summary + +- [Introduction](./README.md) +- [Exploration](./explore/README.md) + - [Design](./explore/design/README.md) + - [Overview](./explore/design/overview.md) + - [Gossip network](./explore/design/gossip.md) + - [Intent gossip](./explore/design/intent_gossip/intent_gossip.md) + - [Intent](./explore/design/intent_gossip/intent.md) + - [Topic](./explore/design/intent_gossip/topic.md) + - [Incentive](./explore/design/intent_gossip/incentive.md) + - [Matchmaker](./explore/design/intent_gossip/matchmaker.md) + - [Fungible token](./explore/design/intent_gossip/fungible_token.md) + - [Distributed key generation gossip](./explore/design/dkg.md) + - [The ledger](./explore/design/ledger.md) + - [Parameters](./explore/design/ledger/parameters.md) + - [Epochs](./explore/design/ledger/epochs.md) + - [Accounts](./explore/design/ledger/accounts.md) + - [Validity predicates](./explore/design/ledger/vp.md) + - [Transactions](./explore/design/ledger/tx.md) + - [WASM VM](./explore/design/ledger/wasm-vm.md) + - [Front-running prevention](./explore/design/ledger/front-running.md) + - [Fractal scaling](./explore/design/ledger/fractal-scaling.md) + - [Upgrade system](./explore/design/upgrade-system.md) + - [Storage](./explore/design/ledger/storage.md) + - [Data schema](./explore/design/ledger/storage/data-schema.md) + - [PoS integration](./explore/design/ledger/pos-integration.md) + - [Crypto primitives](./explore/design/crypto-primitives.md) + - [Actors](./explore/design/actors.md) + - [Proof of Stake system](./explore/design/pos.md) + - [Testnet setup](./explore/design/testnet-setup.md) + - [Testnet launch procedure](./explore/design/testnet-launch-procedure/README.md) + - [Prototypes](./explore/prototypes/README.md) + - [Base ledger](./explore/prototypes/base-ledger.md) + - [Gossip layer](./explore/prototypes/gossip-layer.md) + - [Libraries & Tools](./explore/libraries/README.md) + - [Cryptography]() + - [network](./explore/libraries/network.md) + - [Command-line interface](./explore/libraries/cli.md) + - [Database](./explore/libraries/db.md) + - [Logging](./explore/libraries/logging.md) + - [Networking]() + - [Packaging](./explore/libraries/packaging.md) + - [Serialization](./explore/libraries/serialization.md) + - [WASM runtime](./explore/libraries/wasm.md) + - [Error handling](./explore/libraries/errors.md) + - [Glossary](./explore/design/glossary.md) + - [Resources](./explore/resources/README.md) + - [IDE](./explore/resources/ide.md) +- [Specifications](./specs/README.md) + - [Overview](./specs/overview.md) + - [The ledger](./specs/ledger.md) + - [RPC](./specs/ledger/rpc.md) + - [Default transactions](./specs/ledger/default-transactions.md) + - [Default validity predicates](./specs/ledger/default-validity-predicates.md) + - [Trade system]() + - [Intent gossip system]() + - [Fractal scaling]() + - [Upgrade system]() + - [Crypto](./specs/crypto.md) + - [Encoding](./specs/encoding.md) +- [Archive](./archive/README.md) + - [Domain name addresses](./archive/domain-name-addresses.md) diff --git a/documentation/dev/src/archive/README.md b/documentation/dev/src/archive/README.md new file mode 100644 index 0000000000..415bb0a8b9 --- /dev/null +++ b/documentation/dev/src/archive/README.md @@ -0,0 +1,3 @@ +# Archive + +Deprecated pages archived for possible later re-use. diff --git a/documentation/dev/src/archive/domain-name-addresses.md b/documentation/dev/src/archive/domain-name-addresses.md new file mode 100644 index 0000000000..0b752202ae --- /dev/null +++ b/documentation/dev/src/archive/domain-name-addresses.md @@ -0,0 +1,21 @@ +# Domain name addresses + +The transparent addresses are similar to domain names and the ones used in e.g. [ENS as specified in EIP-137](https://eips.ethereum.org/EIPS/eip-137) and [account IDs in Near protocol](https://nomicon.io/DataStructures/Account.html). These are the addresses of accounts associated with dynamic storage sub-spaces, where the address of the account is the prefix key segment of its sub-space. + +A transparent address is a human-readable string very similar to a domain name, containing only alpha-numeric ASCII characters, hyphen (`-`) and full stop (`.`) as a separator between the "labels" of the address. The letter case is not significant and any upper case letters are converted to lower case. The last label of an address is said to be the top-level name and each predecessor segment is the sub-name of its successor. + +The length of an address must be at least 3 characters. For compatibility with a legacy DNS TXT record, we'll use syntax as defined in [RFC-1034 - section 3.5 DNS preferred name syntax](https://www.ietf.org/rfc/rfc1034.txt). That is, the upper limit is 255 characters and 63 for each label in an address (which should be sufficient anyway); and the label must not begin or end with hyphen (`-`) and must not begin with a digit. + +These addresses can be chosen by users who wish to [initialize a new account](#initializing-a-new-account), following these rules: + +- a new address must be initialized on-chain + - each sub-label must be authorized by the predecessor level address (e.g. initializing address `free.eth` must be authorized by `eth`, or `gives.free.eth` by `free.eth`, etc.) + - note that besides the address creation, each address level is considered to be a distinct address with its own dynamic storage sub-space and validity predicate. +- the top-level names under certain length (to be specified) cannot be initialized directly, they may be [auctioned like in ENS registrar as described in EIP-162](https://eips.ethereum.org/EIPS/eip-162). + - some top-level names may be reserved + +For convenience, the `anoma` top-level address is initially setup to allow initialization of any previously unused second-level address, e.g. `bob.anoma` (we may want to revise this before launch to e.g. auction the short ones, like with top-level names to make the process fairer). + +Like in ENS, the addresses are stored on chain by their hash, encoded with [bech32m](https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki) ([not yet adopted in Zcash](https://github.com/zcash/zips/issues/484)), which is an improved version of [bech32](https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki). Likewise, this is for two reasons: +- help preserve privacy of addresses that were not revealed publicly and to prevent trivial enumeration of registered names (of course, you can still try to enumerate by hashes) +- using fixed-length string in the ledger simplifies gas accounting diff --git a/documentation/dev/src/explore/README.md b/documentation/dev/src/explore/README.md new file mode 100644 index 0000000000..fc5b5117cf --- /dev/null +++ b/documentation/dev/src/explore/README.md @@ -0,0 +1,5 @@ +# Exploration + +This section documents the process of exploring the design and implementation space for Anoma. Ideally, the captured information should provide an overview of the explored space and help to guide further decisions. + +The content of this section is more free-form. This is largely a cross-over of both the implementation details and the design of implementation-independent specifications. diff --git a/documentation/dev/src/explore/design/README.md b/documentation/dev/src/explore/design/README.md new file mode 100644 index 0000000000..ca7061372f --- /dev/null +++ b/documentation/dev/src/explore/design/README.md @@ -0,0 +1,3 @@ +# Design + +This section covers the exploration of the possible design directions of the involved components. diff --git a/documentation/dev/src/explore/design/actors.md b/documentation/dev/src/explore/design/actors.md new file mode 100644 index 0000000000..d742097db7 --- /dev/null +++ b/documentation/dev/src/explore/design/actors.md @@ -0,0 +1,41 @@ +# Actors and Incentives + +Anoma consists of various actors fulfilling various roles in the network. They are all incentivized to act for the good of the network. The native Anoma token `XAN` is used to settle transaction fees and pay for the incentives in Anoma. + +## Fees associated with a transaction + +Users of Anoma can + +- transfer private assets they hold to other users and +- barter assets with other users. + +Each transaction may be associated with the following fees, paid in `XAN`: + +- **Execution fees** to compensate for computing, storage and memory costs, charges at 2 stages: + - **initial fee (init_f)**: charged before the transaction is settled + - **post-execution fee (exe_f)**: charged after the settlement +- **Exchange fee (ex_f)**: a fee proportional to the value exchanged in a trade + +## Actors and their associated fees and responsibilities + +| Actor | Responsibilities | Incentives | Bond in escrow | May also be | +|---|---|---|---|---| +| User | Make offers or send transactions | Features of Anoma | X | Anyone | +| Signer | Generate key shards | portions of init_f, exe_f | ✓ | Validator | +| Validator | Validate | portions of init_f, exe_f |✓ | Signer | +| Submitter | Submit orders & pay init_f | successful orders get init_f back plus bonus | X | | +| Intent gossip operator | Signs and shares orders | portions of init_f, exe_f | X | | +| Market maker | Signs and broadcast orders | the difference between the ask and bid price | X | | +| Proposer | Proposes blocks | portions of init_f, exe_f | | Validator | + +Questions to explore: + +- How do we calculate the incentives? What are the equations for each actor? + +- How do we calculate the bond/reward for the signers and validators? + +- How do we ensure certain dual/multi agencies are allowed but not others? E.g., signers can be validators but we may not want them to be proposers because they may have knowledge of which transactions are encrypted. + +## Actors and fees flowchart + +![Summary](summary.png?raw=true) diff --git a/documentation/dev/src/explore/design/crypto-primitives.md b/documentation/dev/src/explore/design/crypto-primitives.md new file mode 100644 index 0000000000..81f68cb791 --- /dev/null +++ b/documentation/dev/src/explore/design/crypto-primitives.md @@ -0,0 +1,7 @@ +# Crypto primitives + +[Tracking Issue](https://github.com/anoma/anoma/issues/39) + +--- + +This page should describe cryptography primitives that we might want to use, such as types of keys, hashing functions, etc. diff --git a/documentation/dev/src/explore/design/dkg.md b/documentation/dev/src/explore/design/dkg.md new file mode 100644 index 0000000000..204b89c63c --- /dev/null +++ b/documentation/dev/src/explore/design/dkg.md @@ -0,0 +1,2 @@ +# Distributed key generation gossip +> ⚠️ This section is WIP. diff --git a/documentation/dev/src/explore/design/glossary.md b/documentation/dev/src/explore/design/glossary.md new file mode 100644 index 0000000000..7de0447091 --- /dev/null +++ b/documentation/dev/src/explore/design/glossary.md @@ -0,0 +1,17 @@ +# Glossary + +[comment]: <> (Each item in the list below has to be followed by 2 spaces with the description on the very next line) + +- **intent gossip** +The intent gossip network must maintain a mempool of intents and gossips them +via a p2p layer. Each intent gossip node maintains a list of interests that +describe what intents it is interested in. +- **intent** +An expression of intent describes a particular trade an account agrees to. +- **matchmaker** +The matchmaker tries to match intents together. For each match it crafts a valid +transaction and submits it to the base ledger. +- **validity predicate (VP)** +A [validity predicate](ledger/vp.html) is a piece of code +attached to an account that can accept or reject any state changes performed by +a transaction in its sub-space. diff --git a/documentation/dev/src/explore/design/gossip.md b/documentation/dev/src/explore/design/gossip.md new file mode 100644 index 0000000000..4879363d33 --- /dev/null +++ b/documentation/dev/src/explore/design/gossip.md @@ -0,0 +1,17 @@ +# The gossip network + +The gossip network runs in parallel to the ledger network and is used to +propagate off-chain information. The network is based on +[libp2p](https://libp2p.io/) , a peer to peer network system that is implemented +in different languages, has a large user base and an active development. It +allows us to readily implement a network to run our application. + +The gossip network is used to propagate messages of two different applications, +intents for the [intent gossip system](intent_gossip/intent_gossip.md), and message for distributed keys +generation application. + +## Flow diagram: High level overview + +![gossip process](./gossip_process.svg "gossip process") + +[Diagram on Excalidraw](https://excalidraw.com/#room=5d4a2a84ef52cf5f5f96,r4ghl40frJ9putMy-0vyOQ) diff --git a/documentation/dev/src/explore/design/gossip_process.excalidraw b/documentation/dev/src/explore/design/gossip_process.excalidraw new file mode 100644 index 0000000000..3684252693 --- /dev/null +++ b/documentation/dev/src/explore/design/gossip_process.excalidraw @@ -0,0 +1,966 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "https://excalidraw.com", + "elements": [ + { + "type": "ellipse", + "version": 603, + "versionNonce": 717195654, + "isDeleted": false, + "id": "9XNyo7y8QCSEp4yAFf5oy", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1156.111111111111, + "y": 164.3333333333334, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 573.6666666666667, + "height": 372.55555555555554, + "seed": 821968881, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [] + }, + { + "type": "arrow", + "version": 1450, + "versionNonce": 941173851, + "isDeleted": false, + "id": "lXNINuf2v3Bas7FefE3LH", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1586.2054115693877, + "y": -370.2728566628903, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 246.73688630955917, + "height": 192.92404363452567, + "seed": 736805503, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "5xDzwVV0gDBlD-WL85LYy", + "focus": 0.18717224637187657, + "gap": 6.459472910604248 + }, + "endBinding": { + "elementId": "xxAsLeElpbNGHmw4QPxMz", + "focus": -0.23250849205562685, + "gap": 13.411672225924079 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -246.73688630955917, + 192.92404363452567 + ] + ] + }, + { + "type": "diamond", + "version": 278, + "versionNonce": 198810363, + "isDeleted": false, + "id": "5xDzwVV0gDBlD-WL85LYy", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1565.6666666666665, + "y": -444.66666666666663, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 127, + "height": 100, + "seed": 563016927, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "lXNINuf2v3Bas7FefE3LH", + "RR6GEDZFWUssCdTAnrDqo" + ] + }, + { + "type": "text", + "version": 253, + "versionNonce": 1818093109, + "isDeleted": false, + "id": "HskYIBtFFYajWD-2Djn1f", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1605.1666666666665, + "y": -409.66666666666663, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 50, + "height": 26, + "seed": 1643469585, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "lXNINuf2v3Bas7FefE3LH" + ], + "fontSize": 20, + "fontFamily": 1, + "text": "client", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "middle" + }, + { + "type": "rectangle", + "version": 432, + "versionNonce": 232368667, + "isDeleted": false, + "id": "5cPSOu9KDeCIp3Nmd546m", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1176, + "y": -287.2222222222222, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 570.0000000000001, + "height": 356.2222222222222, + "seed": 1306655743, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [] + }, + { + "type": "diamond", + "version": 627, + "versionNonce": 1842306310, + "isDeleted": false, + "id": "xxAsLeElpbNGHmw4QPxMz", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1181.3333333333333, + "y": -207.55555555555554, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 209, + "height": 188, + "seed": 1389553521, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "B4iQSfzoi419GYzKlXw5m", + "MPfW6JEUQYoWrzHeI_NxD", + "z6DMUeY7qrwuosEZr9D8K", + "GJPwvquPv4Afa-iz06Txv", + "bleUDuct9nWGxJfhyl_J2", + "V6oy4uJc_J45aC2sNpHvE", + "lXNINuf2v3Bas7FefE3LH", + "OIBiMf6VpPETwJAGERKti", + "J8EUyGyYHRSW895zskWbp" + ] + }, + { + "type": "diamond", + "version": 604, + "versionNonce": 1476920774, + "isDeleted": false, + "id": "dSBMH7Bqm1h_eoLM_yqkZ", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1184.4444444444446, + "y": 264.99999999999994, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 307.888888888889, + "height": 215.66666666666666, + "seed": 1838896927, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "OIBiMf6VpPETwJAGERKti", + "MPfW6JEUQYoWrzHeI_NxD", + "FqT97u9kn8yPY-e9ZEmwX", + "3w6C3S5gFIBLSOSnHrL9p", + "J8EUyGyYHRSW895zskWbp" + ] + }, + { + "type": "text", + "version": 446, + "versionNonce": 2067771125, + "isDeleted": false, + "id": "FOQ3kxQ9jn8r8iZ6-5Kdn", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1227.3333333333333, + "y": -149.55555555555551, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 121, + "height": 52, + "seed": 1118918783, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "Intent \nbroadcaster", + "baseline": 44, + "textAlign": "center", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 346, + "versionNonce": 94289307, + "isDeleted": false, + "id": "wNwxFCvE4WMQV8QLZiqxu", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1272, + "y": 281.99999999999994, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 131, + "height": 78, + "seed": 197177745, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "OIBiMf6VpPETwJAGERKti", + "MPfW6JEUQYoWrzHeI_NxD", + "J8EUyGyYHRSW895zskWbp" + ], + "fontSize": 20, + "fontFamily": 1, + "text": "intent\nbroadcaster \nnetwork", + "baseline": 70, + "textAlign": "center", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 1548, + "versionNonce": 1059405510, + "isDeleted": false, + "id": "OIBiMf6VpPETwJAGERKti", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1340.8991464307837, + "y": 256.43457590166764, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 19.424658574333307, + "height": 274.53680436823555, + "seed": 413185503, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "dSBMH7Bqm1h_eoLM_yqkZ", + "focus": 0.06980420648639936, + "gap": 8.455707710143173 + }, + "endBinding": { + "elementId": "xxAsLeElpbNGHmw4QPxMz", + "focus": -0.27643465526659067, + "gap": 24.916176360598527 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -19.424658574333307, + -274.53680436823555 + ] + ] + }, + { + "type": "arrow", + "version": 1783, + "versionNonce": 702656213, + "isDeleted": false, + "id": "MPfW6JEUQYoWrzHeI_NxD", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1225.7890453334985, + "y": -41.97976066319893, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 21.266468152933612, + "height": 381.0875685373966, + "seed": 1670492081, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "xxAsLeElpbNGHmw4QPxMz", + "gap": 23.483962590379445, + "focus": 0.5312629502131418 + }, + "endBinding": { + "elementId": "dSBMH7Bqm1h_eoLM_yqkZ", + "gap": 16.103707014847412, + "focus": -0.8818009263489358 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -21.266468152933612, + 381.0875685373966 + ] + ] + }, + { + "type": "text", + "version": 540, + "versionNonce": 1475775174, + "isDeleted": false, + "id": "InLHuKJiMfsKjnhDLER2S", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1224.6666666666667, + "y": 122.99999999999997, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 88, + "height": 52, + "seed": 1075843217, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "validate \nmsg", + "baseline": 44, + "textAlign": "right", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 1384, + "versionNonce": 280535450, + "isDeleted": false, + "id": "J8EUyGyYHRSW895zskWbp", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1386.7368978905408, + "y": 286.51414709947557, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 19.54258711706757, + "height": 343.3666092756827, + "seed": 1500547647, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "dSBMH7Bqm1h_eoLM_yqkZ", + "focus": 0.34597438474774744, + "gap": 10.117038200934843 + }, + "endBinding": { + "elementId": "xxAsLeElpbNGHmw4QPxMz", + "focus": -0.7476913039884736, + "gap": 26.682463765500543 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -19.54258711706757, + -343.3666092756827 + ] + ] + }, + { + "type": "text", + "version": 452, + "versionNonce": 1029595482, + "isDeleted": false, + "id": "3a6V_ozlu_-z813t_fjbn", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1391, + "y": 187.77777777777777, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 156, + "height": 36, + "seed": 15072497, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 28, + "fontFamily": 1, + "text": "libP2P logic", + "baseline": 25, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "diamond", + "version": 365, + "versionNonce": 757518677, + "isDeleted": false, + "id": "hngD3gT8MxLbMtULxwILm", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1204.6111111111113, + "y": -434.0000000000001, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 127, + "height": 100, + "seed": 662285233, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "lXNINuf2v3Bas7FefE3LH", + "V6oy4uJc_J45aC2sNpHvE" + ] + }, + { + "type": "text", + "version": 334, + "versionNonce": 979982971, + "isDeleted": false, + "id": "Tne4ggu_ZDCdoqKD1HVLY", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1244.1111111111113, + "y": -402.0000000000001, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 50, + "height": 26, + "seed": 1728898015, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "lXNINuf2v3Bas7FefE3LH" + ], + "fontSize": 20, + "fontFamily": 1, + "text": "client", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "middle" + }, + { + "type": "arrow", + "version": 1682, + "versionNonce": 1212570555, + "isDeleted": false, + "id": "V6oy4uJc_J45aC2sNpHvE", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1262.664151563201, + "y": -330.8400855354932, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 2.5819871518015134, + "height": 140.4581124311759, + "seed": 1528357951, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "hngD3gT8MxLbMtULxwILm", + "focus": 0.10105347446704833, + "gap": 5.8523740982304915 + }, + "endBinding": { + "elementId": "xxAsLeElpbNGHmw4QPxMz", + "focus": -0.18349209857314347, + "gap": 1 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 2.5819871518015134, + 140.4581124311759 + ] + ] + }, + { + "type": "text", + "version": 377, + "versionNonce": 1391350555, + "isDeleted": false, + "id": "q9mdbiPTZ5bMiHS1pP8Jd", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1267.8333333333333, + "y": -327.77777777777777, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 86, + "height": 26, + "seed": 280036991, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "send msg", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 138, + "versionNonce": 2055493659, + "isDeleted": false, + "id": "JdaaIi8F9pCIbQiuefyHi", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1388.75, + "y": -206.72222222222223, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 180, + "height": 35, + "seed": 476397371, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 28, + "fontFamily": 3, + "text": "Gossip Node", + "baseline": 28, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 419, + "versionNonce": 1035911669, + "isDeleted": false, + "id": "E1bibepZLZFj3VmWghmhk", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1557.1388888888887, + "y": -324.94444444444554, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 86, + "height": 26, + "seed": 1482472437, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "send msg", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "diamond", + "version": 629, + "versionNonce": 251582106, + "isDeleted": false, + "id": "JaiST4fQ2FlodcbDsHGRd", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1525.611111111111, + "y": -178.99999999999997, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 209, + "height": 188, + "seed": 1161636571, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "B4iQSfzoi419GYzKlXw5m", + "MPfW6JEUQYoWrzHeI_NxD", + "z6DMUeY7qrwuosEZr9D8K", + "GJPwvquPv4Afa-iz06Txv", + "bleUDuct9nWGxJfhyl_J2", + "RR6GEDZFWUssCdTAnrDqo", + "yZ1sDbO9UxZw6Yw7d8BGk", + "sofyhfQ6yAERl8W7igqud", + "98jHSy6KgIgI-kigPhATL", + "Jj-F4u_NSjuW-tVWK6ErH" + ] + }, + { + "type": "text", + "version": 477, + "versionNonce": 320811829, + "isDeleted": false, + "id": "yE8obB-cq-eO9tpUS_PcA", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1575.611111111111, + "y": -117.99999999999994, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 121, + "height": 52, + "seed": 413385813, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "DKG \nbroadcaster", + "baseline": 44, + "textAlign": "center", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 115, + "versionNonce": 808640859, + "isDeleted": false, + "id": "RR6GEDZFWUssCdTAnrDqo", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1660.0572555330295, + "y": -366.9575940330065, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 24.665187381169744, + "height": 183.91639038865497, + "seed": 45437883, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "5xDzwVV0gDBlD-WL85LYy", + "focus": -0.5447225569886008, + "gap": 1.5967808146620044 + }, + "endBinding": { + "elementId": "JaiST4fQ2FlodcbDsHGRd", + "focus": -0.07528645180716763, + "gap": 6.5362537154315845 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -24.665187381169744, + 183.91639038865497 + ] + ] + }, + { + "type": "diamond", + "version": 596, + "versionNonce": 1248600538, + "isDeleted": false, + "id": "sJFOeRzApKjnkoavWYSOm", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1415.6666666666667, + "y": 270.6666666666667, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 292.8888888888888, + "height": 207.6666666666666, + "seed": 3834485, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "OIBiMf6VpPETwJAGERKti", + "MPfW6JEUQYoWrzHeI_NxD", + "FqT97u9kn8yPY-e9ZEmwX", + "3w6C3S5gFIBLSOSnHrL9p", + "J8EUyGyYHRSW895zskWbp", + "yZ1sDbO9UxZw6Yw7d8BGk", + "sofyhfQ6yAERl8W7igqud", + "98jHSy6KgIgI-kigPhATL", + "Jj-F4u_NSjuW-tVWK6ErH" + ] + }, + { + "type": "text", + "version": 354, + "versionNonce": 339994458, + "isDeleted": false, + "id": "ERwB6OfVxtsDLuZO1G4dn", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1507.2222222222224, + "y": 292.6666666666667, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 131, + "height": 78, + "seed": 410831707, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "OIBiMf6VpPETwJAGERKti", + "MPfW6JEUQYoWrzHeI_NxD", + "yZ1sDbO9UxZw6Yw7d8BGk" + ], + "fontSize": 20, + "fontFamily": 1, + "text": "DKG\nbroadcaster \nnetwork", + "baseline": 70, + "textAlign": "center", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 432, + "versionNonce": 855557126, + "isDeleted": false, + "id": "yZ1sDbO9UxZw6Yw7d8BGk", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1613.2645903010791, + "y": 5.6816480400971585, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 32.37650849922488, + "height": 267.8739593512054, + "seed": 978571771, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "JaiST4fQ2FlodcbDsHGRd", + "focus": 0.056328322376417134, + "gap": 8.799318498256582 + }, + "endBinding": { + "elementId": "ERwB6OfVxtsDLuZO1G4dn", + "focus": 0.016268660508214034, + "gap": 19.11105927536414 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -32.37650849922488, + 267.8739593512054 + ] + ] + }, + { + "type": "arrow", + "version": 398, + "versionNonce": 2067988678, + "isDeleted": false, + "id": "Jj-F4u_NSjuW-tVWK6ErH", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1623.0089473868802, + "y": 304.406818117378, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 33.75764899556157, + "height": 307.2241654227815, + "seed": 398843163, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "sJFOeRzApKjnkoavWYSOm", + "focus": 0.3632505836483008, + "gap": 7.699251414567215 + }, + "endBinding": { + "elementId": "JaiST4fQ2FlodcbDsHGRd", + "focus": -0.3414897328591685, + "gap": 9.04048516465393 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 33.75764899556157, + -307.2241654227815 + ] + ] + }, + { + "type": "text", + "version": 554, + "versionNonce": 720882453, + "isDeleted": false, + "id": "kXVNso4ItXnAMFArYHbYk", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1486.1111111111115, + "y": 109.99999999999997, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 88, + "height": 52, + "seed": 1662723835, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "validate \nmsg", + "baseline": 44, + "textAlign": "right", + "verticalAlign": "top" + } + ], + "appState": { + "gridSize": null, + "viewBackgroundColor": "#ffffff" + } +} \ No newline at end of file diff --git a/documentation/dev/src/explore/design/gossip_process.svg b/documentation/dev/src/explore/design/gossip_process.svg new file mode 100644 index 0000000000..32a046a1ac --- /dev/null +++ b/documentation/dev/src/explore/design/gossip_process.svg @@ -0,0 +1,16 @@ + + + + + + + clientIntent broadcasterintentbroadcaster networkvalidate msglibP2P logicclientsend msgGossip Nodesend msgDKG broadcasterDKGbroadcaster networkvalidate msg \ No newline at end of file diff --git a/documentation/dev/src/explore/design/intent_gossip/example.excalidraw b/documentation/dev/src/explore/design/intent_gossip/example.excalidraw new file mode 100644 index 0000000000..876d8a453b --- /dev/null +++ b/documentation/dev/src/explore/design/intent_gossip/example.excalidraw @@ -0,0 +1,2202 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "https://excalidraw.com", + "elements": [ + { + "type": "text", + "version": 686, + "versionNonce": 1681340216, + "isDeleted": false, + "id": "8-d43siu84Jr4CoHQ4O3h", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 87.4761904761906, + "y": 120.73809523809535, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 188, + "height": 120, + "seed": 454219117, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 16, + "fontFamily": 3, + "text": "- 400 < X < 1000 USD\n- rate USD to EUR: \n >= 1.5 EUR/USD\n- rate USD to CZK:\n >= 10 USD/CZK\n- in less than 20 mn", + "baseline": 116, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 196, + "versionNonce": 124057672, + "isDeleted": false, + "id": "pMCzM8kGspun9xkTr6k5d", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 61.95238095238085, + "y": 83.64285714285725, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 94, + "height": 25, + "seed": 1950434275, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 3, + "text": "- DATA: ", + "baseline": 20, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 295, + "versionNonce": 1203474488, + "isDeleted": false, + "id": "2p7QI8-lBoSz4ic4BK3eT", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 44.61904761904748, + "y": 43.0714285714287, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 284.3809523809525, + "height": 245.90476190476187, + "seed": 1582276557, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "oYCojvs3_Pz8ZGLg2mw3V", + "954BBr80PqUI9uJuWnFsM", + "uKTSmBiHZULyjH127gePI", + "Czhwb2CjT6al5-6rCgR97" + ] + }, + { + "type": "text", + "version": 156, + "versionNonce": 1336848200, + "isDeleted": false, + "id": "h9Y3DYl2lfuXh9QZLoKSa", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 63.39285714285711, + "y": 255.0476190476184, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 152, + "height": 25, + "seed": 668258179, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 3, + "text": "- timestamp T", + "baseline": 20, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 448, + "versionNonce": 1263323448, + "isDeleted": false, + "id": "UiaZM4EJyss7ILeYlY9LS", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 75.14285714285711, + "y": 118.35714285714295, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 247.28571428571422, + "height": 129.47619047619048, + "seed": 138681901, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "oYCojvs3_Pz8ZGLg2mw3V", + "bMCs-OrsKdLPqnA1PVwiv", + "954BBr80PqUI9uJuWnFsM" + ] + }, + { + "type": "text", + "version": 255, + "versionNonce": 1940489800, + "isDeleted": false, + "id": "MBhNEXU9Gx54BPICMfGTq", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 66.14285714285711, + "y": 47.3333333333334, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 217, + "height": 52, + "seed": 607512355, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "oYCojvs3_Pz8ZGLg2mw3V", + "954BBr80PqUI9uJuWnFsM" + ], + "fontSize": 20, + "fontFamily": 1, + "text": "intent from account A\n", + "baseline": 44, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 1706, + "versionNonce": 441377336, + "isDeleted": false, + "id": "HBiEEEb8ounDRLLN9wXKf", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 797.2148759236247, + "y": 300.28571428571433, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 82.58839012004557, + "height": 92.74093504094964, + "seed": 1181817966, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "UXXI91T9S5l9KHt7Wp0ZV", + "gap": 1, + "focus": -0.6432089438320445 + }, + "endBinding": { + "elementId": "Vva_ZJK0PzeOvHwKtR1hx", + "gap": 4.782874482859853, + "focus": 0.22336105149411092 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -82.58839012004557, + 92.74093504094964 + ] + ] + }, + { + "type": "arrow", + "version": 1822, + "versionNonce": 540114248, + "isDeleted": false, + "id": "oYCojvs3_Pz8ZGLg2mw3V", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 492.80297633357, + "y": 292.13629393845633, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 30.182646679681625, + "height": 92.45738907898789, + "seed": 1847628014, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "hf7oNcONr_HxLhhGRiJqE", + "gap": 10.279151081313444, + "focus": 0.38338854643484865 + }, + "endBinding": { + "elementId": "Vva_ZJK0PzeOvHwKtR1hx", + "gap": 13.215840792079547, + "focus": -0.011602561064372598 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 30.182646679681625, + 92.45738907898789 + ] + ] + }, + { + "type": "rectangle", + "version": 315, + "versionNonce": 1403378488, + "isDeleted": false, + "id": "UXXI91T9S5l9KHt7Wp0ZV", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -2.309523809529537, + "y": -69.04761904761892, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 1041.3809523809525, + "height": 368.33333333333326, + "seed": 1810420256, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "oYCojvs3_Pz8ZGLg2mw3V", + "HBiEEEb8ounDRLLN9wXKf" + ] + }, + { + "type": "arrow", + "version": 941, + "versionNonce": 111318088, + "isDeleted": false, + "id": "Swcv4ZXJejaz5TYfHeDMu", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 876.138834695055, + "y": -424.07142857142946, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 9.184895705945564, + "height": 459.29069763915254, + "seed": 936098418, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "usikQRBWwYKM-qybe0fQH", + "gap": 2, + "focus": -0.255388727353868 + }, + "endBinding": { + "elementId": "swYlyjktS4gIwsiQLSPjZ", + "gap": 9.066445217991259, + "focus": 0.15984810321549953 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -9.184895705945564, + 459.29069763915254 + ] + ] + }, + { + "type": "rectangle", + "version": 310, + "versionNonce": 431338552, + "isDeleted": false, + "id": "usikQRBWwYKM-qybe0fQH", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 774.0119047619048, + "y": -530.0714285714295, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 164, + "height": 104, + "seed": 354374066, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "Swcv4ZXJejaz5TYfHeDMu", + "ol2AB4uLuMEYj138srSeF" + ] + }, + { + "type": "rectangle", + "version": 312, + "versionNonce": 1289276232, + "isDeleted": false, + "id": "swYlyjktS4gIwsiQLSPjZ", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 700, + "y": 44.285714285714334, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 282.8571428571426, + "height": 236, + "seed": 345326578, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "HBiEEEb8ounDRLLN9wXKf", + "Swcv4ZXJejaz5TYfHeDMu" + ] + }, + { + "type": "text", + "version": 268, + "versionNonce": 576875832, + "isDeleted": false, + "id": "wXWmmm8mpOqmxFuLw0x-V", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 798.0119047619048, + "y": -481.07142857142946, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 101, + "height": 26, + "seed": 992734510, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "account C", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 171, + "versionNonce": 2100306504, + "isDeleted": false, + "id": "XDW5IfPRFhlKsj3a1RbYD", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 553.8333333333278, + "y": 327.61904761904776, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 127, + "height": 26, + "seed": 1564124704, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "fetch intents", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 1247, + "versionNonce": 1192232504, + "isDeleted": false, + "id": "954BBr80PqUI9uJuWnFsM", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 522.3067180843871, + "y": -423.5118681617779, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 5.583297287089863, + "height": 443.7930802552394, + "seed": 467951874, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "bDFsD9RIYPQQrHIWUfc_E", + "focus": 0.21113172608583025, + "gap": 6.8690842191745105 + }, + "endBinding": { + "elementId": "hf7oNcONr_HxLhhGRiJqE", + "focus": 0.002175851518750341, + "gap": 15.671168858919486 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -5.583297287089863, + 443.7930802552394 + ] + ] + }, + { + "type": "text", + "version": 399, + "versionNonce": 1988401480, + "isDeleted": false, + "id": "dYXMYP8IeZ5hPB8hDXUkx", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 488.66666666666674, + "y": -491.04761904761915, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 99, + "height": 26, + "seed": 1024864898, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "account B", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 167, + "versionNonce": 1546793032, + "isDeleted": false, + "id": "Z7BWkND-NitKxr9Ih4Ie2", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 389.80952380952374, + "y": 76.52380952380958, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 94, + "height": 25, + "seed": 469053826, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 3, + "text": "- DATA: ", + "baseline": 20, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 268, + "versionNonce": 1534974008, + "isDeleted": false, + "id": "hf7oNcONr_HxLhhGRiJqE", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 372.47619047619037, + "y": 35.95238095238102, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 284.3809523809525, + "height": 245.90476190476187, + "seed": 25601394, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "oYCojvs3_Pz8ZGLg2mw3V", + "954BBr80PqUI9uJuWnFsM" + ] + }, + { + "type": "text", + "version": 459, + "versionNonce": 102033224, + "isDeleted": false, + "id": "oRS3euY4VEuk2SgUKpr1L", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 718.5714285714287, + "y": 138.8095238095238, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 188, + "height": 80, + "seed": 655184434, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 16, + "fontFamily": 3, + "text": "- 0 < X < 0.05 BTC \n- rate BTC to EUR: \n >= 0.00001 BTC/USD\n- in less than 1 mn", + "baseline": 76, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 182, + "versionNonce": 1065750840, + "isDeleted": false, + "id": "XrVgeTerY-7DS-ka0p0Em", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 716.5, + "y": 242.59523809523824, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 176, + "height": 25, + "seed": 1477693777, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 3, + "text": "- timestamp T''", + "baseline": 20, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 128, + "versionNonce": 1888009800, + "isDeleted": false, + "id": "d8WVAhFQ2zo-3HuEkCg6h", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 391.25, + "y": 247.9285714285707, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 164, + "height": 25, + "seed": 204593966, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 3, + "text": "- timestamp T'", + "baseline": 20, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 426, + "versionNonce": 1210001976, + "isDeleted": false, + "id": "Nkvl_WfjngjOTgW9Zbs2_", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 390, + "y": 111.2380952380953, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 247.28571428571422, + "height": 129.47619047619048, + "seed": 1239365918, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "oYCojvs3_Pz8ZGLg2mw3V", + "bMCs-OrsKdLPqnA1PVwiv", + "954BBr80PqUI9uJuWnFsM" + ] + }, + { + "type": "rectangle", + "version": 337, + "versionNonce": 745125192, + "isDeleted": false, + "id": "LxE-VPfS6ezu0mmzjr8F1", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 712.8571428571429, + "y": 130.2380952380953, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 237.2857142857145, + "height": 105.47619047619037, + "seed": 423857246, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [] + }, + { + "type": "text", + "version": 530, + "versionNonce": 640619320, + "isDeleted": false, + "id": "Hk5l9iiBugHCCPMbYtU63", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 12.624999999999886, + "y": 1537.291666666666, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 410, + "height": 250, + "seed": 212882431, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 3, + "text": "if someone takes between\ntx.DATA.A.low to tx.DATA.A.high \ntx.DATA.A.output_asset \nfrom my account,\nit has to credit\nat least tx.DATA.A.min_rate \nthe amount in tx.DATA.A.input_asset\n and to be before\n (tx.DATA.A.timestamp\n + tx.DATA.A.TTL)", + "baseline": 245, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 645, + "versionNonce": 1326697544, + "isDeleted": false, + "id": "EygNVoDyqnn-JbFybEbGe", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 287.5238095238093, + "y": 660.2380952380953, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 281, + "height": 350, + "seed": 2012467634, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 3, + "text": "- STATE FUNCTION : \n - 1/ src: A\n dest: C\n amount: 466.6 USD\n - 2/ src: C\n dest: B\n amount: 800 EUR\n - 3/ src: B \n dest: A\n amount: 0.017 BTC\n- DATA\n - 1/ intent A\n - 2/ intent B\n - 3/ intent C", + "baseline": 345, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 378, + "versionNonce": 1618836792, + "isDeleted": false, + "id": "0XL0H0k8apgsdhnJ1t5ab", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": -3.9166666666667425, + "y": 1448.4999999999995, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 447.08333333333337, + "height": 377.9166666666665, + "seed": 124501362, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "Zd243WE5eHC_WR8epiEAk", + "bMcnnlJo1LpwISJChgmKB", + "69EnjeqAfSHRFsprrsmiO", + "5qf0tF76bMQXA21Z0jkWa", + "cnhSr0ikLZ2glzJteomgZ", + "Jo906mQj2gE8MfU639rAz", + "ubXW8sd3hkMXVly_O_ZOm", + "8R2CEj2oEGuvX1dqJ8gCY" + ] + }, + { + "type": "arrow", + "version": 858, + "versionNonce": 2126699080, + "isDeleted": false, + "id": "Jo906mQj2gE8MfU639rAz", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 468.4392508864622, + "y": 1386.951149425287, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 197.84511112482477, + "height": 37.33444576972829, + "seed": 1746017906, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "VvkwdNT_ReB6o1cn6jyZr", + "focus": -0.3762898352769947, + "gap": 2.034482758620584 + }, + "endBinding": { + "elementId": "0XL0H0k8apgsdhnJ1t5ab", + "focus": -0.8806478681490097, + "gap": 24.21440480498427 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -197.84511112482477, + 37.33444576972829 + ] + ] + }, + { + "type": "text", + "version": 241, + "versionNonce": 1174694472, + "isDeleted": false, + "id": "rDu3FdPNopgW6z9PCoHab", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 480.66666666666674, + "y": 1342.1666666666663, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 96, + "height": 26, + "seed": 1492486702, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "check VPs", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 357, + "versionNonce": 2070927672, + "isDeleted": false, + "id": "TsHuKC9fQpBlBOzMikQ_z", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 305.83333333333326, + "y": 1874.75, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 442.4999999999999, + "height": 382.91666666666646, + "seed": 1984398894, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "y1ij4QN5do9jfy8-88ASN", + "MmzmsyscAAK-oBSzk0-T_", + "tjHofHebcS4-4X76vqi0M" + ] + }, + { + "type": "arrow", + "version": 1601, + "versionNonce": 108809784, + "isDeleted": false, + "id": "GN1g4nPawR3Tizbo7OUxq", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 438.53788770476547, + "y": 517.4917358318999, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 1.8992073358202788, + "height": 90.2497092278901, + "seed": 471491378, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": null, + "endBinding": { + "elementId": "VEHFhWJtyqbM7CEJvy1OY", + "gap": 6.496650178305457, + "focus": -0.2974579993705736 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -1.8992073358202788, + 90.2497092278901 + ] + ] + }, + { + "type": "rectangle", + "version": 371, + "versionNonce": 1915086408, + "isDeleted": false, + "id": "VEHFhWJtyqbM7CEJvy1OY", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 268, + "y": 606.2380952380953, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 471.19047619047615, + "height": 412.00000000000006, + "seed": 465481138, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "GN1g4nPawR3Tizbo7OUxq", + "9m0lD6nkNLEEuDZhOAFaq" + ] + }, + { + "type": "rectangle", + "version": 541, + "versionNonce": 793102136, + "isDeleted": false, + "id": "Vva_ZJK0PzeOvHwKtR1hx", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 193.7142857142859, + "y": 397.8095238095238, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 721.2857142857143, + "height": 138.52380952380955, + "seed": 926229486, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "oYCojvs3_Pz8ZGLg2mw3V", + "HBiEEEb8ounDRLLN9wXKf", + "GN1g4nPawR3Tizbo7OUxq", + "Czhwb2CjT6al5-6rCgR97" + ] + }, + { + "type": "text", + "version": 295, + "versionNonce": 642213960, + "isDeleted": false, + "id": "1nPK7swUFkn2ZECAVz_c2", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 466.71428571428567, + "y": 399.7142857142857, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 201, + "height": 46, + "seed": 985887602, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "GN1g4nPawR3Tizbo7OUxq", + "oYCojvs3_Pz8ZGLg2mw3V", + "HBiEEEb8ounDRLLN9wXKf" + ], + "fontSize": 36, + "fontFamily": 1, + "text": "matchmaker", + "baseline": 32, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 227, + "versionNonce": 1383604280, + "isDeleted": false, + "id": "-G2iBkHpCw0y563oTofms", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 394, + "y": 40.21428571428572, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 218, + "height": 52, + "seed": 1376390450, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "oYCojvs3_Pz8ZGLg2mw3V", + "954BBr80PqUI9uJuWnFsM" + ], + "fontSize": 20, + "fontFamily": 1, + "text": "intent from account B\n", + "baseline": 44, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 161, + "versionNonce": 1220747080, + "isDeleted": false, + "id": "HA5fUOkkjum0HgfnMlIBG", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 733, + "y": 60.95238095238096, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 220, + "height": 26, + "seed": 1992833394, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "intent from account C", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 153, + "versionNonce": 1878481208, + "isDeleted": false, + "id": "nBttw1DAeptrX2lVgvsY7", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 720.7142857142857, + "y": 95.95238095238096, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 82, + "height": 25, + "seed": 1251151454, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 3, + "text": "- DATA:", + "baseline": 20, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 896, + "versionNonce": 407405112, + "isDeleted": false, + "id": "9m0lD6nkNLEEuDZhOAFaq", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 508.568121346975, + "y": 1021.1321908520348, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 3.1429313226068984, + "height": 312.2365395554883, + "seed": 1155072110, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "VEHFhWJtyqbM7CEJvy1OY", + "focus": -0.01207639830586925, + "gap": 2.894095613939328 + }, + "endBinding": { + "elementId": "VvkwdNT_ReB6o1cn6jyZr", + "focus": -0.14754250955099754, + "gap": 2.381269592476542 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 3.1429313226068984, + 312.2365395554883 + ] + ] + }, + { + "type": "text", + "version": 299, + "versionNonce": 580155464, + "isDeleted": false, + "id": "hiykXkLOlmLVWGgrQKtH8", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 532.9999999999999, + "y": 1144.9999999999998, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 265, + "height": 26, + "seed": 2146825074, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "send transaction to ledger", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 212, + "versionNonce": 1497632824, + "isDeleted": false, + "id": "7Ng3PQpN63cbVPHR8aHrn", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 46.66666666666663, + "y": 1475.7499999999995, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 51, + "height": 26, + "seed": 983757230, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "A VP:", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 271, + "versionNonce": 1492004680, + "isDeleted": false, + "id": "AuP1LD1e9BIzr9fnDJADl", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 324.58333333333326, + "y": 1904.5, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 52, + "height": 26, + "seed": 1592796398, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "B VP:", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 309, + "versionNonce": 1344396616, + "isDeleted": false, + "id": "VvkwdNT_ReB6o1cn6jyZr", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 433.16666666666674, + "y": 1335.7499999999998, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 185, + "height": 49.166666666666735, + "seed": 1653182898, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "9m0lD6nkNLEEuDZhOAFaq", + "Jo906mQj2gE8MfU639rAz", + "tjHofHebcS4-4X76vqi0M", + "o8vZWSYePDHs1bN3foTMP" + ] + }, + { + "type": "arrow", + "version": 981, + "versionNonce": 846653512, + "isDeleted": false, + "id": "tjHofHebcS4-4X76vqi0M", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 513.8848064154693, + "y": 1386.951149425287, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 2.1447670720162932, + "height": 467.54798651113333, + "seed": 572567090, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "VvkwdNT_ReB6o1cn6jyZr", + "focus": 0.12853479300213336, + "gap": 2.034482758620584 + }, + "endBinding": { + "elementId": "TsHuKC9fQpBlBOzMikQ_z", + "focus": -0.045390860814372345, + "gap": 20.250864063579456 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 2.1447670720162932, + 467.54798651113333 + ] + ] + }, + { + "type": "text", + "version": 349, + "versionNonce": 540359496, + "isDeleted": false, + "id": "0L6p1qM6u_tVfVgCK_FDY", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 333.14285714285734, + "y": 623.5238095238096, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 307, + "height": 24, + "seed": 2092627950, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 2, + "text": "TRANSACTION from matchmaker ", + "baseline": 17, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "ellipse", + "version": 643, + "versionNonce": 356842808, + "isDeleted": false, + "id": "PcxdOS9NrJhMOgUW0faBx", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -165.8333333333394, + "y": -331.6666666666668, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 1361.333333333333, + "height": 1437.3809523809525, + "seed": 2083480096, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [] + }, + { + "type": "text", + "version": 218, + "versionNonce": 192844360, + "isDeleted": false, + "id": "A6kNrvnIcbKPUZ5GodYoX", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 353.2142857142801, + "y": -291.6666666666665, + "strokeColor": "#364fc7", + "backgroundColor": "transparent", + "width": 364, + "height": 92, + "seed": 389688288, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 36, + "fontFamily": 1, + "text": "Intent broadcaster \nnetwork", + "baseline": 78, + "textAlign": "center", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 158, + "versionNonce": 1595971128, + "isDeleted": false, + "id": "nVSCWf4TYONMAlK6r7v7u", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 607.1666666666612, + "y": -49.71428571428561, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 193, + "height": 36, + "seed": 1611512800, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 28, + "fontFamily": 1, + "text": "global mempool", + "baseline": 25, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 635, + "versionNonce": 293931336, + "isDeleted": false, + "id": "HVqr4I6oVLiB-7Smz4WBL", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 264.6904761904701, + "y": 450.04761904761926, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 584, + "height": 78, + "seed": 644801056, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "GN1g4nPawR3Tizbo7OUxq" + ], + "fontSize": 19.896103896103885, + "fontFamily": 1, + "text": "The matchmacker chooses values for the transaction that\n he thinks will be accepted by the ledger (the validity\npredicate of each account).", + "baseline": 70, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "ellipse", + "version": 452, + "versionNonce": 2052606792, + "isDeleted": false, + "id": "0ilp60kgFqvYZ-R-LlZ_8", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -241.6666666666722, + "y": 1238.6666666666663, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 1547.3333333333326, + "height": 1465.0000000000002, + "seed": 312942560, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [] + }, + { + "type": "text", + "version": 369, + "versionNonce": 781905208, + "isDeleted": false, + "id": "gwJeBcdO_DYmasftBcHif", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 537.8333333333277, + "y": 1261.1666666666665, + "strokeColor": "#364fc7", + "backgroundColor": "transparent", + "width": 258, + "height": 46, + "seed": 721258016, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 36, + "fontFamily": 1, + "text": "ledger network", + "baseline": 32, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 683, + "versionNonce": 1321181768, + "isDeleted": false, + "id": "jU8TxFoAubCE7Tws_-GtR", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 321.8333333333276, + "y": 1954.5, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 410, + "height": 250, + "seed": 1682625504, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 3, + "text": "if someone takes between\ntx.DATA.B.amount \ntx.DATA.B.output_asset \nfrom my account,\nit has to credit\nat least tx.DATA.B.min_rate \nthe amount in tx.DATA.B.input_asset\n and to be before\n (tx.DATA.B.timestamp \n + tx.DATA.C.TTL)", + "baseline": 245, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 1227, + "versionNonce": 385840712, + "isDeleted": false, + "id": "MmzmsyscAAK-oBSzk0-T_", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 537.0941616654786, + "y": 2275.9127064518443, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 0.8399583165244167, + "height": 211.42062688148872, + "seed": 331186144, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "TsHuKC9fQpBlBOzMikQ_z", + "focus": -0.041338956392506655, + "gap": 18.246039785178027 + }, + "endBinding": { + "elementId": "OLiV9Yr0v-YQNJbhTqcuZ", + "focus": 0.664082386729967, + "gap": 1 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 0.8399583165244167, + 211.42062688148872 + ] + ] + }, + { + "type": "text", + "version": 379, + "versionNonce": 884140088, + "isDeleted": false, + "id": "OLiV9Yr0v-YQNJbhTqcuZ", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 508.83333333332746, + "y": 2488.333333333333, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 35, + "height": 25, + "seed": 258550752, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "cnhSr0ikLZ2glzJteomgZ", + "MmzmsyscAAK-oBSzk0-T_", + "r3K74Ft73zYbYmn37KM_a", + "8R2CEj2oEGuvX1dqJ8gCY", + "xfJTcfqB9FHSZl9nnr-SE" + ], + "fontSize": 20, + "fontFamily": 3, + "text": "...", + "baseline": 20, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 172, + "versionNonce": 1265089080, + "isDeleted": false, + "id": "bnfip1RTsFRJNftw4HckK", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 470.8809523809465, + "y": 574.2857142857144, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 175, + "height": 26, + "seed": 111981536, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "craft transaction", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 370, + "versionNonce": 1269966152, + "isDeleted": false, + "id": "bDFsD9RIYPQQrHIWUfc_E", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 458.49999999999466, + "y": -534.3809523809524, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 164, + "height": 104, + "seed": 1802037792, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "Swcv4ZXJejaz5TYfHeDMu", + "ol2AB4uLuMEYj138srSeF", + "954BBr80PqUI9uJuWnFsM" + ] + }, + { + "type": "text", + "version": 336, + "versionNonce": 467907384, + "isDeleted": false, + "id": "xzml5UDbVyEJKPO3if06i", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 816.5273034941135, + "y": -372.08003798021025, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 43, + "height": 26, + "seed": 806763701, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "send", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 385, + "versionNonce": 1271807048, + "isDeleted": false, + "id": "X0SNHo6dQnl8irYcF3Ubf", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 529.5273034941135, + "y": -385.08003798021025, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 43, + "height": 26, + "seed": 207870843, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "send", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 448, + "versionNonce": 1282968632, + "isDeleted": false, + "id": "TVJpZzxoPMIinWFy_aK1i", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 212.9761904761957, + "y": -498.9599810098948, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 98, + "height": 52, + "seed": 505781699, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "account A\n", + "baseline": 44, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 415, + "versionNonce": 1045394248, + "isDeleted": false, + "id": "E7FV6AEnvxE7fX_r3_TzW", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 182.80952380952374, + "y": -542.2933143432281, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 164, + "height": 104, + "seed": 1994281965, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "Swcv4ZXJejaz5TYfHeDMu", + "ol2AB4uLuMEYj138srSeF", + "954BBr80PqUI9uJuWnFsM", + "uKTSmBiHZULyjH127gePI" + ] + }, + { + "type": "text", + "version": 429, + "versionNonce": 654984504, + "isDeleted": false, + "id": "l3RrMlLKlU9laipGh-WIb", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 253.8368273036425, + "y": -392.9923999424859, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 43, + "height": 26, + "seed": 735243619, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "send", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 247, + "versionNonce": 1502726728, + "isDeleted": false, + "id": "uKTSmBiHZULyjH127gePI", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 254.78140471240346, + "y": -433.642857142857, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 18.07520040340512, + "height": 446.8986715332853, + "seed": 1473743181, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "E7FV6AEnvxE7fX_r3_TzW", + "focus": 0.14647529307932466, + "gap": 4.650457200371079 + }, + "endBinding": { + "elementId": "2p7QI8-lBoSz4ic4BK3eT", + "focus": 0.6266906023232607, + "gap": 29.815614181000413 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 18.07520040340512, + 446.8986715332853 + ] + ] + }, + { + "type": "arrow", + "version": 214, + "versionNonce": 419225144, + "isDeleted": false, + "id": "Czhwb2CjT6al5-6rCgR97", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 251.88178381509215, + "y": 291.02380952380963, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 52.803167627033986, + "height": 104.42857142857144, + "seed": 1533710979, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "2p7QI8-lBoSz4ic4BK3eT", + "gap": 2.047619047619051, + "focus": 0.017984625714246562 + }, + "endBinding": { + "elementId": "Vva_ZJK0PzeOvHwKtR1hx", + "gap": 2.3571428571426907, + "focus": -0.5394946080216643 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 52.803167627033986, + 104.42857142857144 + ] + ] + }, + { + "type": "text", + "version": 439, + "versionNonce": 1127503672, + "isDeleted": false, + "id": "mgtimTjmkfFageE4a_ALC", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 401.95238095238096, + "y": 117.14285714285734, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 188, + "height": 80, + "seed": 1741274855, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 16, + "fontFamily": 3, + "text": "- 800 EUR\n- rate EUR to BTC: \n >= 47058 EUR/BTC\n- in less than 10 mn", + "baseline": 76, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 349, + "versionNonce": 859410232, + "isDeleted": false, + "id": "n8qBdtjdYuoZicswHAM8Z", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 605.3690476190475, + "y": 1444.017857142857, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 442.4999999999999, + "height": 382.91666666666646, + "seed": 1102897255, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "tjHofHebcS4-4X76vqi0M", + "y1ij4QN5do9jfy8-88ASN", + "MmzmsyscAAK-oBSzk0-T_", + "o8vZWSYePDHs1bN3foTMP", + "r3K74Ft73zYbYmn37KM_a", + "xfJTcfqB9FHSZl9nnr-SE" + ] + }, + { + "type": "text", + "version": 268, + "versionNonce": 554150456, + "isDeleted": false, + "id": "kEAF_yIT_4cO4uX63467_", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 624.1190476190475, + "y": 1473.767857142857, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 54, + "height": 26, + "seed": 1833762185, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "C VP:", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 691, + "versionNonce": 340342088, + "isDeleted": false, + "id": "LgtU9c20p3iojrteT7TOy", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 621.3690476190416, + "y": 1523.767857142857, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 410, + "height": 250, + "seed": 405945223, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 3, + "text": "if someone takes between\ntx.DATA.C.low to tx.DATA.C. high \ntx.DATA.C.output_asset \nfrom my account,\nit has to credit\nat least tx.DATA.C.min_rate \nthe amount in tx.DATA.C.input_asset\n and to be before\n (tx.DATA.C.timestamp\n + tx.DATA.C.TTL)", + "baseline": 245, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 341, + "versionNonce": 1631355976, + "isDeleted": false, + "id": "o8vZWSYePDHs1bN3foTMP", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 622.3113514729953, + "y": 1387.3092905570172, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 131.8668164720766, + "height": 50.16689991917315, + "seed": 1895758345, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "VvkwdNT_ReB6o1cn6jyZr", + "focus": -0.16380407789917548, + "gap": 4.1446848063285415 + }, + "endBinding": { + "elementId": "n8qBdtjdYuoZicswHAM8Z", + "focus": 0.6183687597387931, + "gap": 6.5416666666667425 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 131.8668164720766, + 50.16689991917315 + ] + ] + }, + { + "id": "8R2CEj2oEGuvX1dqJ8gCY", + "type": "arrow", + "x": 166.28016609367018, + "y": 1833.6428571428573, + "width": 333.2772811594371, + "height": 669.3349011418622, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "round", + "seed": 973478472, + "version": 390, + "versionNonce": 235803208, + "isDeleted": false, + "boundElementIds": null, + "points": [ + [ + 0, + 0 + ], + [ + 61.005548192043705, + 588.333333333333 + ], + [ + 333.2772811594371, + 669.3349011418622 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "0XL0H0k8apgsdhnJ1t5ab", + "focus": 0.3030726950488866, + "gap": 7.226190476191277 + }, + "endBinding": { + "elementId": "OLiV9Yr0v-YQNJbhTqcuZ", + "focus": -0.5710015327583038, + "gap": 9.275886080220175 + }, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "type": "arrow", + "version": 540, + "versionNonce": 1649680456, + "isDeleted": false, + "id": "xfJTcfqB9FHSZl9nnr-SE", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 875.4506366524696, + "y": 1845.3095238095234, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 316.498255700089, + "height": 653.299399447023, + "seed": 253988936, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "n8qBdtjdYuoZicswHAM8Z", + "focus": -0.2859002709985485, + "gap": 18.374999999999773 + }, + "endBinding": { + "elementId": "OLiV9Yr0v-YQNJbhTqcuZ", + "focus": 0.4400244271235751, + "gap": 15.119047619053163 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -53.16492236675572, + 571.6666666666665 + ], + [ + -316.498255700089, + 653.299399447023 + ] + ] + } + ], + "appState": { + "gridSize": null, + "viewBackgroundColor": "#ffffff" + } +} \ No newline at end of file diff --git a/documentation/dev/src/explore/design/intent_gossip/example.svg b/documentation/dev/src/explore/design/intent_gossip/example.svg new file mode 100644 index 0000000000..9a5a48a38c --- /dev/null +++ b/documentation/dev/src/explore/design/intent_gossip/example.svg @@ -0,0 +1,16 @@ + + + + + + + - 400 < X < 1000 USD- rate USD to EUR: >= 1.5 EUR/USD- rate USD to CZK: >= 10 USD/CZK- in less than 20 mn- DATA: - timestamp Tintent from account Aaccount Cfetch intentsaccount B- DATA: - 0 < X < 0.05 BTC - rate BTC to EUR: >= 0.00001 BTC/USD- in less than 1 mn- timestamp T''- timestamp T'if someone takes betweentx.DATA.A.low to tx.DATA.A.high tx.DATA.A.output_asset from my account,it has to creditat least tx.DATA.A.min_rate the amount in tx.DATA.A.input_asset and to be before (tx.DATA.A.timestamp + tx.DATA.A.TTL)- STATE FUNCTION : - 1/ src: A dest: C amount: 466.6 USD - 2/ src: C dest: B amount: 800 EUR - 3/ src: B dest: A amount: 0.017 BTC- DATA - 1/ intent A - 2/ intent B - 3/ intent Ccheck VPsmatchmakerintent from account Bintent from account C- DATA:send transaction to ledgerA VP:B VP:TRANSACTION from matchmaker Intent broadcaster networkglobal mempoolThe matchmacker chooses values for the transaction that he thinks will be accepted by the ledger (the validitypredicate of each account).ledger networkif someone takes betweentx.DATA.B.amount tx.DATA.B.output_asset from my account,it has to creditat least tx.DATA.B.min_rate the amount in tx.DATA.B.input_asset and to be before (tx.DATA.B.timestamp + tx.DATA.C.TTL)...craft transactionsendsendaccount Asend- 800 EUR- rate EUR to BTC: >= 47058 EUR/BTC- in less than 10 mnC VP:if someone takes betweentx.DATA.C.low to tx.DATA.C. high tx.DATA.C.output_asset from my account,it has to creditat least tx.DATA.C.min_rate the amount in tx.DATA.C.input_asset and to be before (tx.DATA.C.timestamp + tx.DATA.C.TTL) \ No newline at end of file diff --git a/documentation/dev/src/explore/design/intent_gossip/fungible_token.md b/documentation/dev/src/explore/design/intent_gossip/fungible_token.md new file mode 100644 index 0000000000..43a34c5c94 --- /dev/null +++ b/documentation/dev/src/explore/design/intent_gossip/fungible_token.md @@ -0,0 +1,35 @@ +# Fungible token encoding and template + +The Heliax team implemented an intent encoding, a filter program template, and a +matchmaker program template that can be used to exchange fungible tokens between +any number of participants. + +## Intent encoding +The intent encoding allows the expression of a desire to participate in an asset +exchange. The encoding is defined as follows : + +```protobuf +message FungibleToken { + string address = 1; + string token_sell = 2; + int64 max_sell = 3; + int64 rate_min = 4; + string token_buy = 5; + int64 min_buy = 6; + google.protobuf.Timestamp expire = 7; +} +``` + +## Matchmaker program + +The filter program attempts to decode the intent and if successful, checks +that it's not yet expired and that the account address has enough funds for the +intended token to be sold. + +The main program can match intents for exchanging assets. It does that by +creating a graph from all intents. When a cycle is found then it removes all +intents from that cycle of the mempool and crafts a transaction based on all the +removed intents. + +![matchmaker](matchmaker_graph.svg) +[excalidraw link](https://excalidraw.com/#room=1db86ba6d5f0ccb7447c,2vvRd4X2Y3HDWHihJmy9zw) diff --git a/documentation/dev/src/explore/design/intent_gossip/gossip_process.excalidraw b/documentation/dev/src/explore/design/intent_gossip/gossip_process.excalidraw new file mode 100644 index 0000000000..3684252693 --- /dev/null +++ b/documentation/dev/src/explore/design/intent_gossip/gossip_process.excalidraw @@ -0,0 +1,966 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "https://excalidraw.com", + "elements": [ + { + "type": "ellipse", + "version": 603, + "versionNonce": 717195654, + "isDeleted": false, + "id": "9XNyo7y8QCSEp4yAFf5oy", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1156.111111111111, + "y": 164.3333333333334, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 573.6666666666667, + "height": 372.55555555555554, + "seed": 821968881, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [] + }, + { + "type": "arrow", + "version": 1450, + "versionNonce": 941173851, + "isDeleted": false, + "id": "lXNINuf2v3Bas7FefE3LH", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1586.2054115693877, + "y": -370.2728566628903, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 246.73688630955917, + "height": 192.92404363452567, + "seed": 736805503, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "5xDzwVV0gDBlD-WL85LYy", + "focus": 0.18717224637187657, + "gap": 6.459472910604248 + }, + "endBinding": { + "elementId": "xxAsLeElpbNGHmw4QPxMz", + "focus": -0.23250849205562685, + "gap": 13.411672225924079 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -246.73688630955917, + 192.92404363452567 + ] + ] + }, + { + "type": "diamond", + "version": 278, + "versionNonce": 198810363, + "isDeleted": false, + "id": "5xDzwVV0gDBlD-WL85LYy", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1565.6666666666665, + "y": -444.66666666666663, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 127, + "height": 100, + "seed": 563016927, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "lXNINuf2v3Bas7FefE3LH", + "RR6GEDZFWUssCdTAnrDqo" + ] + }, + { + "type": "text", + "version": 253, + "versionNonce": 1818093109, + "isDeleted": false, + "id": "HskYIBtFFYajWD-2Djn1f", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1605.1666666666665, + "y": -409.66666666666663, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 50, + "height": 26, + "seed": 1643469585, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "lXNINuf2v3Bas7FefE3LH" + ], + "fontSize": 20, + "fontFamily": 1, + "text": "client", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "middle" + }, + { + "type": "rectangle", + "version": 432, + "versionNonce": 232368667, + "isDeleted": false, + "id": "5cPSOu9KDeCIp3Nmd546m", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1176, + "y": -287.2222222222222, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 570.0000000000001, + "height": 356.2222222222222, + "seed": 1306655743, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [] + }, + { + "type": "diamond", + "version": 627, + "versionNonce": 1842306310, + "isDeleted": false, + "id": "xxAsLeElpbNGHmw4QPxMz", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1181.3333333333333, + "y": -207.55555555555554, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 209, + "height": 188, + "seed": 1389553521, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "B4iQSfzoi419GYzKlXw5m", + "MPfW6JEUQYoWrzHeI_NxD", + "z6DMUeY7qrwuosEZr9D8K", + "GJPwvquPv4Afa-iz06Txv", + "bleUDuct9nWGxJfhyl_J2", + "V6oy4uJc_J45aC2sNpHvE", + "lXNINuf2v3Bas7FefE3LH", + "OIBiMf6VpPETwJAGERKti", + "J8EUyGyYHRSW895zskWbp" + ] + }, + { + "type": "diamond", + "version": 604, + "versionNonce": 1476920774, + "isDeleted": false, + "id": "dSBMH7Bqm1h_eoLM_yqkZ", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1184.4444444444446, + "y": 264.99999999999994, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 307.888888888889, + "height": 215.66666666666666, + "seed": 1838896927, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "OIBiMf6VpPETwJAGERKti", + "MPfW6JEUQYoWrzHeI_NxD", + "FqT97u9kn8yPY-e9ZEmwX", + "3w6C3S5gFIBLSOSnHrL9p", + "J8EUyGyYHRSW895zskWbp" + ] + }, + { + "type": "text", + "version": 446, + "versionNonce": 2067771125, + "isDeleted": false, + "id": "FOQ3kxQ9jn8r8iZ6-5Kdn", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1227.3333333333333, + "y": -149.55555555555551, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 121, + "height": 52, + "seed": 1118918783, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "Intent \nbroadcaster", + "baseline": 44, + "textAlign": "center", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 346, + "versionNonce": 94289307, + "isDeleted": false, + "id": "wNwxFCvE4WMQV8QLZiqxu", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1272, + "y": 281.99999999999994, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 131, + "height": 78, + "seed": 197177745, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "OIBiMf6VpPETwJAGERKti", + "MPfW6JEUQYoWrzHeI_NxD", + "J8EUyGyYHRSW895zskWbp" + ], + "fontSize": 20, + "fontFamily": 1, + "text": "intent\nbroadcaster \nnetwork", + "baseline": 70, + "textAlign": "center", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 1548, + "versionNonce": 1059405510, + "isDeleted": false, + "id": "OIBiMf6VpPETwJAGERKti", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1340.8991464307837, + "y": 256.43457590166764, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 19.424658574333307, + "height": 274.53680436823555, + "seed": 413185503, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "dSBMH7Bqm1h_eoLM_yqkZ", + "focus": 0.06980420648639936, + "gap": 8.455707710143173 + }, + "endBinding": { + "elementId": "xxAsLeElpbNGHmw4QPxMz", + "focus": -0.27643465526659067, + "gap": 24.916176360598527 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -19.424658574333307, + -274.53680436823555 + ] + ] + }, + { + "type": "arrow", + "version": 1783, + "versionNonce": 702656213, + "isDeleted": false, + "id": "MPfW6JEUQYoWrzHeI_NxD", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1225.7890453334985, + "y": -41.97976066319893, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 21.266468152933612, + "height": 381.0875685373966, + "seed": 1670492081, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "xxAsLeElpbNGHmw4QPxMz", + "gap": 23.483962590379445, + "focus": 0.5312629502131418 + }, + "endBinding": { + "elementId": "dSBMH7Bqm1h_eoLM_yqkZ", + "gap": 16.103707014847412, + "focus": -0.8818009263489358 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -21.266468152933612, + 381.0875685373966 + ] + ] + }, + { + "type": "text", + "version": 540, + "versionNonce": 1475775174, + "isDeleted": false, + "id": "InLHuKJiMfsKjnhDLER2S", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1224.6666666666667, + "y": 122.99999999999997, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 88, + "height": 52, + "seed": 1075843217, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "validate \nmsg", + "baseline": 44, + "textAlign": "right", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 1384, + "versionNonce": 280535450, + "isDeleted": false, + "id": "J8EUyGyYHRSW895zskWbp", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1386.7368978905408, + "y": 286.51414709947557, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 19.54258711706757, + "height": 343.3666092756827, + "seed": 1500547647, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "dSBMH7Bqm1h_eoLM_yqkZ", + "focus": 0.34597438474774744, + "gap": 10.117038200934843 + }, + "endBinding": { + "elementId": "xxAsLeElpbNGHmw4QPxMz", + "focus": -0.7476913039884736, + "gap": 26.682463765500543 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -19.54258711706757, + -343.3666092756827 + ] + ] + }, + { + "type": "text", + "version": 452, + "versionNonce": 1029595482, + "isDeleted": false, + "id": "3a6V_ozlu_-z813t_fjbn", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1391, + "y": 187.77777777777777, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 156, + "height": 36, + "seed": 15072497, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 28, + "fontFamily": 1, + "text": "libP2P logic", + "baseline": 25, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "diamond", + "version": 365, + "versionNonce": 757518677, + "isDeleted": false, + "id": "hngD3gT8MxLbMtULxwILm", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1204.6111111111113, + "y": -434.0000000000001, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 127, + "height": 100, + "seed": 662285233, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "lXNINuf2v3Bas7FefE3LH", + "V6oy4uJc_J45aC2sNpHvE" + ] + }, + { + "type": "text", + "version": 334, + "versionNonce": 979982971, + "isDeleted": false, + "id": "Tne4ggu_ZDCdoqKD1HVLY", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1244.1111111111113, + "y": -402.0000000000001, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 50, + "height": 26, + "seed": 1728898015, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "lXNINuf2v3Bas7FefE3LH" + ], + "fontSize": 20, + "fontFamily": 1, + "text": "client", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "middle" + }, + { + "type": "arrow", + "version": 1682, + "versionNonce": 1212570555, + "isDeleted": false, + "id": "V6oy4uJc_J45aC2sNpHvE", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1262.664151563201, + "y": -330.8400855354932, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 2.5819871518015134, + "height": 140.4581124311759, + "seed": 1528357951, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "hngD3gT8MxLbMtULxwILm", + "focus": 0.10105347446704833, + "gap": 5.8523740982304915 + }, + "endBinding": { + "elementId": "xxAsLeElpbNGHmw4QPxMz", + "focus": -0.18349209857314347, + "gap": 1 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 2.5819871518015134, + 140.4581124311759 + ] + ] + }, + { + "type": "text", + "version": 377, + "versionNonce": 1391350555, + "isDeleted": false, + "id": "q9mdbiPTZ5bMiHS1pP8Jd", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1267.8333333333333, + "y": -327.77777777777777, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 86, + "height": 26, + "seed": 280036991, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "send msg", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 138, + "versionNonce": 2055493659, + "isDeleted": false, + "id": "JdaaIi8F9pCIbQiuefyHi", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1388.75, + "y": -206.72222222222223, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 180, + "height": 35, + "seed": 476397371, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 28, + "fontFamily": 3, + "text": "Gossip Node", + "baseline": 28, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 419, + "versionNonce": 1035911669, + "isDeleted": false, + "id": "E1bibepZLZFj3VmWghmhk", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1557.1388888888887, + "y": -324.94444444444554, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 86, + "height": 26, + "seed": 1482472437, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "send msg", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "diamond", + "version": 629, + "versionNonce": 251582106, + "isDeleted": false, + "id": "JaiST4fQ2FlodcbDsHGRd", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1525.611111111111, + "y": -178.99999999999997, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 209, + "height": 188, + "seed": 1161636571, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "B4iQSfzoi419GYzKlXw5m", + "MPfW6JEUQYoWrzHeI_NxD", + "z6DMUeY7qrwuosEZr9D8K", + "GJPwvquPv4Afa-iz06Txv", + "bleUDuct9nWGxJfhyl_J2", + "RR6GEDZFWUssCdTAnrDqo", + "yZ1sDbO9UxZw6Yw7d8BGk", + "sofyhfQ6yAERl8W7igqud", + "98jHSy6KgIgI-kigPhATL", + "Jj-F4u_NSjuW-tVWK6ErH" + ] + }, + { + "type": "text", + "version": 477, + "versionNonce": 320811829, + "isDeleted": false, + "id": "yE8obB-cq-eO9tpUS_PcA", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1575.611111111111, + "y": -117.99999999999994, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 121, + "height": 52, + "seed": 413385813, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "DKG \nbroadcaster", + "baseline": 44, + "textAlign": "center", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 115, + "versionNonce": 808640859, + "isDeleted": false, + "id": "RR6GEDZFWUssCdTAnrDqo", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1660.0572555330295, + "y": -366.9575940330065, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 24.665187381169744, + "height": 183.91639038865497, + "seed": 45437883, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "5xDzwVV0gDBlD-WL85LYy", + "focus": -0.5447225569886008, + "gap": 1.5967808146620044 + }, + "endBinding": { + "elementId": "JaiST4fQ2FlodcbDsHGRd", + "focus": -0.07528645180716763, + "gap": 6.5362537154315845 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -24.665187381169744, + 183.91639038865497 + ] + ] + }, + { + "type": "diamond", + "version": 596, + "versionNonce": 1248600538, + "isDeleted": false, + "id": "sJFOeRzApKjnkoavWYSOm", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1415.6666666666667, + "y": 270.6666666666667, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 292.8888888888888, + "height": 207.6666666666666, + "seed": 3834485, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "OIBiMf6VpPETwJAGERKti", + "MPfW6JEUQYoWrzHeI_NxD", + "FqT97u9kn8yPY-e9ZEmwX", + "3w6C3S5gFIBLSOSnHrL9p", + "J8EUyGyYHRSW895zskWbp", + "yZ1sDbO9UxZw6Yw7d8BGk", + "sofyhfQ6yAERl8W7igqud", + "98jHSy6KgIgI-kigPhATL", + "Jj-F4u_NSjuW-tVWK6ErH" + ] + }, + { + "type": "text", + "version": 354, + "versionNonce": 339994458, + "isDeleted": false, + "id": "ERwB6OfVxtsDLuZO1G4dn", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1507.2222222222224, + "y": 292.6666666666667, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 131, + "height": 78, + "seed": 410831707, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "OIBiMf6VpPETwJAGERKti", + "MPfW6JEUQYoWrzHeI_NxD", + "yZ1sDbO9UxZw6Yw7d8BGk" + ], + "fontSize": 20, + "fontFamily": 1, + "text": "DKG\nbroadcaster \nnetwork", + "baseline": 70, + "textAlign": "center", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 432, + "versionNonce": 855557126, + "isDeleted": false, + "id": "yZ1sDbO9UxZw6Yw7d8BGk", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1613.2645903010791, + "y": 5.6816480400971585, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 32.37650849922488, + "height": 267.8739593512054, + "seed": 978571771, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "JaiST4fQ2FlodcbDsHGRd", + "focus": 0.056328322376417134, + "gap": 8.799318498256582 + }, + "endBinding": { + "elementId": "ERwB6OfVxtsDLuZO1G4dn", + "focus": 0.016268660508214034, + "gap": 19.11105927536414 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -32.37650849922488, + 267.8739593512054 + ] + ] + }, + { + "type": "arrow", + "version": 398, + "versionNonce": 2067988678, + "isDeleted": false, + "id": "Jj-F4u_NSjuW-tVWK6ErH", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1623.0089473868802, + "y": 304.406818117378, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 33.75764899556157, + "height": 307.2241654227815, + "seed": 398843163, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "sJFOeRzApKjnkoavWYSOm", + "focus": 0.3632505836483008, + "gap": 7.699251414567215 + }, + "endBinding": { + "elementId": "JaiST4fQ2FlodcbDsHGRd", + "focus": -0.3414897328591685, + "gap": 9.04048516465393 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 33.75764899556157, + -307.2241654227815 + ] + ] + }, + { + "type": "text", + "version": 554, + "versionNonce": 720882453, + "isDeleted": false, + "id": "kXVNso4ItXnAMFArYHbYk", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1486.1111111111115, + "y": 109.99999999999997, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 88, + "height": 52, + "seed": 1662723835, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "validate \nmsg", + "baseline": 44, + "textAlign": "right", + "verticalAlign": "top" + } + ], + "appState": { + "gridSize": null, + "viewBackgroundColor": "#ffffff" + } +} \ No newline at end of file diff --git a/documentation/dev/src/explore/design/intent_gossip/gossip_process.svg b/documentation/dev/src/explore/design/intent_gossip/gossip_process.svg new file mode 100644 index 0000000000..9129d9eea7 --- /dev/null +++ b/documentation/dev/src/explore/design/intent_gossip/gossip_process.svg @@ -0,0 +1,16 @@ + + + + + + + clientIntent broadcasterintentbroadcaster networkvalidate msglibP2P magicclientsend msgGossip Nodesend msgDKG broadcasterDKGbroadcaster networkvalidate msg \ No newline at end of file diff --git a/documentation/dev/src/explore/design/intent_gossip/incentive.md b/documentation/dev/src/explore/design/intent_gossip/incentive.md new file mode 100644 index 0000000000..51905d457f --- /dev/null +++ b/documentation/dev/src/explore/design/intent_gossip/incentive.md @@ -0,0 +1,9 @@ +# Incentive + +[Tracking Issue](https://github.com/anoma/anoma/issues/37) + +--- + +TODO +- describe incentive function +- describe logic to ensure matchmaker can't cheat intent gossip service diff --git a/documentation/dev/src/explore/design/intent_gossip/intent.md b/documentation/dev/src/explore/design/intent_gossip/intent.md new file mode 100644 index 0000000000..62bffedbe0 --- /dev/null +++ b/documentation/dev/src/explore/design/intent_gossip/intent.md @@ -0,0 +1,28 @@ +# Intents + +An intent is a way of expressing a user's desire. It is defined as arbitrary +data and an optional address for a schema. The data is as arbitrary as possible +to allow the users to express any sort of intent. It could range from defining a +selling order for a specific token to offering piano lessons or even proposing a +green tax for shoes’ manufacturers. + +An intent is written using an encoding, or data schema. The encoding exists +either on-chain or off-chain. It must be known by users that want to express +similar intents. It also must be understood by some matchmaker. Otherwise, it +possibly won’t be matched. The user can define its own schema and inform either +off-chain or on-chain. Having it on-chain allows it to easily share it with other +participants. Please refer to [data schema](./../ledger/storage/data-schema.md) for more +information about the usage of on-chain schema. + +--- + +There is only a single intent type that is composed of arbitrary data and a +possible schema definition. + +```rust +struct Intent { + schema: Option, + data: Vec, + timestamp: Timestamp +} +``` diff --git a/documentation/dev/src/explore/design/intent_gossip/intent_gossip.md b/documentation/dev/src/explore/design/intent_gossip/intent_gossip.md new file mode 100644 index 0000000000..f9342a0181 --- /dev/null +++ b/documentation/dev/src/explore/design/intent_gossip/intent_gossip.md @@ -0,0 +1,51 @@ +# Intent gossip network + +The intent gossip network enables counterparty discovery for bartering. The +users can express any sort of intents that might be matched and transformed into +a transaction that fulfills the intents on the Anoma ledger. + +An [intent](./intent.md) describes the desire of a user, from asset exchange to a +green tax percent for selling shoes. These intents are picked up by a matchmaker +that composes them into transactions to send to the ledger network. A matchmaker +is optionally included in the intent gossip node. + +Each node connects to a specified intent gossip network, either a public or a +private one. Anyone can create their own network where they decide all aspects +of it: which type of intents is propagated, which nodes can participate, the +matchmaker logic, etc. It is possible, for example, to run the intent gossip system +over bluetooth to have it off-line. + +An intent gossip node is a peer in the intent gossip network that has the role +of propagating intents to all other connected nodes. + +The network uses the +[gossipsub](https://github.com/libp2p/specs/tree/512accdd81e35480911499cea14e7d7ea019f71b/pubsub/gossipsub) +network behaviour. This system aggregates nodes around topics of interest. Each +node subscribes to a set of topics and connects to other nodes that are also +subscribed to the same topics. A topic defines a sub-network for a defined +interest, e.g. “asset_exchange”. see +[gossipsub](https://github.com/libp2p/specs/tree/512accdd81e35480911499cea14e7d7ea019f71b/pubsub/gossipsub) +for more information on the network topology. + +Each node has an incentive to propagate intents and will obtain a small portion +of the fees if the intent is settled. (TODO: update when logic is found) See +[incentive](./incentive.md) for more information. + +### Flow diagram: asset exchange + +This example shows three intents matched together by the intent gossip network. +These three intents express user desires to exchange assets. + +![intent gossip and ledger network +interaction](./example.svg "intent gossip network") +[Diagram on Excalidraw](https://excalidraw.com/#room=257e44f4b4b5867bf541,XDEKyGVIpqCrfq55bRqKug) + +# Flow diagram: life cycle of intent and global process + +This diagram shows the process flow for intents, from users expressing their +desire to the ledger executing the validity predicate to check the crafted +transaction. + +![intent life cycle](./intent_life_cycle.svg "intent life +cycle") +[Diagram on Excalidraw](https://excalidraw.com/#room=7ac107b3757c64049003,cdMInfvdLtjaGWSZWEKrhw) diff --git a/documentation/dev/src/explore/design/intent_gossip/intent_life_cycle.excalidraw b/documentation/dev/src/explore/design/intent_gossip/intent_life_cycle.excalidraw new file mode 100644 index 0000000000..83b9eced85 --- /dev/null +++ b/documentation/dev/src/explore/design/intent_gossip/intent_life_cycle.excalidraw @@ -0,0 +1,1686 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "https://excalidraw.com", + "elements": [ + { + "type": "text", + "version": 588, + "versionNonce": 594523952, + "isDeleted": false, + "id": "1u_2wBZI6b8qbCpHVN6MP", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -298.6003582724815, + "y": 1338.2754110612868, + "strokeColor": "#1864ab", + "backgroundColor": "transparent", + "width": 85.4456709210074, + "height": 21.78026905829601, + "seed": 71443719, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 16.75405312176615, + "fontFamily": 1, + "text": "add intent", + "baseline": 14.78026905829601, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 454, + "versionNonce": 786627024, + "isDeleted": false, + "id": "2Wc5lEY411C5Gl9LSu5pY", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -410.91401048972233, + "y": 1360.7731689088182, + "strokeColor": "#c92a2a", + "backgroundColor": "transparent", + "width": 88, + "height": 18, + "seed": 1334554569, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "yk9tRH45JFldlow2BsTQc", + "IfZHk6DCJHzdGQSleRzVY", + "3M7y36XaiPpkZdYFa6HL0" + ], + "fontSize": 13.677130044843086, + "fontFamily": 3, + "text": "filter.wasm", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 2279, + "versionNonce": 1948716336, + "isDeleted": false, + "id": "3M7y36XaiPpkZdYFa6HL0", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -305.31404973574377, + "y": 1369.1513491711225, + "strokeColor": "#1864ab", + "backgroundColor": "transparent", + "width": 105.04325514724303, + "height": 0.1273972078367933, + "seed": 94578119, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "MA9plWdw54jKf3dPF231d", + "focus": 0.11381802003862611, + "gap": 4.5029253777944405 + }, + "endBinding": { + "elementId": "J3PIpIxWftxjM5b3onaa_", + "focus": -1.823336288291325, + "gap": 9.453089222814356 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 105.04325514724303, + 0.1273972078367933 + ] + ] + }, + { + "type": "rectangle", + "version": 628, + "versionNonce": 1926825424, + "isDeleted": false, + "id": "jTa_ZQSjZQ_9wK0AxfkKq", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -200.54779225354866, + "y": 1340.590433482808, + "strokeColor": "#1864ab", + "backgroundColor": "transparent", + "width": 125.3736920777284, + "height": 59.495515695067446, + "seed": 1482668551, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "Q4yHCPe8MjqsFcGPSqmAZ", + "3M7y36XaiPpkZdYFa6HL0", + "9rmYOU060-nUE-om6NWFg", + "dAdWOUfpjNuXJyfO475fP" + ] + }, + { + "type": "rectangle", + "version": 504, + "versionNonce": 1614695216, + "isDeleted": false, + "id": "MA9plWdw54jKf3dPF231d", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -416.8923363492138, + "y": 1350.6808669656184, + "strokeColor": "#1864ab", + "backgroundColor": "transparent", + "width": 107.07536123567559, + "height": 33.48318385650231, + "seed": 186308295, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "IolhdtZMlJt05RE7PSeqH", + "3M7y36XaiPpkZdYFa6HL0" + ] + }, + { + "type": "arrow", + "version": 1314, + "versionNonce": 44918064, + "isDeleted": false, + "id": "IolhdtZMlJt05RE7PSeqH", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -297.62941465804636, + "y": 1305.067079818005, + "strokeColor": "#1864ab", + "backgroundColor": "transparent", + "width": 35.4136526564796, + "height": 41.1911597898536, + "seed": 580979783, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "vMWskj1YJao4q8Szni_9g", + "focus": 0.2739809180363499, + "gap": 3.4310135063774396 + }, + "endBinding": { + "elementId": "MA9plWdw54jKf3dPF231d", + "focus": 0.17835547552991876, + "gap": 4.422627357759893 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -35.4136526564796, + 41.1911597898536 + ] + ] + }, + { + "type": "text", + "version": 630, + "versionNonce": 701297456, + "isDeleted": false, + "id": "J3PIpIxWftxjM5b3onaa_", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -193.70922723112722, + "y": 1346.0612855007478, + "strokeColor": "#c92a2a", + "backgroundColor": "transparent", + "width": 112.83632286995548, + "height": 16.412556053811695, + "seed": 856985703, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "9rmYOU060-nUE-om6NWFg", + "Q4yHCPe8MjqsFcGPSqmAZ", + "MOjksoKslfp16-Y701zlH", + "3M7y36XaiPpkZdYFa6HL0" + ], + "fontSize": 13.67713004484308, + "fontFamily": 2, + "text": "matchmaker.wasm", + "baseline": 11.412556053811695, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 629, + "versionNonce": 2084073754, + "isDeleted": false, + "id": "AfmJxEIuWj5_62161GQ01", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -326.2723811922641, + "y": 1440.665545590435, + "strokeColor": "#1864ab", + "backgroundColor": "transparent", + "width": 176.69394618834113, + "height": 56.203662182361796, + "seed": 337914215, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "9rmYOU060-nUE-om6NWFg", + "mlM1pmVM-052hahaRXJQR", + "ttC9xH3eOGzQ_k5DLzmBu" + ] + }, + { + "type": "text", + "version": 642, + "versionNonce": 1534794758, + "isDeleted": false, + "id": "TzqXubskSAjo2ZuvkxkCC", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -293.94129001139663, + "y": 1468.2503736920773, + "strokeColor": "#1864ab", + "backgroundColor": "transparent", + "width": 112, + "height": 18, + "seed": 647873609, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "ttC9xH3eOGzQ_k5DLzmBu", + "9rmYOU060-nUE-om6NWFg" + ], + "fontSize": 13.67713004484309, + "fontFamily": 3, + "text": "tx.wawm + data", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 2292, + "versionNonce": 1408723920, + "isDeleted": false, + "id": "9rmYOU060-nUE-om6NWFg", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -147.6356968299097, + "y": 1408.7716634080846, + "strokeColor": "#1864ab", + "backgroundColor": "transparent", + "width": 66.68074390630872, + "height": 23.556734178462648, + "seed": 798702697, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "jTa_ZQSjZQ_9wK0AxfkKq", + "gap": 8.685714230208873, + "focus": -0.6781834884379211 + }, + "endBinding": { + "elementId": "AfmJxEIuWj5_62161GQ01", + "gap": 8.337148003887705, + "focus": -0.47373449663638795 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -66.68074390630872, + 23.556734178462648 + ] + ] + }, + { + "type": "text", + "version": 507, + "versionNonce": 260021712, + "isDeleted": false, + "id": "He6AuKTKQxKmk5B38hWHj", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -176.69016893516272, + "y": 1368.6692825112111, + "strokeColor": "#1864ab", + "backgroundColor": "transparent", + "width": 75.90807174887914, + "height": 17.780269058296007, + "seed": 836533545, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 13.677130044843084, + "fontFamily": 1, + "text": "craft data", + "baseline": 11.780269058296007, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 1796, + "versionNonce": 1407883056, + "isDeleted": false, + "id": "ttC9xH3eOGzQ_k5DLzmBu", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -245.0771506636562, + "y": 1508.714667199035, + "strokeColor": "#1864ab", + "backgroundColor": "transparent", + "width": 0.6776858655143201, + "height": 347.40968967814, + "seed": 187206441, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "AfmJxEIuWj5_62161GQ01", + "gap": 11.845459426238218, + "focus": 0.08178190315132251 + }, + "endBinding": { + "elementId": "SehQ2WycVyCQCB-DbZfI1", + "gap": 3.963620241223044, + "focus": -0.07279835372456127 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 0.6776858655143201, + 347.40968967814 + ] + ] + }, + { + "type": "ellipse", + "version": 410, + "versionNonce": 51621680, + "isDeleted": false, + "id": "SehQ2WycVyCQCB-DbZfI1", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -329.5040702804547, + "y": 1859.9240159441954, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 183.84491778774336, + "height": 121.63153961136064, + "seed": 1448762345, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "ttC9xH3eOGzQ_k5DLzmBu" + ] + }, + { + "type": "text", + "version": 374, + "versionNonce": 1588809350, + "isDeleted": false, + "id": "zERziwpui3gX_VflZl-6H", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -294.7738759605737, + "y": 1914.3163926258123, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 102.57847533632317, + "height": 17.780269058296007, + "seed": 1122418569, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 13.677130044843079, + "fontFamily": 1, + "text": "Ledger network", + "baseline": 11.780269058296007, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 349, + "versionNonce": 996390352, + "isDeleted": false, + "id": "95Wz9icO-OmtvwP5kKKfo", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -231.3882257363585, + "y": 1743.2290732436484, + "strokeColor": "#1864ab", + "backgroundColor": "transparent", + "width": 29.405829596412616, + "height": 17.780269058296007, + "seed": 1438218537, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 13.677130044843071, + "fontFamily": 1, + "text": "send", + "baseline": 11.780269058296007, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 236, + "versionNonce": 2057635802, + "isDeleted": false, + "id": "1o37i1BlUHSA_I1CYSHoq", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -369.98077680761, + "y": 1306.2222222222215, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 43.986547085201835, + "height": 24.30835496813786, + "seed": 365688905, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "IolhdtZMlJt05RE7PSeqH" + ], + "fontSize": 18.520651404295513, + "fontFamily": 1, + "text": "apply", + "baseline": 17.30835496813786, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 1479, + "versionNonce": 442628400, + "isDeleted": false, + "id": "dAdWOUfpjNuXJyfO475fP", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -92.3069277739813, + "y": 1403.7229079845479, + "strokeColor": "#1864ab", + "backgroundColor": "transparent", + "width": 9.276809968310843, + "height": 353.05286013400246, + "seed": 203795395, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "jTa_ZQSjZQ_9wK0AxfkKq", + "focus": -0.7039148076260963, + "gap": 3.636958806672169 + }, + "endBinding": { + "elementId": "xA7xWASKaJXAE1SQjNFQ2", + "focus": 0.2211669756965918, + "gap": 14.492622357918698 + }, + "lastCommittedPoint": null, + "startArrowhead": "arrow", + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 9.276809968310843, + 353.05286013400246 + ] + ] + }, + { + "type": "ellipse", + "version": 494, + "versionNonce": 12155910, + "isDeleted": false, + "id": "xA7xWASKaJXAE1SQjNFQ2", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -144.08927207417597, + "y": 1770.7329347284497, + "strokeColor": "#1864ab", + "backgroundColor": "transparent", + "width": 101.89461883408097, + "height": 60.17937219730958, + "seed": 833498093, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "dAdWOUfpjNuXJyfO475fP" + ] + }, + { + "type": "text", + "version": 413, + "versionNonce": 1448457242, + "isDeleted": false, + "id": "Mh7caG46B4Id7Rt9mZVK0", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -78.91214202933338, + "y": 1692.8943697060292, + "strokeColor": "#1864ab", + "backgroundColor": "transparent", + "width": 90, + "height": 19, + "seed": 1753782275, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "dAdWOUfpjNuXJyfO475fP" + ], + "fontSize": 13.677130044843079, + "fontFamily": 1, + "text": "read storage", + "baseline": 13, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 411, + "versionNonce": 706916998, + "isDeleted": false, + "id": "3Nb-sNCg1mpGbUpGqPC6x", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -127.67671602036424, + "y": 1788.5132037867468, + "strokeColor": "#1864ab", + "backgroundColor": "transparent", + "width": 75.22421524663697, + "height": 17.780269058296007, + "seed": 1638966797, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 13.677130044843079, + "fontFamily": 1, + "text": "ledger node", + "baseline": 11.780269058296007, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 162, + "versionNonce": 137567834, + "isDeleted": false, + "id": "vMWskj1YJao4q8Szni_9g", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -294.2777777777778, + "y": 1243.3333333333333, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 86, + "height": 61, + "seed": 1736645018, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "IolhdtZMlJt05RE7PSeqH", + "MODmRH_Ai_h7eca-aYe9A", + "mHbM0I-2cMJHDQh1moe77" + ] + }, + { + "type": "diamond", + "version": 389, + "versionNonce": 416087686, + "isDeleted": false, + "id": "mBiwqFRC0vttSdLSnsU30", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -445.2777777777778, + "y": 1092.6666666666667, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 406.66666666666674, + "height": 525.6666666666669, + "seed": 476615706, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "9rmYOU060-nUE-om6NWFg", + "dAdWOUfpjNuXJyfO475fP" + ] + }, + { + "type": "ellipse", + "version": 352, + "versionNonce": 1356395824, + "isDeleted": false, + "id": "JwMrnB618nsHGBBcf92Nk", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -763.2777777777765, + "y": 874.9999999999998, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 763.3333333333335, + "height": 772.6666666666669, + "seed": 2052937478, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "ttC9xH3eOGzQ_k5DLzmBu" + ] + }, + { + "type": "text", + "version": 170, + "versionNonce": 1019110864, + "isDeleted": false, + "id": "tKzpFkSzFkhgxKS4-AVGh", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -502.944444444443, + "y": 895.6666666666666, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 190, + "height": 52, + "seed": 1397120794, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "node connected to \ntopic X", + "baseline": 44, + "textAlign": "center", + "verticalAlign": "top" + }, + { + "type": "ellipse", + "version": 443, + "versionNonce": 988924208, + "isDeleted": false, + "id": "jLWO7OrtG_BOPVeKMiwwN", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -473.44444444444264, + "y": 870.3333333333328, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 738.6666666666667, + "height": 779.0000000000005, + "seed": 1658325702, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "ttC9xH3eOGzQ_k5DLzmBu" + ] + }, + { + "type": "text", + "version": 46, + "versionNonce": 39391066, + "isDeleted": false, + "id": "GyEOsmqW1Zbdi7mCavkOe", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -302.44444444444275, + "y": 1444, + "strokeColor": "#1864ab", + "backgroundColor": "transparent", + "width": 134, + "height": 21, + "seed": 734861702, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 16, + "fontFamily": 1, + "text": "wrap transaction", + "baseline": 15, + "textAlign": "center", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 364, + "versionNonce": 770571728, + "isDeleted": false, + "id": "MODmRH_Ai_h7eca-aYe9A", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": -479.5404756662694, + "y": 1107.858463582872, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 182.87979526759636, + "height": 175.27063591985802, + "seed": 1217671632, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "KwgaEOt8AQFLzGPvhESKA", + "focus": -0.46643591145185553, + "gap": 6.200069247495527 + }, + "endBinding": { + "elementId": "vMWskj1YJao4q8Szni_9g", + "focus": -0.7361561089573266, + "gap": 2.3829026208952087 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 182.87979526759636, + 175.27063591985802 + ] + ] + }, + { + "type": "diamond", + "version": 778, + "versionNonce": 595069744, + "isDeleted": false, + "id": "1aiocLnc3sR_lZQoFdB-y", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -704.777777777776, + "y": 1239.6666666666663, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 234.6666666666666, + "height": 309.6666666666667, + "seed": 344958598, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "9rmYOU060-nUE-om6NWFg", + "dAdWOUfpjNuXJyfO475fP", + "MODmRH_Ai_h7eca-aYe9A" + ] + }, + { + "type": "text", + "version": 1103, + "versionNonce": 2017820624, + "isDeleted": false, + "id": "50lEI8L3qiqHPIwEeJjSw", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": -633.4444444444428, + "y": 1277.4999999999993, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 88, + "height": 42, + "seed": 2055761114, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 16, + "fontFamily": 1, + "text": "intent\ngossip node", + "baseline": 36, + "textAlign": "center", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 196, + "versionNonce": 951002416, + "isDeleted": false, + "id": "zoKUQOZpsx3bSrQmlje2Y", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -518.4444444444428, + "y": 1209.5, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 13, + "height": 21, + "seed": 1744336198, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 16, + "fontFamily": 1, + "text": "...", + "baseline": 15, + "textAlign": "center", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 235, + "versionNonce": 73640752, + "isDeleted": false, + "id": "l4h4jtqh4lQ5ChrRu_d_W", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -534.9444444444428, + "y": 1211, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 45, + "height": 24.000000000000004, + "seed": 1561834950, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "NbiyFfs9_Zj9QLzFL8qHm", + "sZ8QrMhPhFBK7IsremLwb", + "B6B0y6Mtp0UrJDdAOrL4y" + ] + }, + { + "type": "arrow", + "version": 1093, + "versionNonce": 1896727504, + "isDeleted": false, + "id": "B6B0y6Mtp0UrJDdAOrL4y", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -548.3104597282063, + "y": 1368.7777417215675, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 24.520420568205054, + "height": 124.27733365833865, + "seed": 733305606, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "kfmygtSSHmjQGgRHYzhpm", + "focus": 0.25664643293730066, + "gap": 10.318970816658975 + }, + "endBinding": { + "elementId": "l4h4jtqh4lQ5ChrRu_d_W", + "focus": 0.285651344839639, + "gap": 9.50040806322886 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 24.520420568205054, + -124.27733365833865 + ] + ] + }, + { + "type": "arrow", + "version": 732, + "versionNonce": 138725840, + "isDeleted": false, + "id": "sZ8QrMhPhFBK7IsremLwb", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -519.0071422289418, + "y": 1208, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 4.665799248315011, + "height": 60.764495548789455, + "seed": 1445654746, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "l4h4jtqh4lQ5ChrRu_d_W", + "focus": -0.2310245718703419, + "gap": 3 + }, + "endBinding": { + "elementId": "KwgaEOt8AQFLzGPvhESKA", + "focus": -0.06849615152086622, + "gap": 6.783169732481319 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -4.665799248315011, + -60.764495548789455 + ] + ] + }, + { + "type": "text", + "version": 854, + "versionNonce": 557904688, + "isDeleted": false, + "id": "y-BT1d_fUjOriE9fXDJL5", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": -600.8876146788973, + "y": 1384.7289755351683, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 72, + "height": 57, + "seed": 277391514, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 14.403669724770648, + "fontFamily": 1, + "text": "gossipsub \nintent\nmempool", + "baseline": 51, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 371, + "versionNonce": 434353968, + "isDeleted": false, + "id": "kfmygtSSHmjQGgRHYzhpm", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -611.9444444444428, + "y": 1379.0967125382265, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 86, + "height": 61, + "seed": 405227014, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "IolhdtZMlJt05RE7PSeqH", + "MODmRH_Ai_h7eca-aYe9A", + "B6B0y6Mtp0UrJDdAOrL4y", + "jNcNZ79jIqf8USX6XWVfL" + ] + }, + { + "type": "diamond", + "version": 51, + "versionNonce": 1683064986, + "isDeleted": false, + "id": "SHqk2AS-Tf7dKA-jlraJy", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -642.9444444444428, + "y": 1809, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 126, + "height": 138, + "seed": 111487686, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "jNcNZ79jIqf8USX6XWVfL" + ] + }, + { + "type": "text", + "version": 61, + "versionNonce": 1776051718, + "isDeleted": false, + "id": "4KWmIOGgA881gCSC5JHPR", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -605.4444444444428, + "y": 1867.5, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 45, + "height": 21, + "seed": 1914582042, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 16, + "fontFamily": 1, + "text": "Client", + "baseline": 15, + "textAlign": "center", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 583, + "versionNonce": 1443824080, + "isDeleted": false, + "id": "jNcNZ79jIqf8USX6XWVfL", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -579.5237129692832, + "y": 1804.7181399798692, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 5.784969773188777, + "height": 354.7181399798692, + "seed": 338257542, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "SHqk2AS-Tf7dKA-jlraJy", + "focus": -0.012292118582791034, + "gap": 4.302480703755165 + }, + "endBinding": { + "elementId": "kfmygtSSHmjQGgRHYzhpm", + "focus": 0.09507177161013172, + "gap": 9.903287461773516 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 5.784969773188777, + -354.7181399798692 + ] + ] + }, + { + "type": "text", + "version": 75, + "versionNonce": 1051571526, + "isDeleted": false, + "id": "2KyLbsA0pYg-9FlG-TXOS", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -550.9444444444428, + "y": 1763.5, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 86, + "height": 21, + "seed": 436422490, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 16, + "fontFamily": 1, + "text": "send intent", + "baseline": 15, + "textAlign": "center", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 134, + "versionNonce": 1446470608, + "isDeleted": false, + "id": "_iAmT5vekaBL78IeOELHk", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -616.4444444444428, + "y": 1474.5, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 29, + "height": 21, + "seed": 472650778, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 16, + "fontFamily": 1, + "text": "add", + "baseline": 15, + "textAlign": "center", + "verticalAlign": "top" + }, + { + "type": "diamond", + "version": 649, + "versionNonce": 2130147290, + "isDeleted": false, + "id": "zO0p-uresSJTDL1fIuJzV", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -425.7777777777761, + "y": 1051.6666666666663, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 135.66666666666674, + "height": 118.66666666666676, + "seed": 112661018, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "9rmYOU060-nUE-om6NWFg", + "dAdWOUfpjNuXJyfO475fP", + "MODmRH_Ai_h7eca-aYe9A", + "NbiyFfs9_Zj9QLzFL8qHm", + "sZ8QrMhPhFBK7IsremLwb", + "mHbM0I-2cMJHDQh1moe77", + "ixAHiLZKgPdknMrEKL8E0" + ] + }, + { + "type": "arrow", + "version": 273, + "versionNonce": 2086180304, + "isDeleted": false, + "id": "mHbM0I-2cMJHDQh1moe77", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -349.6653716829509, + "y": 1166.225689032409, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 50.06401310624267, + "height": 82.14785148842725, + "seed": 1712918342, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "zO0p-uresSJTDL1fIuJzV", + "focus": 0.3763418967402116, + "gap": 2.3589356079478208 + }, + "endBinding": { + "elementId": "vMWskj1YJao4q8Szni_9g", + "focus": -0.5326929819465109, + "gap": 5.323580798930379 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 50.06401310624267, + 82.14785148842725 + ] + ] + }, + { + "type": "diamond", + "version": 680, + "versionNonce": 992396592, + "isDeleted": false, + "id": "KwgaEOt8AQFLzGPvhESKA", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -600.7777777777761, + "y": 1027.6666666666667, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 135.66666666666674, + "height": 118.66666666666676, + "seed": 1672626970, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "9rmYOU060-nUE-om6NWFg", + "dAdWOUfpjNuXJyfO475fP", + "MODmRH_Ai_h7eca-aYe9A", + "NbiyFfs9_Zj9QLzFL8qHm", + "sZ8QrMhPhFBK7IsremLwb", + "mHbM0I-2cMJHDQh1moe77" + ] + }, + { + "type": "diamond", + "version": 103, + "versionNonce": 1529867034, + "isDeleted": false, + "id": "5G2DYWMgIW2-Eyu0jHu5M", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -333.94444444444275, + "y": 634.75, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 126, + "height": 138, + "seed": 856516186, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "jNcNZ79jIqf8USX6XWVfL", + "ixAHiLZKgPdknMrEKL8E0" + ] + }, + { + "type": "text", + "version": 111, + "versionNonce": 1461469830, + "isDeleted": false, + "id": "3n5h8veTQO-lECAC8FTbh", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -296.44444444444275, + "y": 693.25, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 45, + "height": 21, + "seed": 1537623110, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 16, + "fontFamily": 1, + "text": "Client", + "baseline": 15, + "textAlign": "center", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 175, + "versionNonce": 288331846, + "isDeleted": false, + "id": "m_iuhNYFucnv5uwttXCPa", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -281.94444444444275, + "y": 819.25, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 86, + "height": 21, + "seed": 1275300634, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 16, + "fontFamily": 1, + "text": "send intent", + "baseline": 15, + "textAlign": "center", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 79, + "versionNonce": 1108019504, + "isDeleted": false, + "id": "ixAHiLZKgPdknMrEKL8E0", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -269.94444444444275, + "y": 777, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 84, + "height": 274, + "seed": 1390808730, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "5G2DYWMgIW2-Eyu0jHu5M", + "focus": -0.37232070443749277, + "gap": 3.604130291018784 + }, + "endBinding": { + "elementId": "zO0p-uresSJTDL1fIuJzV", + "focus": -0.21219892752739253, + "gap": 3.135288841647885 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -84, + 274 + ] + ] + }, + { + "type": "text", + "version": 1136, + "versionNonce": 408089904, + "isDeleted": false, + "id": "Wj0MHJ1dtfAoF25CFCBfi", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": -576.9444444444428, + "y": 1060.2499999999998, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 88, + "height": 42, + "seed": 960837584, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 16, + "fontFamily": 1, + "text": "intent\ngossip node", + "baseline": 36, + "textAlign": "center", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 1149, + "versionNonce": 1606676272, + "isDeleted": false, + "id": "TXaHYoLoaZlRQaR766TLH", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": -400.94444444444275, + "y": 1083.2500000000002, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 88, + "height": 42, + "seed": 1165581104, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 16, + "fontFamily": 1, + "text": "intent\ngossip node", + "baseline": 36, + "textAlign": "center", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 1227, + "versionNonce": 1197055440, + "isDeleted": false, + "id": "9hZsHGB4M9tFJZIfi6Ao_", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": -305.94444444444275, + "y": 1134.2499999999998, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 128, + "height": 63, + "seed": 1645861840, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 16, + "fontFamily": 1, + "text": "intent\ngossip node\nwith matchmaker", + "baseline": 57, + "textAlign": "center", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 210, + "versionNonce": 346021168, + "isDeleted": false, + "id": "26K0-MZ5xxu4N_zB_HZRa", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -164.94444444444275, + "y": 890.2499999999999, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 190, + "height": 52, + "seed": 1266445616, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "node connected to \ntopic Y", + "baseline": 44, + "textAlign": "center", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 913, + "versionNonce": 915376944, + "isDeleted": false, + "id": "ENHebue9f6lfx-kznKF5G", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": -285.94444444444275, + "y": 1243.7500000000002, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 72, + "height": 57, + "seed": 2113192912, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 14.403669724770648, + "fontFamily": 1, + "text": "gossipsub \nintent\nmempool", + "baseline": 51, + "textAlign": "left", + "verticalAlign": "top" + } + ], + "appState": { + "gridSize": null, + "viewBackgroundColor": "#ffffff" + } +} \ No newline at end of file diff --git a/documentation/dev/src/explore/design/intent_gossip/intent_life_cycle.svg b/documentation/dev/src/explore/design/intent_gossip/intent_life_cycle.svg new file mode 100644 index 0000000000..7295dd3431 --- /dev/null +++ b/documentation/dev/src/explore/design/intent_gossip/intent_life_cycle.svg @@ -0,0 +1,16 @@ + + + + + + + add intentfilter.wasmmatchmaker.wasmtx.wawm + datacraft dataLedger networksendapplyread storageledger nodenode connected to topic Xwrap transactionintentgossip node...gossipsub intentmempoolClientsend intentaddClientsend intentintentgossip nodeintentgossip nodeintentgossip nodewith matchmakernode connected to topic Ygossipsub intentmempool \ No newline at end of file diff --git a/documentation/dev/src/explore/design/intent_gossip/matchmaker.md b/documentation/dev/src/explore/design/intent_gossip/matchmaker.md new file mode 100644 index 0000000000..ce2cace5bd --- /dev/null +++ b/documentation/dev/src/explore/design/intent_gossip/matchmaker.md @@ -0,0 +1,80 @@ +# Matchmaker + +The matchmaker is a specific actor in the intent gossip network that tries to +match intents together. When intents are matched together, the matchmaker crafts +a transaction from them and sends it to the ledger network. + +A matchmaker is an intent gossip node started with additional parameters: a +ledger address and a list of sub-matchmakers. A sub-matchmaker is defined with a +topics list, a main program path, a filter program path, and a transaction code. + +The main and filter programs are wasm compiled code. Each has a defined +entrypoint and their own set of environment functions that they can call. + +When the matchmaker receives a new intent from the network it calls the +corresponding sub-matchmaker, the one that has the intent’s topic in their +topics list. A sub-matchmaker first checks if the intent is accepted by the +filter, before adding it to that sub-matchmaker database. Then the main program +is called with the intent and current state. + +## Sub-matchmaker topics' list + +A sub-matchmaker is defined to work with only a subset of encoding. Each intent +propagated to the corresponding topic will be process by this sub-matchmaker. + +Having a topics list instead of a unique topic allows a matchmaker to match +intents from different encodings. For example, when an updated version of an +encoding is out, the matchmaker could match intents from both versions if they +don’t diverge too much. + +## Sub-matchmaker database and state (name TBD) + +Each sub-matchmaker has a database and an arbitrary state. + +The database contains intents received by the node from the topics list that +passed the filter. + +The state is arbitrary data that is managed by the main program. That state is +given to all calls in the main program. + +The database is persistent but the state is not. When a node is started the +state is recovered by giving all intents from the database to the main program. +The invariant that the current state is equal to the state if the node is +restarted is not enforced and is the responsibility of the main program. + +## Filter program + +The filter is an optional wasm program given in parameters. This filter is used +to check each intent received by that sub-matchmaker. If it's not defined, +intents are directly passed to the main program. + + The entrypoint `filter_intent` takes an intent and returns a boolean. The +filter has the ability to query the state of the ledger for any given key. + +## Main program + +The main program is a mandatory wasm program given in parameters. The main +program must match together intents. + +The main program entrypoint `match_intent` takes the current state, a new intent +data and its id. The main program also has the ability to query the state of the +ledger. It also has functions `remove` and `get` to interact with the matchmaker +mempool. When a main matchmaker program finds a match it sends a transaction to +the ledger composed of the code template given in the matchmaker parameter and +the data given to this function. Finally the matchmaker must update its state so +the next run will have up to date values. + +The main program is called on two specific occasion; when intent gossip node is +started, on all intent from database and whenever a new intent is received from +the p2p network and the RPC endpoint, if enabled. + +## Transaction + +The transaction code given in parameters is used when the main program matches a +group of intents. The main program returns arbitrary data that is attached to +the transaction which is then injected into a ledger node. + +## Flow diagram: Matchmaker process +![matchmaker process](./matchmaker_process.svg "matchmaker process") + +[excalidraw link](https://excalidraw.com/#room=92b291c13cfab8fb22a4,OvHfWIrL0jeDzPI-EFZMaw) diff --git a/documentation/dev/src/explore/design/intent_gossip/matchmaker_graph.excalidraw b/documentation/dev/src/explore/design/intent_gossip/matchmaker_graph.excalidraw new file mode 100644 index 0000000000..8d2d29fc95 --- /dev/null +++ b/documentation/dev/src/explore/design/intent_gossip/matchmaker_graph.excalidraw @@ -0,0 +1,1648 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "https://excalidraw.com", + "elements": [ + { + "type": "ellipse", + "version": 304, + "versionNonce": 732978925, + "isDeleted": false, + "id": "0kpaYctW0QC41GkaU0Fnm", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 788, + "y": 448, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 142.99999999999994, + "height": 63.000000000000014, + "seed": 1594329571, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "YebzbhwZPZJG7VeGK6buO", + "x5FlGy9vo-0WFWlvTLxRB" + ] + }, + { + "type": "text", + "version": 66, + "versionNonce": 1832587875, + "isDeleted": false, + "id": "VGy1X1kAYasab67GT_3Vp", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 815, + "y": 464, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 86, + "height": 26, + "seed": 1391569133, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "Intent A", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "ellipse", + "version": 357, + "versionNonce": 1055790499, + "isDeleted": false, + "id": "ipca-2U6Ichp5KRWeBGiU", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1019.5, + "y": 553.5, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 142.99999999999994, + "height": 63.000000000000014, + "seed": 961566285, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "YebzbhwZPZJG7VeGK6buO", + "jrzBVVdi5EqY0mYYzI-qC", + "vUyB6nADBS51AWp7XW9EQ" + ] + }, + { + "type": "text", + "version": 103, + "versionNonce": 2128726541, + "isDeleted": false, + "id": "sh9VeUsrJu8zyMqC4wTTn", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1046.5, + "y": 569.5, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 88, + "height": 26, + "seed": 54575363, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "Intent B", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "ellipse", + "version": 443, + "versionNonce": 813787459, + "isDeleted": false, + "id": "mWM2JyFPRcVz5-LPE35xW", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 912.5, + "y": 728.5, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 142.99999999999994, + "height": 63.000000000000014, + "seed": 1522729677, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "jrzBVVdi5EqY0mYYzI-qC", + "jL-ZuiaA7Yepo4Ood8hh4" + ] + }, + { + "type": "text", + "version": 189, + "versionNonce": 563544173, + "isDeleted": false, + "id": "mkyAaMiHp_aflaPNTUS4h", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 939.5, + "y": 744.5, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 86, + "height": 26, + "seed": 1761418371, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "Intent C", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "ellipse", + "version": 602, + "versionNonce": 665405667, + "isDeleted": false, + "id": "8Kq9uOVih2T18r283qOW_", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 625.8084194993482, + "y": 740.257842502465, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 143.34456240942814, + "height": 63.15180022233556, + "seed": 1558060547, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "jL-ZuiaA7Yepo4Ood8hh4", + "hKuG4FbIRTd9ZuXgsPwJH", + "B-ARwwElkcqpEnbbGinI1" + ] + }, + { + "type": "text", + "version": 336, + "versionNonce": 2031512269, + "isDeleted": false, + "id": "jPnOeECE_YTxUJl_u56s4", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 652.8734767374922, + "y": 756.2963949398833, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 89.21444793314066, + "height": 26.062647710805145, + "seed": 2115827629, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20.048190546773174, + "fontFamily": 1, + "text": "Intent D", + "baseline": 18.062647710805145, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "ellipse", + "version": 596, + "versionNonce": 1193323555, + "isDeleted": false, + "id": "eYMWKEiFVFlYbjiPgu_c4", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1300.5, + "y": 552.5, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 142.99999999999994, + "height": 63.000000000000014, + "seed": 1785759373, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "vUyB6nADBS51AWp7XW9EQ", + "Tz4cdqtGreDIsYuudDs1x" + ] + }, + { + "type": "text", + "version": 347, + "versionNonce": 967433101, + "isDeleted": false, + "id": "rHC_PRTjElJ0lMKCObfnb", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1327.5, + "y": 568.5, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 87, + "height": 26, + "seed": 397063363, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "Intent E", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "ellipse", + "version": 652, + "versionNonce": 590894061, + "isDeleted": false, + "id": "1MaFQq1C6f_KmXrCju5x4", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1084.5, + "y": 873.5, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 142.99999999999994, + "height": 63.000000000000014, + "seed": 1794271469, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "ZVBhabk31rzDP8O9ZI07b", + "wkpAIY8WXU4_DhUYO1aB9" + ] + }, + { + "type": "text", + "version": 393, + "versionNonce": 1012982253, + "isDeleted": false, + "id": "DLt_4JJLkufDMzrR-McEC", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1111.5, + "y": 889.5, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 85, + "height": 26, + "seed": 1115072611, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "Intent F", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 39, + "versionNonce": 1611153251, + "isDeleted": false, + "id": "YebzbhwZPZJG7VeGK6buO", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 933, + "y": 485, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 96, + "height": 76, + "seed": 1699820525, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "0kpaYctW0QC41GkaU0Fnm", + "focus": -0.8133458878104184, + "gap": 2.90910614687202 + }, + "endBinding": { + "elementId": "ipca-2U6Ichp5KRWeBGiU", + "focus": -0.38721567770808374, + "gap": 6.84867663170747 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 96, + 76 + ] + ] + }, + { + "type": "arrow", + "version": 42, + "versionNonce": 858266701, + "isDeleted": false, + "id": "jrzBVVdi5EqY0mYYzI-qC", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1080, + "y": 624, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 40, + "height": 103, + "seed": 1343642477, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "ipca-2U6Ichp5KRWeBGiU", + "focus": -0.05715042949410481, + "gap": 7.857427983505644 + }, + "endBinding": { + "elementId": "mWM2JyFPRcVz5-LPE35xW", + "focus": 0.5953281273765297, + "gap": 12.01223971985118 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -40, + 103 + ] + ] + }, + { + "type": "arrow", + "version": 257, + "versionNonce": 137386755, + "isDeleted": false, + "id": "jL-ZuiaA7Yepo4Ood8hh4", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 909.4582871700171, + "y": 767.0701354272285, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 133.9560247707435, + "height": 0.9487028688702139, + "seed": 520169987, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "mWM2JyFPRcVz5-LPE35xW", + "focus": -0.21904362566296393, + "gap": 4.520486328322136 + }, + "endBinding": { + "elementId": "8Kq9uOVih2T18r283qOW_", + "focus": -0.10330406547410168, + "gap": 6.7389193162100725 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -133.9560247707435, + 0.9487028688702139 + ] + ] + }, + { + "type": "arrow", + "version": 39, + "versionNonce": 366545581, + "isDeleted": false, + "id": "vUyB6nADBS51AWp7XW9EQ", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1165, + "y": 592, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 129, + "height": 9, + "seed": 1771476173, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "ipca-2U6Ichp5KRWeBGiU", + "focus": 0.381367937500731, + "gap": 3.8982105359317814 + }, + "endBinding": { + "elementId": "eYMWKEiFVFlYbjiPgu_c4", + "focus": 0.2019864602059321, + "gap": 6.524513889047455 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 129, + -9 + ] + ] + }, + { + "type": "arrow", + "version": 58, + "versionNonce": 403964579, + "isDeleted": false, + "id": "x5FlGy9vo-0WFWlvTLxRB", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 630.6120629006252, + "y": 483.8482760775462, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 151.38793709937477, + "height": 3.1517239224538116, + "seed": 625380429, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": null, + "endBinding": { + "elementId": "0kpaYctW0QC41GkaU0Fnm", + "focus": -0.28899374373966724, + "gap": 7.345010020824645 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 151.38793709937477, + 3.1517239224538116 + ] + ] + }, + { + "type": "arrow", + "version": 257, + "versionNonce": 677492291, + "isDeleted": false, + "id": "B-ARwwElkcqpEnbbGinI1", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 620.2972122415217, + "y": 767.8259116200478, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 105.25300037055923, + "height": 3.00722858201598, + "seed": 1445768771, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "8Kq9uOVih2T18r283qOW_", + "focus": 0.19635383025160105, + "gap": 5.918038308672706 + }, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -105.25300037055923, + 3.00722858201598 + ] + ] + }, + { + "type": "arrow", + "version": 96, + "versionNonce": 1349387117, + "isDeleted": false, + "id": "Tz4cdqtGreDIsYuudDs1x", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1367, + "y": 622, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 3, + "height": 106, + "seed": 1860965379, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "eYMWKEiFVFlYbjiPgu_c4", + "focus": 0.054884241524747655, + "gap": 6.574103558846954 + }, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -3, + 106 + ] + ] + }, + { + "type": "arrow", + "version": 376, + "versionNonce": 1294704067, + "isDeleted": false, + "id": "ZVBhabk31rzDP8O9ZI07b", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 4.670616178776941, + "x": 959.5453473034307, + "y": 783.1973748150889, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 7.812955781063806, + "height": 238.3078431598483, + "seed": 447610179, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": null, + "endBinding": { + "elementId": "1MaFQq1C6f_KmXrCju5x4", + "focus": 0.1315115545982045, + "gap": 10.746558995595109 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -7.812955781063806, + 238.3078431598483 + ] + ] + }, + { + "type": "arrow", + "version": 246, + "versionNonce": 1817294669, + "isDeleted": false, + "id": "wkpAIY8WXU4_DhUYO1aB9", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1263.104260686975, + "y": 902.4835510585458, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 110.99401075709227, + "height": 3.577325516939027, + "seed": 891868547, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "e1dMmNfjngeSZQw9Q_6bR", + "focus": 1.9182906115878682, + "gap": 15.4835510585458 + }, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 110.99401075709227, + 3.577325516939027 + ] + ] + }, + { + "type": "text", + "version": 60, + "versionNonce": 1709523331, + "isDeleted": false, + "id": "Y_SmrpIdN0Bw5qAuumOQq", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 988, + "y": 482, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 78, + "height": 26, + "seed": 1670115203, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "0.1 BTC", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 84, + "versionNonce": 1194052653, + "isDeleted": false, + "id": "wBU3MwS8Tev8OyGNWq1F6", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1083.5, + "y": 663, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 101, + "height": 26, + "seed": 1534790019, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "1000 XTZ", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 176, + "versionNonce": 1801984291, + "isDeleted": false, + "id": "oPeSCDN2RaQLZlMs4lwHW", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 786.3493583868772, + "y": 791.9373522891948, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 147, + "height": 26, + "seed": 1663457027, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20.04819054677318, + "fontFamily": 1, + "text": "Give 2.3k ADA", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 258, + "versionNonce": 35546349, + "isDeleted": false, + "id": "ECtAtkhrh6wCcSpTFeh6_", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 488.2084241147941, + "y": 793.8867522150837, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 192, + "height": 26, + "seed": 812495341, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20.048190546773178, + "fontFamily": 1, + "text": "Give max 3.5k EUR", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 208, + "versionNonce": 18377827, + "isDeleted": false, + "id": "9ciMh63J68g-vSTAGOaJH", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 609.5, + "y": 437, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 171, + "height": 26, + "seed": 1942912995, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "Want min 3k USD", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 111, + "versionNonce": 1985072557, + "isDeleted": false, + "id": "o0sItaNu9BXqe7GFjkfGK", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1185.5, + "y": 533, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 75, + "height": 26, + "seed": 1598303939, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "1.3 ETH", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 158, + "versionNonce": 717025187, + "isDeleted": false, + "id": "eY178tj8K8fiCB25oqtHg", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1382, + "y": 647, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 198, + "height": 26, + "seed": 650001315, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "Give max 15K DOGE", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 316, + "versionNonce": 181323661, + "isDeleted": false, + "id": "IsXt4dgTY7mgH6itytb74", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 872.5, + "y": 859, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 165, + "height": 26, + "seed": 403581795, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "Want min 3 DOT", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 210, + "versionNonce": 2078831715, + "isDeleted": false, + "id": "e1dMmNfjngeSZQw9Q_6bR", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1244, + "y": 861, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 198, + "height": 26, + "seed": 842009251, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "wkpAIY8WXU4_DhUYO1aB9" + ], + "fontSize": 20, + "fontFamily": 1, + "text": "Give max 0.20 BNB", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 197, + "versionNonce": 495152091, + "isDeleted": false, + "id": "wti3vXhEzdwXVYSSC_Yg4", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 919.75, + "y": 1297.75, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 573.6995798319325, + "height": 340.49999999999994, + "seed": 1080165805, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [] + }, + { + "type": "text", + "version": 194, + "versionNonce": 2141066069, + "isDeleted": false, + "id": "NJGQKI0Bu-BSAQWAGkvs0", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1049.9411764705899, + "y": 1313.487394957982, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 301.8718487394957, + "height": 37.19747899159662, + "seed": 1527490595, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 28.61344537815124, + "fontFamily": 1, + "text": "Crafted transaction ", + "baseline": 26.19747899159662, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 402, + "versionNonce": 1602173051, + "isDeleted": false, + "id": "VZPj77ZO7kpLohrkLcsaq", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 946.9327731092449, + "y": 1363.5609243697459, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 380.55882352941154, + "height": 260.3823529411763, + "seed": 245832803, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 28.613445378151237, + "fontFamily": 1, + "text": "- transfers: \n - A -- 0.1 BTC --> B\n - B -- 1k XTZ --> C\n - C -- 2.3k ADA --> D\n - D -- 3.3k EUR --> G\n - G -- 3.9 USD --> A\n- Intent A, B, C, D, G", + "baseline": 249.3823529411763, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "line", + "version": 131, + "versionNonce": 282971573, + "isDeleted": false, + "id": "dDR0rbGDKpRDhHVnEbj1j", + "fillStyle": "hachure", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 423.7733438086325, + "y": 1030.9922277551025, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 1217.4922266087865, + "height": 0.6666331686519698, + "seed": 1295070381, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": null, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + 1217.4922266087865, + -0.6666331686519698 + ] + ] + }, + { + "type": "ellipse", + "version": 756, + "versionNonce": 1167558477, + "isDeleted": false, + "id": "Y1Mwn-VLiFFNqjTIzDdGi", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 971.395787942603, + "y": 1084.75, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 142.99999999999994, + "height": 63.000000000000014, + "seed": 803447789, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "wn9QHNTxewgA6oWR_jL0I", + "HtZRI-FNYskH4xD-NSUP7" + ] + }, + { + "type": "text", + "version": 491, + "versionNonce": 1766483021, + "isDeleted": false, + "id": "F7Vff6Hn-nwKWlHga6GEW", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 998.395787942603, + "y": 1100.75, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 87, + "height": 26, + "seed": 1821023587, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "Intent E", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 602, + "versionNonce": 1139487939, + "isDeleted": false, + "id": "wn9QHNTxewgA6oWR_jL0I", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 838.2662361154958, + "y": 1115.6051125581707, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 127.08332287156463, + "height": 3.5588919032202284, + "seed": 1515770947, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "GhbNF28zPBdmlEAk4sj4B", + "focus": 0.24968415527183857, + "gap": 10.417486034576314 + }, + "endBinding": { + "elementId": "Y1Mwn-VLiFFNqjTIzDdGi", + "focus": 0.20198646020593047, + "gap": 6.48230359390098 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 127.08332287156463, + -3.5588919032202284 + ] + ] + }, + { + "type": "arrow", + "version": 537, + "versionNonce": 1389208675, + "isDeleted": false, + "id": "HtZRI-FNYskH4xD-NSUP7", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1119.895787942603, + "y": 1112.25, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 158.02664733117444, + "height": 1.6298954558747027, + "seed": 1000247245, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "Y1Mwn-VLiFFNqjTIzDdGi", + "focus": -0.1521545689608934, + "gap": 5.9061722485449195 + }, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 158.02664733117444, + 1.6298954558747027 + ] + ] + }, + { + "type": "text", + "version": 284, + "versionNonce": 2018617933, + "isDeleted": false, + "id": "N9A9cOEizfeHChb2jpWZz", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 853.395787942603, + "y": 1068.25, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 75, + "height": 26, + "seed": 1106624845, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "1.3 ETH", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 319, + "versionNonce": 1565357325, + "isDeleted": false, + "id": "zd6CqXgDZCINde5uj4yN1", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1109.895787942603, + "y": 1068.25, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 198, + "height": 26, + "seed": 1379632643, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "Give max 15K DOGE", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "top" + }, + { + "type": "ellipse", + "version": 488, + "versionNonce": 519207363, + "isDeleted": false, + "id": "GhbNF28zPBdmlEAk4sj4B", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 685.5, + "y": 1078.5, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 142.99999999999994, + "height": 63.000000000000014, + "seed": 1312450381, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "YebzbhwZPZJG7VeGK6buO", + "jrzBVVdi5EqY0mYYzI-qC", + "vUyB6nADBS51AWp7XW9EQ", + "wn9QHNTxewgA6oWR_jL0I", + "KdMOyTpK2hvtrVnL6DNUk" + ] + }, + { + "type": "text", + "version": 229, + "versionNonce": 1476996579, + "isDeleted": false, + "id": "WJ9wOt80gJsxizloGLxfL", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 712.5, + "y": 1094.5, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 88, + "height": 26, + "seed": 377241603, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "Intent B", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "ellipse", + "version": 765, + "versionNonce": 949274637, + "isDeleted": false, + "id": "nADlxrdq_B6PfDfo-HQQG", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 666.2871222634944, + "y": 1200.75, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 142.99999999999994, + "height": 63.000000000000014, + "seed": 1679328365, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "Tv4Heajn0ixll9tSaFYAV", + "gSSopQezSVkjkU58H15H_" + ] + }, + { + "type": "text", + "version": 502, + "versionNonce": 720585923, + "isDeleted": false, + "id": "mX16fM9A-0VWPNNJUyNpS", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 693.2871222634944, + "y": 1216.75, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 85, + "height": 26, + "seed": 1794245859, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "Intent F", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 622, + "versionNonce": 935737251, + "isDeleted": false, + "id": "Tv4Heajn0ixll9tSaFYAV", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 4.670616178776941, + "x": 541.3324695669255, + "y": 1110.447374815089, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 7.812955781063806, + "height": 238.3078431598483, + "seed": 2026335949, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": null, + "endBinding": { + "elementId": "nADlxrdq_B6PfDfo-HQQG", + "focus": 0.07219246840230681, + "gap": 9.727127096910678 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -7.812955781063806, + 238.3078431598483 + ] + ] + }, + { + "type": "arrow", + "version": 492, + "versionNonce": 1577405251, + "isDeleted": false, + "id": "gSSopQezSVkjkU58H15H_", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 844.8913829504695, + "y": 1229.7335510585458, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 110.99401075709227, + "height": 3.577325516939027, + "seed": 1824878723, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "2ga4PRzeyXVKa442XCN2Y", + "focus": 1.9182906115878662, + "gap": 15.4835510585458 + }, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 110.99401075709227, + 3.577325516939027 + ] + ] + }, + { + "type": "text", + "version": 434, + "versionNonce": 1228568397, + "isDeleted": false, + "id": "g4OJ4hTt8EHD2ib5qCNue", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 454.2871222634972, + "y": 1186.25, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 165, + "height": 26, + "seed": 1089080621, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "Want min 3 DOT", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 323, + "versionNonce": 1748647533, + "isDeleted": false, + "id": "2ga4PRzeyXVKa442XCN2Y", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 825.7871222634944, + "y": 1188.25, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 198, + "height": 26, + "seed": 610953251, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "gSSopQezSVkjkU58H15H_" + ], + "fontSize": 20, + "fontFamily": 1, + "text": "Give max 0.20 BNB", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 658, + "versionNonce": 1450766733, + "isDeleted": false, + "id": "KdMOyTpK2hvtrVnL6DNUk", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 4.670616178776941, + "x": 559.906477890532, + "y": 993.9852887975298, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 7.812955781063806, + "height": 238.3078431598483, + "seed": 398907139, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": null, + "endBinding": { + "elementId": "GhbNF28zPBdmlEAk4sj4B", + "focus": -0.05450706234283051, + "gap": 10.753265054089042 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -7.812955781063806, + 238.3078431598483 + ] + ] + }, + { + "type": "text", + "version": 497, + "versionNonce": 1079658179, + "isDeleted": false, + "id": "aM2wnnRNQ8hdsJNJ-zvH6", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 458.36113058710646, + "y": 1069.7879139824408, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 194, + "height": 26, + "seed": 1308118701, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "Want min 0.09 BTC", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "top" + } + ], + "appState": { + "gridSize": null, + "viewBackgroundColor": "#ffffff" + } +} \ No newline at end of file diff --git a/documentation/dev/src/explore/design/intent_gossip/matchmaker_graph.png b/documentation/dev/src/explore/design/intent_gossip/matchmaker_graph.png new file mode 100644 index 0000000000000000000000000000000000000000..ab284b0e70511ec0e8e40a0aa5c2bd6c4ed2ec12 GIT binary patch literal 156552 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:HJZpaSnO`Nr zPrGf&Id(S8K+13@ue90!`TAcjiuElu{N(+r1_UW>_Qr7=ry(bDkBp4ub6zFu;uW>5 z+$!ZFM^}s}kDNGhg0?W3^E-35&7n20Jj%_QJ-^khkPcxjUAfxr?68}s{IPM|@MhL4 zq-B>lpXrg!_S)isY>8b0fiVp#1SQ2t`P-lolF2%y@%;nV@WxLy-%y-OHcE9Yj=n}r zHIND)R%sZi469B(CddyxN9K2qC#OO=lQX{to&UXZo%r}ki+`petq3V^yoo0r3hTg z0}ZibeS{+8zd!nlBVkCBNAWV7%a%f#SXX@f@GO*Fa|uAS`qy~?>5-lJiUa;!u|V;~ ztSy_7+#`j`$|>r$SDejZjJeH84B`}KH|L37{qxOEB{L{Nuk(q;VK?pihfO5{1pxo% zC3u>W&TiU`k*`1L&sWhSyBJ;6QU4D->^g*B*?=YQWd0bsR$g`G{E>G@P_M3sDAF6nW>MU?l4% z=2*VfT`vo+!@@p+{?-2ZZk_-8i=j1f4SB*JLeeEa3F2q#n?nVihp#(H6|=l}_}39c zm`WtsWdKkGRNl!F>^K2SGh`CZl#Fdb?H3+6j@R(4n?$}0#Y^)}6Fx*q%M+Ws=J3I) zB)*;@{VGN;6;K#wVsQLi_Ah$>4prp08=!YYL_h!9au@?eer~egFY(T z_#Fdnr|?oz05%*$cPte{H{cA3$`o=>f?vJkleCd$Me$_}EL;i&nt#8J(%tjeGlal6hvgMM!mEcVLHViP)*|KE|pJp+%UMm0AsyG#3QqJ4m-d#x^UXGf0!C8{daHIoK1tVxLL-D&zt%F6l(O8MERE$3uSe z6yn=mMzPbWc+53XDR7UuxZ#D2-@lTN&p818n2HXg;B|PAc=tGlHc;4)uZ=@@mqVQy zmy~4g%%=C!V3HEF8o+D7fSItP$$$gFoRFE;jz9`*olBwzDbB95LIz2q{LGulkl1qX zOgd}n0YRdJ={8P2SY{du&e*hKS(N<-iu8H(nHPbukN8_=)y>g$s?1%VHtHkL%#c0f ze7dZF;Y_nl(7DE)i+}WJGE_>ztIK;2b>-D%4FYf@P#y< zq-v*5*I}MmiZYAAas!4!~@9?^Ml3mwXJ^ann{lT15Ug*xO@TvC1p0^QhR?zPS?}?B6lw zJP=|?&wilC7+m%qwc5-Y{qVF+N4S3>K)4w4u!<0rBxiyDk~|8Tpg#{rp+o#cJU;9xoEN3 zbeu6)&KxXrfz(ux${gbPv}J~5Q^B2*l7=RY>mLwZewxqZOBI;&!1J*yqp))*yy+$8 z?Wss$93r+I0bB}UzVrTr2f@0548rrjiK0Yn3VR*Hinc{=`n<|X2l;MKeU|U|6LWYt zWh1Svtv_!X5$jFIvY_2B%x11;ePAnacQaSK+Jh>Gyv~i?p4RR%VjgKO9P+(RT;EpQ zFhQr{Eb8~7>^(j6sr5!9=Q{8BWt1QrZaU>BwU<3Xz@?2c>tOq#Qxe9OxH3@Tfp-^$ z)Y|G_KP8c~d&8I7`ZK2}6~rx=fh#A5-7~{&uSpR2&6%N2NaaM7f@|l~Me%(TXH6Jq zRi0{W-4C}Z;9Pf(gM@d+$MU&4d+>CGyDv7c+#Ip%HHN^~nOBkrOW09v z(&Q)*6`R!q$GUw1r158v?-Tm%$Pv$TWLKmiXn}FgIGfyQ?ai*cM?%OP?MW597%*^z zPEMPLU$R1rk7tP}+Eq(xE?Vm{Dkck>34-YjXad51&wLVae)%#Ez&Rbq)YA+81}w`D zIdk^x0J9r&{MLtZPbvQ~Y9GA}yz55jmO)$TUE6Q#T)3PvKx1jxO<=#3uHxvKTU6vv zIOtCvm(~J)(h$KU4fz6Mm64$NG`G@o0ocx`=2z>|rM8NNG?FmEP`>_J- z+2$m~KX@=vxsJ5&R zFdaAR)R0HYm-@^)eFfF_0_i9i^7NMY)}+mVm&DuB9LHjFcrH1x(!tSed;(TTgwgb) z@XaS98p67vmA?VZw2V}o22XL_XLg}E6@=UboB)A_j*YN3`49XHCO|0~POd#7GFGkp zgrhmMY0Q^Zs-KbX1oLDzPO#bRNAjfvZ*} zolTNXwU9eny|be{N$3R`LD!&1d+STbiW{Zm5I{7qs&HXGxHUcXv3tB_#W>^PvPy>D zOk^fv__{?APRx8Rjcq5bRCbZ{S|sYg(unlBInqt!Zwa>~+ViGfk&X(p<7Yv~l`=*6 znSxhOxL+3Nj#0%nZS? z!1slOq%C-(d=#va!{8^NR?nW3c#^?8vkA?96iZxEcTBsa?h^8cm&e;N0*@+7H*@o0 z)VCTJ{+xXt0cz!q5f)B%3~<(y*^L9z3JhaEvM3{%H7; z5j}f8RNiFS!ww$AJ}s*_(d&R1hB(RFS?fv@lxEKW`2T9*|DB^1yyq*05*-gq9= zszqX6?ZphkU26*E*{o0*x1{`{cYYXQiBHOq50z0-plvhSp8Z0KM=X=ZK`5gFEC8!W zEs-x29rOElPq9KvW*TN=sMpo2Quffd1X_{cxlL!$ImZl$9v-rNgocL3jD)9_bP4VP z-GdQiMyf>;sE@GF=`zZg&+w5fitz*rfkIt#R*z!OrOUmvy8MKCWSE@|0 z)a1PPsnHJL1kmt%Ec?D^aKz)8&r8z)CUux-djZ!~({f`!a<0WU6S*pG7VB$Y)9)_<`SZ)EOEx5#rM85*pp0P*;JHiM4Sno(l!kv z5zq<2Nr9aGfsTJxRUuE9%5y!;Xd`J3?Sn25pfA&A0^OjtyS{zY=+R3^_7XFQBE#6< z3{|@Xts7YFVF7@!mhc9PWGne06Nmg>k%KxwP|d9Em&2@o=_DV7v%#uXf;-P&b7|OI zBL4Glzh^UbNWqdu@;UQ9>&3K<8#hLb4+RqxE*|`ee};RV+59gT3SPy0PgXvN6D7fs zFChfL#XageZQTlW3!*1(q56qjTf<9}c$~K}CLB{<`C?4*iZGRA(gk(@x>+CpN+KM# zH_QF^Uv*$~`Y|%^fCMK}u@Sxaqk&D{tb9ZTYRDUsRu;J6D)5Pv{NncutF#Hd{>C~b z6j!wu9G^eA?Bshb5EFq7L?j}#mY|EM$pv;z!61-)b}wgd1I7CB|A7d^CpqafUD7qu z>>_XS4`0o}{POddI`qiyx7RNO+42lU0SDaGG-p_B!5aUS#c zZhk{}em2XtdA;GBFu5<3qeeW==4*wVFTujmJI((^P&`R3-(}x#S#7=G%G}?dXbKaOu zk;Q6j^v!9&goW7+z6^CNFEn7NA&=P19*j1O{lA|72ZGWjk78JHOs$}IuU>%e`l9Fk zQ$QBBaY4R5g`XGl^iEM8ecWl5ixVdUgnQ<+oMy>`n7I+bp63*0SIF@~e879IddzQu zMlgpf7En>1bF^_?#aM-;7{%fKU^1$ZWK=5p5nakNudaOj{8dC~AT9mRA3r`pEZnr{ zy1o%o6Vb3sr-wwTPfbwks?d6eJL*NemweKefnfY zdKkwa?UUe?-LC5ZIn1P>WK9sSbb;ach#Z77R6pHqE zow-(*1vqC!HhbL%`(2Tp5kk`=)pCyjXyubWq@?B*XlgDFe3+wI=YIgrw`~ygbNB~2 zhSnK#W}NdKcuy}9UKW2ekg+EV#Fji=#rCY)grKmxOlX@vZQ4y9^HEHFq@*4_Iy1+g zkMSR37PgDz=R?OTsLC3OWl;7&Zq*f}(iyc7u<@UtHAJ?5e6OfT!<65$c)|J>2*l^H zG4wXNsvA6afpO%;E8d3G9;NNfDVZOksDJ`V&kr3rVcuJReiwCYbk>CCCppyeN$@lIM2V3K^i{~o_&*?X#!CXe0F6WzVPNgX zJl>OL;y8=+4$tzBBpW*S@wKpmG2eLcfB1J2rLwdx{81k|zsy@^d!vo-cb0vJqFN$i zUSvem0==cQSr!4&s|2Z01n#bd7{g`=M8JCxz!|ZDIio9lZ)f5{mxGFwTA+T)PpC{WXghlYYjah(6u!xEDz&A*!S&{w?V~PL6SU8j7Z7`90l}t~fjWq$4 zgJ7CMf<_zHhi1|GbDnj+6V@%*gU($#LQ4XQbX8K{lNC<;xA?#Ue)9(ul)_*{2^! zqYtlgnNUaGm3mXEjamViqn!0 zTwG>kbX6uip74tD@c>8{O5G3f0N{eI%a9k71Xf>^-CLmZ+Hj;O`~=E=TGuH84%0`} zjieEvn)xhN7kGyB7n`G*DbsUhFj>qE&1S8xm-Gt377KMKZKP0;dIGT4f|9b_N{z2S z@XvdxdJHL}jT0Upz!xoMtw?Gi>A?VKY#2_pwL$E8rxWB_-j@Z^K`8|ZRlY#Ylc)|B z!uq6OaglO;@qB_9O~Y;z`+t=>k6eE@$FiP6kzT8WQLOiLgrqFP?a2>Kp|q0}G*of9 z97(|UvZAboLYHE05p5iOnUg6>he`_mVSG3#k$9KK`6Ge~@r3;N%?^dP;uzlR1#INY z32>mYqQ4pL7}|n!_vX*T>+}*)AnQMRg0@VdeRD_g#CT=iyLa80UsvlpcRcZ9KAQeW=Lk8DM<@-|4OM8Z{2Y|T+QXW&$iykT?@O+(9n=%x?cAaIz6HhWpR1>^6 z$^G!T9e)v-Cph8wq5HPG+MsGqkr4gZ{owXXuB0m2#s-bHT$< z9`u0KC#8dQ(kD>$0o{=BJ^Ia`LdadnO_0`E@Dob>MEo`INgV4$&n#@VNN9>r5Tf38 z-Blan#)rVPJ`y5GG4^Zi(dJi*yA%F!d;D_yu0J_J{&g)FBELYPwZHa{%P%{r*0Lb- z%aMI+L%jTQ{oLA{Ex&ww;eUUyJO}>szmMX7PsN{;@c;D%@t&y^MfaJ)fMMVLm#n0B z5zTPF{g=EWuS4wazx3yyE??LFAxf|CJ93=vvXQ&5S<}e|s{i+YJPrgiju_d(o;k+C zZQcGK|J!7P7E4%`mc2o>7+)#qq|D#r|IbhV@9%gRk<>S5OoJ%!N@0?-Te$r9xBvGW z3nutc(_}BZ+g~3HeE}|7*)8_`zkf?#tcAe%vb7?g8`hQ_^5DX1{#4fd@_!@K|6haj zU8fIJi!Z6Xin1G!D(JX=#7)=Ne?{uESz*j5t@L8HD~uI?+2Tnn1drX;*VIfNbm%Bs zm&gF+z>N*=nt)LYoQ3??a7YDTqaX=f4z>w}?j(H8!h)*Js7So6ZGl9um7q`Urqi z!8WI}0shsUJHN|~4|W}A0-qql%r$u@3A99Na?q!o37Si^yO*|FT} z{dwkMj2K9vKHIx@Z`qD?N^=J3o_wG78tLQHcA{rOYqKcJ5oP^GRK7DU--88?b}YZn z8xORdCL%eJ`8wSV^+1Iv!nYA`whoP(GN4{qD4m)Y7+`xdtBzk`YUjnallG5FS3WfO zem5|p&pLtxXEc|c&we0a7Dzb-0WO>BIE8|&plK+c4VPd55Xfx-ay|-TsLEIaUAXiT z!Yas1p@{WG$THgYgKJN7;9m43RCOaPlK>w9IWk7~zS~k1!a@l|c!u-kR{y}#JxkM(W6HvWsTnUOGZa|m%w0BvGOhb=tt;-aT-0CY8(2Qx!_1Wq zg2}UU{xhy8B_lQCQF{B?Cbm|1wmJ29aOW>|14n)~-?tV%(S!r3oQ1 zs~Dh{@e>(V!h1{fJnb&?O@1RU3*Bl0Mi8++6w)j;S(#fatr0JV-%nd};@{zc-*q&W z)l_|meWN79gc$Mp^9dH9Mx93>5bA{!Jw&O4LNUr^`-r{b8|c7*NEvap_>kLgnbm5c zYwA>HG;m`dg4K-JlLHcl9&gRm-+bl`b4tb!23I52$pFEW{rYKBpJfcRHDlOgm&6S)Hk%h&53z?As zqdCeM3$e;R{jY7%n8eu;x@oV0W33|$&(4^(XE-KR#hXgL5yE zl%i0_OZ&OMjpph6B9Vy4wwvXtn;lWa^E|FK#l*yfEn`{B$}Bn>Y-O*bep*b6b)J)F zFkr;=#i}1s{EyrTWIl+$%-fsHVgb!a25>|n-eBO0kB+5~k3q9LY@^A`7`X&!*QkEf zsOwa4gd-H|c3TT!%lpa|$ub~W&OKGs!VH~r?TOvF&>MAMcJ}xN0 zPsk8Zb!b^StnlLH_sMOWNYfiD$Th1S)+!k*ZXz7s7}^!{h}d>IKXZ?s8l$*d2l~<% zS}Ijl>{ecsi)2yoLFC-8ziSEq$w>=}c5~LqDt^Wn_G)5}d(r?iS7`L(`IZ6#$F}SL z^6Ze6`^&=Z0Q&8+{WRa|FvA#;HNrBpClLkE^L43HDc~c6zH(p63vMBy(zeVr+ml5tipMBL5&BbCRy%i%K6X@8?UXjYY>ScEL&(h` zO)Eq$Re9Hb5TeN`;0-C%|HV(rugyAheEDDNC8lch?fdCaRwj4QRV(!Ou20Y?G5HTd zG#gRSY>F^wMO2JXyP5OcD~{x~|DS)t@_r)<3moY9!pD6xh&mD>LB;L*WkdKfbO&z`a1dk~u{x3YIBSXg;*e8UtrQ*9isd zYjAmwK+J$57Tl^z=fdnQOJ`QqH2j({b7)eI;q8FiCyq^8GVNHe8=6^@HwI)M{AWOR z;GmT=T+U2ieE)f(P0^*owm&liZG$FH+YofyJFU1yjIGt>mn+u3{P@%UY}}@VXJ-=} zubPi8(JfA>YR&#Q=$^tiFO{dS^95@&8bo8WWv@?Pa1YxNzHXP3%OD%G@4 z)o|7~zGwJ*dF{rVIiMg0KaggCVdXXbH8j>U2r1rDlt!%NoXE2h!6>wW8i(Xp?&>K# zs*B#@YMkJUqqz zs+dhoJ`!kJ(gjzF294BN3D7387!Wi)Xmtx{^c~b^vg@wAyu2L)N(Wcz&XWeSY|F5F z{g*%6sbo6+>ky;4n09Q+9H)tcbf$~dnc0JpQAK=*2sd>Yt1KaXXr{+^v z{L7Z!CJ21cQp%!hDlYVsdvJ5h&CTuBzkd_#Y`@x%W%atZxA*v|QyXHg|A`?J@m->f zRM*guGGL08)s5Sx@2t_c?)5FT_;r@!@*XZx_GrO|V!8gT`WNE|89tfsaKGHeDN0UB zk#(uKV%+*2-&lQJWJiXzzW)5RcH!QDXBe095VSj-@!9NH`pNzAwpHJ>&2P85j zL!~Zm4VNujR$h@xRi8U{ma%b1=2PyGLu6GNpC-_a88MdIjdg4pe&NFQ=rzXK_br|k z3YE6`4U@SUwhK7b<=^-!e|w(LWnn9ej_Q29Sl1bzhUMmc933%yqUPVj;dPHg{MLpE z;8iu%pYroBG6l#Ind;mvorZRN1}dBTs|=liSc({H(Uqll7_`oK!GhS3q`wykyq zGBzTj$=qje(&-F4;!oPmvnbS-r9s(yfr*8GzGee5X< z8bbkMD0V)31f8CW9!=X$jW{0q1C&IvUqjy7*s-0EVR&zjdi{DShdyZGE0m&tu~7&} z1fuva3Yo#fhRLpP7Rnw%hrIpp>52>f7C74!?re^zg-zFcvGt*8d8nI8d3*2Q^=!?l z%&6jQUZ0{y$Dv)%Ev~AtZGH53DteMi72|Ou$@=masZ_RZo*967cMBFfHqz0F4w(K` zx&BU#Bp+K_+m>o-kG2_5PY+N`yOL-HqteaAuxcoCe^a48(g(Fp{z#JUfSg4(Jt9MH zd~t3gEO=$Zt!xuPS^SE<%UD;}!7_2KkPsn&^)k7pu$|B)lDHanJlXm(!LX+PyY z-muN!=qJsct0D_Lpf&F2en6KazLLx zdx@D+kI1I=qSlM`ZEU_ToU`1CEeDWW^{BqFm@7T%++P>I=i2mldVN*@MjwHkxz%Dt zDWT!_yM#Gdm@HYcgxiw8PZvf-)~X;dnnEH-->sP+Uy$r3^jJ5SZUYA%$_{01;>b~> zoQ7O{{L3%nB?mv!e>m_SlbUoeZAZ~rEhq;dnUzlYXx9Go*9Xoa* zEUX>cUXC&Roads1kErJ-@K-4m#C0{F-sg$N9i8*EoA4kS^y<~?)2C0}w6)dvm0~+~ z*V|QgigII2Dr1J}?bnmkCmR^F=D_*g%d>GmdUV&j zcYjM<9yxOBw{%XgSe2{Sr?mN9P_c$8!6S=>N-Eq9_{Gb&Zy(dKn&nXWCuyv#O&Z6N z;v1WwPgcz2nZwkN0*tfHf!vKNcR!GZnHs%W(*O z)xbovU>w86SW>T1HO+d!wj04d>5pH$Xp z*DhR8@MVcCzuUUe4Pv#Om5_6dmV+2LdBX;+?JXM5xw_LO0|=>?&5#@X_SUVBcF^_n zJy~%mFmMP5_u{2X-G`i~GkCnOIJ94881}M%m;xq8VjV$v*@JaSdY! z75-Ga_@n5F&{^!IgK5u{@1npJjb%R~59dAK?Tz8i&vf9P(a~f-KJa~F{!Jv);$lWG zxh^GwzyP$AKK&iBa=GwDv$ZYzid&stBc>gzQ{w*i{l>lRm--&np#t;2O`DdlUcDD( zMtRBg;k=5q$KEdEC--Sxf98=>m$qS+7+kr+!-0bWF_~Ua%_x?v3P(ZDq3+S69#@)| z&XCBeu679DRrK(7zV`)}?C_OO+px#t>eU7$MiwP0#`CN(wz^0vArIe*L!`3f^yv;&C+GZbMmtr9 z|1G1*0m5|2_}3*98J60z1e+tAc~Hmx>-gNEGp9^xfEdc#XsqY`(zpI+(`(wz zw?BOTd~?Mbtl?BuRnzNNUK{N3YUWe_04Fzgc(EMHRH?C0QzZVms&_hY@^z7W1k!s=w&Y)=^`gAM&|ST3&u*NSC4KG$^-x zeSP14vtOrn3)4)GDr@XxT~w&!KlpiCSZWL>Nl!kqpDWhz#8as>#;BeA`OaY3rjn1c zv?|`dtJ&<44<0-i=Xm}5cN^SwWzC0YREwkSe%jv);$L-QI}{y-k;8d}{>m;YMBj@I z61*L#?km^*y#n>Fwr@KhbFXuFXc9{-I$KY)p$fjf=vH02({)Ft^LQvd#GVtK+D?E6 z#+VDvOwUQ(4W3~Jcw*0!-hbeLJ2r`Q_p%d_HO(%kPPM-s9E?$6J#B4msZ+rt9w6HD z>g*7`{K#3D+E$}-&{9sAmZD^@yZ2OL$F5xmxwoU7RPWQL;!%~BbHm0z2WvV20kUVT zU*r#O4-bz??=E^<8vxu*Xf%P9a>1cP_q~cws+!8OR=q}`VJ#GM7cAI=rK+Rj+0$Dh! zE6XM-eIJ$RhA>g6qL*%49FP8$mD>-?KdsKxV3AH$P;oFn8<~_IkCvCus^Ed!1DxH4 z=)50i^>l*pF^1U}8=EvX(+E7dV&KsqD`p#FwEBGZ<#8A!JvKX4we5Ax2_Hpom$yju zx`zTNbaqh*u^BOXbO(j3_cAg{(fFn{|LWSLy8oKJTd~ z)`!9x?Rc8EK!3aQ6ND9fi++wNTYgt+^WxN1mHmngDzrLx?#$?|lg$Jl&ux`HnVwHR z4n8oul=m3x_VXl5@kmfOO9IHLuxu4!ge>Z&igi)pmA^gU(MsF@wprzhZ8zF(n7A2t z4Y4)O%*(fEKnNK$17mLA#;T4Leu1$GJC5A=&q7c3 zFk|V5g4-Rdc0M{y>g9Xe8fUtT({abK2`ECKFIlGdE;l33EM*{ z(%s`{e&}>y@l98iy7av62ky*l^#wUX-+uk>!P<#yH23XNYTNXa^#`ffXKhMDj1V*G z_X%p(A!tno;oTjxHN8gg81>#h_?bcdPFW`|rGQlp<$Rqu5l5%$=Nh{FK?9!O&5vWZ z>UKr;61=~&0$+prdX1O^Pj^Do>3O!9hr7Fh*M)Aqd+%{-HnLOmVZ(-D-pK&q!&T#n zGj5hy^|yMzyh8^E_}iSiFT}-La^fuwy2?=h|fZFDT+g9zk>2~z! zv*}OybIU6@K+A!+3XQ5xw+j8c-j9I$TQDk7RL@wzqLsJ69DlnN;d;mC*rzs!{6SHD zH_s;H&K(b}0HZZ))*L*O6DlV7f6 zsRVG880txQynXvGOUr|Z(^A$beJy?t%9nmX+m%W{MwL)6oAuv7!>CO8MK87-o`(%@ zjQ|7O2h{&6HF@?m%Po&*&k=y8F3vnu!f7rye?A(b03kj$u3)HvL5;VJ z?P6U2{@4(~;L0_tPgi&&zCT!VgC2fs;K`k})xzn^#P-OoKZiI5UgC_U@ zzvqoJ>9)hXv8+dna;#|1bcpPkb1l&c zbMGO|=W82`YJc|hX*T!*Up{oWLEtw$)PLA8s!g@RC+2y&s}zG_dL)|PTAdzu@*D1# z8P#{G&{i%yyxG>aYK1l(xZ9-JY!H9lSWnlm`%ou6@GX_jotx=;wwN_*)~##jv97t2 zxnE}kCN7;_wmLilKUhbZ18kbm<=Rz`&3B!n&!;3O-z53Due}c%*uiL0O(S3*C7hpm z2;*nXY6gul-o)hm?FW_Wc^^OaAUsft7f#P1FR+p^qeW5+2Rc#eM>cX~vtxB+x$P!s zQ-!YKUq*LcE*!Od!OxnND_1`9%~9G;IU?cCv>H=SX#nt$Rl$PyKBdXG+$XJbKYmR6 zRB|%^DJ!iq5^{<;I&asH?EYJ?J&oOE%?<^xfDdGui`-KF)kI!1KBi4+T4fI@%TIx- zq@>`~Giz~+4Fm+L<%~N|n=xY|UbyTfI>5XMM#z^)rh+waLR|Q3F5|y0P!Z)QWe5|V z^)brCu=66ov@9Omx34khP?;q?{L6bdyMwB%GhKAm>%fTbatEkny&rS6KeIj(;UVOhZNaOUct<`e_4W6()y`UvFq(IHRsfVn@T_LP6u$&w#7m0=flC1Z)oROXNjO%xGjN^D~(8YH1e8ievTMZ1I$Vj~h7q|o=VVjrK+ z_xSzs`}=nszm9$H`@T25hUssqP&vmXlur()L_Jol&VE5T}z(NhWnbID5Rq@|t z8X}>TY)vK_QReYYJQHK5Eh#*XPV~dZ13+aINBc*4jYNnj#pGp@Tukc6Iyk&&vtYBO zfG|_~*HwzG7yo;!66>N}2M_ji4ff!U$Q!wD=z&(MewNnOjxAko=SG0J@HCjO0Af$# zpU!X!!488APaJ)iwRQ4*O%>Q_x}RTCWyzpXfVgY+*QY+&*8F+e$RyaMD;$K*hKA}5 z8f-F{5;S4i&Ft7#c85VZ+IP>DB1x!LXrp&1H8w z$JyHsFMRe#HAy_|mBriQ;S5%O$3-(#(&}?ol z*#jDHo06A?g?s3-cA&{mZ|gRch$fRKw?yi!*Jcv<*m7*3Xil4hIY$+yHZMv_c7WRO zQQOdL_rY(#iq@@KJ%^oWku-e;jv2drE8aYTZ+JYlpLnhB+I4?gmLl&qb*d3zNQO9} zWgo}gtjmHC9XLadG&%1d;M@YVrXg4vuFj^NHI7lM!tx9y2iSrWVACAs0`YZ(}WnGtU-F{kn+GwYG9}s%=8BQd^-XQDgcq0E`9s-x>GSRHP`1(oY=F(fNXILD1so5xGf8APVPZ# zYt5@Rr%Pu{ovLL!rV@Ek{xF}he@+5OMDgvgbm`r0`xn-x>fGWgco_VIG1xCM8d9Cf zOyGODxxOb(bR#s@1Lt9Kfq=}GlP8-}%nG_sBHkG7Mi#jQ`Pv_qAO61N#&0+4Fhqlb zMMKqZ@%3;{KR2xrM!xV(X?J(;Tzv-zdiuRv7(WAQo5*lp8(%%bT*|_|RSP#>P#eCX>da&1IaXG?%&J%J3l8=;+ajSG8PB6B zZkQqTuH5_VW@?_H1z_Pdp1=x%ymmzeJssm%2_yR94KAd3)pjB$C7<46X7GgS=~}g` zoxT0tZtiL4C8;5SAKPT%3WE}DJ<63&-!_z&79O3X^L;Fq4?3{ImeZzfiH+?|Zq=n^ zr+)E40N$a#Tee(f0ylZ1EE*2~-Fo`0*ZSx zf3ZLhW~(XR-ajz#=h7o@ZiN`W4H2DUng1| zIIiX8=DFba7Hu|F2XfoXlwKJ)4e+nop~H4^!aq1AG+8mPvl%&nY0VXLnIWwUHpN$q zvQf2qNzCp~M(W!EX!H#_~`>)zCQm$&a4N^76+Njf)kO{PwdQkaf zI5RXbyMT94qo!2~%Gv}!LpMY9b-zCmV2bFm*mi8o%RIc=?ECkbE2+KeX6+jEChOla z^BIcF$Z7NWtD%wW%D%j|!059zr_P%o!c7gv0h#y-Wm*w!rR8Bu2MQerGA{Gwp|z;+ z$Wtl5?=NU`q)LuoEgZfyL}#*8*2R)i552a`+0kDd28Xe-M->R!7<0jgQ;k!Z?r*)XB0AxclGmieReQxff_Tp8= zd{_-;NiY^8GqVx!RE}D}?{5%2MpkQ}cneW(G|=^(y7nhiYCg&&g_YTem?MK~fnJxkv|XGx{r$T7nggy_SlMjavujs9 z0vxo9g>kFsBNOVtlMe+K{(2m0ncIdsw<+!5vW0n&JOm^1&r2E)2hSlhtYZk2QUBez zb0^qsyyO=0Pu=J3g_<>!Zs7Wzg1VPjMy_+Ksa(Rr5yN)lR@EEJ#KGpIq@g%Xb}d=1 z-@`dKQjUtSrpT>(apjx9^H;-M z@CtA0t5N+(@$2j78Oxq1-V(BRuP?Wf1MG;5{W^cuc_-ngF`2qd;Ssbt*{wGZkCEXX z+=An~b_3m!4o3s0$;}G@9$tL>7)V)uh3F_Hf~RLH@76`qDWCviX%#0SqNCccRnIfI zr))UJYSek6h2+AFm>5Tv8qqQEAyl7kLKmTO<1s(k+GP$5n!F0s`$SXI2J}WSNA;3& zm{!o?!yVC{O)o97Zk~_aDD?R8O=M{q+1cs@&%JKrZ8}P3={~#@)@^SHW_EzAH1cr zuZ)-k2E}Ve>P(0b_KQGOGE*GI93T(KOmea@o4HFr`-zu5YP2}@V5b#>y5;p1K$iq$ zGsAY!Zf#~IER4HE2afRid8j02L+P^-&Ra}>J)<9W`$#_?0Ajqcul4~(ud>p9?fTE3 zLu_6>=q}Cy(XkWe4T4>wt9E9`WVlG_pI&}#;5i^AaC>H6$2;L-pyaDzHf~(NhqTr2 zwRqP?3YA{HdVQkS+PdRgS1uK>-&3nw90^N(g`SWC#C!ARM%01f9o42}BW6@1)>EWe za@q=$DD3|<{*|AkTFLR;JDvMOR*hom_K^|oNxO2?qGoc|Nt+ei*vvP1zv>j-r@Eax zDwZr$^^(8`-~T*r9l*95OZ;lx6LKgkujxAbvh)3 z_0GQ%&4e#iu3r!AHSOOhe+I-(CcV4D!+O8kF1nJ7X$$E$3jv<^2Mx(CO)EWavdu$d zVgkUwowq1F8caQH*Q9-WdYhA{$#dMr^B4^e$bFv4Mv_s-w=pt%>`=G)Dt3f6vELTv z@|ruDQFz`={ybP!voCrb<-(_b@3ePcx6X4)!`O@amFF)h(5CFRIcP)fZU`&4gPXlQ z3V>b9b9KTaBBmH8^2@R=u$^%q|5%Gc9Nv%CJC|i?@GXbCo=M}uHXPn5?panu>ZIw@ z+me9KadvK^wxt2{2;_Q&lnimP6YWZ1pc+6)xOU@;B~6+&Gvli5@}S_5%MkeehU)6- z#8X*vOB%q>w#Z%Rr|ab7ZWW2$OuiV%u1C+}2#d>w|O zf~;~zNeP-A!qbAD&Hvw2KJXbgiZ{b>m|8}@+Ehb94qoFv9U4i>Qy2-J_ULg zN((N?pp%B593C$q%-zS!4;n@lbi|v9)nqTSDF7l^4u=fiIQKDT^rFG`Fg)f=4asy6 z*OT12L=RsLu_SHL{@e*<)Ra4Z)O71~4pt8XC!$2xh4Xvy?p+fqU5cPk9_{!E6U^Au zDVdX}PHhBSMh|P=`-{5;7C{G_``&R&@Cc9URxofs{*8|B>dXWdIgmsql7otlH}Brf z+}mSvXAPA(bLaZ9x-S6B|GV#dfQ4-f>tcYVMY!K4_yjH`OU9)wGn#N@cspM5I#334 z)-0D5)lWyph8%-~9-ZPrx&Mpk*5OKlOMa9eeQA14#d`+M9o+k4FH|XZa{iY;-cCb- zr>vxJXxKO?%aqp9Pd|UGcXxL`^VJ!fSUmm41g^y_fpz2Bn3<|Q#b|^(8&mW(6k&j6 zTWy-bH`zKCZKaXEqX=vOf+G5j?Ai|b>f5KugSj3qU%rgSLY3et*)FJR#qJLYXU{6o zZ5$5#TwSq9xpCt^U}s2l-niij|DKyo8&6XR7ZZq1b=$V1CWT+@N{f?TF4cS?c>T&W7x@8~M1Tox5Aq zC2Ess6wqT15`yl^CiYD)#!d~JdIi!2nlWi3d z(X~T|4xqC>y!ITlx2tnf=h45+whFFVF=`M&8}IkGPIf zqwh?dN4!J@Gmfi)ZqqB3i%)-Cd2*zoq90i<5#5sOe$)~A#nVZ-NTY$gg-4g-+<8mg zA-5S3CcCoOZqg(*^fK2g-($;m6@a&R@o=Wk4CfLgKxI+I6fZth45ineap^}d)5h@b zgTlG)er%vbeH$7bJ@fU?33`K!jcfK~F>9P8`PcO=dN}LJlO-+7DNUr^VeVp*As*J* zC0!YZq3imD>^iYFE*vl;Xku0OZrvOa{!C9f?an4ZThQ=D^$`uv>t$tzFj>VRSWAickIJHVlw=;Xu;akpf&e!W!s8`!@P)vE$+0fos`d*D%XzCUuI7i=cdrjPhcD832sSYP-gbx2!9zX|6! z&6~&L-LW;RPZQ)uQ~I2?+S>(+^O#`Jd3k;*DI>_6G~2iD8SJvUt|%?;BvoS9))SgG zrnHERj&=mpYq6-1krG>gn~$R*Xff1&B1yUW@J{N$NmWSUG+MUY#368`Mp~R9MzfuL zWr&+zfQpev_fboG7_F~_3ozT=lHPE~nlB@n?#1Axsw$zpv3rH-tKK)7|ynIN9?d=Djeh{~ZQg}#*yWM+k+dp>-Hi@xW zkvj(d5?K!K6g2V3EGR;%}FhXEm8ZmB|~ap)yqf;vN1mNz#mi_XhUsmqE=f03!>YS4>^@Xo}YA?+=>k zjO@U($x+)>?IU1_hR&r?e3JHf6IJ|G9l z0sc-R;6q6$J?C2!j_=$l30T2FF5lC;jWARV8~Pap$3T1gp`D>M=rc^~$ z`Q;xoR{pi-->Or}$YZd@Gtv-vhvL+Wsn?>i)#Sqw4bm3U< zJ$SJB`0?X6JY05HtzNb28jXjf3y7OH4y*kp_hOgO0=oEc2QU^$HWDv$#zr-?aII)`bx*Zk+D;RL8ru=y?r(52zW*8S($kQ{xhdw zXkQ%EZcfVn_p>`E7zBCXX&2>@HusIPuMkyXCJ0DC*`R}s$=1Zp#fiK3!^UOMbmUQS zpWE)fho_#v?r6hL<*)FXJHfSrN1*q=JOcipq;+(%0G>AB{ROEPkR5w}(S^}hd5w~v ztHqzv2!~U3I)Tg}>;wfRD@#W`0+c4imT|`!vu1S!o8%zCAHmUV3=VFMqRYY2u|Ah2 zg~Bm*IOB)M@f`1ANhJ@8m%By|UI!dPQKBPesXr`WSj6JsH{aOmgm4v}{mzV-W;Cdk z>{;@cw|bj>>^~*{K6f+Ul))gx8hp)%xeE@?Ym?O*rCLys`ugGjehtys$oti+D$U4Y zC52riKaT(UxvVV4^)|V{MvaXKB5<|$%Hdidc_NFE#1Jlxt>v}>{Ls|Y6gi8xhPB~{ z&7<6YeqRg2ajv&3Stx_;0)U9ZsE9uS*>K(TMI-zjNupftWSlQh{R#U)r`R=AKSp@! zavjL|kjs}OK$A7a?uwzeDk4AUfC>OA5_RB${YYQPWc-G%{C5rvvY;AF{r1M~5ZLw) z>STd5Nw3c!jq5c#wF7ye|Mu$w zT_Px)p5{3MnAV@DCISPI1c0cV!PpJ@#F0*jhnH6Oq@LP5s`h(JNEp#{GtQFC)$NQ| zf7x!>lW}#4FqN9)1LMT&$#F$PdWF(79{ZgSAe%t8GRpn>Gea^$j}5M_{nkH0g&|3j zY+HFn4jkoc6S;9wcK#)UdV%n+a_yf1Et5~f!Fb5TMcV0nf&Lvyb*ShXP=K7l5`~$Z zPJAEsuh6{M+-h?BAyXGsGGCrf+)-zcR#qn1otxi0Io3W!n=LRF6)eJQ4IP~zzyJq2 zk)|iPcBNY0ieHOR3TQY)&kG*%&}-T=QXRnrsq^GomyySw)$h7jZv04#jeG_)9+w`Z zT&}~BqrIB~#f}k@P@aI-JW-@kx3%UVB8kPRpz)@Bs z%g<1j4G=9fgMiKiy8tS;QdW%Y63A^8z?1QRas;^mr7?92NDy3bW1$||3Oo7l=*>w0 z{mZ|{Mv=-$e*s)8K%D=M9j$Ac7E*=5$}TEjIn~nAgusB@ig=e3^G7ZtdM?v|Gr^36(fxH75Ewpgn>|hQ8pXVo08ajytxdYs`vR>d8x4AILCZ!+ zg1GdXKAiiG*!>BQUJuelBguWu7C@CiN-+Rz<N;As;d2`UON1JQ^rHOj$oz zMVBbl*jqjCs_%w{d*&=#rmj#yN7S6lnY(|=w^?akwW!w_k()NeaC8D@fH4~~A=d@B zqY*^w+l-N%>6omT9c%_Bog;qILg6ue*^`T!(&L{{%4mf3l^)DIcaoURx+^%LA_G8A z>NXij`VoyPBGw4CoL+JwEG*;aG%zT{aCu81HT4d%6gA7bc8&OJDcrR@7l=Gj^G-y2 z@)YL&;Y0{QQGNF9>uu7Rf0T}9H|C$9Eczohk%^IR!t{2@6(gGtq!gXe6(At~XyJoX?a(Lg08+n7BNDO{uvHWG zxyZ!Hl;l4WM18@6>1b64y%BO>nxv@8DZG^UFQRR@`XU|v0X*RCqjTM<3PRa!3Kj6> z@GtA@q^EnUwC8SYqY>*rVf^^Wa|UDQzsI@qVczzai*JXVxby@jrg->_5pZn7p0W*# z7snXVlo|QYo6oU}*_@lAqI#(4B7+y;V$pYPEXN&DS_r9+n9zR9s2$a1K#kc`&wqTJ z5O8?XBo&7}Gj4Zd=I_#&bT-bn;xRKM1^@==!VvO`SIHNi18GvrIM8G$A)217h<;Sg8R?4Ia0bqY-KWeoy$ghf|@Z{ydL+IJYap)HLy88E@Yv`;|AQFy0?7+A^v2Q426f~|zz`OJ3LYHTV@J;n0VT^l}Qx&*I${DE%oAvw+??8~3^M489KT z*H4b-C}XO*ZYtj_8+HJTq#a-Ga4w9_zGs@Am01C=`a81~xMJoMm~VJ;nm+o*zBYyC zW9`T`C}I%#a!ZVZnwfr1z1Vc=(mu!oU%YPIU{KZKqVvV)h@3K!Rwb(3Y`L%t*jy}0UKi}j+PTRCLqzs=yHXT7ff zl%-wq>V~E$`~+=d;YHs|4k9HDvSbr9f7FuOfaOGZ(0MGoXT1BcxeIT9s3INZ4@bDINf)I)313@BVGKDgoQ^cgJ2 zlDfKUNq_7$?lJlU5K1v+O2xUa9`FQMm4rq_Gz1yuEd7#@aY#i3A-Do?EuZ;bghd;n zHPJ3f0Ak8HIM^nEL!|DLT-6~%nUYi&m`BbtWuJ6ZN*2j-rb|MGv{8~gc;g|S--pQN zCQ&FNs$GPdCpLYee%(4PXmBg?J5#tB=`0~>kpfY^=jo}~2B;93&af4R1)h)QOl;Kn z@~Bed_JU{vxlDI(8?`65mJ6^QTT_`Vm%N!3^JscUO5j48i`LW6pH%E zX+)q88~5CP>7tW1A8?jRiQ}bLLxbcQl637<106xAeKnYEI-`wr=u&)w(wajm`wXRl zRJ7V4oK#K?n5S+6o=RWC79e`(E#vCIt^GV!n4ou#>m2&G{y3rj#shjc>^f}q_ctN0 zk%pHCpK-+942(`|+0=JEEv$l9Q%uu+qo8{=;h(%1CJh9E&*!c0*~Hvc@Jll@GZU^C ziY6|HbPSqYri>YhOa%?a){-5wj{fTOkp@vomT_^Ier8TR+xXe&$r8tZbJxs*y}`pF zaN?zYa)~HZ;5Bc3Ty#IIA#71SC4euaYd{`KBg^kJZ`#y!`SQN(8nc-?&^_vP@R$lX z!3WQ7yGR-BcEvMPT7(v?j9Vd36gsmnbb7q~LEuIJM1sgmc7p&39M>&m*Ag00tU@+V zPjCs&)!Kg(-94K|0%_FtzXtZAdo_!5CDDC|vGE@y6C9*1RA?-Tw26U7y`WCWQ46jk z(2ed3Nn8N7mVigd9^lwKoS3 zrcV6x8H>>u!BJxD7zltBIPk>{I{{g9=3}HG#n+j zyIvDpCF!tL(WP;q)uUR_Gs;8wu`s#|C?62FLdGa9N1vvlAnUBWKI9Eeg$fm_hv+9K zpxRgv_{6-XJ7xP^E015P03smNg`vWb?uZPT5r_k8Ps9LpuY~3=i|6j z5NHcsM+0L9>O7KDDtDx{GlHM}{6#`~)yWEmp@p#O8fqKz=hGluNVNH2@K2HdtcWZ{ zlAr(3FG_$lqFj%0W_b}Hw$K$)2#`V))jf8<~O^9 z^XISOv#Qa$wFvlkCHA88PZ<1|4sU+R!mhKvW|g?aA6fD)z1P%vbLOP?F`G)657;tkUg4k|ipoEhQ0Wbxv@%rzD9 ztK4rD#jQm!L&IWxo1ndWDNRi17_qkt>+%tZpzUz?z9hapO;IU{I1@7DA;rX!r)F|K zN3|6O#XJlsjM}>~(KV{e>QR|RpXDvkeVw$2V)USJ9Lv|0?TZ>}ym5zUH9?>#xmihX zQc$GY{(StcK`Q}0N#{ag@mh?kJc)=)gPvXeUcIo{2sCTy%Z#KCj?P@6(w)c&Hv5P{ z(Epd}OlGJ#1~IX-qreKcUS~jlvLh1A)Bi68;N$v%v%^lDkZ$!^j~y&W`AclY-q#N? z36%(G|8ta_d`23YEFQm*@7`+4mbwiRH+5)K&sM6BUY$O_`%n)h-w)Tthga3KPcz2X1lTs+?j_ zR#y>M$JZV11nZ$ui+;(gD+_Zb6?-mbUrG}+`|Z4GXlgx(Pz8yJeVS+UJ|R7k&NQK? zOcyh(Ab4((wh+*UFc~>zdq*v;My94$8->{PKsrcddQnug2}~lCoI|V(XlNOI(%Z|2 z95?n^go{{mi$IxTk1m>1r%oZ9w|n*PzvjjR>Ol5zU(t!Quz*FfnKDI?OYQ?OU{gAU zxyZ*)nuHqa=m6&N3X($=oTJvY<>-q4v;cm)MSKTz-4QZP=;?)pw{)&y!+wt;DO|_g z3VOs!(w@^_hY^{_*?Z5tA(6{$Nr;|2c_QWwq8VsRznMD1TB&FN`MCLa{#HTbCzT{oIOa2F(Y+>B2?vbRf_$2}>0|^NAs{J|Oe!dcFmg8LQf{953ScU3e z(GHZ>VT)q@)4#~k=2%!;=C^+IAnhfLlP(G#MN=s!f#NCrg3 zCrw@GZw7V-wxlX_RZJ{Ut~+dFtXd#rMDr%|!bL!grS`_09BY32 zhtB%19b4yBcsBpu_iD40O`SVxT3xGe5UH{;xb5~4ZO3%o>fdq49K(kL2W@v;teKqI zqL-D^*4}@&P3|_CvRHq zfxu6{dshvsX9anc+(%17%yeW5Dh<)gwCa(PQ6Hxhce!1UmALxz^LE6wHJ!}LM^BEj zQEAr97gUx+>|}{6{Wc_{J9lc}fvZUbl-{88vs!pO7Zjc1X;E^soU?d0=z-a#93av0 zkG$6Rc~`v*uX7`B1@~-BT8f%-QE~?ZZ+84K#M>YmrgRv8!Vhd=au+>mQq=WLhl4sl zOV!zjRvtE6Q)=!dAqr9-vr?l*m(9#-XHyR0C8I{00+^dia)))Bc)kKWsQT6Cb8*=B zCR*s-oQ&%Mr0m1>6%C3gFv&*30O+Wm?z;_@mn-k&lx|^GzKwW!m21>BiH6(qdu~I^ zw}GYPo|@58p&~MA3aI;Tf0`|ez)ts5S=m2s?aI~2hhO69t&c}rq6NjCUYNR41AD!& z4N_=uVl4GriKJaT3}@vu?n$AmA&R&xyw(K?Dkjf%HbxAKg91Y(IT`3bV*aj z-LyeNfZ{AA@z$@GRhE|>EENrg+_Dy=MNSlKkNdpaB-kwhvjMcqnF|-Pi21R+@V3Py zemify#sMLg7j|5QcKpU`S3q7m^~M&wrbAoveq-NyhMHFOKy}5hg|7}`Aev5FJ_A+0QjFOD>DVW`}D$eNyu26 zFesGA|wLCJER$r(e#S{zJtGf2hAUtE?uPzv0_li!^e*^9zJYK zp9#&R89=5Wt&L=%=qM4QOI-Cu z7BmJNNY~e7)vEKqwuPP}8`owx+e^Z|V4T3wW58vtQr4};+FO~{4&S&qL+-45_~^mW z9-|Ht(+)wu0qg0=J$1XXO7LSMo7{m{GBWA|I-LPGgx7#T+QwmAlx!Ae-4kJpc|;2^ zDp-aSd;lc?0_p3J6qMu60hFh&*F<*enzvNk0{Sxw(;ui+R+%+5LCQ!@)|gl<{a{RI zZ-|I`8z}Hqwjb-xejCG@NH#TkQzHk8D`6vKevAmUx$0*opGH>vlIJX?G)N15-bx^> z$hf560wC-v`+o-n)WX=YVP_Xomq{BYXe=$kpScd4lf%{Tg09_XL6Fy6W%E)0-{WM< zkG4Ej=SRRQ+_Lq$bn6yI;Uzush`QEUt5rCgAU73G1P3v~9dPgf|g5@u=1Znioi-#gfvjQb)DiyS?f0q(#D7Q~#x zB8hVbqDN{T!6S(*!aBh#VUN&BGA|erd1$CjLqYH&XQz!sLs5@Jh%Ds_{dIg~fkG9b z-aLxA{o1usZCGAjevHj|r^DV`uj_(LI(rXSGST!`^7*k$KmmHfol=v=JR!mIKO|xWA8dTJMKL@Tkf{&K; zkdfiy(Aiv+aP*gK=N6LmPta1-tAWDfn3;8kF=I!W#!QXt!l&0WJq5KN+z2=2((aw=c9xNjjfm27OXAgtPb=%WCJHA0ug{7m(WUbU%-7QHIm zN}ugObSZy{E82|K#869pY2WYTN@8MWHm?z^pAWFs#i#x?`9(7z5ct#V+(W;)AS zv7lGkW9MgetJ_t(+T2R1`gI&DOpl3$EstPbhLW<_kTReeyuX_Noh?OXf z=aBCRL?=RO>`u0K7}|oJFa`-JE}$w{C2`7*A&QoO-fhBuZ*jW7 zu5XCjhqeq+(7~!HZBI4UrdTgFJT*J5lPK8vm@wTcsINfY{|qqGZr}bmJ5U7U^Y0$o z%B>~(@zU_IvK94~{Qhh{R#7(MIV4moyHB8ET=PUJO2Si|9~Z>ksz=NP@@6Y23n?I+ z6&EI!#Rj6Ai;Gi-Yk*V{B|EbijHD-(-h>uJS+JvKz?XgLtdSNxvI*&fL%h`&qgd(c zMR~#gFdaW$1$n3?cP3%$3XPETGwuA}TnR54^$GWMgQJu-0RfWd!kmFaI6rZN{!@9& zT$Vb#bu)KK@y5HNLl+>MEGmm@yf1K+WZZz+;t0Tlw~8=tz1MJdC&W{7Hcy}KL(6%l zX}3Mj!(X`$Jma57o)n3 z7N)p$_pWD5W7&L~!ObK~{O@O8tGa_!_XIdj+ejJy`>|?w-8)1Q-nyU2?Q*I9_hU2m z*DL?}J%i&CM*jN=w)*wefBoJ~{r~^lu`>U^w3uJ0mHjwge~cJ0s~|%1;kuvK0rg7P zFC~;=!{DEIOWz2iHWPDmRm2O@dtn-3-TKx=fKOkI`j|~E{O3e-k+74MXx(~9%&9~y zg*QTMNk8e9SQ27Vx0m*IZ*;lzA-RvFoi8OEyxKs45NV%MZ9FtTIT7IurIV?O?g)+n z^hpDVq8Dgw{5si2SUUhCkPYt195i^avGtemDXyF0XFidec{I+e$1P8^_v-#;T^=FHGIr)b5i^)&el0H-Lm`Hl z`u{cZo3h-S^naIY(>`B>$g)??P!XmfVxTEviZ-poZJ<1|fCviRzf;TJi+38gL*p@B zVXjGb+KUjVQ|0}ytV)`JjopN-F%foV(u_?*qv)M%&)na12x97A; zMawo-la_kZMnQfOKE8hl{vgtHbo=%MdM;Zc16X?`n*fLK@#wTGr%hw@HYNbQQ-&lPIn7~ zD!1l$I{EXkVaP4%bYZ>)+|r*8Wz-c-S9=%)tCGt_+Ft0Bk&&@;|9*eTU`R`Z-KMqa%cdRwXB%uISm010#8Z&PGO>z!w=*6&4?c1Jq?g zeQPrF_kP{Uz25I9)n#X2QIAF};dzgcde2vE63Y(xtVih5hD-GFHcFi6e|))KYwuc;4{Jv zLv4sd9EErA!*2-=Py$J(*N})`ACx-m`3`^odk>Gm-r@(NqAT3MjyLRC9*4TFGIg!J z@lORwjF^j7pcg^4|Ug}*)03frxTlV!U;RAJx z;T?nC|112gvkmIm6bhu{uvO_q;guu2U{85Blt~w~4N)v8R3HHzIlxGruV6wSQTPJP zbgk#|N@6q5k3#nKqx=*UMq^TKud!-OkFYwD&CJPmzp|>eBjeOA!T6kxA2D=jJB13T z%XzW%qoJi{jN8f`6?D0QI}OP$`n_^atQ;kw^J(v|U{1&Z?_Df8hXznXAyy4ZnIfd( zaf^VB1#o25s4_f{ys_XDvd_Z@hjDuSII#kp2Alg4LPV>MsY4ac_tFcbYZmqHj;OYy z3{P_c*pn}?P~tmlt-HTU1d*CVk?apV?)em&Lc()XdENrXGK{5xyFf%e9`a_ntgHL$^|hmT#?t` zvGByi$)1#$%vRW0T2_2-U|gx`YOg9t_=SsucI@!esLyr%;Ni#>FU^Rx?6cw76@ZTf zEJ(#R-xYN$K7LW#Pg?gmr7KgCCKu+g%SS2I=3kvMZQ9^z46IvI8b+yU-Pf7k3xpLi zcs*(U^7`or69F%ghKh)BN2gd8{Z4`x`VNkK?a!}idb8gHsYDbEQtvRto42!YSc2mi zlq9W}C+??}f*56>E{O2j;_EB*zEaB?>ER&O)=_<>>R;6^#DSH9b@Y#^m zb&bBnEW0=R_1m{qnHu~3RhOaZ#pRMgbXCYk1ntO;p3;TzPyY! zc$B3T70N{#N49HkTT|H}5?f1#y?+qde%5y-=-s0#hu0q7Dw93aMuKvf4 z9otZQS1iy8R;JWpD~Qm8kJPgBDDp;|n4~ZIT2@)v=gX|-#ePqKC{~Whr}KisML{FS}>&u_yA`*F0O} z+4i|_@*bUpkP6m%-a>(iazmw`wyz7GJQ+UCqqx92um6&O3~nH?b0ThrR|CIc^V?k4 zchzCT!pH9*bK%wA6@qvMYn?Kp(*ymC7{A|`d)BU=`w9a0XrNLe+|EUn{}fnf??xne z^TLJsP)oiVIZF}&TQ_Oc=YhDFJOp>z$P}8~BQI8CfZFy`YGbmN<+#usq7RF;zea#P z<5AuBFJt^&CU9oY>2ek{^y=Rr~M z%Bwbzrm8;4|H`wqPOCrecG_# zA7=erunzhbQt(n*PU+&wnWYVqa5JxwuHm@A4)?2){|@1+n*8-wX@bt>lpRDr)bHFP zuh&gV(YN*Ny+;XuV>N|}_@CSx7+Ly>v=TocO}st_rk3KZv5hyg%ZeJ+ArE*VB_-wj z2xywZM9pILt#r&Ev(&ddZ8vm>u@8}(7oYNWk#HY+dL?tX`G~ihHR^MVYEqMQPkCg$ zWj%+P2gK!@Kco+RoX{Tx#k_}}v?aWA*Hs3#Jo)+Zy3n?|$}pRHOJof?``&2nICjh! zJ~+t4p9S=``Oz+x|E&7&HUx3~R;tcZ|GtzTTiyIEc>xGZ5GsZ7S>nXOgL41!s)={) z`!@O^x8hg7pXxjcWibM-lO`3HV}XpdlE#G%`&7kfr1TfF#Gs}rIIJC{Au6!;tcm?guNBp&d$MTLkb zYWcYnHUY1-9 zgt@jc2rk#nz7=2)*w(1NLIs#+dXXKso}VJr1n@TeKs;w}GcqqA*)yDH%00Zf8X#x1 zwmq`3iU<_Z>3Okw%e-@2v$nVUBd;*c%j?~KzOjJGXt%T2rs7Q2YJcO1iRukk5|)u`l-2sV_f%(#IzaM(evI2*uRzKr_K;SvFq{>wwN!dZE63 zJ>x6#5c~D)ix|CxZvWRllB9CuBsA>8-J#dnmocMa!l7vkz9JRIi2o|hqS;4Bjf3PkSszdAIgMt2?pY)4K?N~*Ep#5fRP!PE_M8eKQhOKBQT3t4b z8BeFgAy^=Rx5>5~Ug3p7U;U>m#)65AnMTJ0% zxVx@t-;-T9;qb62s#&9cl>c+#@53k6EOQ-(26v=3k_HOF(x|47QQtsmZld(&tfIyA zV{~vBUlGRuQ9+FS_NpZuM+1hlcBFmUhsmj;58^~XaB?@vKl~s1t%&|27zE;%-e*+y zoWUZp?XjSd@?Ij_!hji7J8E^IU#OG^QFf+uz~H30|p4V2iTa&BNpc^eR5Iv#}2`w zH3X0KD~|oi^=#p=!k!KbRf==Og|CMi4>M#5r3*$PHB`?FD50Grmv8vCsPb&~$eIb& zHNkCG2b_Q%N`310+H_VHir#n{QhMRZC(a}U)^PPTTv-Eu{tKMiUhzG@(fFr>rSIDM zujlBD-mEC5UEbW z^N=R&Xg8aqeY0%(>QXy)@w-Gj`hw*?O7|*h$Q?%dGePyZUz@b-HvU{59ahWV<#csE3Z#x2X?*`Jxd9oBG*;r& zY{BITg2MIbiI|UFr|&GVqZX#bV~E~%(g)G1VwYVXbU}bOt|#e}u~sQ_y-__#Ok{OD ztLjmAWpQ#XQ#Y)IdY`QQ*AK~W`QomA^RfDc^SW>zr5K(%`%5b{w4E&dK z5s$q+jn;qmH-?G(Oda-L7Yn3?G=v>8UZY0weT@Jt9deW%?dfJ?&xFkP$K8_JvKd2k zO!y$5?+h-KSq>0=m$dBTb7btghF^QU@y>KAxEY~*&rt9 z5IrrfkKfAT)YFF9!_iwA`)W|`dE?WPS=z==@p)>%z*HQ?6~mqpf02^Ov4bq8CxGen z+o9?dQ8o&yqjU3dI}I}mykr<(ZA72ehHP8}^_@rQ=p4P^lC?7g%`8={qT8O=kL<^L zbiYOO<};Veh;W>>Ts?!>cyFq`S7BdaeX%;45FzHQ@Oa{)rcAPWmJE@IEfq*_}aN7y1Mq-@OtQ`UVm$;gscE zFl|t>c`C0+o2V8LA(}a`xg{-g z(=Ln{KAcvim=)bKxXyHacWU)&sSp}W`@)l$O)o{m4fig-1fmf`OKa!V^4Y#&&s!_z zpqG`>q`bx=rR_}m8L4t9Z{tB8fJ@MsE7jiFP5d5!1W_&oj-0rl!XsA!gu5PQnB_dS zZ_f6~BqN&Rwf0_0WZzln9Emu2(jp~5B0PZj@E{<}-I?!`R}_tXx9oY)sGt74khItU zBt%+<*2l~wBJRg6FH^pB@28<+;OblhR48h^0~0EzHg!(@lVXnEZ1iqNvTFfp*pp~h zat6`7yu)q0VdICGtbI$IW9`+q+NI`XNR;im%ft5^{1ssbH@bXXa&gGxsi#Y5SoAw` zrTi?~kMI*Gw5r`J^!n0HOQto=XVdkZUgV-=8P~b{ICOobGrG5Jq8Ut^7$bl|i0Hpz zr@>@cz;0%!BysDTOPSh;NLFB*;H%$*s;<9G?n@~1dMhCs7%7x|6<<%hQ{r2>(=&Co zpg<;$U#Aj2!>W8I>x^q&Yq1AhOKKAKv7+|p537@tIy$?B(QL%!2-J2T5kIPi)C)TO zfbDHu3_lfLy?b|(Q@7aak2^qw%?kh`NYn;qTqnVhKhhTLMZ4*)dIDck%u?uVE18*F zFK(DJ!woju^~s;UaAHRn;NK!nC15yNI%UfKCUWx+?uDNp-8`Vt7l=_RssdD4iA`< zNDIRFxU?->8bczsy40Z7qc$6_c-7Awg9shc6D@ihiJdpcnugk@)DK9qz(g!Y+j4CCvRytrNjjJQK3#+_S zYj8orqBgV!oQnU8jyQ&{gqxIsl|)X9>qIXh82)xd4Z}UZPcPap^#iArU@w}_+!kU4 zL+PL6Nu987X3nepKF=rOvf3x1k#)8z8+3VU)4!jlte^HcpKhX}BtC)kd;@gSL`7@u zt%|{)SqN-D@}`&f17lI0lZRPJ>F`pswYFF;Op~BMEIZq z;JRX1LV+RqDP^Hc^6eJ+Fi2!gj^9$Dn0(+Y$iS_RH==A6y_jzQ{w*a90Z?a*OXK$K z57zIUSotN)?)p30w4{s#vHm>~i9BfE_~rl%8PbMLnm0I6^-o;x$P%$=^Co@KD&9cI zS=;D_%zVRc#VT@4k$o^eqzx}GTSpFdjB8VSO_O<8RQBlcF1F2nTSiXV9=7P%#gG{m zH}XZwf@)GrzJF&?ceB+tVtC1IBk4X-8O-W(debi+H>8CItHfECRzIZ>!g)pd5ydxN zFsXvB`~1DVl@MEM6}St{F;2%LT=PSUc4`9Z-@->Rk6roFdWQWfb(#KqodaWpU_eGe zz|f83ZupcpZMNWTVsrpPGIjA1AIVmUZld%;pfCP<4f&AqUg*2h_*<$Ldw(V zk`@7X=tnl6`#Fj8dJLRPzNO$3uuSM^4)wnwk_LZ&{n;@5Z&MQK(HpSnK{H~!0CC*Y zq8Ne-UX*

od;35t<611IYuCRz)&VncyvR&|H#-*L`rku&?!5{dJ{J(!2zR69+6n z4r~LY6Q4`OCHcJi1Cmy`F%e>fQvbmAjAJ=h0M?*~tb2rJHYboHgni8<^T0`5u!so5)Y(1kpFld&ZkRN4P^lBaLg2 zz>oWEeI^RD6)RTATk|C9H)!zrb;#^5i|V9EW@a`fEJx(+$F%m-L@nS5-2_WQOc|E= z!gRa#Kvk;wYj8PM@VS(WrUmorpgyD+?dpCJE*7V$Hrzx^mUkxhVJtB~0#)>cG;&bvj1T0s9SQBRb7G+pPWuoM`xt&-e zS69J2%O=ULuT{T)|1NZ<+^|3ze9zx2k;_Vy*F(3T31NDER%UzPY#ENg;^(>bC|3hH zY|aL`MtUf0-Y-=&ziZwVsfW&)@bE4)Z+F(!9bFLd3MkrE#J5zp2xFbE5Ll)AO(;5U zwa0y!ULZe_xu}22>$$F2F`Dm8?}h=s4e6UMLd3<6f)Mk4A2O@vRta5h{cx@%Q*2Z%Nn zv|s;0S*i={LDh$I*&+jjYS{ZWX?(Jz3GCy&my%U~Et>fsthe&>+W8fiE?!J$e4;{y zkKz*XbqVm=^LOuNguQXEF7JVPXCRnqXWSqFt$iT6P&SD=S=uX7)+MADod^$y;^A?I znB*0&oTr3sw7N z2nb;|hJok!Q4)q!eH(9#8-@yRB$yq^E$#`|>q5=h-(Nwt%wEAbAh5dmtwUBde*Ad% z?y>D*glex)#(^E_-!H>Re^`F6+z=hAIv(g`pR6C`Pt@v|3pBC$F`qCz)K>#x%J^Tf z1+O!}_ySK~LM17}vJ(S<9qe>q|u%ThaOW3q_lr7H#*hk!t&^r(03Kry934~j{3;72YfB$=$X z=vtA~i7B>B0fY<)_-5exo{JXTY{>G?qA(`Iz++kmIU1MXpFWwin9=BkFhf7orRf{O zTGiX*L84kENfkwZW8fGc{_|A|OZ1Kc!cp>w3(R*Wq(ANxRQCnO$H={4yEehklxF^| z`lStpT_Kvk>JZ_vM|HW6z|fj>PaIAjwtyI|V=zjf zrEkkL1wFlu0sZQN(*4F;k(#xBc&m2@bSF*oZgw`LP4u4moWUp@6c+}%m%r7dG;(bi zP1-4@fnujd`rneYsH^2rxiMe2qgb?UL*kK1@~!%G>gbN2PJ{OCkLlBivuK85Q+SjT z>+wy=ZMTWx&Z9>&s_ijU@*(RUS@WU4Bvg<4h<<^#j>B`f0Q@S6*|+~5*p%$%dd|rU zXeT0B7NeVe{Kl-Lj$P4yd6D6?9x0rQ;qDc1>r0XBF`2tRh?iqee5_syJ zw7et`6C=#c2n|QqS$gg9b`m>GcTp?9U=DPjL)KLn7{nK$Wej z>-;prrf2kCoo>9~ZU?1w#H`Y~O+al-y)y<~meqx&v*_E7x$(weJ0gH)xFk`@<=y-i zRZbU$p(x7fzZD-Ax*|kyB5Fz$y>&|HuD|Yz;I?den_kk;2YM$s7d*JMhxueJcXiDG z1hP1GDZd8n0&l(G(lUq&8UPv|OB!-e5t>edyRu}NlM~Y)qA!2GT>G=eP@Khmy(x6y zRD3n0nTD*qxe`M{ancppH_D~v=$PJp=Z%swY2-pb#$WkSVDFhqIdy4dl3kx4wg6Lb z@*sBxx%rod@QK^gYBZKF{h2oZ*j$r{Z0vh9FnB@yBvUuQf=%&ZLr)WcsLW!N?XN_k zv?*V2=5jzm$e7y0Bk|=3D97r@Z29s}?RAJ3erTg*>fh3(fux;I>E887xYrfE599VB zAKP79|8fRUDfi{KkvjCt@qCe*j0W`ueHceA%aK263GP9(@jY5>P?!OeM$+S6yRivWV*dA;+ z8iy{)S3@+k+`WQqLSBKg$t|5!iE-vyC&L#+N~B${UipH*&jA6RerZ+IfPk-AI$p|3 z65DdN&(Ku{%~z&YO$Z+1QGGu1B1THU|LFPr+`A5lYVeGvf`#XI=ud=Q@T2V&9giDgL5pA71S}1Yx_7|+oU67 z$+GW*Hj4yESOyp&xSPKue3K$dlaOS=^eH;>fu>(}HsDsO&+kbJAYB z4xQWY!1=i98hnkUeM~4JgJ5A#=!wSk#$o>aMmW+)Lo{iy{_ND@@B^6QZe#H?2y`6q zG4SkGV7*)i@-eSmxw7!dMI*As%|RopRV4a>Wl77I6nVft1UO}h4Th;z($paQCfjNY z6uTbmGwXDfLL8Uh>EK|RVv&Y3OJ9VPWE6U&hB6~U3;_w=92+^*!f!gbxNHOddP#co z_@@j<=f~hozt*4X*FJUq)@Rv7oxXEScGaJ{x^H;wfrHCh>V?=`{1)2qpw8J4(^(Z? zPXkZ;YAno)mbuG*q{JyJIxq@$O{Y(UMzmtMuQ?$yl~xft=OU(RqFw<`}~(rn%ET z2V}{=NXg8f;B`<|oSR*VqB2vc0Ee75iQ6&kxktq%i#-$zGPk&@`h8r&Eb{}>Qvu!j zoC{d|Q-n7lOcudXNt@ak;9G#GmLg?fapPTIn{R+v7EDG~6Qd6rC#+Q?+5CahDZ)3F zFE2P1H?PS4NTg}#+YCU*X_M{<)W&cP8APMMpPsVRCuaH+-DH#j2p=4eH-H3sq=@Ag z!BC`015!8Qo-sQDIyk3rWJTd~h$^6GX&9v%YDhXIJzS_l<;Dc6vUbN9U_0s0q8f`| z(jl8U^ZGnrLW7Kt>D@5pLqIwP);GQl3e~cjv3FV|*9`AT)Yy6Gklph$Q$sCJ{C=X-{Fk?+!{P~=u>Zqu4XBUj16@O4$!T6`nU%5+6)NHyBa9&OTtsUq4V08v zPaX(HejA()lX2g<@OmS}6(4(G;?p{z)_{fgl=vNK0;7_UEx{r+79^$!-=w6>wE(i5yUiSPm&LQs&fS`u1IuJtoDicnoh3Kyt)T5TY4C$#B%M3f z6qXqjG6*iqmsvABezr;e3f;aW^>TvaZ>R zqkHefsTx2b*2{9~=b6K!y1v>u;wDeh@^s3wzNi1w0@w{D{V?T`_gGo`(?ilt0AFDq3P~Hnb0@i?z7OEMyc3NU;@I ztyGa>QCZicEtBBs{MagZfzRZ|m-s6Cw8l<04BWSOZ~5K#R{E_-U&@U~#U;{$+l1sn zhDUJ@_$40EG8k@O>CIKqwdCK- zKs`F!>({BO4dUqq52N1NLf?Cm_??pn z{CWxNE%FlPLXyPA#UEIAr(l64NZ(vistWVf446uB@Aac3G$m!_(YxiZtbATUB>?%>5 z{O-;NCoJY6g;|%t^K2o)qPq{1;uJujF(^GQFL+gr`_;V776=|z_mXsU8}YW{Aj=Dt z-lL60vI2w|&dIInzMx*1b%1=sCTX=ljUj`DrI)`dg#~yd4m1%Z)-3!_F;kc|CHSJp zhQe0XDp7lVcbe4?)$i=z`Plen^$l*Md+T>j$-g(I_+CJLRh688R`2}ltLmq0Eq@li zrpbu^mHm8iu&hk2N!NaMORGE|JYKYW_nf+tQu@jr8{2sQQ}tqt4r8cJ zazcgvJpQSs12taoRpJaq+viL+W01$Us$lr5+iG+RC4;FYQ5Zk!rJMHemN~aRbL?WfTgX zWPWsH3gk&HeX8TK>dEhQ9>d4}f7pBTupZa$?>{r!m|;ui2t^1P%h--GH=xLrP?51z zWFFd-Xfg{GjY5)CWD1dlN+_YW6qO-S==WOXzPG;5?>V01`TyC+ao>l%eLkP-y3Xr7 z*IMuQdat$ioS^N&NFcyIUteFgQ!3gB4byWsQqIm^Oaq;1(9vGZWVI`No{_Sm@@nIz za$o-A;0ujF8@WYA;lT87U%v*DdNzw#=;r4a*Nl+&B*E$(B|jF=2GQ)Vl^VHI_iDpV zf5nhh110$LMa$%)=5_vPIfbH^&%7UNG6)2UK7L(JDq-!7p~Z6Ezt`Y3#R1rdf~fo~ zDsO(ziK)dk9p;ILg?;eW)cb2^%aobR;sWqQt<(&4srfy?3wx92GHDUPD*nm`O4+O1 zL}gmT7_p!$R`;rWoY_h(V-;qPqh@H`t!AW$t4jkO zh2n0z9$UG=+z<#!iL2MUP#5}qxX`XKcw z$2J1lP7^8z6A-CWY6M?(3i~9hgg`yqugeG{^2KIn=Wi4Cjz+49r~+YpoN~RVgN*x% zLMTPCauFPkvk37o5U}dQc^lJafu@21L=C~f32WHr;Xl7x!1YbS!8^T=OgBcLh%9Y1 z!TCdkwe8yf2%`7@VUW#99#{=e+Arbu&6|H=e}aup?fxg(H=IPvkfGfwpXh4^FFw2T z&)HuufBWZ9B5jr^7eCG^3WUiCo^$1L)`kk_Z98_{ee}qPQFionNPSGD2isAfmNE~x zk9I!>G`E98r0MolpiN3h_~l?ao8O@@j5|y`suP3w{}?bWk37`w-G5YG)??(=h6Oz#&KWgGM0S&{Mi^A zQF4D+(PDJ`PuUMfNtJh}@H0wQrQ;>~!3(2@BV_3&IUyHmrKs51!WFrg$@#@oQ;7>$ ziK(P9Q_1JEHU_M~RB)t8;FQjm_Ya$@8hGu|)T7~1;-1c1(EXp#cKjGf$+Ei9Nmp4} ztz}uW_}as@MRBJvP5EI_S%yco9lcb?|G91J)*hWYjpVx|DfaH#wTpvJv!iZ^Xykmc z@@b2FoloMh^(lZ_^Lc!|%6tFW8N2bdg8c{vds{y_a~#emh+Iuiuteg1 zO+VJL%b}!`5bQk%51wIqZoyOnyb@U77%mFxd)V; zfZ!hXYco3Ro>E-1>gyXlPh{7r`lCYkzt}8Q|4iDsx%IC<9&TBu&#ylYR^yqg{#kCw z39b4k+n+nA`eVF4XR7Lt|L=$Y-%`|27}uGEL;LoX+oRZ3R%B02kfS*z8RfS`L@ZKp znjM9(I}5N|msY&qPHU^vXaw@fEM8jvax?w4!YRbfLj&~y5NJoW7V;`%>Wdyifsox8 z{yrmOEWkXCcq`K4RuefPoV^tMLL^zC9}oa$G4^57Qw2@%WJnNin7iYMFGrEmPRAUa zr?6OKcI*tOlE?h(=gc)PtT?0xb=F?E{Nu~aq{BmuaB=B~G6%r)Q_f|Il}a7-Vx1pc zR34h@G)TSyFfbCP&v7pC)^qO=Cb*ouN!hDieFo5!pmE3Hv*2nTaX__b70|eY_6*$4 zW7L?B5tsjXGooTDLC0efJtc*iqKz>G36x|k@_oxhdJ{lXD&<&q6bXo9WXWB{xQZ;G);&L3U<|%AIFl%A`=%gFH6vD9dL9kEO8Rr7f2p*RY!$4bS z#YW>#7rNocf+=&he(3)<;lv3{dkDNk8W3o&vX-?!^{i%ols;HLIJODlfVK0F!G0`) zd)zV-!M=IVA*SqKROl?bwo1NH5-Y!{^M)Ta3m;3Qlgi|GG!vs?_Ri0~B|k34k~=Fg zi?T_d1ZbTu#+_W7UEYIH{8;{zvwrkf3B(smbKQJILPS$1;9dgZUT6t*h)Cxo3BVAX zY#FaLl`1`oM8-($LP1a{EE2K8?EK7_DAHMepaHz>dJ-ePKR@|a$T}(aox71KiGe(o z6-1FTt$`5xoxllU#pfvxUw4u2D#wXjX3@51o76YC!2y90AJWLC1f2jj{PII7A(c1Z zcF-gm_eVldhRdd)*HH>UM$779*UJ5Jass2x9t~i+LDGKBG3@8Zh<-oAJXu5O9~`#k zG@JhvdNLcTe$1FBPCMIB)$u-y=?q==v%Dx0l<)&DERjt~L>XJ+Eoss;+;$|D#087K zA(>2NMb5L~mp(Z&3RMun>Y?+rJfhOp93k=}&|rzQ10u{~ckH7POPG)lB&&xm&)!Hc zkw8Q%l@7!H-F}FR(*WaqIdr5s?Ebme2ADO8Y*sp{AlkL6nn$nvOM0{t{g!Ym>a^Gr zaE_;14bv^!C<3vaZf+*))_phn8g}U8cOFBoPu#YyYGd*4%fu%y2&&L`h<8S@nTaOQlNs$$XSujc(rVNIB`VWe z;3FgsB}-c3OzE!7-=G?N<|dApgTlbjspLheF7~5Q)RV@@#bT(l?nC*64Sd4w7cX8Y zll)1ms9U>skG_2$D3i%cyDk3vsWPA8R6X%N3A8eV>SjSJp&u9dFC|#9v z|H!klq3Y`Sn+m!OoW0?PT|vPuoo*X`ez(81;Eu;lr%4+spkny^)A#!b%DN`|7C%3? zFsUs5QxXXbkMNs4!(-={{&?}ibKh(yeS#9lZ0GXwwPi1S4^V4U@X2e)s)YrsN?!P0 zzp}xe=^pQgKLcPT9vK!@5>KF^jx`I*}TS zz1Q8{-SE^T4VuKzI{yw~t-PY*;wd0KVjbHbvkkts-(Nhe_scbA*IqZcatizu_F`0n zD{Gpszru7shFp)s9!0MIGG_GXP~S&#Tm27c*-T^Rh#J*dPBg(GHtU^x$8#()9OKLD zz6s!nL(ru@g+HRna8t5Va-qlJ-1{Sme&6 zhY*NNvxwIS#H~Z@cD|KPdFC<{jLig@@OY|s*FHz2sj(GdE=rtF$83bswa3fZn zX@SGRGE6_0fLVQinbN%%VP_HK#7Gyh3^y_n+8_85#f!FX_>~Md&bl?$Kg~72JAe7^ zO!;~&y~uJrGs$uLX^HfbY@&8b<$o%r(jlrXpN~jDC}QnKZt(5CIqOpdOaLLC%J{1p z7A$ER9niwo|NOSdM$&?5(tuYBbYSI%+}MT!iZUvsrJ~&|B3a7Gp@3(TR*nA-J0B27hM_PgYhKQ#62R8isK)s>xK0@c@$VHhSd< zU_$5;Z-pHe$V46Pyrkv6L+ygK?m837AEec?)+1-?&;Pz}F9QU%q*z&5EAik5X;NZy z!$lEy`M6d@R=vi`UU~OQaXk4WD!#d+Df|(CuavxMMv{a3?%mVCWMORz5$>EllzO!9 z7M*z~orn)oNkHa4bk$A;VNu2xm(Pp)kkB?5^~CJ8@3nH14oyd#o5txs!6T~+L^-Gx zQc}+i!ri;Kxf#i*O6+%XVhF-VdS096MqpDhw%(c+dLeTs_3$wYFtBWu2wa-B_b|ti zC7;B%1nFSz{K4{q#{}j;gL!os+ax#H_l5dyc18%GNPvwTPf)18%3nK4pRW|O7j}*& z_7Az8Q263g{AC~nh(I}QfB$`U z<{xjk#L%^0LWvpz$UwXmG{lA%U-x2t`9yJpc*W3M+x5&d2%B+sv}_!4wc>dt;?uJ6 z;R7eJk=A6Ll>0Aqh42a>)x4MpA)hi&i6x}miANS}={M(31%*A01Pl2qNagO8D_6w9 z9X3X-E2d<~(7Fl=3&x=-Fcvcx+?KV<10+eZ7xVU4oNKK&LVG7Kp3T%#8fw0m)e0)77d= z&_i4@fYWFZbK2jiA7BHAsn_W)sM74i16=3}#za`vIa#r?&z7S$u9)0KT-S(>+{kzQEfr+uPm!C!aCd3i`>|D0k95&dh)$Q&QikxN>6cGIH z-d!`hGu}IdpmFf;uYohw6Jb1eRgYGJuCP!GT+ixZl3TTI{U&d5qVI?+u9{D=V19lI z4k7?{E_-|G_h-oVb02PqfnXJz^rLlK8w+F3pb#KDEOZ)0yD7C)i%9xt5&0816&_eH z-m{yVtEL$&I5Uhk{EU@Q^Xu2Irw;eZeR|Gvmn3=el$Q5HnIIwS@2?D{!a<4z`RhKR z^eT~!nV;gfLw*3ZEg#gA{H~0`3NKB)dQIBx=}L?6Abd=}gg_FD_Nqn1ZdLaqZm)J5*pQEJl8d+v zf6Qi2b@fDB$J!RInAPHY{b<}VBVm6%gIsRsu96?6buX@(D&K zCrriH$;OLhOuICQF-p>6c3()gIh&6gB;U(BrLp|P{e4FX;KFSQII&6S_l|cvmbJwL zDpQ6`=N4w-#%J8IyvzOfFy0tUbsWAn3%OE+_w7?HFyzO>rP zCi8Vg2MIu%bR6DG|0$Kb7{HTFhkuQ~`u0OCZSWqTEU0FnU`dUSjjS>Dmcwymk5dwq zO5Q$tv*}iI+m)pD&e!VzSGivtO@O|q9-lR&pkOuO>;g+^fxG_uhq2xa%Slk8D?`C1 zXEOBN4kdjVnem3Gh&O0O2N&4EC{f~tHfqWa?byb`i@^8R@P&BszkNJe20?;sxnsys zM=Y1wXpb4BBrzcz9s{$dQUm0hVRjq2?E^Bw#;ABXlM}PDvOu84sZgT2c}SrYQhB zreVoCK3PWC0PnX&d5~==n`WE`i`&h@mH+=TBi+NF2Nr85d^>W_(=7V%w23c+F)DdB zhX|nCYdbu6T7=(K9=bYEtTz>R)~H1Edk09(|9iTrKAh8k*GxDAFiwo=ZUCeap$DPt zQu9Y(GZL3hXeB)Fl@Bf|dO_fM!|Z35c~XXi>Q(A>gvF)bB6Z>qoHUMpPFPJwRM7Tp z=Mob(u{sit;3>y9OQ=<{L4}eioXauFR`4f=^t@3AtB#$^6;|; zu>udlXNexFyVlb%E@oBXv#80@=s(UsIiIoQkETthvsuG7`1p1ri|DQu@`a>~knOIT z0$d|!ZAP||Sr)}A?}IzeETPybgtKs4>65#UA>)wUO%`@z2WpTUxOHnR^^_q**QcbG z;`zlD5;ct;Ge-4?-I!SD0W;Mlz($%OK>erdF6z6l$JEiRu7^KK+8N17nVFgDZf&)! z7cA{#66^(-J%KyucA!K*3sYUUf$tGgLO>Q1zS1vYF_Ci9cO!^S+gJ$C(Cxr$-m!iE zdu*d%*aBn1H8ORAJx#c(Kf6WpAP8(2Zix#1 z8_aM@Lde4G-u>a)xEXrKAXMC)@4?yOYe3}9oxfwL*>Fd}dny*LIMTzN zoe+e)-eiG?wRBAxRut=pET`|vv+Mt(1qh*hTCf`N0lx`3fVt@H!*{&UqV zBf#@qmxN@yr-duMNCxRYBnM~deV)U0?vEn2NC+wuE-VQHemMjqfp_4^deSxx7sLi+ zhLDH5dvgDof7ZgCC)nzcX3W;Eio|yQsS(Ue8a6bcp#@fvFMxP?M+jv+do^!C{fa?? zk^oiPavn4EV;FQ!Q>jxJjB|#@sMlfql7-ex3m}Fne-K+0VUQ&kJ0aN`QkJF>4lR7V zz7odfgH_ipr+E}iCVpzw0<+~@E_)wmuYiSUn0})lMMw zt(IP4rZ8m-3tXo{A|U6sUNh_X=xw1H4|scNP?)Rf#u$C^Vjea->PtDWPcofm5$1j; zPJBk^GDCIc=A76oEEdrWTi$5atizEyy?aj*rE#tFJ^rNX5|utZXuA-vdhhgua_+Um z(4Nldf78x2ZE&FZ!lmiKCga&fLX4VQHF~oG@kz##3p?(YvDuURR7LJ^y++V+tFikA z>~4=ke>^XWE zsX;>7Kf~BtTgGtKV5yi2a*`kZv?;fv9FO+<)Qq~xfh?Rwu;vjH6Jr-kqeGNx-)Cg} zd{!04@rds)P`zhEfriIVvlBOz{D9b9opx_kt;77IxlwTttMPaV|oF0;BW|vdRygc|Mx*i4JdaJ-SY$EG|I_ zqWZ~GsX8aj84vHW_jCHC=maI9o;`TGT5T*sOFS!P(sE*fYl;_SD2!*%Ww`4wk0J9G zmSYe)4(oZeDOSgWy2ue`lgKs=Zc+tzc+p1}4^;aZ4MoKi&BTMpFWF`ejk(2-Sr1w} z@a1-krakj_w(dhDHyH;y!Q(uIzi}TEd!~7ay7O$}{VV&nHn21&7to<6qLrJLu4jjh zg$er1(HidolEV+u+*wWEj6&PtKRz3kynj}@=}jA4D3xyoCv7DPhN$9YoM+s#joQXr z8om`X*+YbkB?)bp&3IN7q?{x?(f2SJO?_dHlvNbqn}&}?GJIm;U_*HUv}k{_B^Y7Tic|=OW&;Z<`AG&lC@yz zw-CZ<9ed(IfYYirSGKN#;weA7^3}H$3`1brmld!ST=XxX6g)oXa;%?4>~dg|Ki{8O zVXV`ypCQP|i!#Yh z?Cty_NaZjetKjU2S`7w$LuqjUhqp+h)bTeXI(ra=>{bKI()A`imq&_yu|)2q+YWvTXpNgGf^(XM53`%0Cv-e{jh+N$ks2rk`ep2Mvc9ATAy7jMnhNm#Ke?aREPpWdrp;^22)kU zkC=BWB7#(w1n$c&e>;gq@$NjPt~cQ(#SVt+*2Q*xOW_~9Y6`vYJhdnD0J5L!)T?(F z&xKWZ1U7j01)20zECcrrd9-9{QCiruT7!(nCt_wSG<5b%(GwOr7n-5`SBjh5*_*w| zI_yXc1&>7!qZBB^cV9C2%m}m5IapjDO+6lRCA_<)9-T(d%zg$zc4uLP6$)SdqZY)2 zvV3TnT5+zJss)J3wDpB&N=#3m&PFaH{J>4->n4+Mng~LiNpl`g|0@e`b$h-ziHq{0 zcDlIiK}2J6Z_>d5Z#%|a!T+31OuIrG)Ii-`U$>sq={$Y@-7OfGN^wfb4|Yrmf`S>* zjPx;v@j{?>*LGkTJSOa0plS_A|O1mT2(wKGeLCVyBqxqb>`z90c zgE6(QQRNY4_|aE%m*?E+BztscOSSo}wi0?g`>tJUt$j_jD52|uxqKhDIfX(RMyko~@Nlzx` zf8YiZ7e<)&AKAj^#5g5POgcphzWQ0@RP$NqPqiw&9A!FdRk2oXT6%+T^K`)r9znzS3-iDNCE`1jWkTb3Up z;;>3i=>gUvmn04E10~qM;igDYAVP(PSuQThaQX5x0w~9h<>`L0UwgVw?vNT}bgPm& zT1?RWv82TL)u9j2hi`r{Y(&j7PSjA?(+f6wAF4rqGB>Zszx0&|)DVCV6aK3~n0d@J z2$?d7U09KSX*yyexY#P1j@JI_-zYp}1O9GUnWQj_|HP6gY;0k6d0q7PA3vny=HTC- ziFhpN7d^IoG-?nDf!6;hnO^OgupO`z302Pob&WjjF?U$)hH&Bx#(=LV79^}nWxSSy@wpo-+yc)p87JadgRA&U3Zl{=iAmzhZt#NA=%iN_xNtC zIPPlslzs{h{X{gtazp#P`+d1#LM5giJTzg95MK#O;(zD|IRz(7cG-s9{MCbX3MTwd za;;;J4K=bIr5P<7FQ4rA?;9_k)E|u7iq(yVv08%rMSg${QX4SfapCp_4Xz{6TlLSq z6|0|jpGJ}`Iwq!j85yHTbQbUJW2KPY64xC-8AbaM>!1I=fsmmuW^e7@J#Ue)Lw{cS zmmS)(_<+<~Nm7n9>mT*&PXThEv#3}!u;c7`wtGpp}MGE8Z%-km<6vT~|QB54W^nb(9gspNG(kYslEJ(01q-ImE&<#;^ zX_FVt&i4C#l|(*L8^oUzsI*MAgF8 z=>G1y#Y?mnKNv{{9SNb=@3vqZGzl2D{Bd&mfJI4#XmtpkA6LEsk0k;=Mpt8jZ-=Rq%SU7yn zi>Hf7^z=)}!y!K+4w4KLoil=YF+lBykcL*~-FffsL~(SH zgh|1Xih@ZXWAo-GKmz$}77u?Ki%kchDG$io^coVFwIulMjc$=ZKZtm%3h{gR6O%}g zn4pB9z?vF9R2j|-(j@1N0Aw117UNil6*k+K66NEC%5|DX@n zNpi6xB0q_83!0R*G^F7QTabBxt%{p1Q%K2h<#=K_zmn41BN?1%~iiba9`nxDPo)(FKWk<*LJt|3g zMkEIiT_>pTt)R?)MZbiumlBp<>-7qwjpPG1Tey8ueThDdeGGgTrfg`pu3dFuko7MQ zd^o3|g0$Ns^%J#f)_hELC=liC@mn?GuOkmOCsvS5V3kbLP=RX#1D~g8cF0FM!rLIO zvwsHX6-f^ieM0~XkQwT#xy~&N5`Tu>eRrYs{j+r2pshrPPjqHe_+4<8K+g0Ty^OkB z+^c2t2KO)xUp|$c?5g=kg9ZW!fK)m*zW*g0wC}umP97QJk2Lqwu=h5uQ^{LK((A%z z4maiK;Lz3a^pzOLPbVeWNxLi4f?|^Ovyk^heTn8^L&W=`D;SYBq($lK1oG`(a zc^sYL&_vmeQzSm~hCelbd1OkveZ5Q{7V0gj%1iM}-d*WRlwg~&g*rbQZb&5DutWgm zu#8w}J-~>-ua83(B^@-ugH8vvQ+68&Rt;erNunO=WXYN%TVItDY)|;OPV`C8LGLcm z!$6Pt5@61fJ?24G^~urjuTc92AJ-{#(#Kx-07o)A{!LKxNyJK>>d^AwY}y*51OZ!52M*!=O+gvE%Yhxd*+~?cYncCebF33BB~@^6XJ(-QuP)|yFKV}J>wht>sGR-&VQ{yI0e4?UC zyQC-53;cpfF}3G?@BC=)vu*K%V^?bp8Y9X!S51-acYRB{lc==zbvN!%1LhM?sgb3v z67TveAdD|V$JVa>>%AgrDM(m~Vw-)+j^G*o??IllPSj0L^!CRXh``T7SPQd)XLKD` zBkzWP{`l!r#2-(DIlN_Gkd}1mfSKW&feDgic3-!YRB|v8=v!QXexdXYjDx?L<|Abx zNT%5HX&1I0$`&FBr{475*E$<3rUe_T5q%e2+t#pJ%&{;+HQM(5ryMXdM?_TJz_}B= z>7D}zrrG+Qvb%l;5H@^u^cH`al1N@G)h0adB)MJ=M-Oz`f~bi>j^@n*<9U$PXFbg# zgC#|fd1b>KDCjbZ@TA})_x9c~%i>CWNWH!HSvoFJASiKN95R2oG&G(>%nW4+!dc@R z(prpIq|oOAwm{^t**B_K09@ER+b1R3G0>r~prq83@8J=>QCQe)50lJ7QX0ba&-4%+ zI<(uy)-ynrIh2n;><#@5QYcusqA7Zrr!?*wwq4|gvY+58rhpS4lki05I@mPAwMMoT z)f5Us!%cFnlorG*`LPNjSBP&QzASzMG{VS7ug5e5uG%*4mId!v4ig`bYBCnN;pcdY6*r0A4k}R=+3wD@5D`P z^pt0J)f~F+>luk34o?AQQFgLAH?h^f;S--?%P$#t2pn1oOS*djkk|r7vY3@h^yMo# z=w3++AMv^+NY360EjL!KK)zK}hvXiFup_IsdUZ?f?!35GEn2(=JRQ~rfXOBCDAg{B zN#v5E!WujF>Z)v>UJjyUV>Z;N!?07>^zS{ z329l5g=ydZ&GAWuq9o()D0N}pt!Rk|OaxoOG1G&?BKbjEvT>{;5n9QOA>6zj32&JF z9z%ypqJNs?q>(F;4hQZqS*POdqAxgq=7*8-6?UgFvn@0^k&5LE;sxJe`{ z#K_G+0)!C4KG6(8S(cQf5+b*2-=Yb534`BWy?Ly|R9-!k6_>B}Y8k|7Omltm#vJA~ zEaL#l>oXT<^*sl(4qAe3amsO|RH+MQyN!j1NwI-w?}$mrpuE4(QQKh(B=lZQJz-4v zUkja|Y&0PYh=e-{7$oMIP76a(^7JGm;>8H}5`a!B5bL;e*RF`&nX!%$lv;M!A9;y} z{|j{XEm9-7LoOoMXwH~#q$q`;&%D6Fv%-aoLD7`vC~Je$w|*Meql`f`h5sVBv z``G!2vf8y*y$J=k8zzxAz;}5^dlCG!B7)?#>J&dAo#X|_$Yvb=xt+NFh4w!^H?IK| z5Lsu(Z~A+978-M21}!!9A99$qKp=7Dg)u~8Mknt6p=810ioq7!&U8J=mD1;I_1EHg z`k1^!QhP>d5NVr9Wm}TyWw;Rt4Bv9QjV*p2qhdEmSf!vNQMg7TLW9p|d7(7LngG=( z!S~UpS})rX>2@a(Um1NURhk@;MiPsL`h6QAlR`pf+yg=Rz1DtAC`Et(0p;=h4J)@- zGeLb!3x22`dn#nXMBA$|#OlN%SVrBBOhtj~43bQN4G#-ZcXqZ7G(am2Gh=e^qVwj* zFhP=kd0>-pw0uOo;(VK!tx zi`j?F95(df7&hjl1SMWv?>o*CNm;nU&K%4c4zLzHb{QgVgK;r@-k0OsK9R?l2t#Cc zaM55IQ4A0d2SU)#EEgjPz*jT+XKy-HjK^Fx^Br^SToVipl$p5FYU9?;QTWrQaaq4c zrE1hL!t!<~!1RP2a@7P#8l3ysHS}r$rv-`{0>$iZ*RHNa`NKbIOYEVk$3At;Ti;;Y zO7@zkcd3=rD6n#R1w~IdM{zO8UPd?>XrdV>v3+JD82H z4!?xkXCwh4lyr}p|j)((m1YymKRpS{5t);*h-ghf*$uc5Cs79!J$uFQHCrA9u zVvf+~h_@1989mCuY-~nEtS`^rKd?L^{F_oyi0yy00H5BBu-|K`Cp!&@^QqFB-e4 zW}O+g%InybeYO%qW^iO^NyBeDMx)KFS!rON10JyNgmCTK=N=eBD_AUME@h!ioDi)l z9hJO*z$ZZw-O6KSi=cp%+#3$epe!WNj&GjX#`!Ig z9jeA@Y#Gr)h)x|%m@&3dG70SA!oSZk4C(fxNB!??KFP+!c7TT6?JiUJJ7c_Y*IQU) zOV_=Gr6(u*o+hheMG{hK54pL8-m&gxuLr$ss^qTj0Me*Dz~p+=WWQ*#7}-b)u-0sdt47O!>Hdpsp`GuvG4$X zeuE?F9>S};dMPLsx7}ODRW)kynbZbMNMa3<;qqG@FxIcB3 zohLK)h|$!1Un5etvJYbg#^}P|Z0;9M2lzIy>plDTKk&0Hic0B_aGk+Cl!r#y52L(e zL0y`W>FTPlK}X|KA3q=f4l{Kv2!wbD3x!CTrF>cHxCd;e9#omN%@lqYWMZ^e75uQ3!v#92 z(2FK@X;CRUeYG7PIv;O$c|sT$lpapm=gy8>r5#7zEj2i8%@n1l5Wi{?Y}Hq(lgfTN znnj1Vb<>mCkV#2l2Bn=#hB%iEAOvkAgI|M`=#-$M;yrBDKaF(1PIoe)ug@4=#%#GG ziO!}>?k2uw&ygdI6%u=AVN^|{AMI@8rpIiC1}d95opX`HOYaNa+FblAk`frxfnoVW%jt)+FJ~7FkK7KrwYE3WVg@z9tu}9L|j)dXz zHEVXbyElcs+a_A#KhA~tMP)fPRM{*HN6>w;u}u^=F~;azm-0>ZI!Gr7^guhL$pu#a zFDgv<(c|d_NgeKt%9lD2=@xYL>dO&!GrB7(ro?TnP^Oi)VRVb`^cB%Ey0b2wI7>ao z?rsZO-YH%Mu-LVZ=|6euR7IRWP34~&w0}I1Aj^SvDP#tEm3&9T&fwU25A)n_+|bP{ zDeLFgJ8`XymT?=D6==K|(nkeWJ>a2ppgF&S1bAxh(8<~#bOSE`sj?ZlD`Q&HYi4>r zmH87$Mk{AS`_KQL-bqn$Zz9;Xy~3=76a)iU3bf-?)Ro&V->d}ZS2H6a!3RR z9KR+v6-$*vU!_JfF0UIRdVac*%!o-{JA3x*4%DdZCI*&9ZPNQk3Z$fIaQ}t(;-zUN zzV{_~D$UkAG>_e)N65%1M0c>9SxkHOd%s#0TJ(_iUy0sjlb+vM`?mbcXi`X{aL9Dt z{Ow?@&TA%nsNY?jYYO6fM)w?WKGu=DG;LjVc6PbDFQVIy?!pY(2-9}xj?7*jceCne zp5wNTr&@<)*5x-Ju&F*!rFZeo{xSsG zP_xR|lu{IUmE6SBrOg!g{vpAU18gRHVd|7AbKl$ZQ@0z@c!Yg!i`SPw-R^~#R_eE) ze$^?Eo0iA zU3D+gmDpumE}UYcxY^6z4>S&;aDlBo7J%Fr^>?qC7aGCcUq|3-`996XrSPIOl_Cka z)y=IjEmA`>o3MfhHqrfrUExeAQX_|uxwHp*uy{bTz5QfH)m&+01_cwAc~YM)wJSJ6 zvNr0)GH#f*E(j%G)E1d~X1xWp$U)FtRQ zycymHXx9vbr39^}ASP`8z@-Q64xO;>-nnxP?h9yH_vnV7jy%P^ry6^`Wss`_>?B8T z>a1Bys;@O*t&xMqT=*nzJjQMV8+G-&CyFYY$q$}4tJkSbn>NyrURSq)!wyDGfQ~aG zJJ8Uu_+J0yxpZc*oXre~y6EY*lF^t;{{$JN0XMysFpmnRb{rX9dfR{oHsPq+5R=p` zE^Vrb>)J*hX&&`dPhuVW(;;ck!Gkj7)9>O%B|X0nr^7zj$`ni)11x1$e}*0M^>xR| z?aPSl(6Z%%l=3}JGT~9F|H4Mqwg-fz2EBMfGq>lrX;jyxKJ3ZeSbNk(bk!cM%cx-I z(nBG&{Zd@W5%<_+t{-21tzjQoTXyuH(aD&bGl*-k%3h8dLxz|(*pHxfE3QN4f1q&~ z2~=bq@3!C8StZakqT4!WXX>JzrSTMSh!Mo93NpN@)#dP<e@0uM1^j}kt5&u4}`h7PVVV`wIhjE z=K99;nyg?Q#jDV{cb%Q77HFm@GKDqK5sBaMI)oA>B^s@Ychdx1Wi!)#HVdY~8nSdeE6QgdBgGhD0uXeo>L(JBiwPbW%}I?fI><9&Gsd zIte6dH@X~ySTI?7z*zK>x3)HDaV%wVVf2w=qLGTK!S%+4Jn(jA(M3L+636}@ty|1T z_m!8iA8RXKg(@msxyXAB3>bmcrRN(5si_4$js!Gag-cRw-FneO9pQ>q$GN$>)>c48 zbOMnoi$e;G+KL;Pu+AzMNoAj@8Y$!*{0Q*2t9_G;R4`lS$XFQ-!-z|RSG=m-VO{Yk zm-@6vEan&=GU+~OP-|>=pn1$dVj6?E3$)~OsgGcG$=^QumeRqDsJq|q7B7m_LfzOu zrPrZLeO5VKdky*`=>?9H-sBQbqfgLW#Qc3xYmj`q)bFt2`wE4CT3MSn*Ib8W+<|IN z?-dOQw+DXf0Hd7vauu8JTCJwq3UmsEfjaTnPUhci+cXud_A)1DL0Qd;tBVK7pxH#1 z9r&aR1|`8EuU^fkU86AEFWK-SgeS`#tKj_-6=+FtT+l>Oeer4_F=HI{6! zWzCYAZ|OEkwA!zK|DHcOlr7s&pI&tOSE~-pf1Y4g^v4mcix)B&x>F|wm6`+WUJJB;34tm3iQmL1KJTQe*nZ;T~?0=+wCEgRXjv zZt+u_@ETt$Hb&)qAOkH8{<@|Ah$75V(_$Lyg!LQ9R?_shSEY8-- z>2;HLLkPyidPJJu|HTZLZIJ|T zf$IvPA%j;>hWmRJYO9{kaqw!B!|Cy#^nK=G@o6xp4ZyfIQ7fjacJD4zKX`dKkg?Qr zDk>}QB+677I`nDiK|qL+{T7;8bfCQ8YQ2u@Hj02{hXX|n^GW-6OC_?@Kye|RS&56t z7}X>GLpj56fY_Vq=g<|o)JLORLjil%yHzo<%%hxx6{MxyA3S(qXotRhVzA70_pFum z{Q0a{awW|a>Bb)Nw8P11#>QKT%&%R&S_2k#B#TEs|LvSj3y?OI)$v#cu3M9RBhE-# zsj|i8Gt84)SwNDWT{U2%OFTM5M7GA%2#qy}P zZr|QK*YspZSQC^Ry%B3LyjC;;WD3eDpqH%9vBfR z4G;1%B2M+I=Y(cuVY>Q(i2Q&4*)Ee$A;uDID3!nHR1&Oe*3G-kF#BGx57ltkuHCy& zKb&V$VaIG5#;}Zar_I(^D5v_g^YGyvRBGaU;2~s0 z3sQ08CVDpX{LqiYM@@h7^yz3_ncJHC4a=o^radh<1MKTZEl#PavhuED1gUzOgKu^@ zhTOu^J`B9m0h!v>{>j=~*s_BM4<4z@SYTH|?Stnp>u6e}spmBq;6m4AlpPak0&;3rij%3C6pd*BCgB# zW7kta@cI3-)+(DxvL7@qXNBUadfWk^i@Rq-hiT~w>@pXIJSwaNQ!`rEcF0&JpkyVw zzQA}Y;>&txIhUHplHzvA-c-*ZNg=JEL>jV^<=nw>Kf&?o78W*?Imuh;E-Zu6Bp^uD z;G9X2S)*3nW5fnbHPyu?d|+8rh78G=U)tGD{QMaJQ?;O3srcYB%EkglUz@2TdH9{? z#{ujTf}VR8$#CQ61;Ep-$TVht&Z2a&)@LW30m?~Bn~r=&15{E8wvI^*VdOA)uDsI0 zEbLF%Vm$|k!4SneF%#o^2Rt1&Y0~M>Pa3MM(k^|ziZObV9k=T-1)|pk zEHV^i^6+o9u`kzQ*OCr)oSp$KDZ`Z_Pl*hOw59A zRm&vvm*r0jd@viYWa!PLQxVlZQOaPx%FPtfNO?egFost3>o8JRDnhGp3+f3Oo>uJ@ z(7P>JJlws9^xUC4b`=iU`D=qhw;d-qOtakrmdXPJCBXkwJErA;IQb8IO{L8&a#z|z z{tMI=^;JR;v#{zhC2r>pRf}s#Uux4xCA|vCA-t*sCX*Qky8gfLj4jRpe;EZZowkq0 z##p^$7cV|}8fLs!y5f?h;^|Ck!FqP0_C2XucuU>CQnANPSk2C=s&%Ls9_i$CDe{?G zI)Cv10i?`&ROri~c$fMJ-akAX-$&+H{@Hl#uAMvkIuy^<{`_DJ#Tw^knA>1LyXeX& zf}50ZZNWF2#;Bh2AY_&SrB%qwwQ55p9U0adC=y}cwp6fzbo55(A%ia;z*Nzx+AK!H zb5@LfV|XeZr_UpyW@KfEhiUj}aw!2zeLQ7xCzZtO^yrrnHAF=71}NW+U4)7R!Ql?o zeJjT^(p2aZ7wHbJK$r1Wjgk$j`oJM^wLerj^pWgu_rm*LG%g6d7*X=Q0;(kY*e95OK~nfgq+^T#iBQ z4u&OIDqTuP>B>ao&+jr?h<62O0Q0@gI9NR*`hS7O+3u1}4rGnBV?gMfE3@A&LZuck zdp!NJA@LeBTrO7`=g|vYy}`>|qzQEuH_Z+Yw=VBi{yS(3u^ON(BW$!w9vcN*o(^sI zfpa?J-EiZ$I(6#2r2RqlCpoCKtH!ccmX?;s$qqDAl-BkVoRBPQptuPlO+RK%*xSqH zgTXswwd`Hvg(Uyos{)KMG--K)?^N5?!PbuCv3vYpW2 zz)2Vq+ND>cEq2#fmI|C1qx%36KtGFmfS|^TR~z<;of}X%VHJ!Aqa9-Jed0ZBa*^4N z-BQ}I`jDZ_nXiR=kj}<@l9-nwi33F^yoCl z_9iekuIQ1}VuF9+w}^tc?;r05*cbmaVqz5zX%pssW=_G_RClHcFd3>E0eFb%R7dccHVqOKhyRpam7f!mC!y z)*(!v+t+KRXrKsXWM0e)%*`J~(Q~iXbg3^JPC;T1%-p^FD`(CW`|OBqrk=_VLqU&K>s8H%!lZ5_gB|(oVhCWp z8U2tInQzZfRqbQoRzgAop9>G|=#@;Eof%VVUX)S=%9<%cCBi0O%gXA2MTQT#@T9XD zab`0`fPzn(QS)}QRb@J!94QtY9VC;mYGrwh1(`uFE#14;=Xn%RN(=-1g~IoWQ8u~X zXbVF+gJjw^Ek*#>R1E5?q{AedB}46&$tSRvqN`&jMdW{9iBeMFGWT?65~90 zyE>43y0j2)-MSvg&ZR!@yavWshC^g##yvN`tttwWb^mY!{i6FQIM5BGvx-b}RgV=Z z4A}^>HJSw-jGa;1Hl@>fHKR)zioqN+Nn9lvzg+$lGN#c zn!i9bA#VX&sh~g_Vy1dFlKG%_R=eBpO*twGH<1ZvY}MESoV za@gni9vMp|z14%v5U&fJPg+jP%szbdNJ1zFM@N}4jp>w; z9^kuXEn9A-#mPz=5q%Gtkz55P2LzpJuG-&$F#|ngPcFD8UCNU#)iV*%O#;g3YJn6C z#nTPFvm?81xvHQzitI-4fLo8BLieU1w(Qq`)%Xq&2aMX98+7&$6D?3c?();z6ebqb+}Gu zJn8iGe%nugm~yjvcI#Fb-Wd)eDzCJuNmEJeO`K?1EtDh1huqG_$RviB3GyOR?x|Hz zYuK=7DxWNh&SPLk>T<$1N|Ef#5Z-{Gg4&)C)WqB4gGy&pU1Y2z^et6sFTNZ_p1#Rt zE-{Wa6 zT@)Qd6U$bJGEP2rWV7FmT|>_q%feGBi>swCzZ?vHg<~HDJK9+V;5UO-z1}uI;W9b9 zBN^km@yen)-BnfRQFKb)E$Cyd%}jSWpICY#{}zYu?c2B256Y3Dtymx-=}7@dnqcs- zVPqSXG)?CHM+@-w?ceC~9&y%4o2*cxv z1XMPY;%?cxweX5lop{oP@B3z+nO6&YET1~%yIvUu=$`|ZJlS~u{CPv0pUAEizB?Z? zhd>a_%Hbe!dL6vk%<>SYWDR9;+nRpVlSRgoz zOZV((7A7{H5V@X$17^m%?=sXU3L6PLM){?9W!wyY^w!`<2ELZPS4%<6mgv+AS3#z@ zb{ru`wV7f&9jC|sC86dqfAX)zpFitjC!*86-kBX8xKvqTE)Usicc4r|fg&TWnmVs< z8AKrD4zhv;3?^GU5e(f~`>?On$&rM`k>5yiBDpA73I<>usM!(Sy}31uH? zf4I>?jGAB)nL9-uk`(-u(|vmP)`K}duvWEe*KA(PfaqJC<1UP6s3eZlyZz-B=s+n zz*rXhp{`5<0ZC@#`7a{euXCxZ){5oJML6=z--B>(w@s zTy$@=F6reu)ednbMqWjs1*ypGRoL$rY$nL6{F7(yn>S=QeSZJTA(eoBH-QbIf%+&o z2*sdZjNKu|6iVpP&y*V^Sy1(~?JA=Y@5)>K=l1>k+cAs3{U`sGa#Oe4u_0vc+yBqs zkSE)I=#WfEM&9u2iP11hnh_+1E(EA*>?UWP`Yxb;-tN1JiJJ+l|K~S~KYl!C-!|Cm z(4mG$Ce?G(+k#wOC@A9RG~19wDE&Re)j(F_{kW%(4R^7vI;d<0(pVsleS!>P!@~C! z_ORl}8gD&a`k=kX-n}&-W~-K)u^qxXBlFpfJvNJJoQjyTF&nkBN@XZTbzvjae`&T! zy};kw^!%o#by4A-t_iP!s!qu*VVIe;CXt*>VczLHlv5Ts5ShG)4cQK4eTl^!E4$bx zYDvas(pEFm=vH|XhVAtCXnr&xZPrKU6d)b>rcQnOB)_r=w#B{*k)=MT0)A#jjOwLY zK;tPiqpNn;S+p-N%nmz2+R*|Xdi@3s)LP|((mSiE-Ff=ngz0t4y0r=7$KXNa0+P=( z3!7$YM5m-Fvu3TkWqm~3vAN1-%%ItViPKNdx{9`L8~M2wC<*RW~R9h49g1b3Ig?R=XFl%uG7 ztPTh&!_u8YA}fzQZ1_3HhF|y5iu$;*%S`f|6OL-P zp}_STf#g&;{Li0P3x{#0$WXU7-=@B>AYg3HvAW5IpS{yqIKfKd^)I=c&07U$C<5^}YM|FFw0=O36xi zQrc6=SQZ$-szW>Ees*L#{1do+{I^w1X`;%wsiHXi70@d^?H3({>6D?G0RQRhld`T} zJ$|qE^zrEilPB+R$v&{?=-GJnjg{oQATAki#@qLHnzLesCcqMcB<@+^jMIeQy0wW0 zWW*kMt>NWMwxz$x$vH-gwMt-@;$Jf38e7=A*#&g8l1L=VfCiC>ShqHFK&0DfouL8w zg{%NI#l!!XGy3`Sd10R9NkGz%R}rHiLTD=yI=cy8l$(kVz;>N%wAL34AYwR#f&V6OMOaPG+{g{(@Ci9`Iwn7t3{Y0=*wGz!TIOQaZ`4RMQAE38 zwUg<=wbdmX>gS5(dj>z}77xxYI*_J1Y*qIO`;UG8{$Nbgm(Z+#u@$_(oyRdTeRR9N z%~^k9P(R*MGetB(^C9QD?T8=(m#nUCZH&yt3n`q*|`Q6v9jpjzL5ss2(km-cv6#Z%^ z5kufv^~f<2e|hh1fFzoe1~`ZcUDj90t5%7E@PDMeK@#XIBF^34FdVD81@-#=A0?ME z%h?S*b!Mh79`Fj)+jOUfjT+s6u2#<+f9GB%A5u`D_|?!lj37wnwTi^X^2^zv5uJ|Z z7obd940}>-6Ia~aIH*gPT9nr&E|~^MC9owpezDR%|Gh{f%)%~QTdvW)dp$59BcS>R z*-{Mmv1c*8FgD`laNya6g}cEfFV2>He+H-5*CL@2>6>`cm(;PHa|rVw(JF{h9zf@* zimGbBg!p`dNKz=xQ3)}l?%>L$m=4>l*aq1}DXJ=)aU?I!t>@i!R$}%!;JfcM2f1l9StsCKzDCi@*RPEN_BJzihBU6*bj0_*)fPxV7^PN1NO*X9zI^kh z9{(_5Q6{m~Z`}AVUZ5i6fxS64z@q zV&W@pbeeVSxZzfs(O!{^lFVkF<{5{u(9lrBd2?B}VB-p!N+zDp0F&sB9Xs9n%{!cU zXB8S4FWr{TAM2^qWXdGNgKKR(*VY~om1xI;8Ewvh)esUhH1c_2!L0v7vbIN5A)@>2 z>}((~kE!1N#@4kRl#Yc}^w@B8`l>Dbszkvzct6OruWO0A1Y zlN!%1*@a|8(jTn8qUMmi;jk;ZwefkmmwyuZ_V_XJ$WRl<_2`hRc;bN5$#?EZ;V)Nc4XCH(Akyv)YX6 zyF5GIu%4&)yYKG_LblnU10p*~Tl39#3eI}rTB_K1A;$^MwL&Iwi{2S=bV;O((RHqO zhC8wxUNmCFE?gpvc8=#{Gi$X4e{om!>({T!3{^(FF2+I``}_M#3PciLgm>HEP>vCN zFGe1|a^!xO_&awR&|OFK?ecy$s3*^yJu9k4Nzv#^{y?`jFQQx6shl(C6NiJSgJMg8J5Y3+T%egw zu+`XvMyH)o$tAW^qWJL-q7=%B=1qo+5cC266}B?_2|zYHR7e(R60Mjt9$_0t#jD)Z zdVsQIE3B-n5=&&NtxGnw_-Ahz-cE$a-CnPQ!^Yp^mS~FG>meA$>jxXpn$>9S+VYjx zHR5KwvmWyxg~03=aFjDBa^1*C&Nbu*cV9=O`;9^Vo*#PQUGazYPiGK zneN``(G~_>zo%Y+SKNV65wq%*(v-El%4-#U0BR@|4UNX8rlyHXn>L8V7|LqyqDA%4 z6N&hjR;$fv>5&-sg5(JTA5CE4%rCU|6QO|TLd}_p5Wn6T(I;IO1dbauss`EIW@s`5 zE1(42-*;Zk<}F%`H(x_T377gvN7N73n~=Y0ZD@2oV)ww*X1;giX`#k(kWVXPd|rQTjn$tV(#Ah`{9F7r|j zm^&%#|PJs>vtV!=kd%JYpH|Bgw0mN%YgK zUArpS{hzZ7?cs1+Sut}3n|uq(00?z*&!)FwGK3ZR&;3`T9+|g{ihM>)W0kU|U%BP5 z%$lYT=zSuy)2n?FUDalKZ_MPADuxFbHGSSDeRs7TLBk936E`b!s)^r`fq(;QRdXTY zm9Z z=MlKXourXjYfsR-z}LZOo7sBx{8ARDlrew&;>ujG(jUFd(wl>7ms8t7u7%pj*7$Vd zCB#dlS+5afgk_!xo^^3~4dmUTC*<{J)}W?Em*fo;YUBGWyZ@UEXBc47s8f$jA*CiU zK~-A95~jM;hfACL-bdXM-7J$%x4ZOc%EC)s0kdI*|1h;f-!HQhDQFn=Z30B5CPmlW z`2mwp*f3_Lqr~~!%`MJy94wqGq_9ZB$b;bViJBEQVjbeC;{VnQ?@8g{cJ@q!)6ej4 zpa8&QYOr_Y%;Uq3br^R{f2}=3H0lw$rP;ndN*4Mo5)S-L&*R5nAuyXr zn$-hD@j*6*z~aO0F7AS5V1cKny@J6c8sBf+zh}>e^e>oV4FgaY%R6mz7Od65)Q~Gz zMnKD;;;8spI>Mzs{9$6O&*8(am<&Jau?&`>O}i#s((_fxYU$=z*0(25G^AHE%R#5)(|#oZoiP*VhO@PMXO z>iu8L(OPZ>(SRtG(bWEn78e#7g!M)px1Fu(M+YkLOq(z9R;FD_0C$sGuyCmlE#&nE zx=ixUJ+v79X60EvlOf2uwGlu?=i0%;A{xS#DEu5z+)9z&M{T75!`j+9pztmAG1O?Q zZJ0D}+(=~Z-tB`4do&%}uXzUQOQ8j{OZ@@LjS;bL#TyJ;8BT3;4`1mHwr*_UsI*9C zSP@2T`Q2^|fvl_Ie@v*}>TYQjd)hsp^lxJ4co2Mf3hLhvQm1@WW^p1}^h z2$@oUeJ78>Jm-EzDF{$OWst6|0QL69f{Q5I^?b_pe>Q0cd|pNseH0%vQRVCF8}BE* z;x>QWu>s=#5%eZG*$PfB0(5GdaaAC6Vo_1;(IT*@=4LA)Qd?);4}L*|(3FiA8B4!@ zRoL1dkOFdQmIRG&F3x^GlF5H%gedIyTji`_U%iQZFhT)x??71|7dM+>2l4qs<|c01 zj#IC96zuEx;F=n0j7%^2FU1=7MkCoxcsc)L^NY|lxMmFb?|Lursu#)<)}m3%id*5g@smj8En~#ITjQDOVXf?$>;z9R~j2^3OQxqI`Wh zu3SR{RVL#(vt{qZR20bk8C%V}Ek(ps?d2N+wBzY5@JCc|9;$3p(X3gsWGO#@w@*&n zwR`t{t3?)a5+&{J#8Y?Ts<)ndPX35&f9ipxpAUo_IPfin-Fw=!aMXr0SKB|d+5GK*0Uc=0 zhBB`62V*2VIo!3c zAOH}~Do2su(imly`h!yHCA*FHj@T6)-3ZMj2D5EPcI83=ju{dxOd_5Fy5-=LC+#^h zWM)n6FM)x5Db<@^<|Vb$?ZX!A{9V-WuRM03oBzu$u@2B7l`5ldVAQUnFLjCS8r%Nt z3b)GbjJmvwh)qyI2qa4wIOl|okzw-0b(&KXGcZ2O+G@ZE)xkp5fm_~C`*g1te4_d{ z(I3R_Vs(2CJ}auHE(5O|u+FL(3MtFbv>tTIW7(n_>KrFsMTyDUqTfW09d^{F!LxmL zS_pWBBBAP+eK!-@b?!wbl2hS?qchvUYXM<$_Rsa6sqf#vAMA)|`=+k{k(qx1#?q8J z-M!Tk%SKpC%s2S*Xz|w4Bbs#VsLieu5f#DR?2NI6A-o9L}8l zL}v(t4MUQ#{T3gu%0Ufwqw8MQ5P5Ef;e%a!i}xxbtFSQrY{n7#ln|ipUy~i|>r zll`bk;A=foQ8z2hRub9(+fC0cjxtj-u0`6jgthjaY;5#-$1%S8%OP)ki*nh?)SNIv z>Y@orbOwovU~`qC}nlff32SYvJN?_YA% zN)1^?L`DwAs0QDdy)BM>8Q=l zJJ8QB>91-!K;SiJ-I7_w0rSF!n3!;?Ep@~PlX6u}4ejAWKk&!-?jV~7yZ(~;n|=#s+MWlCm?|uHrvoq~ zW?bZ+XHn0FdoBly=v46GY0zohb{X5YJ)>1@C13IXVAA-UNQzd`)VHY`dK zhYwZfbce2o9q}TMgpx9tU3)bCZ$Jzk6xnBiN;o~C&bhjxqT))6m(_v&X<))Yr?F*u zxDGH`!eLU~=2wkl$*L&;5uuH$Tzi)`$Rhl+YthRkJttjGsiiPuBfj>(Zh3U{m_*P0 z0n>n=f%!PW?5yf|%LDmHN&bZF90LZmL z?5LZX!83|Vxv~Dk&pwrd=ucJTaWnv*ziZu`q2q#jl*#Qshe?$laj>)VZz$E14r7t% zd9vUN0aY8j8ebS%ScIrS+!l`@i`AlBwFUeO)FxtILO9m^6P zIGll?alxExaJfpwph_bL1j|Lj%DG0SL~d|{DUp)GdN4;vUjH+KHHw~r)=E;U8w@LQ zY8}u;XXr+s3OCrqAMlb!LQ^)_xv7FWJoGy`Ap6TpmK@U)0Wrp|9!Pr{_SQQFEO+3I z=6!fO&mXysW7osTE3lGm{O_hU106Vj^C4^W_H3{umw$aR+is|5IQ@?eMjPlmx!!k* z28>5peO{et(GxF$msj2Ki8Afq-xxDe!)}sINZ3Z2oUHm!OR-W?Nb99FU$C%Bj%iW> zEFEG}=TmltRn}zs5DWaj8FhH8$Bc_KVYg@JO=g!0r)6focbNsFzXvoACU`IdSHscU z3gs2iKiS;IL0EMM6Rsq_8)OXIV&t1@*$m`8dxFZZj8uNnx zG3ONO4Mw!4%qPfIZH41|TUTesu8gaW6W7~-i~p2DO8yT}RO^kG>YT_tEpr(9q(xK1 zr-Md*o#i`i+W0tM`Uz3p(bIC0DWX}2ES~liG*GI2HwQZ2pck=kwFha~GS0|Aa@Ut$ zD+F_pnT^fOy|wQ3^z`PupJ`SYx#`r7WM`=OjxhUKFO$+<%iOP)30XzG5XltFjh8bYOnQhYo7S`^3|M!bE-+iN3`~04$dSO9>P5meM6FOySxlq+iVY-9DV*e2_vjW5UEr(;Cu%VqLlpU)G9>HYw#7jR!zu z! zs-M-qv(d)@BMkNM*nV`pg)5COq`tkt-;_S3Y7Zl*5NvGDw(Y;4%dJ+JnnYht<9K5c z2!fjqL{>Av>5j31K_gRb&Wl(99%TlT3F3O5$Mnjq7%Po_%RjYqb93Y6*aMy{oT$+U z>1n8PD_IeVd3wlEREhvJYNdVzgzKR~Q>sJ{gAjF~kU^m%@#c*0kC(e)S4ev-@%YZ978l7wwv2g(D&OcmT5?=!k=z1NsAWAJ?>?6lY6AgL&D z9h%ohGQ>){WAY@p8NjL7(z5H@?S}U~HlcfuW3RPR=cqb|W(nOJl$n;M#6~}=OUoy2 ze*(^P9RMW!qOciuP$_uA5=;FIpOR?W%f}WB2Qruo!1m27*CDQwGCDfZxs$>asp>lV zXg%lfVFtjw!4tY)WRCRq_dlrihYzb)<_DAlw3)_S5&h(>WB<5GLUNSdae`HB+a7(} zvv+T?6&?zB?!2?lJgpuiQEB|%2*f!N-S4@a zPXaU9N?h1-3Z9}FXiV@i!{9#FB=~B6_i^8Td*Ew(2Td{5^Nh?%UJ9Uk>B)SBsn^Vz z&Cwz7e|&vc0nuq`P%HS(95}OvV2iyZia38nF1$DAd)Ivixt1S391!=nBA77U+8P`1>#KL>_?5{XcVE*@$#(@WC=jZ>k zE>EvrAEinGXZ`fFKMaC`+huKQD?V^d4T<$TnbN9ND`eh7K!0s;6|J9bk}TFmDn9ys z*Gp4+&QiAlM)hsLW4u>-Y!TfEI4r%sgp<2)LXF)%V>}0lwQkdf_dHyX_S(~;r7qI5 z)325cA3mH8d!KmFRidU4p#f{|(xoo10*4O0c^%)IK#V%91UwO2w{4SmaJ+LGYX`NRs?#DR=ZyX0DwDPA)z`t^#FfzKRo5fjDofJQC&AbnV)(1Fver58(n}?&?joWb?@Hc(b2b- z7QqXJDz)It@_mS)40TRi_V|UbsWy!F+iYJ=gUv$>U#RV1`LpUvU@5$~^pLOCU2$3f z<_6H2ef4T{&f{#5FOIih2(mWs#qA^DVH zr=GmBYh`FC20E~mY#7BWvF{I$4*T$VS%=8iZ{BcakO;kW9bSDdgzjV0;*_+sQQM!s z0Q&_V$2O!%41`i8sT?m|cO-O^*2$%-sF8T~{nhwyetnl@EJi^d4cz!6OOihvJP|BJO^tqwt2DTUOyrjH)`H-7>(;HH{djDV9Q2{5aeTqkuew=T znMPkm&h9e#;*?iy0|idbe@trpM&CFwc&ijMi;w)6{PX*X)-6Q$id{Co3L7Ff<Z-Tm$I$e1PaVpH1E~8WCB7~D7ARl3lrK`1$JAtYuCNDPp!V~*m0mD zm@C<6@#%BN3Bj8VTDQ%=e^6aZF_x&Z5ME=L_UqktDcO{(jdNd)Nj*+)&jkPvXr!^L z-;$Mrd?0~J@JR0(s!Th4_$&)0&W9{rO{zQ7v)o z*s{{mP!8-jLr+{DM?*7w=VLI2@QjQltAF1#>DPCiLX|R)FgFXXW2#L?lct93w@NL^ z1ohvIiYoB&r7-%o&0CjCe>x+^m!F2JZBCl&*6rILLFi4*aMV}<4jCz)3TI%d;A#c3227aPG~I$ugkO^pKKd|v%>Ob;jl@YRdR2sUooBtkr-HWKCN zw|gjGS?Fh)ELZzqL3!r1)BC3vnlWZ>%j)mu`1!2?m^roV-Pc*=nNm{pYsh+!WLx~7OT($R${h5+Dwv0o;O)UpSod4i-d(|Tiwt2V>NORkt>MK z6RMmOt0H(JB>Bkiaa-Hu+Ok4R?&%hzG$VFK03SRnE!YWwy~mb)FQye!ZM->lbw-53 ztmBRgM9bR^2698#G-+~a4s5(h=s>s$+oZv9iEKw%rKLO7GyM8`QS@UD%+U%{1w;3Z zD@oo|hIUWJ0c1fNqoeory8lKFtd@4wIOU@0x+z|pghy0sD*`OqPo5kLJTp2V3YN0YBUJx-LV?Fm)-_+z$=>=b*k8BBax zXKQV}Vnk=lF{edJ%LrER;Pvh+rKRm?+qfQx9Vi^F$Wr_})z#qTm^m;lZ&AuvFMB%| zgYjgra*+Yq-*-#~)l;gb_Z#!hQy3$a;tv8$LT;PZ9RQ4@$#^J0PC!6GgNJrDY6&rl zk$04Sca0lN^T+aGp|lcG9Q@AwmRg*h^9XsN!gkNVY@VW8`+dKz==8d1UsJ7Bm zl)X_M1~kzS43X~J%xv#fI~HdIw1tEZ2wO`5Tr1j8`lbtDxrb;%Ufer6O#bzgk z>0CLQq6kN5$^mD0cLi;lySw}JWdDucj#(Gu3`r%Ga zD`8VG1IAaleLDC%!!sy6eEn~~dVa!4v!wjlD#FxXwWJPyPWS~B(0lsy2-u^KBX5t% z2zdT=s1i-$Wu4S&!lKvx-OFIJ4s~%SFGC|=EZ|OrZ9UOV^3ABkX_cW~GX zu`#%Fv?(OjzS{u(=g2UTS0mbDQ0M5=x8624^Yr!h4#q!I|JCcQ=j%lz2d!d5ePc75%nv6Jc$G(M})H}_{%5Bw{eR9nnG0HhSf(Q8XqH<1ykDt zY}$pAIuPe0i3bcFc;9{~0kG5Gxav!D&(kgD9K2MUk4nUa@ng)P7(O92TpRu*qYGHg zULJS#wG3E0q5DwCB{kY({AE|>FsfGcK1j@O*1s=`5Hh`V8At@xi}=q(3C|-`IjE$I zyvxS*O%;kPD6V=9UHF$8$xV^e8sMrUauJ?y72}G9MN`_!hWC@h$Aq1Nbh=&tzFbUE zJT$n-CCBHP(*R0-z?X~6{<;;t9U}UM7nz2AFe2l#XU~3lUtxb)|8xuu-#7lifqg*I zqURQt1Odqd8g9x67t`EqZ`8lIyo+BwYRs+`!G(Ls#32fm>$?X;0fRh*T97>)s4*DP zfH$roRO04zL2KCp(Q=L}nWRN^`S-mqA-aOP?LB3RwxuP9L66ex+_^J_J0v(*^Xk>B z9FE?JyDly>B(@^#K$e63J(7C72QR(EfncV*iAzZWb#@2Uv=KoAE=vIqo)x8bfa$j; zlS!Oju-4}ha*JC0>dx;CunJjHwjw0ojY{WEy^1Y=EH84&?4ftzFw(CQitrx730SWI|9x9s%o%Y$~3En@lBek;Q!J>QzVF zUvlC%Le_3T(1OqAOCEwqfcR{3=>ng+eyFAciFSkeKO!hSHTN+!iQujr`&2IQ$FZj; z-tv(n-aSJe6?L+=A78QE@Jvcl?PDa^elKs~(vGW5JyPphy=$7UuhZ@jYygQt4lcX5 z@xjaxlPv%6D*T9?2xnFJ^rv*bLyu&>#0yYo?&f*GphM)+Q2yEyxUj|HBKJQB2vWdK zVG%^nMvky3BWK<{VTd;^8?Q$ihABJ}ZD7uZjT|Y{xMZcsm4rZ$bP}=X0mJx!BcU)v zuF+L4HJzO|^C+@iD*%HKo<<~;UKmrvrv;m^NKh;=fgC~()6g6t>ukq@8ce?r9hC+= z!(j#@49TY5r@sj$8dJ6$JeBTfM&#zQ?U5bZcq_O$6K<3kQD~YaMoG|9f~tj>+1h_; zF9|wBJH)iFNz!-@3Pfvk4L2efm9)&}9UR)xG@b)smHeg22qBP&SZ99zw3Ojk z>;U*`P3SOfhyWLJ3?=Rd;v1`wA3Q=@AtsPl2>dW!XG#nyK}l;VIW0fG%Udq)Te`wl z2*5;JDpdht!#;FZSb&6$B=}g84r9@ULb{60o2}tNMMVp8yu`1M9G|U}$wJbH$W>rs z1;_OA_m2cx-^<@ja7#A&BRP3AsDLo@h`AhT^1NrvXi7IJQ+z=|OCDhBUcFW^nl^9V zd=Ib^n<98<=!*FGPW(>X)ala|xR3=^xO1nq{IrctFlDj0C;#Tx(a-kg$bedWDVR(h zVSG^Dm9tyNicSgg%h_Gr2J&5{J?E!IuSq4^M@^6@FQ6%^3exouKC~pB(f3Q<5IVz_ z!ytuY8FWM?i<*=d_MSR5j1GDDpwNtr@2NUoK0b})6B-$*CQX{8+u==hwKuOA)`H?1 zwryLRtJkjK7}TVsO2ML$a3uI!25-(`Xe`?Q5uHQQ)9uiy@=77>Q?bmv0E8!6Mo9V~ zn0hcm8f1bfDRdC3Gt@IhpTn9@rkTiWxb&iddG<_!9zt*jw8QeZ@Ds6nJ|sa5J_UI& zy@$A4**pBMa7;+unAlOnmM=t^S9eksyCOXN;+Yh$xNNf@Vr7x*7rMKEe;kwAdWsgT@>Vp{4u#Y5s{&@ypkSK+5+ zxA+!q$-DBL%t1k0PPkN)cOFS?a{8E1hht2%8Ek$q#v*rfx$9&a#3+y!;wrp7i z4-a^(3E7dwkbreA0?hU?*w}dxP}$H$SqvDn^GL}{jvdPa?T%u4m9PYEoS?>SMkF8$alzKqgMVH1Spl{NS9vuRIG-}_F7Gf+w>LbJvyBtB5+VRd7 zjq}c*o9dcS#-kP%Pha^gKR&YM$|TiD*Q`X{?_4$acRkfyPp^mF@ow!sl2#6ncV4}9 zYio;+%ZdsmuBwB9p`ojvBC%|^p<^pObJWJGz?N0I=B|ULu&WH$-ayL;e;0p68y31y#BYuUt*wCh^X4!>Oede_E + + + + + + Intent AIntent BIntent CIntent DIntent EIntent F0.1 BTC1000 XTZGive 2.3k ADAGive max 3.5k EURWant min 3k USD1.3 ETHGive max 15K DOGEWant min 3 DOTGive max 0.20 BNBCrafted transaction - transfers: - A -- 0.1 BTC --> B - B -- 1k XTZ --> C - C -- 2.3k ADA --> D - D -- 3.3k EUR --> G - G -- 3.9 USD --> A- Intent A, B, C, D, GIntent E1.3 ETHGive max 15K DOGEIntent BIntent FWant min 3 DOTGive max 0.20 BNBWant min 0.09 BTC \ No newline at end of file diff --git a/documentation/dev/src/explore/design/intent_gossip/matchmaker_process.excalidraw b/documentation/dev/src/explore/design/intent_gossip/matchmaker_process.excalidraw new file mode 100644 index 0000000000..dcb48040f9 --- /dev/null +++ b/documentation/dev/src/explore/design/intent_gossip/matchmaker_process.excalidraw @@ -0,0 +1,1883 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "https://excalidraw.com", + "elements": [ + { + "type": "text", + "version": 250, + "versionNonce": 477786094, + "isDeleted": false, + "id": "-fWwS7rt9LYqEFNzDaOFL", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1334.071428571429, + "y": 1108.4285714285713, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 115, + "height": 70, + "seed": 1676859603, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "yBtnqGclgLrHk5_Ql7cuO" + ], + "fontSize": 28, + "fontFamily": 3, + "text": "send_tx\n(data)", + "baseline": 63, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "ellipse", + "version": 178, + "versionNonce": 1385647602, + "isDeleted": false, + "id": "-AUKbp8i4Y0O6x-LjVldd", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 297, + "y": 132, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 1587.8571428571427, + "height": 1546, + "seed": 2049426387, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [] + }, + { + "type": "text", + "version": 102, + "versionNonce": 1069695534, + "isDeleted": false, + "id": "8SDYqin0B7kut0s8YSY5Z", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 870, + "y": 178, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 355, + "height": 46, + "seed": 1891888509, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 36, + "fontFamily": 1, + "text": "Matchmaker process", + "baseline": 32, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 666, + "versionNonce": 1176289202, + "isDeleted": false, + "id": "9rcJtdHxvs9duQVcmN6pg", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1018.4827638040854, + "y": -498.6392023935267, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 221.76726681910736, + "height": 784.1206838750081, + "seed": 395336627, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "u-ME94nrrlTlc6E3cTspG", + "focus": 0.5186114360714434, + "gap": 14.860797606473284 + }, + "endBinding": { + "elementId": "20SyJveLAUi7KoBBp_oDS", + "focus": 0.14947349178376995, + "gap": 4.518518518518533 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -221.76726681910736, + 784.1206838750081 + ] + ] + }, + { + "type": "rectangle", + "version": 296, + "versionNonce": 1188416622, + "isDeleted": false, + "id": "20SyJveLAUi7KoBBp_oDS", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 670, + "y": 290, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 201, + "height": 61, + "seed": 1788635837, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "9rcJtdHxvs9duQVcmN6pg", + "EV9g4uNJem7yTF0HdehQG", + "coek_IDR9PRlSqn_xuBfH" + ] + }, + { + "type": "text", + "version": 126, + "versionNonce": 328071538, + "isDeleted": false, + "id": "u-ME94nrrlTlc6E3cTspG", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 983, + "y": -549.5, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 197, + "height": 36, + "seed": 1618827037, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "9rcJtdHxvs9duQVcmN6pg", + "MQZgoJ0QZeyWyyOlwsTJ7", + "wX2vQSP79rzqU32fALRHb" + ], + "fontSize": 28, + "fontFamily": 1, + "text": "gossip mempool", + "baseline": 25, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 194, + "versionNonce": 796790446, + "isDeleted": false, + "id": "CcRIOeocsp5wp09s5Cald", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 683, + "y": 298.5, + "strokeColor": "#d9480f", + "backgroundColor": "transparent", + "width": 176, + "height": 36, + "seed": 1367059613, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 28, + "fontFamily": 1, + "text": "Filter_1.wasm", + "baseline": 25, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 343, + "versionNonce": 439483186, + "isDeleted": false, + "id": "q87Hkm0Sw3bVVd3Wg6HND", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 996.5, + "y": 276.5, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 201, + "height": 61, + "seed": 903521971, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "9rcJtdHxvs9duQVcmN6pg", + "wX2vQSP79rzqU32fALRHb" + ] + }, + { + "type": "rectangle", + "version": 386, + "versionNonce": 1449396462, + "isDeleted": false, + "id": "pF6B18evRJlwUi2JcmQxA", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1352.5, + "y": 275.5, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 201, + "height": 61, + "seed": 2098314525, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "9rcJtdHxvs9duQVcmN6pg", + "MQZgoJ0QZeyWyyOlwsTJ7", + "quXd_TqwuN2CmoyI_vXkX", + "tQlObdUcJ4e-eO1KrOatP", + "AFE8t2QPl0MtqNC64Ktcv" + ] + }, + { + "type": "text", + "version": 268, + "versionNonce": 946849010, + "isDeleted": false, + "id": "dLtlrcEEya8xcYfwZhZia", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1365, + "y": 287, + "strokeColor": "#d9480f", + "backgroundColor": "transparent", + "width": 185, + "height": 36, + "seed": 2000393875, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "quXd_TqwuN2CmoyI_vXkX" + ], + "fontSize": 28, + "fontFamily": 1, + "text": "Filter_n.wasm", + "baseline": 25, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 160, + "versionNonce": 454081326, + "isDeleted": false, + "id": "B5qXjcTYw3uMpWIOVJW6r", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1077.5, + "y": 289, + "strokeColor": "#d9480f", + "backgroundColor": "transparent", + "width": 23, + "height": 36, + "seed": 1953378803, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 28, + "fontFamily": 1, + "text": "...", + "baseline": 25, + "textAlign": "center", + "verticalAlign": "middle" + }, + { + "type": "arrow", + "version": 452, + "versionNonce": 1741575858, + "isDeleted": false, + "id": "MQZgoJ0QZeyWyyOlwsTJ7", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1154.9140472935462, + "y": -501.5, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 207.63095361581804, + "height": 762.5, + "seed": 52989821, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "u-ME94nrrlTlc6E3cTspG", + "focus": -0.63125, + "gap": 12 + }, + "endBinding": { + "elementId": "pF6B18evRJlwUi2JcmQxA", + "focus": -0.718727980147667, + "gap": 14.5 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 207.63095361581804, + 762.5 + ] + ] + }, + { + "type": "arrow", + "version": 398, + "versionNonce": 65873262, + "isDeleted": false, + "id": "wX2vQSP79rzqU32fALRHb", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1089.7329110152689, + "y": -503.5, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 0.6477652019841571, + "height": 777.5, + "seed": 858158013, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "u-ME94nrrlTlc6E3cTspG", + "focus": -0.08333333333333333, + "gap": 10 + }, + "endBinding": { + "elementId": "q87Hkm0Sw3bVVd3Wg6HND", + "focus": -0.06557377049180328, + "gap": 2.5 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 0.6477652019841571, + 777.5 + ] + ] + }, + { + "type": "rectangle", + "version": 251, + "versionNonce": 1492430962, + "isDeleted": false, + "id": "Qby63QOrxFMccQD3d2c92", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 584.4285714285714, + "y": 892.8571428571428, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 305, + "height": 129.8571428571429, + "seed": 906153683, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "EV9g4uNJem7yTF0HdehQG", + "yBtnqGclgLrHk5_Ql7cuO", + "Wb12KbhuRcEHH5IclCfjz" + ] + }, + { + "type": "text", + "version": 175, + "versionNonce": 1648510894, + "isDeleted": false, + "id": "EU8SONkJD9g8GszHushxg", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 613.4285714285714, + "y": 905.3571428571428, + "strokeColor": "#d9480f", + "backgroundColor": "transparent", + "width": 264, + "height": 34, + "seed": 711796221, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 28, + "fontFamily": 2, + "text": "matchmaker_1.wasm", + "baseline": 24, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 882, + "versionNonce": 262787634, + "isDeleted": false, + "id": "EV9g4uNJem7yTF0HdehQG", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 739.6354774988769, + "y": 363.8196459125622, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 2.694775060113102, + "height": 59.792753760100425, + "seed": 589900403, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "20SyJveLAUi7KoBBp_oDS", + "focus": 0.32213015232123915, + "gap": 12.81964591256218 + }, + "endBinding": { + "elementId": "NUXnLdbMG_fQSEDQtu2Ik", + "focus": -0.4632754266251567, + "gap": 9.81617175590884 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 2.694775060113102, + 59.792753760100425 + ] + ] + }, + { + "type": "rectangle", + "version": 313, + "versionNonce": 1983455726, + "isDeleted": false, + "id": "02X_kZ6WrMz4xBI8cgnGg", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1349.9285714285716, + "y": 894.7857142857143, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 305, + "height": 148.42857142857147, + "seed": 1614285181, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "EV9g4uNJem7yTF0HdehQG", + "quXd_TqwuN2CmoyI_vXkX", + "Q1Ij1-SrX5G6sFDtWRjZD" + ] + }, + { + "type": "text", + "version": 233, + "versionNonce": 2127870962, + "isDeleted": false, + "id": "zwDG2KxyuTcJmWoH5zXjV", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1378.9285714285716, + "y": 907.2857142857143, + "strokeColor": "#d9480f", + "backgroundColor": "transparent", + "width": 264, + "height": 34, + "seed": 1715804371, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 28, + "fontFamily": 2, + "text": "matchmaker_n.wasm", + "baseline": 24, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 260, + "versionNonce": 612134322, + "isDeleted": false, + "id": "qFSA3c0L_Ds7pnNR9vyEk", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 988.4285714285716, + "y": 1605.7142857142858, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 221.00000000000006, + "height": 55, + "seed": 1486037725, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "KdQIFFwY0Q-VCyIjJLjqc", + "RuPyouXclWRd1e2Onhfm4", + "tqejUpWw7UdRQgeKJx1Qs", + "jfK56lesWGBAsc29YGxXx" + ] + }, + { + "type": "text", + "version": 175, + "versionNonce": 1108344430, + "isDeleted": false, + "id": "CWmX8zj_7xHE5WtGuwcr9", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1025.4285714285716, + "y": 1615.2142857142858, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 159, + "height": 36, + "seed": 1565496083, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 28, + "fontFamily": 1, + "text": "Tx Channel", + "baseline": 25, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 173, + "versionNonce": 1909000873, + "isDeleted": false, + "id": "NUXnLdbMG_fQSEDQtu2Ik", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 717.9285714285712, + "y": 433.42857142857144, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 97, + "height": 36, + "seed": 335380755, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "EV9g4uNJem7yTF0HdehQG", + "Wb12KbhuRcEHH5IclCfjz", + "AzA1FaOgPEa4cFOKIb_XI" + ], + "fontSize": 28, + "fontFamily": 1, + "text": "is valid", + "baseline": 25, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 323, + "versionNonce": 1795041586, + "isDeleted": false, + "id": "QmaxQnRFTdOUnNNcMPy7X", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 524.4999999999995, + "y": 1261.9285714285713, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 537.8571428571428, + "height": 67, + "seed": 1680157853, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "EV9g4uNJem7yTF0HdehQG", + "RuPyouXclWRd1e2Onhfm4", + "yBtnqGclgLrHk5_Ql7cuO", + "tqejUpWw7UdRQgeKJx1Qs" + ] + }, + { + "type": "text", + "version": 333, + "versionNonce": 1782168302, + "isDeleted": false, + "id": "NUM8zAtLsxNcBlfW4Jj7Q", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 541.4999999999995, + "y": 1278.4285714285713, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 492, + "height": 35, + "seed": 1032271795, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "yBtnqGclgLrHk5_Ql7cuO" + ], + "fontSize": 28, + "fontFamily": 3, + "text": "tx_wrapper(data:Vec) -> Tx", + "baseline": 28, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 836, + "versionNonce": 998650610, + "isDeleted": false, + "id": "yBtnqGclgLrHk5_Ql7cuO", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 745.9085294063941, + "y": 1042.550408585807, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 0.5420749370830436, + "height": 221.1355590894077, + "seed": 1278179069, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "Qby63QOrxFMccQD3d2c92", + "focus": -0.05746246854310238, + "gap": 19.836122871521297 + }, + "endBinding": { + "elementId": "NUM8zAtLsxNcBlfW4Jj7Q", + "focus": -0.16651713537544344, + "gap": 14.742603753356661 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 0.5420749370830436, + 221.1355590894077 + ] + ] + }, + { + "type": "rectangle", + "version": 405, + "versionNonce": 1298148654, + "isDeleted": false, + "id": "ZJr3NtMIhOWJfBQVo_6Fv", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1195.7857142857133, + "y": 1253.6428571428569, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 534.9999999999999, + "height": 67, + "seed": 422192253, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "EV9g4uNJem7yTF0HdehQG", + "yBtnqGclgLrHk5_Ql7cuO", + "KdQIFFwY0Q-VCyIjJLjqc", + "jfK56lesWGBAsc29YGxXx" + ] + }, + { + "type": "text", + "version": 372, + "versionNonce": 1508312242, + "isDeleted": false, + "id": "HCJ2WIORw1W3_N60QE3F-", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1224.7857142857133, + "y": 1266.1428571428569, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 492, + "height": 35, + "seed": 22425043, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "Q1Ij1-SrX5G6sFDtWRjZD" + ], + "fontSize": 28, + "fontFamily": 3, + "text": "tx_wrapper(data:Vec) -> Tx", + "baseline": 28, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 280, + "versionNonce": 533175922, + "isDeleted": false, + "id": "-Bpweaa_yHbmmzQ8Fbx5I", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 786.7142857142856, + "y": 1113.2142857142856, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 115, + "height": 70, + "seed": 194669533, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "yBtnqGclgLrHk5_Ql7cuO" + ], + "fontSize": 28, + "fontFamily": 3, + "text": "send_tx\n(data)", + "baseline": 63, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 170, + "versionNonce": 1490893230, + "isDeleted": false, + "id": "W9zv5kY3tnQEBVzDDO4N6", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 600.1428571428569, + "y": 947.142857142857, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 220, + "height": 72, + "seed": 876039485, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 28, + "fontFamily": 1, + "text": "tries to match\nasset exchange", + "baseline": 61, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 233, + "versionNonce": 435093554, + "isDeleted": false, + "id": "6hdBGIrkrZ5cxGEvo-GL2", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1366.1428571428569, + "y": 957.7142857142857, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 203, + "height": 72, + "seed": 1851337181, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "Q1Ij1-SrX5G6sFDtWRjZD" + ], + "fontSize": 28, + "fontFamily": 1, + "text": "tries to match\nbid for NFT", + "baseline": 61, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 735, + "versionNonce": 10867694, + "isDeleted": false, + "id": "Q1Ij1-SrX5G6sFDtWRjZD", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1475.9494785236807, + "y": 1045.8571428571422, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 0.4267578776036771, + "height": 208.23402295192489, + "seed": 1632703357, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "6hdBGIrkrZ5cxGEvo-GL2", + "focus": -0.08283125635170244, + "gap": 16.14285714285637 + }, + "endBinding": { + "elementId": "HCJ2WIORw1W3_N60QE3F-", + "focus": 0.019007158541393378, + "gap": 12.051691333789677 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -0.4267578776036771, + 208.23402295192489 + ] + ] + }, + { + "type": "text", + "version": 192, + "versionNonce": 444084334, + "isDeleted": false, + "id": "bQlxAsWkDvgA9E8xnJtCS", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 929.2857142857142, + "y": 1434.2857142857142, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 57, + "height": 36, + "seed": 288110269, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 28, + "fontFamily": 1, + "text": "push", + "baseline": 25, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 240, + "versionNonce": 213112178, + "isDeleted": false, + "id": "oCUz5xIu6AGXHaNP05Lz-", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1232.7857142857142, + "y": 1418.2857142857142, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 57, + "height": 36, + "seed": 18964637, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 28, + "fontFamily": 1, + "text": "push", + "baseline": 25, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "diamond", + "version": 171, + "versionNonce": 125953897, + "isDeleted": false, + "id": "K_xcNPiBXE-cXJS9zVPXW", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1359.2857142857142, + "y": 1675.6428571428573, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 530, + "height": 522.8571428571429, + "seed": 1923266557, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [] + }, + { + "type": "text", + "version": 353, + "versionNonce": 394354599, + "isDeleted": false, + "id": "-b3XUoKQR2HkQtxmLNJ8P", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1460.7857142857144, + "y": 1770.2857142857142, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 341, + "height": 340, + "seed": 307253395, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 28, + "fontFamily": 2, + "text": "intent type \n\n\n- Asset Exchange V1,... ,Vn\n\n- NFT Bid V1, ....,Vm\n\n- Proposal tax rate\n\n- ...", + "baseline": 330, + "textAlign": "center", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 321, + "versionNonce": 1380748402, + "isDeleted": false, + "id": "tqejUpWw7UdRQgeKJx1Qs", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 737.3862781852455, + "y": 1337.5000000000002, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 361.4616837725865, + "height": 256, + "seed": 519759858, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "QmaxQnRFTdOUnNNcMPy7X", + "focus": 0.36506890309214235, + "gap": 8.571428571428896 + }, + "endBinding": { + "elementId": "qFSA3c0L_Ds7pnNR9vyEk", + "focus": 0.3749733951794426, + "gap": 12.214285714285552 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 361.4616837725865, + 256 + ] + ] + }, + { + "type": "arrow", + "version": 309, + "versionNonce": 767591918, + "isDeleted": false, + "id": "jfK56lesWGBAsc29YGxXx", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1464.4663097459384, + "y": 1327.5000000000002, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 304.9230901746971, + "height": 266.0000000000002, + "seed": 1704766194, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "ZJr3NtMIhOWJfBQVo_6Fv", + "focus": -0.15595141865445492, + "gap": 6.857142857143344 + }, + "endBinding": { + "elementId": "qFSA3c0L_Ds7pnNR9vyEk", + "focus": 0.10624312511016634, + "gap": 12.214285714285552 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -304.9230901746971, + 266.0000000000002 + ] + ] + }, + { + "type": "diamond", + "version": 308, + "versionNonce": 1298647335, + "isDeleted": false, + "id": "NgADSumoY4-dLkgWi5N4Z", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 897.9285714285716, + "y": 455.1071428571429, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 425, + "height": 386.99999999999994, + "seed": 335028978, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "EV9g4uNJem7yTF0HdehQG", + "AzA1FaOgPEa4cFOKIb_XI" + ] + }, + { + "type": "text", + "version": 217, + "versionNonce": 1471444327, + "isDeleted": false, + "id": "MvTHemdF09EZ6oXZkE1jc", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1018.9285714285716, + "y": 531.1071428571429, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 170, + "height": 46, + "seed": 724442674, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 36, + "fontFamily": 1, + "text": "database", + "baseline": 32, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 757, + "versionNonce": 1293338825, + "isDeleted": false, + "id": "AzA1FaOgPEa4cFOKIb_XI", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 820.3073244931843, + "y": 471.5118365287101, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 108.81143098291295, + "height": 175.18267082955458, + "seed": 360610866, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "NUXnLdbMG_fQSEDQtu2Ik", + "gap": 5.768100034460303, + "focus": -0.6938097555601055 + }, + "endBinding": { + "elementId": "18SWFQMli2cPThvdOpuoo", + "gap": 7.798248129571567, + "focus": -0.6635324351244143 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 108.81143098291295, + 175.18267082955458 + ] + ] + }, + { + "type": "arrow", + "version": 30, + "versionNonce": 1985069938, + "isDeleted": false, + "id": "coek_IDR9PRlSqn_xuBfH", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 668.9285714285716, + "y": 354.1071428571429, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 68, + "height": 62, + "seed": 1014756974, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "20SyJveLAUi7KoBBp_oDS", + "focus": 0.48309968177517726, + "gap": 3.1071428571428896 + }, + "endBinding": { + "elementId": "7tbyhZRSlrMMeTwNPcbDl", + "focus": -0.14152410575427682, + "gap": 6 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -68, + 62 + ] + ] + }, + { + "type": "text", + "version": 27, + "versionNonce": 590603438, + "isDeleted": false, + "id": "7tbyhZRSlrMMeTwNPcbDl", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 540.9285714285716, + "y": 422.1071428571429, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 74, + "height": 46, + "seed": 1767538158, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "coek_IDR9PRlSqn_xuBfH" + ], + "fontSize": 36, + "fontFamily": 1, + "text": "drop", + "baseline": 32, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 32, + "versionNonce": 1173128498, + "isDeleted": false, + "id": "Wb12KbhuRcEHH5IclCfjz", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 774.9285714285716, + "y": 474.1071428571429, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 8, + "height": 406, + "seed": 939628210, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "NUXnLdbMG_fQSEDQtu2Ik", + "focus": -0.1831322697972629, + "gap": 4.678571428571445 + }, + "endBinding": { + "elementId": "Qby63QOrxFMccQD3d2c92", + "focus": 0.1851313721138299, + "gap": 12.749999999999886 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -8, + 406 + ] + ] + }, + { + "type": "text", + "version": 13, + "versionNonce": 1089412846, + "isDeleted": false, + "id": "jEi03IUAXxK1nj2Y42B7G", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 800.9285714285716, + "y": 624.1071428571429, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 53, + "height": 46, + "seed": 665121458, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 36, + "fontFamily": 1, + "text": "run", + "baseline": 32, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 26, + "versionNonce": 1615400690, + "isDeleted": false, + "id": "lI0I06cVAOlfanFTA8Ffo", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 612.9285714285716, + "y": 574.1071428571429, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 65, + "height": 46, + "seed": 752657582, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 36, + "fontFamily": 1, + "text": "add", + "baseline": 32, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 976, + "versionNonce": 1550157735, + "isDeleted": false, + "id": "tQlObdUcJ4e-eO1KrOatP", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1459.3837617831516, + "y": 349.05652363076683, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 1.1844667472269066, + "height": 55.55587604189577, + "seed": 1629950318, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "pF6B18evRJlwUi2JcmQxA", + "focus": -0.0721870437439987, + "gap": 12.556523630766833 + }, + "endBinding": { + "elementId": "i-tn-ZhFtCTs742XKlQ71", + "focus": -0.29298735309248414, + "gap": 9.81617175590884 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -1.1844667472269066, + 55.55587604189577 + ] + ] + }, + { + "type": "text", + "version": 209, + "versionNonce": 435052722, + "isDeleted": false, + "id": "i-tn-ZhFtCTs742XKlQ71", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1423.428571428571, + "y": 414.42857142857144, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 97, + "height": 36, + "seed": 1973388402, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "tQlObdUcJ4e-eO1KrOatP", + "ho8uhQaYopUXmE-cOb5Oy", + "-aa5R0cDAH1OKloselZA3" + ], + "fontSize": 28, + "fontFamily": 1, + "text": "is valid", + "baseline": 25, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 801, + "versionNonce": 1290356583, + "isDeleted": false, + "id": "ho8uhQaYopUXmE-cOb5Oy", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1438.8508824450746, + "y": 460.6001539378572, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 160.01481739098062, + "height": 177.3752734807801, + "seed": 652742126, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "i-tn-ZhFtCTs742XKlQ71", + "gap": 10.171582509285766, + "focus": 0.08985472450032943 + }, + "endBinding": { + "elementId": "zBxeCe2V0Axk5Bu9Z7zb_", + "focus": 0.10695154534385387, + "gap": 3.009196397424489 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -160.01481739098062, + 177.3752734807801 + ] + ] + }, + { + "type": "arrow", + "version": 309, + "versionNonce": 214916146, + "isDeleted": false, + "id": "AFE8t2QPl0MtqNC64Ktcv", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1553.1148808294615, + "y": 349.7631332623532, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 91.75609240578751, + "height": 126.39460265738433, + "seed": 635080690, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "pF6B18evRJlwUi2JcmQxA", + "focus": -0.5572753230194984, + "gap": 13.263133262353222 + }, + "endBinding": { + "elementId": "SW06q84zYJLMiyPVkQ1xY", + "focus": 0.049091461638458705, + "gap": 8.949406937405342 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 91.75609240578751, + 126.39460265738433 + ] + ] + }, + { + "type": "text", + "version": 129, + "versionNonce": 1871263726, + "isDeleted": false, + "id": "SW06q84zYJLMiyPVkQ1xY", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1628.4285714285716, + "y": 485.1071428571429, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 74, + "height": 46, + "seed": 650911790, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "AFE8t2QPl0MtqNC64Ktcv" + ], + "fontSize": 36, + "fontFamily": 1, + "text": "drop", + "baseline": 32, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 116, + "versionNonce": 314115570, + "isDeleted": false, + "id": "-aa5R0cDAH1OKloselZA3", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1480.4285714285716, + "y": 455.1071428571429, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 8, + "height": 406, + "seed": 329761202, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "i-tn-ZhFtCTs742XKlQ71", + "focus": -0.18313226979726524, + "gap": 4.678571428571445 + }, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -8, + 406 + ] + ] + }, + { + "type": "text", + "version": 44, + "versionNonce": 1438124590, + "isDeleted": false, + "id": "cl7vkyLcyLB5BfJMeXjQw", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1506.4285714285716, + "y": 605.1071428571429, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 53, + "height": 46, + "seed": 754182766, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 36, + "fontFamily": 1, + "text": "run", + "baseline": 32, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 200, + "versionNonce": 155678642, + "isDeleted": false, + "id": "DF_4GrKBdi7IsRviOYf09", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1306.4285714285716, + "y": 487.1071428571429, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 65, + "height": 46, + "seed": 1013496690, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 36, + "fontFamily": 1, + "text": "add", + "baseline": 32, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "diamond", + "version": 500, + "versionNonce": 1653880585, + "isDeleted": false, + "id": "18SWFQMli2cPThvdOpuoo", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 921.4285714285716, + "y": 614.6071428571429, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 110, + "height": 99.00000000000001, + "seed": 1872566985, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "tQlObdUcJ4e-eO1KrOatP", + "ho8uhQaYopUXmE-cOb5Oy", + "AzA1FaOgPEa4cFOKIb_XI" + ] + }, + { + "id": "bvMzoIc6JDXbDVYJF9Ibg", + "type": "text", + "x": 941.9285714285716, + "y": 654.6071428571429, + "width": 76, + "height": 26, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 1926098473, + "version": 27, + "versionNonce": 1791601191, + "isDeleted": false, + "boundElementIds": null, + "text": "table 1 ", + "fontSize": 20, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "baseline": 18 + }, + { + "id": "r0pIVYRB3ZOSkyTYj3h2g", + "type": "text", + "x": 1212.9285714285716, + "y": 649.1071428571429, + "width": 70, + "height": 26, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 1775138089, + "version": 27, + "versionNonce": 1051956679, + "isDeleted": false, + "boundElementIds": null, + "text": "table n", + "fontSize": 20, + "fontFamily": 1, + "textAlign": "center", + "verticalAlign": "middle", + "baseline": 18 + }, + { + "type": "diamond", + "version": 524, + "versionNonce": 1186891401, + "isDeleted": false, + "id": "zBxeCe2V0Axk5Bu9Z7zb_", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1193.9285714285716, + "y": 615.1071428571429, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 110, + "height": 99.00000000000001, + "seed": 748894505, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "tQlObdUcJ4e-eO1KrOatP", + "ho8uhQaYopUXmE-cOb5Oy", + "AzA1FaOgPEa4cFOKIb_XI" + ] + } + ], + "appState": { + "gridSize": null, + "viewBackgroundColor": "#ffffff" + } +} \ No newline at end of file diff --git a/documentation/dev/src/explore/design/intent_gossip/matchmaker_process.svg b/documentation/dev/src/explore/design/intent_gossip/matchmaker_process.svg new file mode 100644 index 0000000000..226afae23b --- /dev/null +++ b/documentation/dev/src/explore/design/intent_gossip/matchmaker_process.svg @@ -0,0 +1,16 @@ + + + + + + + send_tx(data)Matchmaker processgossip mempoolFilter_1.wasmFilter_n.wasm...matchmaker_1.wasmmatchmaker_n.wasmTx Channelis validtx_wrapper(data:Vec<u8>) -> Txtx_wrapper(data:Vec<u8>) -> Txsend_tx(data)tries to matchasset exchangetries to matchbid for NFTpushpushintent type - Asset Exchange V1,... ,Vn- NFT Bid V1, ....,Vm- Proposal tax rate- ...databasedroprunaddis validdroprunaddtable 1 table n \ No newline at end of file diff --git a/documentation/dev/src/explore/design/intent_gossip/topic.md b/documentation/dev/src/explore/design/intent_gossip/topic.md new file mode 100644 index 0000000000..08a6465d07 --- /dev/null +++ b/documentation/dev/src/explore/design/intent_gossip/topic.md @@ -0,0 +1,11 @@ +# Topic + +A topic is string and an encoding that describes this sub-network. In a topic +all intents use the exact same encoding. That encoding is known by matchmakers +so it can decode them to find matches. Whenever a node subscribes to a new topic +it informs all connected nodes and each of them propagate it. With this it’s +easy to create new topics in the intent gossip network and inform others. + +Other nodes can choose to subscribe to a new topic with the help of a +filter. This filter is defined as a combination of a whitelist, a regex +expression, and a maximum limit. diff --git a/documentation/dev/src/explore/design/ledger.md b/documentation/dev/src/explore/design/ledger.md new file mode 100644 index 0000000000..3c3fd8ce25 --- /dev/null +++ b/documentation/dev/src/explore/design/ledger.md @@ -0,0 +1,80 @@ +# The ledger + +The ledger depends on [Tendermint node](https://github.com/tendermint/tendermint). Running the Anoma node will also initialize and run Tendermint node. Anoma communicates with Tendermint via the ABCI. + +## Overview + +The following diagram illustrates the current boundaries between the async and blocking code. + +![ledger threads](ledger/ledger_threads.svg "ledger threads") +[Diagram on Excalidraw](https://excalidraw.com/#room=952eca1f17ac3c7b5cee,ReXYfqLLleTjVnSQM9zrjw) + +## Threads config + +Configuration for threads usage can be changed via environment variables: + +- `ANOMA_TOKIO_THREADS`: Defaults to 1/2 logical cores +- `ANOMA_RAYON_THREADS`: Defaults to 1/2 logical cores. +- `ANOMA_ROCKSDB_COMPACTION_THREADS`: Defauls to 1/4 logical core. RocksDB also uses 1 more background thread for flushing. + +## Tendermint ABCI + +We are using the Tendermint state-machine replication engine via ABCI. It provides many useful things, such as a BFT consensus protocol, P2P layer with peer exchange, block sync and mempool layer. + +Useful resources: +- Tendermint ABCI +- Tendermint RPC reference +- Awesome collection + +Rust ABCI implementations: +- + - the future update planned for this crate is to add async support + - longer term the goal is to be able to [seamlessly switch from Go Tendermint + to Rust Tendermint](https://github.com/informalsystems/tendermint-rs/issues/29#issuecomment-672444401) + - includes RPC and light-client libraries +- + - async support +- + - deprecated in favor of informalsystems/tendermint-rs + +### ABCI Integration + +The ledger wraps the Tendermint node inside the Anoma node. The Tendermint node +communicates with the Anoma shell via four layers as illustrated below. + +```mermaid +flowchart LR + C[Client] --- R + subgraph Anoma Node + S((Anoma Shell)) + subgraph Tendermint ABCI + R[RPC] === T{Tendermint} + T --- TC[Consensus] + T --- TM[Mempool] + T --- TQ[Query] + T --- TS[Snapshot] + end + TC --- S + TM --- S + TQ --- S + TS --- S + end +``` + +The *consensus* connection allows the shell to: +- initialize genesis on start-up +- begin a block +- apply a transaction(s) in a block +- end a block +- commit a block + +The *mempool* connection asks the shell to validate transactions before they get +stored in the mempool and broadcasted to peers. The mempool will signify that +the transaction is either new, when it has not been validated before, or to be +re-checked when it has been validated at some previous level. + +The *query* connection is used for: +- the Tendermint node asks the last known state from the shell to determine if it needs to replay any blocks +- relay client queries for some state at a given path to the shell + +The *snapshot* connection is used to serve state sync snapshots for other nodes and/or restore state sync snapshots to a local node being bootstrapped. diff --git a/documentation/dev/src/explore/design/ledger/accounts.md b/documentation/dev/src/explore/design/ledger/accounts.md new file mode 100644 index 0000000000..3b14a086a8 --- /dev/null +++ b/documentation/dev/src/explore/design/ledger/accounts.md @@ -0,0 +1,54 @@ +# Accounts + +[Tracking Issue](https://github.com/anoma/anoma/issues/45) + +--- + +There's only a single account type. Each account is associated with: + +- a unique [transparent address](../../../specs/ledger.html#transparent-addresses) +- a [validity predicate](./vp.md) +- [dynamic storage sub-space](#dynamic-storage-sub-space) + +## Shielded addresses + +Similar to [Zcash Sapling protocol payment addresses and keys (section 3.1)](https://raw.githubusercontent.com/zcash/zips/master/protocol/protocol.pdf), users can generate spending keys for private payments. A shielded payment address, incoming viewing key and full viewing key are derived from a spending key. In a private payment, a shielded payment address is hashed with a diversifier into a diversified transmission key. When a different diversifier function is chosen for different transactions, it prevents the transmission key from being matched across the transactions. + +The encoding of the shielded addresses, spending and viewing keys is not yet decided, but for consistency we'll probably use a the same schema with different prefixes for anything that can use an identifier. + +- TODO consider using a schema similar to the [unified addresses proposed in Zcash](https://github.com/zcash/zips/issues/482), that are designed to unify the payment addresses across different versions by encoding a typecode and the length of the payment address together with it. This may be especially useful for the protocol upgrade system and fractal scaling system. + +## Dynamic storage sub-space + +Each account can have an associated dynamic account state in the storage. This +state may be comprised of keys of the built-in supported types and values of arbitrary user bytes. + +The dynamic storage sub-space could be a unix filesystem-like tree under the +account's address key-space with `read, write, delete, has_key, iter_prefix` +(and maybe a few other convenience functions for hash-maps, hash-sets, optional values, etc.) functions parameterized with the the account's address. + +In addition, the storage sub-space would provide: + +- a public type/trait for storage keys and key segments: + - this should allow to turn types to storage key segments, key segments back to types + - combine key segments into keys + - can be extended with custom types in the code in a transaction +- a public type/trait for storage values: + - values need to implement encoding traits, e.g. `BorshSerialize, BorshDeserialize` + - this allows composition of types as specified for [Borsh](https://borsh.io) + - the Merkle tree hashing function should hash values from the encoded bytes of this trait (the encoded value may be cached, because we update the Merkle tree in-memory before we commit the finalized block to the DB) +- functions to get the size of a key and an encoded value (for storage fees) +- the updates to account storage should be immediately visible to the transaction that performed the updates + - validity predicate modifications have to be handled a little differently - + the old validity predicate should be run to check that the new validity + predicate (and other state changes included in the transaction) is valid + +## Initializing a new account + +A new account can be initialized on-chain with a transaction: + +- anything be written into its storage (initial parameter) +- a validity predicate has to be provided (we can have a default out-of-band) +- at minimum, accounts need to be enumerated on chain, this could be done with an address or a counter + +A newly created account should be validated by all the VPs triggered by the transaction, i.e. it should be included in the set of changed keys passed to each VP. If the VPs are not interested in the newly created account, they can choose to ignore it. diff --git a/documentation/dev/src/explore/design/ledger/epochs.md b/documentation/dev/src/explore/design/ledger/epochs.md new file mode 100644 index 0000000000..daa26f965d --- /dev/null +++ b/documentation/dev/src/explore/design/ledger/epochs.md @@ -0,0 +1,15 @@ +# Epochs + +An epoch is a range of blocks whose length is determined by the [epoch duration protocol parameter](./parameters.md#epoch-duration): minimum epoch duration and minimum number of blocks in an epoch. They are identified by consecutive natural numbers starting at 0. + +We store the current epoch in global storage and the epoch of each block in the block storage. We also store the minimum height and minimum time of a first block in the next epoch in global storage, so that changes to the epoch duration protocol parameter don't affect the current epoch, but rather apply from the following epoch. Note that protocol parameters changes may themselves be delayed. + +The first epoch (ID 0) starts on the genesis block. The next epoch minimum start time is set to the genesis time configured for the chain + minimum duration and the next epoch minimum height is set to the height of the genesis block (typically 1) + minimum number of blocks. + +On each block `BeginBlock` Tendermint call, we check if the current epoch is finished, in which case we move on to the next epoch. An epoch is finished when both the minimum number of blocks and minimum duration of an epoch have been created from the first block of a current epoch. When a new epoch starts, the next epoch minimum height is set to the block's height + minimum number of blocks and minimum start time time is set to block's time from the block header + minimum duration. + +## Predecessor blocks epochs + +We store the epoch ranges of predecessor blocks. This is used for example for to look-up the epoch from an evidence of validators that acted maliciously (which includes block height and block time) for PoS system. For the PoS system, in block at height `h`, we only need to know values from Tendermint `max(h - consensus_params.evidence.max_age_num_blocks, 0)`, which is set to `100000` by default. + +The predecessor epochs are stored in the block storage. We update this structure on every new epoch and trim any epochs that ended more than `max_age_num_blocks` ago. diff --git a/documentation/dev/src/explore/design/ledger/fractal-scaling.md b/documentation/dev/src/explore/design/ledger/fractal-scaling.md new file mode 100644 index 0000000000..d3da491b47 --- /dev/null +++ b/documentation/dev/src/explore/design/ledger/fractal-scaling.md @@ -0,0 +1,5 @@ +# Fractal scaling + +[Tracking Issue](https://github.com/anoma/anoma/issues/41) + +--- diff --git a/documentation/dev/src/explore/design/ledger/front-running.md b/documentation/dev/src/explore/design/ledger/front-running.md new file mode 100644 index 0000000000..67f37bc821 --- /dev/null +++ b/documentation/dev/src/explore/design/ledger/front-running.md @@ -0,0 +1,7 @@ +# Front-running prevention + +[Tracking Issue](https://github.com/anoma/anoma/issues/42) + +--- + +This page should describe how DKG can be integrated for front-running prevention. diff --git a/documentation/dev/src/explore/design/ledger/governance.md b/documentation/dev/src/explore/design/ledger/governance.md new file mode 100644 index 0000000000..d518b99ae8 --- /dev/null +++ b/documentation/dev/src/explore/design/ledger/governance.md @@ -0,0 +1,104 @@ +# Governance + +Anoma introduce a governance mechanism to propose and apply protocol changes with and without the need for an hard fork. Anyone holding some M1T will be able to prosose some changes to which delegators and validator will cast their yay or nay votes. Governance on Anoma supports both signaling and voting mechanism. The difference between the the two, is that the former is needed when the changes require an hard fork. In cases where the chain is not able to produce blocks anymore, Anoma relies an off chain signaling mechanism to agree on a common strategy. + +## Governance & Treasury addresses + +Governance introduce two internal address with their corresponding native vps: +- Governance address, which is in charge of validating on-chain proposals and votes +- Treasury address, which is in charge of holding treasury funds + +Also, it introduces some protocol parameters: +- `min_proposal_fund` +- `max_proposal_code_size` +- `min_proposal_period` +- `max_proposal_content_size` +- `min_proposal_grace_epochs` +- `max_proposal_fund_transfer` + +## On-chain proposals + +On-chain proposals are created under the `governance_address` storage space and, by default, this storage space is initialized with following storage keys: +``` +/$GovernanceAddress/counter: u64 +/$GovernanceAddress/min_proposal_fund: u64 +/$GovernanceAddress/max_proposal_code_size: u64 +/$GovernanceAddress/min_proposal_period: u64 +/$GovernanceAddress/max_proposal_content_size: u64 +/$GovernanceAddress/min_proposal_grace_epochs: u64 +/$GovernanceAddress/max_proposal_fund_transfer: u64 +``` + +In order to create a valid proposal, a transaction need to modify these storage keys: +``` +/$GovernanceAddress/proposal/$id/content : Vec +/$GovernanceAddress/proposal/$id/author : Address +/$GovernanceAddress/proposal/$id/startEpoch: Epoch +/$GovernanceAddress/proposal/$id/endEpoch: Epoch +/$GovernanceAddress/proposal/$id/graceEpoch: Epoch +/$GovernanceAddress/proposal/$id/proposalCode: Option> +/$GovernanceAddress/proposal/$id/funds: u64 +``` + +and follow these rules: +- `$id` must be equal to `counter + 1`. +- `startEpoch` must: + - be grater than `currentEpoch`, where current epoch is the epoch in which the transaction is executed and included in a block + - be a multiple of `min_proposal_period`. +- `endEpoch` must: + - be at least `min_proposal_period` epoch greater than `startEpoch` + - be a multiple of `min_proposal_period` +- `graceEpoch` must: + - be at least `min_grace_epoch` epochs greater than `endEpoch` +- `proposalCode` can be empty and must be a valid transaction with size less than `max_proposal_code_size` kibibytes. +- `funds` must be equal to `min_proposal_fund` and should be moved to the `governance_address`. +- `content` should follow the `Anoma Improvement Proposal schema` and must be less than `max_proposal_content_size` kibibytes. +- `author` must be a valid address on-chain + +A proposal gets accepted if, at least 2/3 of the total voting power (computed at the epoch definied in the `startEpoch` field) vote `yay`. If the proposal is accepted, the locked funds are returned to the address definied in the `proposal_author` field, otherwise are moved to the treasury address. + +The `proposal_code` field can execute arbitrary code in the form of a wasm transaction. If the proposal gets accepted, the code is executed in the first block of the epoch following the `graceEpoch`. + +Proposal can be submitted by any address as long as the above rules are respected. Votes can be casted only by active validators and delegator (at epoch `startEpoch` or less). +Moreover, validator can vote only during the first 2/3 of the voting period (from `startEpoch` and 2/3 of `endEpoch` - `startEpoch`). + +The preferred content template (`Anoma Improvement Proposal schema`) is the following: + +```json +{ + "title": "", + "authors": " ", + "discussions-to": "", + "created": "", + "license": "", + "abstract": "", + "motivation": "", + "details": " - optional field", +} +``` + +In order to vote a proposal, a transaction should modify the following storage key: +``` +/$GovernanceAddress/proposal/$id/vote/$validator_address/$voter_address: ProposalVote +``` + +where ProposalVote is a borsh encoded string containing either `yay` or `nay`, `$validator_address` is the delegation validator address and the `$voter_address` is the address of who is voting. A voter can be cast for each delegation. + +Vote is valid if it follow this rules: +- vote can be sent only by validator or delegators +- validator can vote only during the first 2/3 of the total voting period, delegator can vote for the whole voting period + +The outcome of a proposal is compute at the epoch specific in the `endEpoch` field and executed at `graceEpoch` field (if it contains a non-empty `proposalCode` field). +A proposal is accepted only if more than 2/3 of the voting power vote `yay`. +If a proposal gets accepted, the locked funds will be reimbursed to the author. In case it gets rejected, the locked funds will be moved to treasury. + + +## Off-chain proposal + +In case where its not possibile to run a proposal online (for example, when the chain is halted), an offline mechanism can be used. +The ledger offers the possibility to create and sign proposal which are verified against a specific chain epoch. + + + + diff --git a/documentation/dev/src/explore/design/ledger/ledger_threads.excalidraw b/documentation/dev/src/explore/design/ledger/ledger_threads.excalidraw new file mode 100644 index 0000000000..819629ee55 --- /dev/null +++ b/documentation/dev/src/explore/design/ledger/ledger_threads.excalidraw @@ -0,0 +1,1340 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "https://excalidraw.com", + "elements": [ + { + "type": "text", + "version": 515, + "versionNonce": 1491685727, + "isDeleted": false, + "id": "pd_XdsJCvYgXqlJNpQD8q", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": -310.9761904761901, + "y": 1403.8928571428573, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 911, + "height": 41, + "seed": 1316411295, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "updated": 1638281507048, + "fontSize": 20, + "fontFamily": 2, + "text": "- async main with async sub-processes and ctrl + c handler\n- a dedicated OS thread for RocksDB with a sequential loop over channel with messages from the shell", + "baseline": 36, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "ellipse", + "version": 330, + "versionNonce": 1245219103, + "isDeleted": false, + "id": "VmJo9ip-_Nb-VTVZEw8Kr", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 78.02380952381029, + "y": 1599.3571428571431, + "strokeColor": "#c92a2a", + "backgroundColor": "transparent", + "width": 163, + "height": 146, + "seed": 1806613471, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "Airq4-IKmbHT7aCAW3smZ", + "FRo3C6f6zW4iBBh1q8jaK", + "Aqac15Quru7DFq1J1zJ75", + "zNgYoohABcyhwzIbYb-Lo", + "I713YnaMZhOtFyLmXEF6C", + "ygicdvODl0-UPGPM9mOad", + "VR2l08AG-i7-7iT2EAl8J", + "DrJMvlZMVg268rjjsHD7B", + "Bh3r3CcvEfm1bVHZqeK1a" + ], + "updated": 1638283266585 + }, + { + "type": "text", + "version": 531, + "versionNonce": 1044522961, + "isDeleted": false, + "id": "80Zu63hFbcM_lvy25aCJr", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": -111.92857142857068, + "y": 1656.9523809523816, + "strokeColor": "#c92a2a", + "backgroundColor": "transparent", + "width": 171, + "height": 17, + "seed": 2022880657, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "updated": 1638281507048, + "fontSize": 16, + "fontFamily": 2, + "text": "tokio worker thread pool", + "baseline": 13, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 56, + "versionNonce": 1546762687, + "isDeleted": false, + "id": "0VaGRuLD2GMiFpIQiPqMR", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 141.35714285714357, + "y": 1651.8571428571431, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 43, + "height": 21, + "seed": 390719487, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "wDh62TNPODaTXftcfo__h", + "FRo3C6f6zW4iBBh1q8jaK" + ], + "updated": 1638281507048, + "fontSize": 20, + "fontFamily": 2, + "text": "main", + "baseline": 16, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 178, + "versionNonce": 704264639, + "isDeleted": false, + "id": "kKhMt_jqXFdZVfYVS52F1", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 377.52380952381037, + "y": 1661.857142857143, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 94, + "height": 21, + "seed": 1218960241, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "wDh62TNPODaTXftcfo__h", + "FRo3C6f6zW4iBBh1q8jaK", + "kV0NNyq4-xWHwvvcCPDyL", + "xaHJ5tNfkGKeq6e--abG0", + "I713YnaMZhOtFyLmXEF6C", + "UJiFTL3VeXcVlCGjdLbBU", + "-C7l5eC8Dm4YoMORDUQGW" + ], + "updated": 1638283282004, + "fontSize": 20, + "fontFamily": 2, + "text": "tendermint", + "baseline": 16, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 643, + "versionNonce": 1815876767, + "isDeleted": false, + "id": "p66i1EgzUhPqrGZEygxGo", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 414.35714285714363, + "y": 1726.309523809524, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 47, + "height": 21, + "seed": 1525321759, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "wDh62TNPODaTXftcfo__h", + "FRo3C6f6zW4iBBh1q8jaK", + "kV0NNyq4-xWHwvvcCPDyL", + "xaHJ5tNfkGKeq6e--abG0", + "VR2l08AG-i7-7iT2EAl8J", + "SBaWRnKQiQocECulcwV4k", + "ffbOz_H2zSWPzpThk5_fq" + ], + "updated": 1638283279100, + "fontSize": 20, + "fontFamily": 2, + "text": "ABCI", + "baseline": 16, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 255, + "versionNonce": 1768335409, + "isDeleted": false, + "id": "I713YnaMZhOtFyLmXEF6C", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 244.78461330949256, + "y": 1664.8194537417958, + "strokeColor": "#087f5b", + "backgroundColor": "transparent", + "width": 129.52276720017073, + "height": 15.533897768680845, + "seed": 182273361, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "updated": 1638283271486, + "startBinding": { + "elementId": "VmJo9ip-_Nb-VTVZEw8Kr", + "focus": -0.2411681420070903, + "gap": 4.170455686749136 + }, + "endBinding": { + "elementId": "kKhMt_jqXFdZVfYVS52F1", + "focus": -0.8687447328303558, + "gap": 3.2164290141470815 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 129.52276720017073, + 15.533897768680845 + ] + ] + }, + { + "type": "text", + "version": 235, + "versionNonce": 708334705, + "isDeleted": false, + "id": "01cRBcLYn8LXrrOMiIrB2", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 5.939884494803849, + "x": 199.52380952381043, + "y": 1551.8571428571431, + "strokeColor": "#087f5b", + "backgroundColor": "transparent", + "width": 119, + "height": 21, + "seed": 276902975, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "I713YnaMZhOtFyLmXEF6C", + "DrJMvlZMVg268rjjsHD7B" + ], + "updated": 1638283263136, + "fontSize": 20, + "fontFamily": 2, + "text": "async futures", + "baseline": 16, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 1111, + "versionNonce": 1702628721, + "isDeleted": false, + "id": "VR2l08AG-i7-7iT2EAl8J", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 238.33212400494563, + "y": 1703.1980835703648, + "strokeColor": "#087f5b", + "backgroundColor": "transparent", + "width": 161.19522982640007, + "height": 31.032708996170186, + "seed": 445281073, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "updated": 1638281507048, + "startBinding": { + "elementId": "VmJo9ip-_Nb-VTVZEw8Kr", + "focus": 0.2086363906376382, + "gap": 4.419948117124861 + }, + "endBinding": { + "elementId": "p66i1EgzUhPqrGZEygxGo", + "focus": -0.3195111398796351, + "gap": 14.829789025797936 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 161.19522982640007, + 31.032708996170186 + ] + ] + }, + { + "type": "arrow", + "version": 826, + "versionNonce": 2051497041, + "isDeleted": false, + "id": "DrJMvlZMVg268rjjsHD7B", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 221.51578459884615, + "y": 1610.8100470351471, + "strokeColor": "#087f5b", + "backgroundColor": "transparent", + "width": 127.92316248352705, + "height": 54.95644848553911, + "seed": 2081875217, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "updated": 1638283266585, + "startBinding": { + "elementId": "VmJo9ip-_Nb-VTVZEw8Kr", + "focus": -0.4312502886203979, + "gap": 10.37056842119496 + }, + "endBinding": { + "elementId": "z3DZNuUiMC7mSDWrwEmHF", + "focus": 0.35415681298384605, + "gap": 9.084862441436712 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 127.92316248352705, + -54.95644848553911 + ] + ] + }, + { + "type": "text", + "version": 368, + "versionNonce": 900205887, + "isDeleted": false, + "id": "z3DZNuUiMC7mSDWrwEmHF", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 358.5238095238099, + "y": 1526.8571428571431, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 132, + "height": 21, + "seed": 989469425, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "wDh62TNPODaTXftcfo__h", + "FRo3C6f6zW4iBBh1q8jaK", + "kV0NNyq4-xWHwvvcCPDyL", + "DrJMvlZMVg268rjjsHD7B" + ], + "updated": 1638283266585, + "fontSize": 20, + "fontFamily": 2, + "text": "ctrl + c handler", + "baseline": 16, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 375, + "versionNonce": 1451934303, + "isDeleted": false, + "id": "xle96qVuOvkE6VADHzlni", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": -63.54761904761864, + "y": 2002.3333333333335, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 281, + "height": 21, + "seed": 494799007, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "xX0Sjp4d5xmMxZueHitLy", + "ygicdvODl0-UPGPM9mOad", + "iGXEcqMfe32IhFFoybdOg", + "SBaWRnKQiQocECulcwV4k", + "cKyMJJsCmpWKOTWNSqDMM", + "be-hOvlUqvUr4DyAypVOA" + ], + "updated": 1638281507048, + "fontSize": 20, + "fontFamily": 2, + "text": "shell loop over channel receiver", + "baseline": 16, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 667, + "versionNonce": 1044403985, + "isDeleted": false, + "id": "ygicdvODl0-UPGPM9mOad", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 114.0925803512514, + "y": 1739.752193937748, + "strokeColor": "#c92a2a", + "backgroundColor": "transparent", + "width": 133.51443718807064, + "height": 247.74780606225272, + "seed": 129733841, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "updated": 1638281507048, + "startBinding": { + "elementId": "VmJo9ip-_Nb-VTVZEw8Kr", + "focus": 0.10559015514879938, + "gap": 5.893085487515066 + }, + "endBinding": { + "elementId": "xle96qVuOvkE6VADHzlni", + "focus": -0.7527898136437603, + "gap": 14.833333333332803 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -133.51443718807064, + 247.74780606225272 + ] + ] + }, + { + "type": "text", + "version": 558, + "versionNonce": 98639487, + "isDeleted": false, + "id": "ZGLhGr9pwJBpxl80_p2qt", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 5.262346732480442, + "x": -35.254492783874916, + "y": 1807.9987063687224, + "strokeColor": "#c92a2a", + "backgroundColor": "transparent", + "width": 154, + "height": 21, + "seed": 319921343, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "ygicdvODl0-UPGPM9mOad" + ], + "updated": 1638281507048, + "fontSize": 20, + "fontFamily": 2, + "text": "spawn OS thread", + "baseline": 16, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 1621, + "versionNonce": 240580255, + "isDeleted": false, + "id": "SBaWRnKQiQocECulcwV4k", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 409.6368150642577, + "y": 1752.9709154297034, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 298.640755194554, + "height": 237.6580025907415, + "seed": 358460639, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "updated": 1638281507048, + "startBinding": { + "elementId": "p66i1EgzUhPqrGZEygxGo", + "focus": 0.21883904748132793, + "gap": 7.3710819795555835 + }, + "endBinding": { + "elementId": "xle96qVuOvkE6VADHzlni", + "focus": 0.039960091713429936, + "gap": 11.704415312888614 + }, + "lastCommittedPoint": null, + "startArrowhead": "arrow", + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -298.640755194554, + 237.6580025907415 + ] + ] + }, + { + "type": "text", + "version": 851, + "versionNonce": 1605404369, + "isDeleted": false, + "id": "Hc47nGW_gtOiXtmx_puAw", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 279.04761904761995, + "y": 1856.380952380953, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 191, + "height": 21, + "seed": 977753233, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "xX0Sjp4d5xmMxZueHitLy", + "SBaWRnKQiQocECulcwV4k", + "iGXEcqMfe32IhFFoybdOg" + ], + "updated": 1638281507048, + "fontSize": 20, + "fontFamily": 2, + "text": "ABCI service channel", + "baseline": 16, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "ellipse", + "version": 439, + "versionNonce": 379374271, + "isDeleted": false, + "id": "LSahqK9R8i6hSOFV5OmIF", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 298.1904761904764, + "y": 2085.5000000000005, + "strokeColor": "#c92a2a", + "backgroundColor": "transparent", + "width": 176, + "height": 158, + "seed": 1878178047, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "zNgYoohABcyhwzIbYb-Lo", + "xX0Sjp4d5xmMxZueHitLy", + "cKyMJJsCmpWKOTWNSqDMM", + "935hGv7CJb6ABYlB1w7Un", + "OOFLVlfvhKVR1Is2xCi1q" + ], + "updated": 1638281507048 + }, + { + "type": "text", + "version": 616, + "versionNonce": 1182368945, + "isDeleted": false, + "id": "XDidT01qaUV1Gznzbw6VR", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 311.97619047619105, + "y": 2254.5714285714294, + "strokeColor": "#c92a2a", + "backgroundColor": "transparent", + "width": 177, + "height": 17, + "seed": 1215339121, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "updated": 1638281507048, + "fontSize": 16, + "fontFamily": 2, + "text": "rayon worker thread pool", + "baseline": 13, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 1276, + "versionNonce": 458431199, + "isDeleted": false, + "id": "cKyMJJsCmpWKOTWNSqDMM", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 106.85462331104353, + "y": 2033.6964929459075, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 196.50126412469146, + "height": 93.86693191348036, + "seed": 676413727, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "updated": 1638281507048, + "startBinding": { + "elementId": "xle96qVuOvkE6VADHzlni", + "focus": 0.08460522257970042, + "gap": 10.363159612574037 + }, + "endBinding": { + "elementId": "LSahqK9R8i6hSOFV5OmIF", + "focus": -0.02942051669513393, + "gap": 4.391855423725104 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 196.50126412469146, + 93.86693191348036 + ] + ] + }, + { + "type": "text", + "version": 580, + "versionNonce": 822765311, + "isDeleted": false, + "id": "rRG2raWKW7GyhL34UFhlV", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 343.3809523809524, + "y": 2144.476190476191, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 98, + "height": 41, + "seed": 1072284991, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "wDh62TNPODaTXftcfo__h", + "FRo3C6f6zW4iBBh1q8jaK", + "kV0NNyq4-xWHwvvcCPDyL", + "xaHJ5tNfkGKeq6e--abG0" + ], + "updated": 1638281507048, + "fontSize": 20, + "fontFamily": 2, + "text": "VPs\nparallel iter", + "baseline": 36, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 306, + "versionNonce": 2074851441, + "isDeleted": false, + "id": "b50SmACnvUidkzXVx04HS", + "fillStyle": "hachure", + "strokeWidth": 4, + "strokeStyle": "dashed", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": -339.26190476190436, + "y": 1730.1428571428578, + "strokeColor": "#364fc7", + "backgroundColor": "transparent", + "width": 319, + "height": 62, + "seed": 907855199, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "updated": 1638282845956, + "fontSize": 20, + "fontFamily": 2, + "text": "number of threads configurable\nwith `ANOMA_TOKIO_THREADS`, \nby default `num_cpus::get() / 2`", + "baseline": 57, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 419, + "versionNonce": 1754525407, + "isDeleted": false, + "id": "-jwLDhFONkUnH8p6dVCpU", + "fillStyle": "hachure", + "strokeWidth": 4, + "strokeStyle": "dashed", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 269.88095238095275, + "y": 2283.380952380953, + "strokeColor": "#364fc7", + "backgroundColor": "transparent", + "width": 413, + "height": 62, + "seed": 1526989841, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "updated": 1638282841096, + "fontSize": 20, + "fontFamily": 2, + "text": "number of threads configurable\nwith `ANOMA_RAYON_THREADS`, by default\n`num_cpus::get() / 2`", + "baseline": 57, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 713, + "versionNonce": 1325527761, + "isDeleted": false, + "id": "bLAc_B_EwGVAebjgfW-GM", + "fillStyle": "hachure", + "strokeWidth": 4, + "strokeStyle": "dashed", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 695.2619047619047, + "y": 2167.3333333333344, + "strokeColor": "#364fc7", + "backgroundColor": "transparent", + "width": 635, + "height": 62, + "seed": 1245364607, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "updated": 1638282834114, + "fontSize": 20, + "fontFamily": 2, + "text": "RocksDB uses threads internally\n- one background thread for flush and 1/4 logical cores for compaction \n (configurable with `ANOMA_ROCKSDB_COMPACTION_THREADS`)`", + "baseline": 57, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "id": "HKxtedzENwDDoYQRW85X4", + "type": "text", + "x": -340.1666666666664, + "y": 1328.6666666666665, + "width": 272, + "height": 29, + "angle": 0, + "strokeColor": "#0b7285", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 4, + "strokeStyle": "dashed", + "roughness": 0, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 781497873, + "version": 85, + "versionNonce": 655172657, + "isDeleted": false, + "boundElementIds": null, + "updated": 1638281507048, + "text": "Ledger threads usage", + "fontSize": 28, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "baseline": 22 + }, + { + "id": "SX_rkUsCtuv-LdKRlIwFx", + "type": "rectangle", + "x": -358.4999999999998, + "y": 1504.9999999999998, + "width": 978.3333333333333, + "height": 298.3333333333337, + "angle": 0, + "strokeColor": "#087f5b", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 4, + "strokeStyle": "dashed", + "roughness": 0, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 647348369, + "version": 302, + "versionNonce": 1627937745, + "isDeleted": false, + "boundElementIds": null, + "updated": 1638283137559 + }, + { + "id": "kxQSCVcgQAsdNI3rXp9ER", + "type": "text", + "x": -350.1666666666663, + "y": 1508.9999999999998, + "width": 74, + "height": 36, + "angle": 0, + "strokeColor": "#087f5b", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 4, + "strokeStyle": "dashed", + "roughness": 0, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 1948605009, + "version": 215, + "versionNonce": 1981838193, + "isDeleted": false, + "boundElementIds": null, + "updated": 1638283035428, + "text": "async", + "fontSize": 28, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "baseline": 25 + }, + { + "type": "text", + "version": 277, + "versionNonce": 2053364255, + "isDeleted": false, + "id": "TV2bEmL-2y11hAOT8IMOk", + "fillStyle": "hachure", + "strokeWidth": 4, + "strokeStyle": "dashed", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": -177.33333333333292, + "y": 1918.6666666666663, + "strokeColor": "#c92a2a", + "backgroundColor": "transparent", + "width": 98, + "height": 71, + "seed": 91868159, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "updated": 1638283038347, + "fontSize": 28, + "fontFamily": 1, + "text": "blocking\n", + "baseline": 61, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 486, + "versionNonce": 423922673, + "isDeleted": false, + "id": "t7FMzpG22hf9K9b8Hgx5u", + "fillStyle": "hachure", + "strokeWidth": 4, + "strokeStyle": "dashed", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": -190.99999999999977, + "y": 1910.8333333333323, + "strokeColor": "#c92a2a", + "backgroundColor": "transparent", + "width": 1556.666666666667, + "height": 466.6666666666668, + "seed": 1098773535, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "updated": 1638281507049 + }, + { + "id": "YmOdBqI72YlYOC_tFyiBt", + "type": "ellipse", + "x": 611.5000000000001, + "y": 2019.999999999999, + "width": 155.0000000000002, + "height": 131.66666666666697, + "angle": 0, + "strokeColor": "#c92a2a", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 726287967, + "version": 142, + "versionNonce": 1947150239, + "isDeleted": false, + "boundElementIds": [ + "be-hOvlUqvUr4DyAypVOA", + "OOFLVlfvhKVR1Is2xCi1q" + ], + "updated": 1638281507049 + }, + { + "type": "text", + "version": 602, + "versionNonce": 1972364753, + "isDeleted": false, + "id": "ebWanxdnHMSCjVXAJ1sWn", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 654.166666666667, + "y": 2079.5, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 83, + "height": 21, + "seed": 1386786559, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "wDh62TNPODaTXftcfo__h", + "FRo3C6f6zW4iBBh1q8jaK", + "kV0NNyq4-xWHwvvcCPDyL", + "xaHJ5tNfkGKeq6e--abG0" + ], + "updated": 1638281507049, + "fontSize": 20, + "fontFamily": 2, + "text": "RocksDB", + "baseline": 16, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 1807, + "versionNonce": 1478941631, + "isDeleted": false, + "id": "be-hOvlUqvUr4DyAypVOA", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 227.48704426394386, + "y": 2009.5043320379616, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 401.3592448054459, + "height": 32.65800259074172, + "seed": 1701426353, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "updated": 1638281507049, + "startBinding": { + "elementId": "xle96qVuOvkE6VADHzlni", + "focus": -0.7102674913486405, + "gap": 10.034663311562497 + }, + "endBinding": { + "elementId": "YmOdBqI72YlYOC_tFyiBt", + "focus": 0.5863245840872268, + "gap": 1.5114834147282323 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 401.3592448054459, + 32.65800259074172 + ] + ] + }, + { + "type": "arrow", + "version": 1882, + "versionNonce": 1192559537, + "isDeleted": false, + "id": "OOFLVlfvhKVR1Is2xCi1q", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 480.82037759727757, + "y": 2152.004332037962, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 131.35924480544588, + "height": 49.008664075925026, + "seed": 1636785279, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "updated": 1638281507049, + "startBinding": { + "elementId": "LSahqK9R8i6hSOFV5OmIF", + "focus": 0.2666217822310704, + "gap": 7.629048621732977 + }, + "endBinding": { + "elementId": "YmOdBqI72YlYOC_tFyiBt", + "focus": 0.15991624090733284, + "gap": 1.9092717911904202 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 131.35924480544588, + -49.008664075925026 + ] + ] + }, + { + "type": "text", + "version": 275, + "versionNonce": 1596631519, + "isDeleted": false, + "id": "yeegCSHnOaDfKfuSekj9E", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 389.5000000000003, + "y": 1589.4999999999995, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 46, + "height": 21, + "seed": 673712433, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "wDh62TNPODaTXftcfo__h", + "FRo3C6f6zW4iBBh1q8jaK", + "kV0NNyq4-xWHwvvcCPDyL", + "xaHJ5tNfkGKeq6e--abG0", + "I713YnaMZhOtFyLmXEF6C", + "UJiFTL3VeXcVlCGjdLbBU", + "Bh3r3CcvEfm1bVHZqeK1a", + "-C7l5eC8Dm4YoMORDUQGW", + "ffbOz_H2zSWPzpThk5_fq" + ], + "updated": 1638283282004, + "fontSize": 20, + "fontFamily": 2, + "text": "abort", + "baseline": 16, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 409, + "versionNonce": 1855755007, + "isDeleted": false, + "id": "Bh3r3CcvEfm1bVHZqeK1a", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 231.67423860056107, + "y": 1623.025565469656, + "strokeColor": "#087f5b", + "backgroundColor": "transparent", + "width": 143.44099325300573, + "height": 27.283924274329593, + "seed": 1950715775, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "updated": 1638283202172, + "startBinding": { + "elementId": "VmJo9ip-_Nb-VTVZEw8Kr", + "focus": -0.47713874101051523, + "gap": 8.880495302337962 + }, + "endBinding": { + "elementId": "yeegCSHnOaDfKfuSekj9E", + "focus": 0.7643325901211494, + "gap": 14.384768146433487 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 143.44099325300573, + -27.283924274329593 + ] + ] + }, + { + "id": "-C7l5eC8Dm4YoMORDUQGW", + "type": "arrow", + "x": 484.8333333333335, + "y": 1678.2689363402262, + "width": 74.99999999999994, + "height": 58.632102220163915, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dotted", + "roughness": 0, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "round", + "seed": 495614865, + "version": 224, + "versionNonce": 892241329, + "isDeleted": false, + "boundElementIds": null, + "updated": 1638283282004, + "points": [ + [ + 0, + -13.985083726697901 + ], + [ + 35, + -72.61718594686181 + ], + [ + -39.99999999999994, + -72.40614231244754 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "kKhMt_jqXFdZVfYVS52F1", + "focus": 1.0417199777977608, + "gap": 13.309523809523114 + }, + "endBinding": { + "elementId": "yeegCSHnOaDfKfuSekj9E", + "focus": 0.5635527734305699, + "gap": 9.333333333333258 + }, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "id": "ffbOz_H2zSWPzpThk5_fq", + "type": "arrow", + "x": 466.50000000000017, + "y": 1756.1135929634597, + "width": 140.58726302441448, + "height": 170.55307370320688, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dotted", + "roughness": 0, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "round", + "seed": 669428511, + "version": 271, + "versionNonce": 347359441, + "isDeleted": false, + "boundElementIds": null, + "updated": 1638283279100, + "points": [ + [ + 0, + -24.446926296793116 + ], + [ + 115.00000000000006, + -44.85498639803167 + ], + [ + 53.333333333333314, + -195 + ], + [ + -25.587263024414426, + -157.16590320205424 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "p66i1EgzUhPqrGZEygxGo", + "focus": -0.004080057248600112, + "gap": 5.142857142856542 + }, + "endBinding": { + "elementId": "yeegCSHnOaDfKfuSekj9E", + "focus": 0.5838779200338639, + "gap": 5.41273697558546 + }, + "startArrowhead": null, + "endArrowhead": "arrow" + } + ], + "appState": { + "gridSize": null, + "viewBackgroundColor": "#ffffff" + }, + "files": {} +} \ No newline at end of file diff --git a/documentation/dev/src/explore/design/ledger/ledger_threads.svg b/documentation/dev/src/explore/design/ledger/ledger_threads.svg new file mode 100644 index 0000000000..506f18a16e --- /dev/null +++ b/documentation/dev/src/explore/design/ledger/ledger_threads.svg @@ -0,0 +1,16 @@ + + + + + + + - async main with async sub-processes and ctrl + c handler- a dedicated OS thread for RocksDB with a sequential loop over channel with messages from the shelltokio worker thread poolmaintendermintABCIasync futuresctrl + c handlershell loop over channel receiverspawn OS threadABCI service channelrayon worker thread poolVPsparallel iternumber of threads configurablewith `ANOMA_TOKIO_THREADS`, by default `num_cpus::get() / 2`number of threads configurablewith `ANOMA_RAYON_THREADS`, by default`num_cpus::get() / 2`RocksDB uses threads internally- one background thread for flush and 1/4 logical cores for compaction (configurable with `ANOMA_ROCKSDB_COMPACTION_THREADS`)`Ledger threads usageasyncblockingRocksDBabort \ No newline at end of file diff --git a/documentation/dev/src/explore/design/ledger/parameters.md b/documentation/dev/src/explore/design/ledger/parameters.md new file mode 100644 index 0000000000..b10fecd144 --- /dev/null +++ b/documentation/dev/src/explore/design/ledger/parameters.md @@ -0,0 +1,13 @@ +# Parameters + +The parameters are used to dynamically control certain variables in the protocol. They are implemented as an internal address with a native VP. The current values are written into and read from the block storage in the parameters account's sub-space. + +Initial parameters for a chain are set in the genesis configuration. On chain, these can be changed by 2/3 of voting power (specifics are TBA). + +## Epoch duration + +The parameters for [epoch](./epochs.md) duration are: + +- Minimum number of blocks in an epoch +- Minimum duration of an epoch +- Maximum expected time per block \ No newline at end of file diff --git a/documentation/dev/src/explore/design/ledger/pos-integration.md b/documentation/dev/src/explore/design/ledger/pos-integration.md new file mode 100644 index 0000000000..bf6b0f6952 --- /dev/null +++ b/documentation/dev/src/explore/design/ledger/pos-integration.md @@ -0,0 +1,245 @@ +# PoS integration + +The [PoS system](../pos.md) is integrated into Anoma ledger at 3 different layers: +- base ledger that performs genesis initialization, validator set updates on new epoch and applies slashes when they are received from ABCI +- an account with an internal address and a [native VP](vp.md#native-vps) that validates any changes applied by transactions to the PoS account state +- transaction WASMs to perform various PoS actions, also available as a library code for custom made transactions + +The `votes_per_token` PoS system parameter must be chosen to satisfy the [Tendermint requirement](https://github.com/tendermint/spec/blob/60395941214439339cc60040944c67893b5f8145/spec/abci/apps.md#validator-updates) of `MaxTotalVotingPower = MaxInt64 / 8`. + +All [the data relevant to the PoS system](../pos.md#storage) are stored under the PoS account's storage sub-space, with the following key schema (the PoS address prefix is omitted for clarity): + +- `params` (required): the system parameters +- for any validator, all the following fields are required: + - `validator/{validator_address}/consensus_key` + - `validator/{validator_address}/state` + - `validator/{validator_address}/total_deltas` + - `validator/{validator_address}/voting_power` +- `slash/{validator_address}` (optional): a list of slashes, where each record contains epoch and slash rate +- `bond/{bond_source}/{bond_validator} (optional)` +- `unbond/{unbond_source}/{unbond_validator} (optional)` +- `validator_set (required)` +- `total_voting_power (required)` + +- standard validator metadata (these are regular storage values, not epoched data): + - `validator/{validator_address}/staking_reward_address` (required): an address that should receive staking rewards + - `validator/{validator_address}/address_raw_hash` (required): raw hash of validator's address associated with the address is used for look-up of validator address from a raw hash + - TBA (e.g. alias, website, description, delegation commission rate, etc.) + +Only XAN tokens can be staked in bonds. The tokens being staked (bonds and unbonds amounts) are kept in the PoS account under `{xan_address}/balance/{pos_address}` until they are withdrawn. + +## Initialization + +The PoS system is initialized via the shell on chain initialization. The genesis validator set is given in the genesis configuration. On genesis initialization, all the epoched data is set to be immediately active for the current (the very first) epoch. + +## Staking rewards and transaction fees + +Staking rewards for validators are rewarded in Tendermint's method `BeginBlock` in the base ledger. A validator must specify a `validator/{validator_address}/staking_reward_address` for its rewards to be credited to this address. + +To a validator who proposed a block (`block.header.proposer_address`), the system rewards tokens based on the `block_proposer_reward` PoS parameter and each validator that voted on a block (`block.last_commit_info.validator` who `signed_last_block`) receives `block_vote_reward`. + +All the fees that are charged in a transaction execution (DKG transaction wrapper fee and transactions applied in a block) are transferred into a fee pool, which is another special account controlled by the PoS module. Note that the fee pool account may contain tokens other than the staking token XAN. + +- TODO describe the fee pool, related to , and + +## Transactions + +The transactions are assumed to be applied in epoch `n`. Any transaction that modifies [epoched data](../pos.md#epoched-data) updates the structure as described in [epoched data storage](../pos.md#storage). + +For slashing tokens, we implement a [PoS slash pool account](vp.md#pos-slash-pool-vp). Slashed tokens should be credited to this account and, for now, no tokens can be be debited by anyone. + +### Validator transactions + +The validator transactions are assumed to be applied with an account address `validator_address`. + +- `become_validator(consensus_key, staking_reward_address)`: + - creates a record in `validator/{validator_address}/consensus_key` in epoch `n + pipeline_length` + - creates a record in `validator/{validator_address}/staking_reward_address` + - sets `validator/{validator_address}/state` for to `pending` in the current epoch and `candidate` in epoch `n + pipeline_length` +- `deactivate`: + - sets `validator/{validator_address}/state` for to `inactive` in epoch `n + pipeline_length` +- `reactivate`: + - sets `validator/{validator_address}/state` for to `pending` in the current epoch and `candidate` in epoch `n + pipeline_length` +- `self_bond(amount)`: + - let `bond = read(bond/{validator_address}/{validator_address}/delta)` + - if `bond` exist, update it with the new bond amount in epoch `n + pipeline_length` + - else, create a new record with bond amount in epoch `n + pipeline_length` + - debit the token `amount` from the `validator_address` and credit it to the PoS account + - add the `amount` to `validator/{validator_address}/total_deltas` in epoch `n + pipeline_length` + - update the `validator/{validator_address}/voting_power` in epoch `n + pipeline_length` + - update the `total_voting_power` in epoch `n + pipeline_length` + - update `validator_set` in epoch `n + pipeline_length` +- `unbond(amount)`: + - let `bond = read(bond/{validator_address}/{validator_address}/delta)` + - if `bond` doesn't exist, panic + - let `pre_unbond = read(unbond/{validator_address}/{validator_address}/delta)` + - if `total(bond) - total(pre_unbond) < amount`, panic + - decrement the `bond` deltas starting from the rightmost value (a bond in a future-most epoch) until whole `amount` is decremented + - for each decremented `bond` value write a new `unbond` with the key set to the epoch of the source value + - decrement the `amount` from `validator/{validator_address}/total_deltas` in epoch `n + unbonding_length` + - update the `validator/{validator_address}/voting_power` in epoch `n + unbonding_length` + - update the `total_voting_power` in epoch `n + unbonding_length` + - update `validator_set` in epoch `n + unbonding_length` +- `withdraw_unbonds`: + - let `unbond = read(unbond/{validator_address}/{validator_address}/delta)` + - if `unbond` doesn't exist, panic + - if no `unbond` value is found for epochs <= `n`, panic + - for each `((bond_start, bond_end), amount) in unbond where unbond.epoch <= n`: + - let `amount_after_slash = amount` + - for each `slash in read(slash/{validator_address})`: + - if `bond_start <= slash.epoch && slash.epoch <= bond_end)`, `amount_after_slash *= (10_000 - slash.rate) / 10_000` + - credit the `amount_after_slash` to the `validator_address` and debit the whole `amount` (before slash, if any) from the PoS account + - burn the slashed tokens (`amount - amount_after_slash`), if not zero +- `change_consensus_key`: + - creates a record in `validator/{validator_address}/consensus_key` in epoch `n + pipeline_length` + +For `self_bond`, `unbond`, `withdraw_unbonds`, `become_validator` and `change_consensus_key` the transaction must be signed with the validator's public key. Additionally, for `become_validator` and `change_consensus_key` we must attach a signature with the validator's consensus key to verify its ownership. Note that for `self_bond`, signature verification is also performed because there are tokens debited from the validator's account. + +### Delegator transactions + +The delegator transactions are assumed to be applied with an account address `delegator_address`. + +- `delegate(validator_address, amount)`: + - let `bond = read(bond/{delegator_address}/{validator_address}/delta)` + - if `bond` exist, update it with the new bond amount in epoch `n + pipeline_length` + - else, create a new record with bond amount in epoch `n + pipeline_length` + - debit the token `amount` from the `delegator_address` and credit it to the PoS account + - add the `amount` to `validator/{validator_address}/total_deltas` in epoch `n + pipeline_length` + - update the `validator/{validator_address}/voting_power` in epoch `n + pipeline_length` + - update the `total_voting_power` in epoch `n + pipeline_length` + - update `validator_set` in epoch `n + pipeline_length` +- `undelegate(validator_address, amount)`: + - let `bond = read(bond/{delegator_address}/{validator_address}/delta)` + - if `bond` doesn't exist, panic + - let `pre_unbond = read(unbond/{delegator_address}/{validator_address}/delta)` + - if `total(bond) - total(pre_unbond) < amount`, panic + - decrement the `bond` deltas starting from the rightmost value (a bond in a future-most epoch) until whole `amount` is decremented + - for each decremented `bond` value write a new `unbond` with the key set to the epoch of the source value + - decrement the `amount` from `validator/{validator_address}/total_deltas` in epoch `n + unbonding_length` + - update the `validator/{validator_address}/voting_power` in epoch `n + unbonding_length` + - update the `total_voting_power` in epoch `n + unbonding_length` + - update `validator_set` in epoch `n + unbonding_length` +- `redelegate(src_validator_address, dest_validator_address, amount)`: + - `undelegate(src_validator_address, amount)` + - `delegate(dest_validator_address, amount)` but set in epoch `n + unbonding_length` instead of `n + pipeline_length` +- `withdraw_unbonds`: + - for each `validator_address in iter_prefix(unbond/{delegator_address})`: + - let `unbond = read(unbond/{validator_address}/{validator_address}/delta)` + - if no `unbond` value is found for epochs <= `n`, `continue` to the next `validator_address` + - for each `((bond_start, bond_end), amount)` in epochs <= `n`: + - let `amount_after_slash = amount` + - for each `slash in read(slash/{validator_address})`: + - if `bond_start <= slash.epoch && slash.epoch <= bond_end)`, `amount_after_slash *= (10_000 - slash.rate) / 10_000` + - credit the `amount_after_slash` to the `delegator_address` and debit the whole `amount` (before slash, if any) from the PoS account + - burn the slashed tokens (`amount - amount_after_slash`), if not zero + +For `delegate`, `undelegate`, `redelegate` and `withdraw_unbonds` the transaction must be signed with the delegator's public key. Note that for `delegate`, signature verification is also performed because there are tokens debited from the delegator's account. + +## Slashing + +Evidence for byzantine behaviour is received from Tendermint ABCI on `BeginBlock`. For each evidence: + +- append the `evidence` into `slash/{evidence.validator_address}` +- calculate the slashed amount from deltas in and before the `evidence.epoch` in `validator/{validator_address}/total_deltas` for the `evidence.validator_address` and the slash rate +- deduct the slashed amount from the `validator/{validator_address}/total_deltas` at `pipeline_length` offset +- update the `validator/{validator_address}/voting_power` for the `evidence.validator_address` in and after epoch `n + pipeline_length` +- update the `total_voting_power` in and after epoch `n + pipeline_length` +- update `validator_set` in and after epoch `n + pipeline_length` + +## Validity predicate + +In the following description, "pre-state" is the state prior to transaction execution and "post-state" is the state posterior to it. + +Any changes to PoS epoched data are checked to update the structure as described in [epoched data storage](../pos.md#storage). + +Because some key changes are expected to relate to others, the VP also accumulates some values that are checked for validity after key specific logic: +- `balance_delta: token::Change` +- `bond_delta: HashMap` +- `unbond_delta: HashMap` +- `total_deltas: HashMap` +- `total_stake_by_epoch: HashMap>` +- `expected_voting_power_by_epoch: HashMap>`: calculated from the validator's total deltas +- `expected_total_voting_power_delta_by_epoch: HashMap`: calculated from the validator's total deltas +- `voting_power_by_epoch: HashMap>` +- `validator_set_pre: Option>` +- `validator_set_post: Option>` +- `total_voting_power_delta_by_epoch: HashMap` +- `new_validators: HashMap` + +The accumulators are initialized to their default values (empty hash maps and hash set). The data keyed by address are using the validator addresses. + +For any updated epoched data, the `last_update` field must be set to the current epoch. + +The validity predicate triggers a validation logic based on the storage keys modified by a transaction: + +- `validator/{validator_address}/consensus_key`: + ```rust,ignore + match (pre_state, post_state) { + (None, Some(post)) => { + // - check that all other required validator fields have been initialized + // - check that the `state` sub-key for this validator address has been set + // correctly, i.e. the value should be initialized at `pipeline_length` offset + // - insert into or update `new_validators` accumulator + }, + (Some(pre), Some(post)) => { + // - check that the new consensus key is different from the old consensus + // key and that it has been set correctly, i.e. the value can only be changed at `pipeline_length` offset + }, + _ => false, + } + ``` +- `validator/{validator_address}/state`: + ```rust,ignore + match (pre_state, post_state) { + (None, Some(post)) => { + // - check that all other required validator fields have been initialized + // - check that the `post` state is set correctly: + // - the state should be set to `pending` in the current epoch and `candidate` at pipeline offset + // - insert into or update `new_validators` accumulator + }, + (Some(pre), Some(post)) => { + // - check that a validator has been correctly deactivated or reactivated + // - the `state` should only be changed at `pipeline_length` offset + // - if the `state` becomes `inactive`, it must have been `pending` or `candidate` + // - if the `state` becomes `pending`, it must have been `inactive` + // - if the `state` becomes `candidate`, it must have been `pending` or `inactive` + }, + _ => false, + } + ``` +- `validator/{validator_address}/total_deltas`: + - find the difference between the pre-state and post-state values and add it to the `total_deltas` accumulator and update `total_stake_by_epoch`, `expected_voting_power_by_epoch` and `expected_total_voting_power_delta_by_epoch` +- `validator/{validator_address}/voting_power`: + - find the difference between the pre-state and post-state value and insert it into the `voting_power_by_epoch` accumulator +- `bond/{bond_source}/{bond_validator}/delta`: + - for each difference between the post-state and pre-state values: + - if the difference is not in epoch `n` or `n + pipeline_length`, panic + - find slashes for the `bond_validator`, if any, and apply them to the delta value + - add it to the `bond_delta` accumulator +- `unbond/{unbond_source}/{unbond_validator}/deltas`: + - for each difference between the post-state and pre-state values: + - if the difference is not in epoch `n` or `n + unboding_length`, panic + - find slashes for the `bond_validator`, if any, and apply them to the delta value + - add it to the `unbond_delta` accumulator +- `validator_set`: + - set the accumulators `validator_set_pre` and `validator_set_post` +- `total_voting_power`: + - find the difference between the post-state and pre-state + - add it to the `total_voting_power_delta_by_epoch` accumulator +- PoS account's balance: + - find the difference between the post-state and pre-state + - add it to the `balance_delta` accumulator + +No other storage key changes are permitted by the VP. + +After the storage keys iteration, we check the accumulators: + +- For each `total_deltas`, there must be the same delta value in `bond_delta`. +- For each `bond_delta`, there must be validator's change in `total_deltas`. +- Check that all positive `unbond_delta` also have a `total_deltas` update. Negative unbond delta is from withdrawing, which removes tokens from unbond, but doesn't affect total deltas. +- Check validator sets updates against validator total stakes. +- Check voting power changes against validator total stakes. +- Check expected voting power changes against `voting_power_by_epoch`. +- Check expected total voting power change against `total_voting_power_delta_by_epoch`. +- Check that the sum of bonds and unbonds deltas is equal to the balance delta. +- Check that all the new validators have their required fields set and that they have been added to the validator set diff --git a/documentation/dev/src/explore/design/ledger/storage.md b/documentation/dev/src/explore/design/ledger/storage.md new file mode 100644 index 0000000000..7186dd00a3 --- /dev/null +++ b/documentation/dev/src/explore/design/ledger/storage.md @@ -0,0 +1,146 @@ +# Storage + +By default, we persist all the historical data for the predecessor blocks to be able to replay the whole chain and to be able to support Tendermint's rollback command (that allows to rollback the state to the predecessor block, which is useful recovering from a corrupt state). For values that change on every block, we can simply prefix their storage key with the block height. + +However, for the accounts storage it is reasonable to expect that in each block only a small subset of the data will be updated, so we can avoid persisting values that haven't changed from the predecessor block. To achieve that: + +- The latest value is written into and read from its storage key without any height prefix +- If the previous value is overwritten or deleted at block height `n`, we store the diff (old and new value) under `n` prefix (the height at which it's been changed from this value) + +Note that when there are multiple updates of a value with the same storage key in the same block, only the last value will be persisted to the block. + +The block's mutable metadata is permanently in-memory and batch written to DB once a block is finalized. + +```mermaid +graph LR + subgraph "in-memory" + LN[level n] + end + subgraph "DB (each level is immutable once written)" + LN .-> LNL[level n - 1] + LNL ===== L0[level 0] + end +``` + +The accounts storage data are written and read directly to/from the DB and the DB layer manages its cache. + +## In-memory (mutable state) + +The current state is stored in a Sparse Merkle tree. The layout of data in memory should be flexible to allow to optimize throughput. For example, the values of key/value pairs may better stored in a sequence outside of the tree structure. Furthermore, it maybe be better to have the data sorted in memory. This may be possible by decoupling the merkle tree structure from the data and the key/value pairs, as illustrated below. + +```mermaid +graph TD + subgraph storage + subgraph sparse merkle tree + B[branches as paths segments in hashes of keys] .-> L[leaves as a hashes of values] + end + subgraph columns + KV[dictionaries of key/value pairs] + end + end +``` + +It may be advantageous if the data columns keys are not hashed to preserve ordering. + +## DB (immutable state) + +The immutable state doesn't have the same requirements as the mutable. This means that a different data structures or memory layout may perform better (subject to benchmarks). The state trees in the immutable blocks should take advantage of its properties for optimization. For example, it can save storage space by sharing common data and/or delta compression. + +It's very likely that different settings for immutable storage will be provided in future, similar to e.g. [Tezos history modes](https://tezos.gitlab.io/user/history_modes.html). + +## Benchmarks + +We'd like to have easily reproducible benchmarks for the whole database integration that should be filled over time with pre-generated realistic data. This should enable us to tune and compare different hashing functions, backends, data structures, memory layouts, etc. + +### Criteria +- in-memory + - writes (insert, update, delete) + - possibly also concurrent writes, pending on the approach taken for concurrent transaction execution + - reads + - proof generation (inclusion, non-inclusion) +- DB (lower priority) + - writes in batched mode + - reads + - proof generation (inclusion, non-inclusion) + +## DB backends + +The considered options for a DB backend are given in [Libraries & Tools / Database page](../../libraries/db.md). + +### RocksDB + +A committed block is not immediately persisted on RocksDB. When the block is committed, a set of key-value pairs which compose the block is written to the memtable on RocksDB. For the efficient sequential write, a flush is executed to persist the data on the memtable to the disk as a file when the size of the memtable is getting big (the threshold is one of the tuning parameters). + +We can disable write-ahead log(WAL) which protects these data on the memtable from a crash by persisting the write logs to the disk. Disabling WAL helps reduce the write amplification. That's because WAL isn't required for Anoma because other nodes have the block. The blocks which have not been persisted to the disk by flush can be recovered even if an Anoma node crashes. + +## Implementation + +### `storage` module + +This is the main interface for interacting with storage in Anoma. + +This module and its sub-modules should implement the in-memory storage (and/or a cache layer) with Merkle tree (however, the interface should be agnostic to the choice of vector commitment scheme or whether or not there even is one, we may want non-Merklised storage) and the persistent DB. + +The in-memory storage holds chain's metadata and current block's storage. + +Its public API should allow/provide: +- get the Merkle root and Merkle tree proofs +- read-only storage API for ledger's metadata to be accessible for transactions' code, VPs and the RPC + - with public types of all the stored metadata +- unless specified otherwise, read the state from the current block + +An API made visible only to the shell module (e.g. `pub ( in SimplePath )` - https://doc.rust-lang.org/reference/visibility-and-privacy.html) should allow the shell to: +- load state from DB for latest persisted block or initialize a new storage if none found +- begin a new block +- within a block: + - transaction can modify [account sub-space](accounts.md#dynamic-storage-sub-space) + - the function that modify storage (e.g. `write` and `delete`) have to guarantee to also update the Merkle tree + - store each applied transaction and its result +- end the current block +- commit the current block (persist to storage) + +### `storage/merkle_tree` module +It consists of one Sparse Merkle Tree (base tree) and multiple Sparse Merkle Trees (subtrees). The base tree stores the store type and the root of each subtree as a key-value pair. Each subtree has the hashed key-value pairs for each data. + +```mermaid +graph TD + subgraph "Merkle tree" + subgraph "Base tree" + R[Root] --> I0 + R --> I1 + I0 --> L0[Subtree 0] + I0 --> L1[Subtree 1] + I1 --> L2[Subtree 2] + I1 --> L3[Subtree 3] + end + subgraph "Subtree 1" + L1 --> SR[Subroot] + SR --> SI0 + SR --> SI1 + SI0 --> SI00 + SI0 --> SI01 + SI1 --> SI10 + SI1 --> SI11 + SI00 --> SL000 + SI00 --> SL001 + SI01 --> SL010 + SI01 --> SL011 + SI10 --> SL100 + SI10 --> SL101 + SI11 --> SL110 + SI11 --> SL111 + end + end +``` + +The first segment of a [DB key](#db-keys) is used as a key in the base tree and the sub key (without the first segment) specifies the leaf of the subtree. + +A proof of the key-value pair in the Merkle tree should be made of two proofs for the base tree and the subtree. Merkle root is the root of the base tree. In the proof verification, the sub root is calculated with the subtree's proof at first. Then, the root is calculated with the base tree's proof and the calculated sub root as a value, and the calculated root is compared with the Merkle root. + +### `storage/db` module + +The persistent DB implementation (e.g. RocksDB). + +### DB keys + +The DB keys are composed of key segments. A key segment can be an `Address` which starts with `#` (there can be multiple addresses involved in a key) or any user defined non-empty utf-8 string (maybe limited to only alphanumerical characters). Also, `/` and `?` are reserved. `/` is used as a separator for segments. `?` is reserved for a validity predicate and the key segment `?` can be specified only by the specific API. \ No newline at end of file diff --git a/documentation/dev/src/explore/design/ledger/storage/data-schema.md b/documentation/dev/src/explore/design/ledger/storage/data-schema.md new file mode 100644 index 0000000000..792f911968 --- /dev/null +++ b/documentation/dev/src/explore/design/ledger/storage/data-schema.md @@ -0,0 +1,93 @@ +# Data schema + +At high level, all the data in the [accounts' dynamic +sub-spaces](../accounts.md#dynamic-storage-sub-space) is just keys associated with +arbitrary bytes and intents are just wrapper around arbitrary data. To help the +processes that read and write this data (transactions, validity predicates, +matchmaker) interpret it and implement interesting functionality on top it, the +ledger could provide a way to describe the schema of the data. + +For storage data encoding, we're currently using the borsh library, which +provides a way to derive schema for data that can describe its structure in a +very generic way that can easily be consumed in different data-exchange formats +such as JSON. In Rust code, the data can be composed with Rust native ADTs +(`struct` and `enum`) and basic collection structures (fixed and dynamic sized +array, hash map, hash set). Borsh already has a decent coverage of different +implementations in e.g. JS and TypeScript, JVM based languages and Go, which +we'll hopefully be able to support in wasm in near future too. + +Note that the borsh data schema would not be forced upon the users as they can +still build and use custom data with arbitrary encoding. + +A naive implementation could add optional `schema` field to each stored key. To +reduce redundancy, there could be some "built-in" schemas and/or specific +storage space for commonly used data schema definitions. Storage fees apply, but +perhaps they can be split between all the users, so some commonly used data +schema may be almost free. + +A single address in the ledger is define with all schema. A specific schema can +be looked up with a key in its subspace. The schema variable is not yet +implemented and the definition might change to something more appropiate. + +## Schema derived library code + +### account example +Let's start with an example, in which some users want to deploy a +multi-signature account to some shared asset. They create a transaction, which +would initialize a new account with an address `shared-savings` and write into +its storage sub-space the initial funds for the account and data under the key +`"multisig"` with the following definition: + +```rust +#[derive(Schema)] +struct MultiSig { + threshold: u64, + counter: u64, + keys: Vec, +} +``` + +When the transaction is applied, the data is stored together with a reference to +the derived data schema, e.g.: + +```json +{ + "MultiSig": { + "struct": { + "named_fields": { + "threshold": "u64", + "counter": "u64", + "keys": { + "sequence": "PublicKey" + } + } + } + } +} +``` + +Now any transaction that wants to interact with this account can look-up and use its data schema. We can also use this information to display values read from storage from e.g. RPC or indexer. + +What's more, when the data has schema attached on-chain, with borsh we have bijective mapping between the data definitions and their schemas. We can use this nice property to generate code for data definitions back from the schema in any language supported by borsh and that we'll able to support in wasm. + +We can take this a step further and even generate some code for data access on top of our wasm environment functions to lift the burden of encoding/decoding data from storage. For our example, from the key `"multisig"`, in Rust we can generate this code: + +```rust +fn read_multisig() -> MultiSig; +fn write_multisig(MultiSig); +fn with_multisig(FnMut(MultiSig) -> MultiSig); +``` + +Which can be imported like regular library code in a transaction and arbitrarily extended by the users. Similarly, the schema could be used to derive some code for validity predicates and intents. + +We can generate the code on demand (e.g. we could allow to query a node to generate library code for some given accounts for a given language), but we could also provide some helpers for e.g. foundation's or validator's node to optionally automatically publish generated code via git for all the accounts in the current state. In Rust, using this library could look like this: + +```rust +// load the account(s) code where the identifier is the account's address. +use anoma_accounts::SharedSavings; + +fn transaction(...) { + let multisig = SharedSavings::read_multisig(); + ... +} +``` diff --git a/documentation/dev/src/explore/design/ledger/tx.md b/documentation/dev/src/explore/design/ledger/tx.md new file mode 100644 index 0000000000..c4c3344b2b --- /dev/null +++ b/documentation/dev/src/explore/design/ledger/tx.md @@ -0,0 +1,88 @@ +# Transactions + +[Tracking Issue](https://github.com/anoma/anoma/issues/43) + +--- + +There is only a single general transaction (tx) type: + +```rust +struct Transaction { + // A wasm module with a required entrypoint + code: Vec + // Optional arbitrary data + data: Option>, + // A timestamp of when the transaction was created + timestamp: Timestamp, + gas_limit: TODO, +} +``` + +The tx allows to include arbitrary `data`, e.g zero-knowledge proofs and/or arbitrary nonce bytes to obfuscate the tx's minimum encoded size that may be used to derive some information about the tx. + +TODO once we have DKG, we will probably want to have some kind of a wrapper transaction with submission fees, payer and signature + +## Tx life cycle + +```mermaid +flowchart TD + subgraph Node + I[Initialize chain] --> Begin + Begin[Begin block] --> Poll + Poll[Poll mempool queue] --> Apply + Apply[Apply txs] --> End + End[End block] --> Commit[Commit block] + Commit --> Begin + Commit --> Flush + subgraph Mempool + Validate --> V{is valid?} + V -->|Yes| Add[Add to local queue] + V -->|No| Fail[Drop tx] + Flush -->|Re-validate txs not included in this block| V + end + end + subgraph Client + Submit[Submit tx] --> Validate + end +``` + +New txs are injected by the client via mempool. Before including a tx in a local mempool queue, some cheap validation may be performed. Once a tx is included in a mempool queue, it will be gossiped with the peers and may be included in a block by the block proposer. Any txs that are left in the queue after flush will be subject to re-validation before being included again. + +The order of applying transactions within a block is fixed by the block proposer in [the front-running prevention protocol](front-running.md). + +TODO we might want to randomize the tx order after DKG protocol is completed + +### Block application + +Within a block, each tx is applied sequentially in three steps: + +```mermaid +flowchart TD + B[Begin block] --> N{Has next tx and within block gas limit?} + N --> |Yes|E + N -----> |No|EB[End block] + E[Exec tx code] -->|"∀ accounts with modified storage"| VP[Run validity predicates in parallel] + VP --> A{all accept} + A --> |No|R[Reject tx] + A --> |Yes|C[Commit tx and state changes] + R --> N + C --> N + +``` + +## Tx execution + +The code is allowed to read and write anything from [accounts' sub-spaces](./accounts.md#dynamic-storage-sub-space) and to [initialize new accounts](./accounts.md#initializing-a-new-account). Other data that is not in an account's subspace is read-only, e.g. chain and block metadata, account addresses and potentially keys. + +In addition to the verifiers specified in a transaction, each account whose sub-space has been modified by the tx triggers its VP. + +For [internal addresses](accounts.md#internal-transparent-addresses), we invoke their module's native VP interface directly. For other addresses, we look-up validity predicates WASM to be executed from storage. + +The VPs are then given the prior and posterior state from the account's sub-space together with the tx to decide if it accepts the tx's state modifications. + +Within a single tx the execution of the validity predicates will be parallelized and thus the fee for VPs execution would their maximum value (plus some portion of the fees for each of the other parallelized VPs - nothing should be "free"). Once any of the VPs rejects the modifications, execution is aborted, the transaction is rejected and state changes discarded. If all the VPs accept the modifications, the transaction is successful and modifications are committed to storage as the input of the next tx. + +The transaction's API should make it possible to transfer tokens to a hash of a public key that is not revealed. This could be done by having a "deposit" account from which the key's owner can claim the deposited funds. + +Should some type of token prefer not to allow to receive tokens without recipient's approval, a token account can implement logic to decline the received tokens. + diff --git a/documentation/dev/src/explore/design/ledger/vp.md b/documentation/dev/src/explore/design/ledger/vp.md new file mode 100644 index 0000000000..7cf939f331 --- /dev/null +++ b/documentation/dev/src/explore/design/ledger/vp.md @@ -0,0 +1,53 @@ +# Validity predicates + +[Tracking Issue](https://github.com/anoma/anoma/issues/44) + +--- + +Each [account](accounts.md) is associated with exactly one validity predicate (VP). + +Conceptually, a VP is a function from the transaction's data and the storage state prior and posterior to a transaction execution returning a boolean value. A transaction may modify any data in the [accounts' dynamic storage sub-space](accounts.md#dynamic-storage-sub-space). Upon [transaction execution](tx.md#tx-execution), the VPs associated with the accounts whose storage has been modified are invoked to verify the transaction. If any of them reject the transaction, all of its storage modifications are discarded. + +There are some native VPs for [internal transparent addresses](accounts.md#internal-transparent-addresses) that are built into the ledger. All the other VPs are implemented as [WASM programs](wasm-vm.md). One can build a custom VP using the [VP template](https://github.com/anoma/anoma/tree/master/wasm/vp_template) or use one of the pre-defined VPs. + +The VPs must implement the following interface that will be invoked by the protocol: + +```rust +fn validate_tx( + // Data of the transaction that triggered this VP call + tx_data: Vec, + // Address of this VP + addr: Address, + // Storage keys that have been modified by the transation, relevant to this VP + keys_changed: BTreeSet, + // Set of all the addresses whose VP was triggered by the transaction + verifiers: BTreeSet

, +) -> bool; +``` + +The host functions available to call from inside the VP code can be found in [docs generated from code](https://dev.anoma.net/master/rustdoc/anoma_vm_env/imports/vp/index.html#functions). + +## Native VPs + +The native VPs follow the same interface as WASM VPs and rules for how they are [triggered by a transaction](tx.md#tx-execution). They can also call the same host functions as those provided in [WASM VPs environment](wasm-vm.md#vps-environment) and must also account any computation for gas usage. + +### PoS slash pool VP + +The Proof-of-Stake slash pool is a simple account with a native VP which can receive slashed tokens, but no token can ever be withdrawn from it by anyone at this point. + +## Fungible token VP + +The [fungible token VP](https://github.com/anoma/anoma/tree/master/wasm/wasm_source) allows to associate accounts balances of a specific token under its account. + +For illustration, users `Albert` and `Bertha` might hold some amount of token with the address `XAN`. Their balances would be stored in the `XAN`'s storage sub-space under the storage keys `@XAN/balance/@Albert` and `@XAN/balance/@Bertha`, respectively. When `Albert` or `Bertha` attempt to transact with their `XAN` tokens, its validity predicate would be triggered to check: + +- the total supply of `XAN` token is preserved (i.e. inputs = outputs) +- the senders (users whose balance has been deducted) are checked that their validity predicate has also been triggered + +Note that the fungible token VP doesn't need to know whether any of involved users accepted or rejected the transaction, because if any of the involved users rejects it, the whole transaction will be rejected. + +## User VP + +The [user VP](https://github.com/anoma/anoma/blob/master/wasm/wasm_source/src/vp_user.rs) currently provides a signature verification against a public key for sending tokens as prescribed by the fungible token VP. In this VP, a transfer of tokens doesn't have to be authorized by the receiving party. + +It also allows arbitrary storage modifications to the user's sub-space to be performed by a transaction that has been signed by the secret key corresponding to the user's public key stored on-chain. This functionality also allows one to update their own validity predicate. diff --git a/documentation/dev/src/explore/design/ledger/wasm-vm.md b/documentation/dev/src/explore/design/ledger/wasm-vm.md new file mode 100644 index 0000000000..3964caf80e --- /dev/null +++ b/documentation/dev/src/explore/design/ledger/wasm-vm.md @@ -0,0 +1,125 @@ +# WASM VM + +A wasm virtual machine will be used for [validity predicates](./vp.md) and [transactions code](./tx.md). + +The VM should provide: +- an interface for compiling from higher-level languages to wasm (initially only Rust) +- a wasm compiler, unless we use [an interpreted runtime](../../libraries/wasm.md) +- provide and inject [environments for higher-level languages for VPs and transactions](#wasm-environment) +- pre-process wasm modules + - check & sanitize modules + - inject gas metering + - inject stack height metering +- a runner for VPs and transaction code +- encode/decode wasm for transfer & storage +- [manage runtime memory](#wasm-memory) +- wasm development helpers +- helpers to estimate gas usage +- VM and environment versioning + +## Resources + +- [WebAssembly Specifications](https://webassembly.github.io/spec/) +- [wasmer examples](https://docs.wasmer.io/integrations/examples) +- [The WebAssembly Binary Toolkit](https://github.com/webassembly/wabt/) + - bunch of useful wasm tools (e.g. `wasm2wat` to convert from wasm binary to human-readable wat format) +- [Rust wasm WG](https://github.com/rustwasm/team) and [wasm book](https://rustwasm.github.io/book/introduction.html) (some sections are JS specific) +- [A practical guide to WebAssembly memory](https://radu-matei.com/blog/practical-guide-to-wasm-memory/) modulo JS specific details +- [Learn X in Y minutes Where X=WebAssembly](https://learnxinyminutes.com/docs/wasm/) + + +## Wasm environment + +The wasm environment will most likely be libraries that provide APIs for the wasm modules. + +### Common environment + +The common environment of VPs and transactions APIs: + +- math & crypto +- logging +- panics/aborts +- gas metering +- storage read-only API +- context API (chain metadata such as block height) + +The accounts sub-space storage is described under [accounts' dynamic storage sub-space](./accounts.md#dynamic-storage-sub-space). + +### VPs environment + +Because VPs are stateless, everything that is exposed in the VPs environment should be read-only: + +- storage API to account sub-space the [storage write log](#storage-write-log) +- transaction API + +### Transactions environment + +- storage write access for all public state via the [storage write log](#storage-write-log) + +Some exceptions as to what can be written are given under [transaction execution](./tx.md#tx-execution). + + +## Wasm memory + +The wasm memory allows to share data bi-directionally between the host (Rust shell) and the guest (wasm) through a [wasm linear memory instance](https://webassembly.github.io/spec/core/exec/runtime.html#syntax-meminst). + +Because [wasm currently only supports basic types](https://webassembly.github.io/spec/core/syntax/types.html), we need to choose how to represent more sophisticated data in memory. + +The options on how the data can be passed through the memory are: +- using ["C" structures](https://doc.rust-lang.org/nomicon/other-reprs.html#reprc) (probably too invasive because everything in memory would have to use C repr) +- (de)serializing the data with some encoding (JSON, binary, ...?) +- currently very unstable: [WebIDL](https://developer.mozilla.org/en-US/docs/Glossary/WebIDL) / [Interface Types](https://github.com/WebAssembly/interface-types/blob/master/proposals/interface-types/Explainer.md) / [Reference types](https://github.com/WebAssembly/reference-types) + +The choice should allow for easy usage in wasm for users (e.g. in Rust a bindgen macro on data structures, similar to [wasm_bindgen used for JS <-> wasm](https://github.com/rustwasm/wasm-bindgen)). + +Related [wasmer issue](https://github.com/wasmerio/wasmer/issues/315). + +We're currently using borsh for storage serialization, which is also a good option for wasm memory. +- it's easy for users (can be derived) +- because borsh encoding is safe and consistent, the encoded bytes can also be used for Merkle tree hashing +- good performance, although it's not clear at this point if that may be negligible anyway + +### The data + +The data being passed between the host and the guest in the order of the execution: + +- For transactions: + - host-to-guest: pass tx.data to tx.code call + - guest-to-host: parameters of environment functions calls, including storage modifications (pending on storage API) + - host-to-guest: return results for host calls +- For validity predicates: + - host-to-guest: pass tx.data, prior and posterior account storage sub-space state and/or storage modifications (i.e. a write log) for the account + - guest-to-host: parameters of environment function calls + - host-to-guest: return results for host calls + - ~~guest-to-host~~: the VP result (`bool`) can be passed directly from the call + +### Storage write log + +The storage write log gathers any storage updates (`write`/`delete`s) performed by transactions. For each transaction, the write log changes must be accepted by all the validity predicates that were triggered by these changes. + +A validity predicate can read its prior state directly from storage as it is not changed by the transaction directly. For the posterior state, we first try to look-up the keys in the write log to try to find a new value if the key has been modified or deleted. If the key is not present in the write log, it means that the value has not changed and we can read it from storage. + +The write log of each transaction included in a block and accepted by VPs is accumulated into the block write log. Once the block is committed, we apply the storage changes from the block write log to the persistent storage. + +![write log](./wasm-vm/storage-write-log.svg "storage write log") +[Diagram on Excalidraw](https://excalidraw.com/new#room=333e1db689b083669c80,Y0i8yhvIAZCFICs753CSuA) + +## Gas metering + +The two main options for implementing gas metering within wasm using wasmer are: +- a [gas metering middleware included in wasmer](https://github.com/wasmerio/wasmer/tree/72d47336cc1461d63baa2322b38c4cb5f67bb72a/lib/middlewares). +- + +Both of these allow us to assign a gas cost for each wasm operation. + +`wasmer` gas middleware is more recent, so probably more risky. It injects the gas metering code into the wasm code, which is more efficient than host calls to a gas meter. + +`pwasm-utils` divides the wasm code into metered blocks. It performs host call with the gas cost of each block before it is executed. The gas metering injection is linear to the code size. + +The `pwasm-utils` seems like a safer option to begin with (and we'll probably need to use it for [stack height metering](#stack-height-metering) too). We can look into switching to `wasmer` middleware at later point. + +## Stack height metering + +For safety, we need to limit the stack height in wasm code. Similarly to gas metering, we can also use `wasmer` middleware or `pwasm-utils`. + +We have to use `pwasm-utils`, because `wasmer`'s stack limiter is currently non-deterministic (platform specific). This is to be fixed in this PR: . diff --git a/documentation/dev/src/explore/design/ledger/wasm-vm/storage-write-log.excalidraw b/documentation/dev/src/explore/design/ledger/wasm-vm/storage-write-log.excalidraw new file mode 100644 index 0000000000..c9fc0eb5e4 --- /dev/null +++ b/documentation/dev/src/explore/design/ledger/wasm-vm/storage-write-log.excalidraw @@ -0,0 +1,2194 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "https://excalidraw.com", + "elements": [ + { + "type": "text", + "version": 249, + "versionNonce": 1349029114, + "isDeleted": false, + "id": "QZDxznfmnnPUJUIgeuSXh", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 1303, + "y": 645.5, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 213, + "height": 26, + "seed": 1482810554, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "current block storage", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 309, + "versionNonce": 837703590, + "isDeleted": false, + "id": "V9SouvzuSlJK9NBpLw-Lu", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 1282, + "y": 601, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 261, + "height": 152, + "seed": 1467983226, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "hUA84yk4qfMCZG_gRU50z", + "D5zvn3BUfPBp5UmhfH-R6", + "eYxCi8UKcn5uAWz3t_8mk", + "dkBfRJuKw60zXeKHUFpx7", + "eaup2MZzC_fxXF-rrJcQL", + "pAAuF8rBfvJVRZOI-su_9", + "4K7cklh56YvUmwWJnvyMn" + ] + }, + { + "type": "rectangle", + "version": 132, + "versionNonce": 1820384698, + "isDeleted": false, + "id": "1qijVCNE7PVbjyfSBXz7x", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 419, + "y": 343, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 186.00000000000003, + "height": 89, + "seed": 59124154, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "d9oF2lqBkYEPA2mhaoxx1", + "3DaZweLcKBTYk46SAiGnF", + "v6ToHf-twsNDUsIyBovKd", + "hUA84yk4qfMCZG_gRU50z", + "TaACFAGwqruq3j9gT7vCO", + "bZqG2HKWxNREQ7T_hO4g6", + "GBk9xqSLQuWPibzKJhodn", + "b8DDDjU-Sm7_Kd9ymWfaa" + ] + }, + { + "type": "text", + "version": 59, + "versionNonce": 1053848294, + "isDeleted": false, + "id": "UpYqf8dA_2EzFYxosHbTQ", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 430, + "y": 375, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 160, + "height": 20, + "seed": 966406310, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "v6ToHf-twsNDUsIyBovKd" + ], + "fontSize": 16, + "fontFamily": 3, + "text": "apply transaction", + "baseline": 16, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 256, + "versionNonce": 1276917562, + "isDeleted": false, + "id": "__A77YQzon7uaQw6WLbXT", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 412, + "y": 944.5, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 186.00000000000003, + "height": 89, + "seed": 1869390118, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "pEl0DEXOohm3dPPO6t0_x", + "AUeSz0iQoeFeO4ux6Fh0G", + "MCAwfJNVZfn_l-DJyt7B7", + "fp5_BqnGg98c0yKJzRcYE", + "oHae4DgxREq35ry9VS7-m" + ] + }, + { + "type": "text", + "version": 59, + "versionNonce": 12926970, + "isDeleted": false, + "id": "IgWkRriPRAVGdf4ONSzab", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 451, + "y": 260, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 129, + "height": 25, + "seed": 859678842, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "d9oF2lqBkYEPA2mhaoxx1" + ], + "fontSize": 20, + "fontFamily": 3, + "text": "begin block", + "baseline": 20, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 231, + "versionNonce": 1227510950, + "isDeleted": false, + "id": "d9oF2lqBkYEPA2mhaoxx1", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 511.7057128734241, + "y": 303, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 5.554969500967559, + "height": 39, + "seed": 595645882, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "zVu269gdQqC4-Z9Hujhtc", + "focus": -0.08125628303367922, + "gap": 1 + }, + "endBinding": { + "elementId": "1qijVCNE7PVbjyfSBXz7x", + "focus": -0.12412177985948478, + "gap": 1 + }, + "points": [ + [ + 0, + 0 + ], + [ + -5.554969500967559, + 39 + ] + ], + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "type": "text", + "version": 122, + "versionNonce": 1541212538, + "isDeleted": false, + "id": "jza0ceFstQW-YWoG6OQuI", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 447, + "y": 966, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 105, + "height": 25, + "seed": 950213882, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "AUeSz0iQoeFeO4ux6Fh0G" + ], + "fontSize": 20, + "fontFamily": 3, + "text": "end block", + "baseline": 20, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 267, + "versionNonce": 672714923, + "isDeleted": false, + "id": "iYO2n7hMiKxoHgmIIyceE", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 834.6666666666667, + "y": 188.66666666666652, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 384.00000000000006, + "height": 826.3333333333335, + "seed": 1588804794, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "B4hqeI5QKuwc_ZKQ90Cs6", + "fp5_BqnGg98c0yKJzRcYE", + "QHFY7aCNAn9lT-m8c_PHq", + "tMCdNkMMAZBekJGu2L7GR", + "7wSUMENT531su3n6Iow_Q", + "dkBfRJuKw60zXeKHUFpx7", + "Tq0MwFDWLgdxVHK7MbdAZ", + "b8DDDjU-Sm7_Kd9ymWfaa", + "7ppiLydiNHgqsK20RKRCk", + "9wOVQkDmBFA-8h8sXkUyj" + ] + }, + { + "type": "text", + "version": 131, + "versionNonce": 640891685, + "isDeleted": false, + "id": "g1KRxQ25BwJR6IMDL9wx6", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 854.6666666666667, + "y": 210.33333333333331, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 118, + "height": 36, + "seed": 150594662, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 28, + "fontFamily": 1, + "text": "write log", + "baseline": 25, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 751, + "versionNonce": 1500643627, + "isDeleted": false, + "id": "v6ToHf-twsNDUsIyBovKd", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 624.5, + "y": 417.6554282830066, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 268.8023255813953, + "height": 17.072981304704626, + "seed": 2057969574, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "1qijVCNE7PVbjyfSBXz7x", + "gap": 19.500000000000007, + "focus": 0.45575397392109807 + }, + "endBinding": { + "elementId": "GvawR-j7WrctsjHTQx6y-", + "gap": 12.697674418604656, + "focus": 0.5445206473336952 + }, + "points": [ + [ + 0, + 0 + ], + [ + 268.8023255813953, + 17.072981304704626 + ] + ], + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "type": "text", + "version": 146, + "versionNonce": 671076774, + "isDeleted": false, + "id": "OSTKDbfaiP68QofnvRZzT", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 623, + "y": 368, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 188, + "height": 20, + "seed": 1409193638, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 16, + "fontFamily": 3, + "text": "read & write storage", + "baseline": 16, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 439, + "versionNonce": 210391493, + "isDeleted": false, + "id": "S-FHHu4Wq-0IIIQU9qTRD", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 849.3333333333335, + "y": 338.00000000000006, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 357, + "height": 59, + "seed": 1045438310, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 16, + "fontFamily": 3, + "text": "For each transaction store a hash map \nfrom DB keys to values of \n`Update(value) | Delete`", + "baseline": 55, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 316, + "versionNonce": 694541626, + "isDeleted": false, + "id": "9iE7-Xt5uU99Dq8OR70FT", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 924.6666666666666, + "y": 560.6666666666666, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 155, + "height": 68, + "seed": 2023349862, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "QHFY7aCNAn9lT-m8c_PHq", + "dkBfRJuKw60zXeKHUFpx7", + "D5zvn3BUfPBp5UmhfH-R6" + ], + "fontSize": 13.948717948717952, + "fontFamily": 3, + "text": "try to find in the \nwrite log first,\nif no entry found,\nread storage", + "baseline": 65, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 695, + "versionNonce": 1851599718, + "isDeleted": false, + "id": "D5zvn3BUfPBp5UmhfH-R6", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 1109.2498432736227, + "y": 599.0041137810159, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 171.30552397389124, + "height": 12.776928288053455, + "seed": 1454445862, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "UdhUrYmgxC05m-H6pBEVT", + "focus": 0.05559216571754019, + "gap": 4.916509940288961 + }, + "endBinding": { + "elementId": "V9SouvzuSlJK9NBpLw-Lu", + "focus": 0.6459299538936937, + "gap": 1.4446327524860862 + }, + "points": [ + [ + 0, + 0 + ], + [ + 171.30552397389124, + 12.776928288053455 + ] + ], + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "type": "rectangle", + "version": 138, + "versionNonce": 476534458, + "isDeleted": false, + "id": "gW1KXDYTam9sFP9t3H7zs", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 392, + "y": 567, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 166, + "height": 73, + "seed": 1582554298, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "z_yLKRxOC9fRqAuU0gapI", + "dkBfRJuKw60zXeKHUFpx7", + "66wNRVaMBQ_LuSsbzKxuz", + "gbwPr1c5T09O00WkQQ-Q5" + ] + }, + { + "type": "text", + "version": 43, + "versionNonce": 1097468390, + "isDeleted": false, + "id": "lzhN5VgZhOe5LWp4bpH7x", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 443, + "y": 590, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 82, + "height": 25, + "seed": 1820850534, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 3, + "text": "run VPs", + "baseline": 20, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 320, + "versionNonce": 1770024826, + "isDeleted": false, + "id": "TaACFAGwqruq3j9gT7vCO", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 504.2862949189084, + "y": 433, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 2.4160869119018002, + "height": 26.06302729025481, + "seed": 1006966374, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "1qijVCNE7PVbjyfSBXz7x", + "focus": -0.008823761658798604, + "gap": 1 + }, + "endBinding": { + "elementId": "NuGlGaRuYWd7MpH1YbSpO", + "focus": -0.07657894358195909, + "gap": 4.936972709745191 + }, + "points": [ + [ + 0, + 0 + ], + [ + -2.4160869119018002, + 26.06302729025481 + ] + ], + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "type": "arrow", + "version": 675, + "versionNonce": 48593413, + "isDeleted": false, + "id": "z_yLKRxOC9fRqAuU0gapI", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 471.17515729282275, + "y": 648.6109585800341, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 1.7747959460477887, + "height": 33.171299759019576, + "seed": 1290697530, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "gW1KXDYTam9sFP9t3H7zs", + "gap": 8.610958580034094, + "focus": 0.07338129663473107 + }, + "endBinding": { + "elementId": "YSMPWeP5aBKhZYlx6tYkk", + "gap": 11.62499519211975, + "focus": -0.0006202187392369463 + }, + "points": [ + [ + 0, + 0 + ], + [ + 1.7747959460477887, + 33.171299759019576 + ] + ], + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "type": "diamond", + "version": 163, + "versionNonce": 1988834123, + "isDeleted": false, + "id": "YSMPWeP5aBKhZYlx6tYkk", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 408, + "y": 693, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 136.00000000000003, + "height": 90.00000000000003, + "seed": 549577786, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "QHFY7aCNAn9lT-m8c_PHq", + "z_yLKRxOC9fRqAuU0gapI", + "tMCdNkMMAZBekJGu2L7GR", + "e_XAGm7U_62kJBVB0LwwS", + "9wOVQkDmBFA-8h8sXkUyj" + ] + }, + { + "type": "arrow", + "version": 1113, + "versionNonce": 1948111045, + "isDeleted": false, + "id": "QHFY7aCNAn9lT-m8c_PHq", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 549.1768379545191, + "y": 744.0766248064365, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 265.1790177344675, + "height": 10.925022761954438, + "seed": 1109141606, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "YSMPWeP5aBKhZYlx6tYkk", + "gap": 7.982795265165528, + "focus": 0.19941886735023753 + }, + "endBinding": { + "elementId": "iYO2n7hMiKxoHgmIIyceE", + "gap": 20.31081097768015, + "focus": -0.2896844776924461 + }, + "points": [ + [ + 0, + 0 + ], + [ + 265.1790177344675, + -10.925022761954438 + ] + ], + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "type": "text", + "version": 158, + "versionNonce": 892414394, + "isDeleted": false, + "id": "JioJP53WPdSLFwR7f998s", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 423.5, + "y": 725, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 103, + "height": 20, + "seed": 2018171962, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "QHFY7aCNAn9lT-m8c_PHq" + ], + "fontSize": 16, + "fontFamily": 3, + "text": "any reject?", + "baseline": 16, + "textAlign": "center", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 377, + "versionNonce": 740660901, + "isDeleted": false, + "id": "NfrHkeDj-lzeKgSVsyR5L", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 546.3333333333331, + "y": 757.0000000000001, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 250, + "height": 50, + "seed": 778432314, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "z_yLKRxOC9fRqAuU0gapI" + ], + "fontSize": 13.333333333333332, + "fontFamily": 3, + "text": "yes - clear current tx write log\nno - merge current tx write log \nto block write log", + "baseline": 46, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 383, + "versionNonce": 673745771, + "isDeleted": false, + "id": "e_XAGm7U_62kJBVB0LwwS", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 477.7799139738019, + "y": 784.819294955471, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 8.9855334080533, + "height": 23.652787900168505, + "seed": 1312295482, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "YSMPWeP5aBKhZYlx6tYkk", + "focus": 0.23538850078685178, + "gap": 2.4994442635820278 + }, + "endBinding": { + "elementId": "lgZeJc37pIP2-kkWn1vyx", + "focus": 0.3122449582090152, + "gap": 5.494234114668458 + }, + "points": [ + [ + 0, + 0 + ], + [ + 8.9855334080533, + 23.652787900168505 + ] + ], + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "type": "text", + "version": 191, + "versionNonce": 1838081382, + "isDeleted": false, + "id": "TP8ombONfZMcHJ7OZd0kZ", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 372, + "y": 827, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 35, + "height": 25, + "seed": 2057277734, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 3, + "text": "yes", + "baseline": 20, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 347, + "versionNonce": 591989754, + "isDeleted": false, + "id": "MCAwfJNVZfn_l-DJyt7B7", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 501.9192773055894, + "y": 894.4685196465915, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 4.961131884428028, + "height": 46.53148035340848, + "seed": 2139483706, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "8qM2rdsDJixvsMsOBOLdt", + "focus": 2.3139762359713836, + "gap": 13.08072269441061 + }, + "endBinding": { + "elementId": "__A77YQzon7uaQw6WLbXT", + "focus": -0.1346321605117777, + "gap": 3.5 + }, + "points": [ + [ + 0, + 0 + ], + [ + -4.961131884428028, + 46.53148035340848 + ] + ], + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "type": "rectangle", + "version": 211, + "versionNonce": 754547898, + "isDeleted": false, + "id": "5RG_eP1pQS_n4qHqSQa6w", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 399, + "y": 1077, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 189, + "height": 94, + "seed": 925979258, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "7wSUMENT531su3n6Iow_Q", + "oHae4DgxREq35ry9VS7-m", + "eaup2MZzC_fxXF-rrJcQL" + ] + }, + { + "type": "text", + "version": 86, + "versionNonce": 1458914278, + "isDeleted": false, + "id": "89Rp6nfcxdIYV_OuZH6MH", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 421, + "y": 1109, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 141, + "height": 25, + "seed": 1715049722, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 3, + "text": "commit block", + "baseline": 20, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 354, + "versionNonce": 819844474, + "isDeleted": false, + "id": "oHae4DgxREq35ry9VS7-m", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 524.6770123783945, + "y": 1040, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 0.24529202278836237, + "height": 35, + "seed": 1688947110, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "__A77YQzon7uaQw6WLbXT", + "focus": -0.21245896629727823, + "gap": 6.5 + }, + "endBinding": { + "elementId": "5RG_eP1pQS_n4qHqSQa6w", + "focus": 0.3349775055454588, + "gap": 2 + }, + "points": [ + [ + 0, + 0 + ], + [ + 0.24529202278836237, + 35 + ] + ], + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "type": "arrow", + "version": 836, + "versionNonce": 272176698, + "isDeleted": false, + "id": "dkBfRJuKw60zXeKHUFpx7", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 571.5845786407255, + "y": 631.4167806943483, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 696.1225127179008, + "height": 52.3309196923766, + "seed": 1959593766, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "gW1KXDYTam9sFP9t3H7zs", + "focus": 0.4045523376623099, + "gap": 13.584578640725454 + }, + "endBinding": { + "elementId": "V9SouvzuSlJK9NBpLw-Lu", + "focus": -0.2054821425998669, + "gap": 14.292908641373742 + }, + "points": [ + [ + 0, + 0 + ], + [ + 696.1225127179008, + 52.3309196923766 + ] + ], + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "type": "text", + "version": 437, + "versionNonce": 2083914342, + "isDeleted": false, + "id": "K0c3eNfT4HAbD1ELvntSL", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 442, + "y": 474, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 133, + "height": 47, + "seed": 1721741434, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "dkBfRJuKw60zXeKHUFpx7" + ], + "fontSize": 12.591715976331365, + "fontFamily": 3, + "text": "get written keys, \ngrouped by \naccount addresses", + "baseline": 44, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 306, + "versionNonce": 200163066, + "isDeleted": false, + "id": "_Ea9v9eIaEmLyBfP99CSz", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 613, + "y": 1080, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 200, + "height": 14, + "seed": 806880698, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 11.38339920948617, + "fontFamily": 3, + "text": "commit & get the new root hash", + "baseline": 11, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 76, + "versionNonce": 542426534, + "isDeleted": false, + "id": "zVu269gdQqC4-Z9Hujhtc", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 412, + "y": 250, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 191, + "height": 52, + "seed": 1230275898, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "d9oF2lqBkYEPA2mhaoxx1" + ] + }, + { + "type": "diamond", + "version": 101, + "versionNonce": 889746629, + "isDeleted": false, + "id": "lgZeJc37pIP2-kkWn1vyx", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 426, + "y": 815, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 121, + "height": 85, + "seed": 570961146, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "e_XAGm7U_62kJBVB0LwwS", + "MCAwfJNVZfn_l-DJyt7B7", + "bZqG2HKWxNREQ7T_hO4g6", + "7ppiLydiNHgqsK20RKRCk" + ] + }, + { + "type": "text", + "version": 67, + "versionNonce": 34752634, + "isDeleted": false, + "id": "RBGs5Z1BvXDxZjL8B06q7", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 446, + "y": 846, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 75, + "height": 20, + "seed": 1097948666, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 16, + "fontFamily": 3, + "text": "next tx?", + "baseline": 16, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 282, + "versionNonce": 359666726, + "isDeleted": false, + "id": "bZqG2HKWxNREQ7T_hO4g6", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 434.07232800210454, + "y": 843.1392737175299, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 118.07232800210454, + "height": 445.67932237159897, + "seed": 2041794106, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "lgZeJc37pIP2-kkWn1vyx", + "focus": -0.775322895469081, + "gap": 7.110900555096563 + }, + "endBinding": { + "elementId": "1qijVCNE7PVbjyfSBXz7x", + "focus": 0.7731104443491926, + "gap": 9 + }, + "points": [ + [ + 0, + 0 + ], + [ + -118.07232800210454, + -307.13927371752993 + ], + [ + -24.07232800210454, + -445.67932237159897 + ] + ], + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "type": "text", + "version": 48, + "versionNonce": 1214720314, + "isDeleted": false, + "id": "8qM2rdsDJixvsMsOBOLdt", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 515, + "y": 902, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 19, + "height": 20, + "seed": 274658854, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "MCAwfJNVZfn_l-DJyt7B7" + ], + "fontSize": 16, + "fontFamily": 3, + "text": "no", + "baseline": 16, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 129, + "versionNonce": 1524756986, + "isDeleted": false, + "id": "p8RmBsnbDlvCLxUWzkqcZ", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 933.6666666666666, + "y": 855.3333333333333, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 179, + "height": 100.99999999999996, + "seed": 2052091174, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "7wSUMENT531su3n6Iow_Q", + "eYxCi8UKcn5uAWz3t_8mk", + "QHFY7aCNAn9lT-m8c_PHq", + "eaup2MZzC_fxXF-rrJcQL" + ] + }, + { + "type": "text", + "version": 115, + "versionNonce": 837403302, + "isDeleted": false, + "id": "IJrVOcfYxINAROxPFuLeA", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 948.0000000000001, + "y": 862.5, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 61, + "height": 26, + "seed": 1769974650, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "commit", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 317, + "versionNonce": 210084538, + "isDeleted": false, + "id": "eYxCi8UKcn5uAWz3t_8mk", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 1113.9956140350878, + "y": 909.4723758668379, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 164.60264744033384, + "height": 153.19766082791693, + "seed": 1265160934, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "p8RmBsnbDlvCLxUWzkqcZ", + "gap": 1.3289473684213549, + "focus": 0.6596619480074992 + }, + "endBinding": { + "elementId": "V9SouvzuSlJK9NBpLw-Lu", + "gap": 4.721819943171903, + "focus": 0.22966534728241816 + }, + "points": [ + [ + 0, + 0 + ], + [ + 164.60264744033384, + -153.19766082791693 + ] + ], + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "type": "rectangle", + "version": 183, + "versionNonce": 1322093195, + "isDeleted": false, + "id": "GvawR-j7WrctsjHTQx6y-", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 906, + "y": 428.3333333333333, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 215.3333333333335, + "height": 78.00000000000003, + "seed": 723160166, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "v6ToHf-twsNDUsIyBovKd" + ] + }, + { + "type": "text", + "version": 96, + "versionNonce": 967430438, + "isDeleted": false, + "id": "NSWpTYPEYZxXI-8WcRUqC", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 926, + "y": 438.8333333333333, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 48, + "height": 26, + "seed": 134514342, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "write", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 394, + "versionNonce": 1726897675, + "isDeleted": false, + "id": "yGf3O9V0mLEn2tNudJdZh", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 924, + "y": 473.3333333333333, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 178, + "height": 20, + "seed": 1608581498, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 16, + "fontFamily": 3, + "text": "update tx write log", + "baseline": 16, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 114, + "versionNonce": 65059942, + "isDeleted": false, + "id": "UdhUrYmgxC05m-H6pBEVT", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 908.3333333333334, + "y": 529.3333333333334, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 196, + "height": 116.00000000000006, + "seed": 718081638, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "D5zvn3BUfPBp5UmhfH-R6", + "dkBfRJuKw60zXeKHUFpx7", + "GBk9xqSLQuWPibzKJhodn", + "gbwPr1c5T09O00WkQQ-Q5" + ] + }, + { + "type": "text", + "version": 66, + "versionNonce": 887366906, + "isDeleted": false, + "id": "KL6ovSZYanGyaqkNspfsG", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 922.3333333333333, + "y": 533.3333333333334, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 45, + "height": 26, + "seed": 1683396154, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "read", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 188, + "versionNonce": 1841919418, + "isDeleted": false, + "id": "GBk9xqSLQuWPibzKJhodn", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 617, + "y": 418.589731514062, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 286.3333333333335, + "height": 119.90055382235471, + "seed": 812516262, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "1qijVCNE7PVbjyfSBXz7x", + "focus": -0.15890157358839865, + "gap": 12 + }, + "endBinding": { + "elementId": "UdhUrYmgxC05m-H6pBEVT", + "focus": 0.05767894371091034, + "gap": 5 + }, + "points": [ + [ + 0, + 0 + ], + [ + 286.3333333333335, + 119.90055382235471 + ] + ], + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "type": "rectangle", + "version": 41, + "versionNonce": 1174231782, + "isDeleted": false, + "id": "NuGlGaRuYWd7MpH1YbSpO", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 413, + "y": 464, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 185, + "height": 70, + "seed": 2095274278, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "TaACFAGwqruq3j9gT7vCO", + "66wNRVaMBQ_LuSsbzKxuz", + "Tq0MwFDWLgdxVHK7MbdAZ" + ] + }, + { + "type": "arrow", + "version": 12, + "versionNonce": 658943610, + "isDeleted": false, + "id": "66wNRVaMBQ_LuSsbzKxuz", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 498, + "y": 535, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 8, + "height": 29, + "seed": 1684111034, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "NuGlGaRuYWd7MpH1YbSpO", + "focus": -0.023797468354430376, + "gap": 1 + }, + "endBinding": { + "elementId": "gW1KXDYTam9sFP9t3H7zs", + "focus": 0.04409040385327899, + "gap": 3 + }, + "points": [ + [ + 0, + 0 + ], + [ + -8, + 29 + ] + ], + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "type": "arrow", + "version": 111, + "versionNonce": 806449189, + "isDeleted": false, + "id": "Tq0MwFDWLgdxVHK7MbdAZ", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 603, + "y": 501.6951363222473, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 222.33333333333326, + "height": 31.47197411749505, + "seed": 1078758310, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "NuGlGaRuYWd7MpH1YbSpO", + "gap": 5, + "focus": -0.23588105185549268 + }, + "endBinding": { + "elementId": "iYO2n7hMiKxoHgmIIyceE", + "gap": 9.333333333333485, + "focus": 0.09328582885594748 + }, + "points": [ + [ + 0, + 0 + ], + [ + 222.33333333333326, + 31.47197411749505 + ] + ], + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "type": "arrow", + "version": 73, + "versionNonce": 1444859706, + "isDeleted": false, + "id": "gbwPr1c5T09O00WkQQ-Q5", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 563, + "y": 585.9319073246128, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 335.3333333333335, + "height": 7.707422255936649, + "seed": 1331710202, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "gW1KXDYTam9sFP9t3H7zs", + "focus": -0.5146527966463533, + "gap": 5 + }, + "endBinding": { + "elementId": "UdhUrYmgxC05m-H6pBEVT", + "focus": -0.14585804665875834, + "gap": 10 + }, + "points": [ + [ + 0, + 0 + ], + [ + 335.3333333333335, + 7.707422255936649 + ] + ], + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "type": "text", + "version": 27, + "versionNonce": 996432230, + "isDeleted": false, + "id": "8PI67tSXe-2_f03yUlcRa", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 599, + "y": 616, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 150, + "height": 20, + "seed": 880206118, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 16, + "fontFamily": 3, + "text": "read prior state", + "baseline": 16, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 30, + "versionNonce": 1588910074, + "isDeleted": false, + "id": "lxnsACKVdDqtZozs-yqGY", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 602, + "y": 556, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 131, + "height": 20, + "seed": 20211002, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 16, + "fontFamily": 3, + "text": "read posterior", + "baseline": 16, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 76, + "versionNonce": 162625126, + "isDeleted": false, + "id": "Gtm-iUVm6IbvqH8tz1TND", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dotted", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 384, + "y": 324, + "strokeColor": "#0b7285", + "backgroundColor": "transparent", + "width": 228, + "height": 574, + "seed": 1809652474, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "b8DDDjU-Sm7_Kd9ymWfaa" + ] + }, + { + "type": "arrow", + "version": 81, + "versionNonce": 1024723706, + "isDeleted": false, + "id": "eaup2MZzC_fxXF-rrJcQL", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 590.6578947368422, + "y": 1078.2362764961533, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 328.83333333333303, + "height": 163.84999122870886, + "seed": 1237435194, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "5RG_eP1pQS_n4qHqSQa6w", + "gap": 2.657894736842105, + "focus": 0.02930958629792011 + }, + "endBinding": { + "elementId": "p8RmBsnbDlvCLxUWzkqcZ", + "gap": 14.175438596491256, + "focus": 0.4532915238011503 + }, + "points": [ + [ + 0, + 0 + ], + [ + 328.83333333333303, + -163.84999122870886 + ] + ], + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "type": "rectangle", + "version": 155, + "versionNonce": 1447147942, + "isDeleted": false, + "id": "m42knBULIHuzjxMcUMF6W", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 1651, + "y": 570.6666666666667, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 76.6666666666667, + "height": 150.0000000000001, + "seed": 1880246138, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "4K7cklh56YvUmwWJnvyMn" + ] + }, + { + "type": "text", + "version": 51, + "versionNonce": 1930206138, + "isDeleted": false, + "id": "5naFWFL6OuXdfTCj6ZmAb", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 1671.0000000000002, + "y": 629.3333333333334, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 34, + "height": 26, + "seed": 2141200506, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "DB", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "ellipse", + "version": 43, + "versionNonce": 107451622, + "isDeleted": false, + "id": "0s-VD7dlz0TLaDSZ6FJrC", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 1437.6666666666667, + "y": 197.33333333333331, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 236.66666666666674, + "height": 215, + "seed": 467196070, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "pAAuF8rBfvJVRZOI-su_9" + ] + }, + { + "type": "text", + "version": 23, + "versionNonce": 624235642, + "isDeleted": false, + "id": "qDTCpJwz9c-obbatOOxPc", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 1531.0000000000002, + "y": 289.99999999999994, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 42, + "height": 26, + "seed": 1152088826, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "RPC", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 62, + "versionNonce": 1135609894, + "isDeleted": false, + "id": "pAAuF8rBfvJVRZOI-su_9", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 1537.6666666666667, + "y": 414, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 40, + "height": 181.66666666666663, + "seed": 960413862, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "0s-VD7dlz0TLaDSZ6FJrC", + "focus": -0.047261244886885635, + "gap": 2.935697999642244 + }, + "endBinding": { + "elementId": "V9SouvzuSlJK9NBpLw-Lu", + "focus": 0.28134747348721195, + "gap": 5.333333333333371 + }, + "points": [ + [ + 0, + 0 + ], + [ + -40, + 181.66666666666663 + ] + ], + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "type": "text", + "version": 44, + "versionNonce": 357594426, + "isDeleted": false, + "id": "46pcFDq9j3f0_s3AIB6Ha", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 1374.3333333333333, + "y": 476.66666666666674, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 132, + "height": 26, + "seed": 1239245414, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "read storage", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 366, + "versionNonce": 1421983226, + "isDeleted": false, + "id": "4K7cklh56YvUmwWJnvyMn", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 1544.0504201680671, + "y": 657.2571664710368, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 103.06095532627751, + "height": 9.861453065337173, + "seed": 1042201402, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "V9SouvzuSlJK9NBpLw-Lu", + "gap": 1.0504201680672294, + "focus": -0.07019023283236196 + }, + "endBinding": { + "elementId": "m42knBULIHuzjxMcUMF6W", + "gap": 3.888624505655482, + "focus": 0.029376489045781547 + }, + "points": [ + [ + 0, + 0 + ], + [ + 103.06095532627751, + -9.861453065337173 + ] + ], + "lastCommittedPoint": null, + "startArrowhead": "arrow", + "endArrowhead": "arrow" + }, + { + "type": "text", + "version": 349, + "versionNonce": 930579002, + "isDeleted": false, + "id": "2xVAcKXeOrcECl0c74XEx", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 1559.3333333333333, + "y": 431.66666666666663, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 488, + "height": 78, + "seed": 658232230, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 16, + "fontFamily": 3, + "text": "From the RPC storage PoV, a block should be atomic. \nThe RPC shouldn't see any changes applied \nin between \"begin block\" and \"end block\"\nuntil the block is committed.", + "baseline": 74, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 90, + "versionNonce": 382318778, + "isDeleted": false, + "id": "5CDWytpqmSRwxIAxtdj7V", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 947.6666666666666, + "y": 892.6666666666666, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 150, + "height": 59, + "seed": 1756148730, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 16, + "fontFamily": 3, + "text": "commit all write\nlog changes \nin order", + "baseline": 55, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "id": "TWBXonroWqWjQmNrtcfIh", + "type": "text", + "x": 852.1666666666664, + "y": 262.83333333333377, + "width": 338, + "height": 59, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 287623627, + "version": 115, + "versionNonce": 1376514443, + "isDeleted": false, + "boundElementIds": null, + "text": "There are two levels of write log,\none for the current block and one of\ncurrent transaction.", + "fontSize": 16, + "fontFamily": 3, + "textAlign": "left", + "verticalAlign": "top", + "baseline": 55 + } + ], + "appState": { + "gridSize": null, + "viewBackgroundColor": "#ffffff" + } +} \ No newline at end of file diff --git a/documentation/dev/src/explore/design/ledger/wasm-vm/storage-write-log.svg b/documentation/dev/src/explore/design/ledger/wasm-vm/storage-write-log.svg new file mode 100644 index 0000000000..5764d2d5c4 --- /dev/null +++ b/documentation/dev/src/explore/design/ledger/wasm-vm/storage-write-log.svg @@ -0,0 +1,16 @@ + + + + + + + current block storageapply transactionbegin blockend blockwrite logread & write storageFor each transaction store a hash map from DB keys to values of `Update(value) | Delete`try to find in the write log first,if no entry found,read storagerun VPsany reject?yes - clear current tx write logno - merge current tx write log to block write logyescommit blockget written keys, grouped by account addressescommit & get the new root hashnext tx?nocommitwriteupdate tx write logreadread prior stateread posteriorDBRPCread storageFrom the RPC storage PoV, a block should be atomic. The RPC shouldn't see any changes applied in between "begin block" and "end block"until the block is committed.commit all writelog changes in orderThere are two levels of write log,one for the current block and one ofcurrent transaction. \ No newline at end of file diff --git a/documentation/dev/src/explore/design/overview.md b/documentation/dev/src/explore/design/overview.md new file mode 100644 index 0000000000..9e6d419774 --- /dev/null +++ b/documentation/dev/src/explore/design/overview.md @@ -0,0 +1,10 @@ +# Overview + +> ⚠️ This section is WIP. + +- TODO: add high-level interaction diagram(s) + +The Rust crates internal dependency graph: + +![crates](./overview/crates.svg "crates") +[Diagram on Excalidraw](https://excalidraw.com/#room=e32fc914de750ed4f5e4,6CWRFjnmCoiFR4BQ6i9K4g) diff --git a/documentation/dev/src/explore/design/overview/crates.excalidraw b/documentation/dev/src/explore/design/overview/crates.excalidraw new file mode 100644 index 0000000000..e305dfa088 --- /dev/null +++ b/documentation/dev/src/explore/design/overview/crates.excalidraw @@ -0,0 +1,1560 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "https://excalidraw.com", + "elements": [ + { + "type": "arrow", + "version": 940, + "versionNonce": 1634924291, + "isDeleted": false, + "id": "XW8p0b2UGBcU4qhuM50S5", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 234.4292897735185, + "y": 27.074492275773665, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 46.74897051875004, + "height": 31.84747245633222, + "seed": 244640995, + "groupIds": [], + "strokeSharpness": "round", + "boundElements": [], + "updated": 1638978981591, + "startBinding": { + "elementId": "TPinNTC84gdo4Heiyfrcl", + "gap": 7.842259549321174, + "focus": -0.23457593568181878 + }, + "endBinding": { + "elementId": "Vv4I15UDLDULEN3MM7cWR", + "gap": 6.876060164133929, + "focus": 0.014193953434318363 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -46.74897051875004, + -31.84747245633222 + ] + ] + }, + { + "type": "text", + "version": 562, + "versionNonce": 1411527693, + "isDeleted": false, + "id": "lZbFKRT7NFNBN-N0PEGt4", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 282.7198361155589, + "y": 168.66666666666663, + "strokeColor": "#0008", + "backgroundColor": "transparent", + "width": 225, + "height": 59, + "seed": 150535982, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [ + { + "type": "arrow", + "id": "qGwRshNFhRxZVbc_9XoOK" + }, + { + "type": "arrow", + "id": "vjztA9aT9wXo-Mz6v8PpC" + }, + { + "type": "arrow", + "id": "XW8p0b2UGBcU4qhuM50S5" + }, + { + "type": "arrow", + "id": "j6R5PVZmpe0pg3dobMg_R" + } + ], + "updated": 1638978994165, + "fontSize": 16, + "fontFamily": 3, + "text": "sdk\n(generated by the node) \nnot yet implemented", + "baseline": 55, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "" + }, + { + "type": "arrow", + "version": 762, + "versionNonce": 1801214061, + "isDeleted": false, + "id": "N3WOXF2nAY4GBP26E12jj", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": -31.790406370277623, + "y": 287.1153118375381, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 3.8931189336645673, + "height": 134.30791048138838, + "seed": 1843746505, + "groupIds": [], + "strokeSharpness": "round", + "boundElements": [], + "updated": 1638978645308, + "startBinding": { + "elementId": "XCGaurOdV80qWvLWgvMKA", + "focus": -0.3858314613263561, + "gap": 9.235647817769404 + }, + "endBinding": { + "elementId": "EbkJ-mbPprZhdzO3Ukel2", + "focus": 0.29946861113645, + "gap": 8.92494756021722 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -3.8931189336645673, + -134.30791048138838 + ] + ] + }, + { + "type": "rectangle", + "version": 118, + "versionNonce": 1233481955, + "isDeleted": false, + "id": "XCGaurOdV80qWvLWgvMKA", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": -111.64597821935695, + "y": 296.3509596553075, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 266, + "height": 73, + "seed": 1005582, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [ + { + "type": "arrow", + "id": "N3WOXF2nAY4GBP26E12jj" + } + ], + "updated": 1638978645308 + }, + { + "type": "text", + "version": 288, + "versionNonce": 275825357, + "isDeleted": false, + "id": "2Uv1LCKqBFINap90QX39G", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -93.0922484347459, + "y": 310.70191931061504, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 235, + "height": 39, + "seed": 166206202, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [ + { + "type": "arrow", + "id": "u9PpgMxWMRirdT4zSPC5f" + }, + { + "type": "arrow", + "id": "N3WOXF2nAY4GBP26E12jj" + } + ], + "updated": 1638978645308, + "fontSize": 16, + "fontFamily": 3, + "text": "apps \n(node/client/broadcaster)", + "baseline": 35, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "" + }, + { + "type": "text", + "version": 430, + "versionNonce": 2114673795, + "isDeleted": false, + "id": "q1u2GL7wVw4Exe4X5PaPJ", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -30, + "y": -61, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 328, + "height": 39, + "seed": 1199188794, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [ + { + "type": "arrow", + "id": "XW8p0b2UGBcU4qhuM50S5" + } + ], + "updated": 1638978645308, + "fontSize": 16, + "fontFamily": 3, + "text": "shared\n(has to be able to compile to wasm)", + "baseline": 35, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "" + }, + { + "type": "text", + "version": 380, + "versionNonce": 1078518061, + "isDeleted": false, + "id": "iXim05PslRfMMcHgO5M77", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 262.28822012513956, + "y": 409.9572198364548, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 188, + "height": 39, + "seed": 896396134, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [ + { + "type": "arrow", + "id": "qGwRshNFhRxZVbc_9XoOK" + }, + { + "type": "arrow", + "id": "vjztA9aT9wXo-Mz6v8PpC" + } + ], + "updated": 1638978645308, + "fontSize": 16, + "fontFamily": 3, + "text": "wasm\n(tx/vp/mm/mm_filter)", + "baseline": 35, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "" + }, + { + "type": "text", + "version": 392, + "versionNonce": 1880902221, + "isDeleted": false, + "id": "7hkmbpKqpRG1mw7i72ETt", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 250.93816429817616, + "y": 43.98982838512771, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 131, + "height": 39, + "seed": 1444467750, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [ + { + "type": "arrow", + "id": "qGwRshNFhRxZVbc_9XoOK" + } + ], + "updated": 1638978958291, + "fontSize": 16, + "fontFamily": 3, + "text": "vm_env\n(wasm imports)", + "baseline": 35, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "" + }, + { + "type": "arrow", + "version": 1508, + "versionNonce": 1553870509, + "isDeleted": false, + "id": "qGwRshNFhRxZVbc_9XoOK", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 262.5545524579702, + "y": 396.8364074603423, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 31.03570718753258, + "height": 149.5928584864882, + "seed": 1454454153, + "groupIds": [], + "strokeSharpness": "round", + "boundElements": [], + "updated": 1638978981591, + "startBinding": { + "elementId": "Wzbm5P1iAViA47cEtf8fo", + "gap": 2.0964817197048013, + "focus": -0.9079512244676058 + }, + "endBinding": { + "elementId": "ar_8ezfEs1dcv1WTLbxpz", + "gap": 9.559255985213227, + "focus": 0.673948837020252 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 31.03570718753258, + -149.5928584864882 + ] + ] + }, + { + "type": "arrow", + "version": 1768, + "versionNonce": 1721966243, + "isDeleted": false, + "id": "vjztA9aT9wXo-Mz6v8PpC", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 5.789250827564958, + "x": 321.9782879333155, + "y": 154.088665021562, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 1.9590387446170325, + "height": 60.524866420498, + "seed": 2120846791, + "groupIds": [], + "strokeSharpness": "round", + "boundElements": [], + "updated": 1638978981592, + "startBinding": { + "elementId": "ar_8ezfEs1dcv1WTLbxpz", + "focus": -0.20986675637201763, + "gap": 7.748380459840945 + }, + "endBinding": { + "elementId": "TPinNTC84gdo4Heiyfrcl", + "focus": 0.2559196066333591, + "gap": 3.3655914385186065 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 1.9590387446170325, + -60.524866420498 + ] + ] + }, + { + "type": "text", + "version": 429, + "versionNonce": 297558701, + "isDeleted": false, + "id": "5P-9jtz0VpZvFi_qlrfFI", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -58.36066384290253, + "y": 114.97042619428194, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 75, + "height": 20, + "seed": 818570969, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [ + { + "type": "arrow", + "id": "XW8p0b2UGBcU4qhuM50S5" + }, + { + "type": "arrow", + "id": "lLOOrmC-Vjj7oIfMlYSb8" + }, + { + "type": "arrow", + "id": "N3WOXF2nAY4GBP26E12jj" + } + ], + "updated": 1638978645308, + "fontSize": 16, + "fontFamily": 3, + "text": "apps lib", + "baseline": 16, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "" + }, + { + "type": "arrow", + "version": 772, + "versionNonce": 1085418147, + "isDeleted": false, + "id": "lLOOrmC-Vjj7oIfMlYSb8", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": -28.858815305624397, + "y": 93.34045003053473, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 27.182921232842055, + "height": 99.9429435430508, + "seed": 959014413, + "groupIds": [], + "strokeSharpness": "round", + "boundElements": [], + "updated": 1638978645308, + "startBinding": { + "elementId": "EbkJ-mbPprZhdzO3Ukel2", + "gap": 10.542003765397801, + "focus": -0.28644471223848134 + }, + "endBinding": { + "elementId": "Vv4I15UDLDULEN3MM7cWR", + "gap": 5.046546832176402, + "focus": 0.7161156739729357 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 27.182921232842055, + -99.9429435430508 + ] + ] + }, + { + "type": "rectangle", + "version": 194, + "versionNonce": 489430499, + "isDeleted": false, + "id": "Vv4I15UDLDULEN3MM7cWR", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": -35.64597821935695, + "y": -70.64904034469248, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 346, + "height": 59, + "seed": 479498130, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [ + { + "type": "arrow", + "id": "lLOOrmC-Vjj7oIfMlYSb8" + }, + { + "type": "arrow", + "id": "XW8p0b2UGBcU4qhuM50S5" + }, + { + "type": "arrow", + "id": "gjvzsG78lEToLfHSwix2l" + } + ], + "updated": 1638978645309 + }, + { + "type": "rectangle", + "version": 97, + "versionNonce": 832005581, + "isDeleted": false, + "id": "EbkJ-mbPprZhdzO3Ukel2", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": -78.38023114904445, + "y": 103.88245379593252, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 120, + "height": 40, + "seed": 1523867342, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [ + { + "type": "arrow", + "id": "lLOOrmC-Vjj7oIfMlYSb8" + }, + { + "type": "arrow", + "id": "N3WOXF2nAY4GBP26E12jj" + }, + { + "type": "arrow", + "id": "Q-Lc8vIaRv7dEQF96Es40" + } + ], + "updated": 1638978645309 + }, + { + "type": "rectangle", + "version": 186, + "versionNonce": 1802791885, + "isDeleted": false, + "id": "TPinNTC84gdo4Heiyfrcl", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 237.35402178064305, + "y": 34.35095965530752, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 160.00000000000003, + "height": 59, + "seed": 451677582, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [ + { + "type": "arrow", + "id": "vjztA9aT9wXo-Mz6v8PpC" + }, + { + "type": "arrow", + "id": "XW8p0b2UGBcU4qhuM50S5" + }, + { + "type": "arrow", + "id": "aFB1JfXdwInJtc3gPYN7J" + }, + { + "type": "arrow", + "id": "VyqgKewhv649Rl_VgfMCi" + } + ], + "updated": 1638978965417 + }, + { + "type": "rectangle", + "version": 260, + "versionNonce": 1071718765, + "isDeleted": false, + "id": "ar_8ezfEs1dcv1WTLbxpz", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 270.4373551139763, + "y": 158.68429298864083, + "strokeColor": "#0008", + "backgroundColor": "transparent", + "width": 237, + "height": 79, + "seed": 947289294, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [ + { + "type": "arrow", + "id": "vjztA9aT9wXo-Mz6v8PpC" + }, + { + "type": "arrow", + "id": "qGwRshNFhRxZVbc_9XoOK" + }, + { + "type": "arrow", + "id": "j6R5PVZmpe0pg3dobMg_R" + }, + { + "type": "arrow", + "id": "ZIRL-fdZPjVJvZGV2ldOy" + }, + { + "type": "arrow", + "id": "6kR5qmpuk9pmD6Oi1l544" + }, + { + "type": "arrow", + "id": "i1YmU9V2mNKEn1n-x42MI" + } + ], + "updated": 1638978965416 + }, + { + "type": "rectangle", + "version": 258, + "versionNonce": 1605517603, + "isDeleted": false, + "id": "Wzbm5P1iAViA47cEtf8fo", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 251.4386978874138, + "y": 398.932889180047, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 219.00000000000003, + "height": 63, + "seed": 1729566674, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [ + { + "type": "arrow", + "id": "qGwRshNFhRxZVbc_9XoOK" + }, + { + "type": "arrow", + "id": "qTCZ_7N0fuYegT9jZLwYS" + } + ], + "updated": 1638978645309 + }, + { + "type": "text", + "version": 560, + "versionNonce": 1068083432, + "isDeleted": false, + "id": "3K5BlHfHmWQqJECqYjhrw", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 327.6412405007913, + "y": -61.5, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 179, + "height": 39, + "seed": 1395949267, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [ + { + "type": "arrow", + "id": "XW8p0b2UGBcU4qhuM50S5" + } + ], + "updated": 1640603531311, + "fontSize": 16, + "fontFamily": 3, + "text": "macros\n(procedural macros)", + "baseline": 35, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "macros\n(procedural macros)" + }, + { + "type": "rectangle", + "version": 278, + "versionNonce": 246686915, + "isDeleted": false, + "id": "NsweUiJ4jKgjdA0qcz00O", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 321.99526228143435, + "y": -71.14904034469248, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 186.00000000000003, + "height": 59, + "seed": 125160413, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [ + { + "type": "arrow", + "id": "lLOOrmC-Vjj7oIfMlYSb8" + }, + { + "type": "arrow", + "id": "XW8p0b2UGBcU4qhuM50S5" + }, + { + "type": "arrow", + "id": "aFB1JfXdwInJtc3gPYN7J" + } + ], + "updated": 1638978645309 + }, + { + "type": "arrow", + "version": 1011, + "versionNonce": 482577251, + "isDeleted": false, + "id": "aFB1JfXdwInJtc3gPYN7J", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 349.1354167882846, + "y": 23.491799798579976, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 46.682726805305435, + "height": 28.281680286544898, + "seed": 190431859, + "groupIds": [], + "strokeSharpness": "round", + "boundElements": [], + "updated": 1638978958370, + "startBinding": { + "elementId": "TPinNTC84gdo4Heiyfrcl", + "focus": -0.2707765433519321, + "gap": 10.859159856727544 + }, + "endBinding": { + "elementId": "NsweUiJ4jKgjdA0qcz00O", + "focus": -0.2940419127098849, + "gap": 7.359159856727558 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 46.682726805305435, + -28.281680286544898 + ] + ] + }, + { + "type": "rectangle", + "version": 127, + "versionNonce": 922260579, + "isDeleted": false, + "id": "4VBZ0MkHPtewJl2Z2t0Bg", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 62.17464203103873, + "y": 144.10095965530752, + "strokeColor": "#2b8a3e", + "backgroundColor": "transparent", + "width": 152, + "height": 76, + "seed": 1777026810, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [ + { + "type": "arrow", + "id": "gjvzsG78lEToLfHSwix2l" + }, + { + "type": "arrow", + "id": "Q-Lc8vIaRv7dEQF96Es40" + }, + { + "type": "arrow", + "id": "VyqgKewhv649Rl_VgfMCi" + }, + { + "type": "arrow", + "id": "_2-3bn8mf08UmbZ6BXIFS" + } + ], + "updated": 1638978645309 + }, + { + "type": "text", + "version": 142, + "versionNonce": 1104385869, + "isDeleted": false, + "id": "rBCHOnrbLb_daQkqQR3iM", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 72.17464203103873, + "y": 157.60095965530752, + "strokeColor": "#2b8a3e", + "backgroundColor": "transparent", + "width": 134, + "height": 50, + "seed": 1079092262, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [ + { + "type": "arrow", + "id": "_2-3bn8mf08UmbZ6BXIFS" + } + ], + "updated": 1638978645309, + "fontSize": 16, + "fontFamily": 2, + "text": "tests\n(integration tests &\nwasm test helpers)", + "baseline": 46, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "" + }, + { + "type": "arrow", + "version": 309, + "versionNonce": 676204547, + "isDeleted": false, + "id": "gjvzsG78lEToLfHSwix2l", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 121.80008801370579, + "y": 137.1918687462166, + "strokeColor": "#2b8a3e", + "backgroundColor": "transparent", + "width": 31.75599726538033, + "height": 135.45454545454544, + "seed": 789434278, + "groupIds": [], + "strokeSharpness": "round", + "boundElements": [], + "updated": 1638978645309, + "startBinding": { + "elementId": "4VBZ0MkHPtewJl2Z2t0Bg", + "gap": 6.909090909090908, + "focus": -0.06885109912899212 + }, + "endBinding": { + "elementId": "Vv4I15UDLDULEN3MM7cWR", + "gap": 13.386363636363635, + "focus": 0.31883892934573677 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -31.75599726538033, + -135.45454545454544 + ] + ] + }, + { + "type": "arrow", + "version": 359, + "versionNonce": 664938243, + "isDeleted": false, + "id": "VyqgKewhv649Rl_VgfMCi", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 217.6291874855842, + "y": 152.50812625104635, + "strokeColor": "#2b8a3e", + "backgroundColor": "transparent", + "width": 50.95431878398884, + "height": 57.42989386846611, + "seed": 1052874982, + "groupIds": [], + "strokeSharpness": "round", + "boundElements": [], + "updated": 1638978958370, + "startBinding": { + "elementId": "4VBZ0MkHPtewJl2Z2t0Bg", + "gap": 3.454545454545454, + "focus": 0.48484848484848486 + }, + "endBinding": { + "elementId": "TPinNTC84gdo4Heiyfrcl", + "gap": 1.727272727272727, + "focus": 0.1983948188896127 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 50.95431878398884, + -57.42989386846611 + ] + ] + }, + { + "type": "rectangle", + "version": 213, + "versionNonce": 1969612813, + "isDeleted": false, + "id": "5bb86M_XNHtgqUWdz-kf-", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 253.507975364372, + "y": 462.4342929886408, + "strokeColor": "#2b8a3e", + "backgroundColor": "transparent", + "width": 217, + "height": 49, + "seed": 236566138, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [ + { + "type": "arrow", + "id": "_2-3bn8mf08UmbZ6BXIFS" + }, + { + "type": "arrow", + "id": "j6R5PVZmpe0pg3dobMg_R" + } + ], + "updated": 1638978645309 + }, + { + "type": "text", + "version": 189, + "versionNonce": 1784032067, + "isDeleted": false, + "id": "8rk_Ui9gDtaE7NNb8u2Ir", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 266.507975364372, + "y": 478.9342929886408, + "strokeColor": "#2b8a3e", + "backgroundColor": "transparent", + "width": 80, + "height": 17, + "seed": 491861798, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [ + { + "type": "arrow", + "id": "_2-3bn8mf08UmbZ6BXIFS" + } + ], + "updated": 1638978645309, + "fontSize": 16, + "fontFamily": 2, + "text": "wasm tests", + "baseline": 13, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "" + }, + { + "type": "arrow", + "version": 692, + "versionNonce": 770137709, + "isDeleted": false, + "id": "_2-3bn8mf08UmbZ6BXIFS", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 251.507975364372, + "y": 491.77419156750113, + "strokeColor": "#2b8a3e", + "backgroundColor": "transparent", + "width": 115.09760463885584, + "height": 264.19037738291837, + "seed": 2066093498, + "groupIds": [], + "strokeSharpness": "round", + "boundElements": [], + "updated": 1638978645309, + "startBinding": { + "elementId": "8rk_Ui9gDtaE7NNb8u2Ir", + "gap": 15, + "focus": -1.3018695247008474 + }, + "endBinding": { + "elementId": "4VBZ0MkHPtewJl2Z2t0Bg", + "gap": 7.482854529275244, + "focus": 0.23315187671020038 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -115.09760463885584, + -264.19037738291837 + ] + ] + }, + { + "type": "rectangle", + "version": 491, + "versionNonce": 227920611, + "isDeleted": false, + "id": "c9FTgvEkL5qGqshm1XkEc", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 500.007975364372, + "y": 404.8092929886408, + "strokeColor": "#2b8a3e", + "backgroundColor": "transparent", + "width": 142.99999999999994, + "height": 76.00000000000001, + "seed": 1631226957, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [ + { + "type": "arrow", + "id": "gjvzsG78lEToLfHSwix2l" + }, + { + "type": "arrow", + "id": "Q-Lc8vIaRv7dEQF96Es40" + }, + { + "type": "arrow", + "id": "VyqgKewhv649Rl_VgfMCi" + }, + { + "type": "arrow", + "id": "_2-3bn8mf08UmbZ6BXIFS" + }, + { + "type": "arrow", + "id": "j6R5PVZmpe0pg3dobMg_R" + }, + { + "type": "arrow", + "id": "6kR5qmpuk9pmD6Oi1l544" + } + ], + "updated": 1638978645309 + }, + { + "type": "text", + "version": 441, + "versionNonce": 397084877, + "isDeleted": false, + "id": "CTPEGHIc-rJMuCSTtfFbf", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 511.507975364372, + "y": 419.3092929886408, + "strokeColor": "#2b8a3e", + "backgroundColor": "transparent", + "width": 118, + "height": 50, + "seed": 296172003, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [ + { + "type": "arrow", + "id": "j6R5PVZmpe0pg3dobMg_R" + } + ], + "updated": 1638978645309, + "fontSize": 16, + "fontFamily": 2, + "text": "wasm_for_tests\n(pre-build scripts\nused for testing)", + "baseline": 46, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "" + }, + { + "type": "arrow", + "version": 1118, + "versionNonce": 530436365, + "isDeleted": false, + "id": "j6R5PVZmpe0pg3dobMg_R", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 547.2189008950138, + "y": 396.7891966896191, + "strokeColor": "#2b8a3e", + "backgroundColor": "transparent", + "width": 45.12760305424797, + "height": 156.0355604263109, + "seed": 1559261453, + "groupIds": [], + "strokeSharpness": "round", + "boundElements": [], + "updated": 1638978981592, + "startBinding": { + "elementId": "c9FTgvEkL5qGqshm1XkEc", + "gap": 8.020096299021654, + "focus": -0.1330943061411234 + }, + "endBinding": { + "elementId": "ar_8ezfEs1dcv1WTLbxpz", + "gap": 3.069343274667317, + "focus": -0.7786387743677071 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -45.12760305424797, + -156.0355604263109 + ] + ] + }, + { + "type": "text", + "version": 550, + "versionNonce": 1498721827, + "isDeleted": false, + "id": "dqZ0GfpvY8Ewz9AEmMCWa", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 348.822239073299, + "y": 310.3749999999999, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 122, + "height": 20, + "seed": 320921059, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [ + { + "type": "arrow", + "id": "qGwRshNFhRxZVbc_9XoOK" + }, + { + "type": "arrow", + "id": "vjztA9aT9wXo-Mz6v8PpC" + }, + { + "type": "arrow", + "id": "XW8p0b2UGBcU4qhuM50S5" + }, + { + "type": "arrow", + "id": "j6R5PVZmpe0pg3dobMg_R" + }, + { + "type": "arrow", + "id": "qTCZ_7N0fuYegT9jZLwYS" + } + ], + "updated": 1638978645309, + "fontSize": 16, + "fontFamily": 3, + "text": "tx/vp_prelude", + "baseline": 16, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "" + }, + { + "type": "rectangle", + "version": 281, + "versionNonce": 372177293, + "isDeleted": false, + "id": "fjybklv3t7WGXd-_o4IGU", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 332.2897580717163, + "y": 297.39262632197415, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 157, + "height": 42.75000000000006, + "seed": 1380885965, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [ + { + "type": "arrow", + "id": "vjztA9aT9wXo-Mz6v8PpC" + }, + { + "type": "arrow", + "id": "qGwRshNFhRxZVbc_9XoOK" + }, + { + "type": "arrow", + "id": "j6R5PVZmpe0pg3dobMg_R" + }, + { + "type": "arrow", + "id": "qTCZ_7N0fuYegT9jZLwYS" + }, + { + "type": "arrow", + "id": "ZIRL-fdZPjVJvZGV2ldOy" + }, + { + "type": "arrow", + "id": "6kR5qmpuk9pmD6Oi1l544" + }, + { + "type": "arrow", + "id": "i1YmU9V2mNKEn1n-x42MI" + } + ], + "updated": 1638978645309 + }, + { + "type": "arrow", + "version": 1483, + "versionNonce": 1386463587, + "isDeleted": false, + "id": "qTCZ_7N0fuYegT9jZLwYS", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 268.3511599115648, + "y": 397.7956129422673, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 116.90967732188545, + "height": 53.055973240586525, + "seed": 1160691853, + "groupIds": [], + "strokeSharpness": "round", + "boundElements": [], + "updated": 1638978645309, + "startBinding": { + "elementId": "Wzbm5P1iAViA47cEtf8fo", + "focus": -0.9194768569701585, + "gap": 1.1372762377797017 + }, + "endBinding": { + "elementId": "fjybklv3t7WGXd-_o4IGU", + "focus": -0.2523947759723368, + "gap": 4.597013379706624 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 116.90967732188545, + -53.055973240586525 + ] + ] + }, + { + "type": "arrow", + "version": 1662, + "versionNonce": 1619056269, + "isDeleted": false, + "id": "ZIRL-fdZPjVJvZGV2ldOy", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 381.5826013057739, + "y": 292.4896723063988, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 27.405787418156137, + "height": 51.49682634384905, + "seed": 349033581, + "groupIds": [], + "strokeSharpness": "round", + "boundElements": [], + "updated": 1638978962317, + "startBinding": { + "elementId": "fjybklv3t7WGXd-_o4IGU", + "gap": 4.902954015575294, + "focus": -0.16935822108573825 + }, + "endBinding": { + "elementId": "ar_8ezfEs1dcv1WTLbxpz", + "gap": 3.308552973908919, + "focus": 0.41102454938800637 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -27.405787418156137, + -51.49682634384905 + ] + ] + }, + { + "type": "arrow", + "version": 1085, + "versionNonce": 1611373827, + "isDeleted": false, + "id": "6kR5qmpuk9pmD6Oi1l544", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 526.3463625380697, + "y": 398.463201431366, + "strokeColor": "#2b8a3e", + "backgroundColor": "transparent", + "width": 66.5807279311241, + "height": 53.14115021878365, + "seed": 889471565, + "groupIds": [], + "strokeSharpness": "round", + "boundElements": [], + "updated": 1638978645309, + "startBinding": { + "elementId": "c9FTgvEkL5qGqshm1XkEc", + "focus": 0.08731195893821785, + "gap": 6.346091557274804 + }, + "endBinding": { + "elementId": "fjybklv3t7WGXd-_o4IGU", + "focus": -0.14917958172151385, + "gap": 5.179424890608146 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -66.5807279311241, + -53.14115021878365 + ] + ] + }, + { + "type": "arrow", + "version": 1222, + "versionNonce": 77626605, + "isDeleted": false, + "id": "i1YmU9V2mNKEn1n-x42MI", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 436.8729532949412, + "y": 295.6281799726297, + "strokeColor": "#2b8a3e", + "backgroundColor": "transparent", + "width": 32.396136366778364, + "height": 56.23087292631101, + "seed": 1441329475, + "groupIds": [], + "strokeSharpness": "round", + "boundElements": [], + "updated": 1638978962317, + "startBinding": { + "elementId": "fjybklv3t7WGXd-_o4IGU", + "gap": 1.7644463493444311, + "focus": 0.1404156908922036 + }, + "endBinding": { + "elementId": "ar_8ezfEs1dcv1WTLbxpz", + "gap": 1.7130140576778468, + "focus": -0.7361095992935177 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 32.396136366778364, + -56.23087292631101 + ] + ] + } + ], + "appState": { + "gridSize": null, + "viewBackgroundColor": "#ffffff" + }, + "files": {} +} \ No newline at end of file diff --git a/documentation/dev/src/explore/design/overview/crates.svg b/documentation/dev/src/explore/design/overview/crates.svg new file mode 100644 index 0000000000..49f36fd6bc --- /dev/null +++ b/documentation/dev/src/explore/design/overview/crates.svg @@ -0,0 +1,16 @@ + + + + + + + sdk(generated by the node) not yet implementedapps (node/client/broadcaster)shared(has to be able to compile to wasm)wasm(tx/vp/mm/mm_filter)vm_env(wasm imports)apps libmacros(procedural macros)tests(integration tests &wasm test helpers)wasm testswasm_for_tests(pre-build scriptsused for testing)tx/vp_prelude \ No newline at end of file diff --git a/documentation/dev/src/explore/design/pos.md b/documentation/dev/src/explore/design/pos.md new file mode 100644 index 0000000000..55a2d91794 --- /dev/null +++ b/documentation/dev/src/explore/design/pos.md @@ -0,0 +1,282 @@ +# Proof of Stake (PoS) system + +## Epoch + +An epoch is a range of blocks or time that is defined by the base ledger and made available to the PoS system. This document assumes that epochs are identified by consecutive natural numbers. All the data relevant to PoS are [associated with epochs](#epoched-data). + +### Epoched data + +Epoched data are data associated with a specific epoch that are set in advance. The data relevant to the PoS system in the ledger's state are epoched. Each data can be uniquely identified. These are: +- [System parameters](#system-parameters). A single value for each epoch. +- [Active validator set](#active-validator-set). A single value for each epoch. +- Total voting power. A sum of all active and inactive validators' voting power. A single value for each epoch. +- [Validators' consensus key, state and total bonded tokens](#validator). Identified by the validator's address. +- [Bonds](#bonds) are created by self-bonding and delegations. They are identified by the pair of source address and the validator's address. + +Changes to the epoched data do not take effect immediately. Instead, changes in epoch `n` are queued to take effect in the epoch `n + pipeline_length` for most cases and `n + unboding_length` for [unbonding](#unbond) actions. Should the same validator's data or same bonds (i.e. with the same identity) be updated more than once in the same epoch, the later update overrides the previously queued-up update. For bonds, the token amounts are added up. Once the epoch `n` has ended, the queued-up updates for epoch `n + pipeline_length` are final and the values become immutable. + +## Entities + +- [Validator](#validator): An account with a public consensus key, which may participate in producing blocks and governance activities. A validator may not also be a delegator. +- [Delegator](#delegator): An account that delegates some tokens to a validator. A delegator may not also be a validator. + +Additionally, any account may submit evidence for [a slashable misbehaviour](#slashing). + +### Validator + +A validator must have a public consensus key. Additionally, it may also specify optional metadata fields (TBA). + +A validator may be in one of the following states: +- *inactive*: + A validator is not being considered for block creation and cannot receive any new delegations. +- *pending*: + A validator has requested to become a *candidate*. +- *candidate*: + A validator is considered for block creation and can receive delegations. + +For each validator (in any state), the system also tracks total bonded tokens as a sum of the tokens in their self-bonds and delegated bonds, less any unbonded tokens. The total bonded tokens determine their voting voting power by multiplication by the `votes_per_token` [parameter](#system-parameters). The voting power is used for validator selection for block creation and is used in governance related activities. + +#### Validator actions + +- *become validator*: + Any account that is not a validator already and that doesn't have any delegations may request to become a validator. It is required to provide a public consensus key and staking reward address. For the action applied in epoch `n`, the validator's state will be immediately set to *pending*, it will be set to *candidate* for epoch `n + pipeline_length` and the consensus key is set for epoch `n + pipeline_length`. +- *deactivate*: + Only a *pending* or *candidate* validator account may *deactivate*. For this action applied in epoch `n`, the validator's account is set to become *inactive* in the epoch `n + pipeline_length`. +- *reactivate*: + Only an *inactive* validator may *reactivate*. Similarly to *become validator* action, for this action applied in epoch `n`, the validator's state will be immediately set to *pending* and it will be set to *candidate* for epoch `n + pipeline_length`. +- *self-bond*: + A validator may lock-up tokens into a [bond](#bonds) only for its own validator's address. +- *unbond*: + Any self-bonded tokens may be partially or fully [unbonded](#unbond). +- *withdraw unbonds*: + Unbonded tokens may be withdrawn in or after the [unbond's epoch](#unbond). +- *change consensus key*: + Set the new consensus key. When applied in epoch `n`, the key is set for epoch `n + pipeline_length`. + +#### Active validator set + +From all the *candidate* validators, in each epoch the ones with the most voting power limited up to the `max_active_validators` [parameter](#system-parameters) are selected for the active validator set. The active validator set selected in epoch `n` is set for epoch `n + pipeline_length`. + +### Delegator + +A delegator may have any number of delegations to any number of validators. Delegations are stored in [bonds](#bonds). + +#### Delegator actions + +- *delegate*: + An account which is not a validator may delegate tokens to any number of validators. This will lock-up tokens into a [bond](#bonds). +- *undelegate*: + Any delegated tokens may be partially or fully [unbonded](#unbond). +- *withdraw unbonds*: + Unbonded tokens may be withdrawn in or after the [unbond's epoch](#unbond). + +## Bonds + +A bond locks-up tokens from validators' self-bonding and delegators' delegations. For self-bonding, the source address is equal to the validator's address. Only validators can self-bond. For a bond created from a delegation, the bond's source is the delegator's account. + +For each epoch, bonds are uniquely identified by the pair of source and validator's addresses. A bond created in epoch `n` is written into epoch `n + pipeline_length`. If there already is a bond in the epoch `n + pipeline_length` for this pair of source and validator's addresses, its tokens are incremented by the newly bonded amount. + +Any bonds created in epoch `n` increment the bond's validator's total bonded tokens by the bond's token amount and update the voting power for epoch `n + pipeline_length`. + +The tokens put into a bond are immediately deducted from the source account. + +### Unbond + +An unbonding action (validator *unbond* or delegator *undelegate*) requested by the bond's source account in epoch `n` creates an "unbond" with epoch set to `n + unbounding_length`. We also store the epoch of the bond(s) from which the unbond is created in order to determine if the unbond should be slashed if a fault occurred within the range of bond epoch (inclusive) and unbond epoch (exclusive). + +Any unbonds created in epoch `n` decrements the bond's validator's total bonded tokens by the bond's token amount and update the voting power for epoch `n + unbonding_length`. + +An "unbond" with epoch set to `n` may be withdrawn by the bond's source address in or any time after the epoch `n`. Once withdrawn, the unbond is deleted and the tokens are credited to the source account. + +### Staking rewards + +To a validator who proposed a block, the system rewards tokens based on the `block_proposer_reward` [system parameter](#system-parameters) and each validator that voted on a block receives `block_vote_reward`. + +### Slashing + +Instead of absolute values, validators' total bonded token amounts and bonds' and unbonds' token amounts are stored as their deltas (i.e. the change of quantity from a previous epoch) to allow distinguishing changes for different epoch, which is essential for determining whether tokens should be slashed. However, because slashes for a fault that occurred in epoch `n` may only be applied before the beginning of epoch `n + unbonding_length`, in epoch `m` we can sum all the deltas of total bonded token amounts and bonds and unbond with the same source and validator for epoch equal or less than `m - unboding_length` into a single total bonded token amount, single bond and single unbond record. This is to keep the total number of total bonded token amounts for a unique validator and bonds and unbonds for a unique pair of source and validator bound to a maximum number (equal to `unbonding_length`). + +To disincentivize validators misbehaviour in the PoS system a validator may be slashed for any fault that it has done. An evidence of misbehaviour may be submitted by any account for a fault that occurred in epoch `n` anytime before the beginning of epoch `n + unbonding_length`. + +A valid evidence reduces the validator's total bonded token amount by the slash rate in and before the epoch in which the fault occurred. The validator's voting power must also be adjusted to the slashed total bonded token amount. Additionally, a slash is stored with the misbehaving validator's address and the relevant epoch in which the fault occurred. When an unbond is being withdrawn, we first look-up if any slash occurred within the range of epochs in which these were active and if so, reduce its token amount by the slash rate. Note that bonds and unbonds amounts are not slashed until their tokens are withdrawn. + +The invariant is that the sum of amounts that may be withdrawn from a misbehaving validator must always add up to the total bonded token amount. + +## System parameters + +The default values that are relative to epoch duration assume that an epoch last about 24 hours. + +- `max_validator_slots`: Maximum active validators, default `128` +- `pipeline_len`: Pipeline length in number of epochs, default `2` +- `unboding_len`: Unbonding duration in number of epochs, default `6` +- `votes_per_token`: Used in validators' voting power calculation, default 100‱ (1 voting power unit per 1000 tokens) +- `block_proposer_reward`: Amount of tokens rewarded to a validator for proposing a block +- `block_vote_reward`: Amount of tokens rewarded to each validator that voted on a block proposal +- `duplicate_vote_slash_rate`: Portion of validator's stake that should be slashed on a duplicate vote +- `light_client_attack_slash_rate`: Portion of validator's stake that should be slashed on a light client attack + +## Storage + +The [system parameters](#system-parameters) are written into the storage to allow for their changes. Additionally, each validator may record a new parameters value under their sub-key that they wish to change to, which would override the systems parameters when more than 2/3 voting power are in agreement on all the parameters values. + +The validators' data are keyed by the their addresses, conceptually: + +```rust,ignore +type Validators = HashMap; +``` + +Epoched data are stored in the following structure: +```rust,ignore +struct Epoched { + /// The epoch in which this data was last updated + last_update: Epoch, + /// Dynamically sized vector in which the head is the data for epoch in which + /// the `last_update` was performed and every consecutive array element is the + /// successor epoch of the predecessor array element. For system parameters, + /// validator's consensus key and state, `LENGTH = pipeline_length + 1`. + /// For all others, `LENGTH = unbonding_length + 1`. + data: Vec> +} +``` + +Note that not all epochs will have data set, only the ones in which some changes occurred. + +To try to look-up a value for `Epoched` data with independent values in each epoch (such as the active validator set) in the current epoch `n`: + +1. let `index = min(n - last_update, pipeline_length)` +1. read the `data` field at `index`: + 1. if there's a value at `index` return it + 1. else if `index == 0`, return `None` + 1. else decrement `index` and repeat this sub-step from 1. + +To look-up a value for `Epoched` data with delta values in the current epoch `n`: + +1. let `end = min(n - last_update, pipeline_length) + 1` +1. sum all the values that are not `None` in the `0 .. end` range bounded inclusively below and exclusively above + +To update a value in `Epoched` data with independent values in epoch `n` with value `new` for epoch `m`: + +1. let `shift = min(n - last_update, pipeline_length)` +1. if `shift == 0`: + 1. `data[m - n] = new` +1. else: + 1. for `i in 0 .. shift` range bounded inclusively below and exclusively above, set `data[i] = None` + 1. rotate `data` left by `shift` + 1. set `data[m - n] = new` + 1. set `last_update` to the current epoch + +To update a value in `Epoched` data with delta values in epoch `n` with value `delta` for epoch `m`: + +1. let `shift = min(n - last_update, pipeline_length)` +1. if `shift == 0`: + 1. set `data[m - n] = data[m - n].map_or_else(delta, |last_delta| last_delta + delta)` (add the `delta` to the previous value, if any, otherwise use the `delta` as the value) +1. else: + 1. let `sum` to be equal to the sum of all delta values in the `i in 0 .. shift` range bounded inclusively below and exclusively above and set `data[i] = None` + 1. rotate `data` left by `shift` + 1. set `data[0] = data[0].map_or_else(sum, |last_delta| last_delta + sum)` + 1. set `data[m - n] = delta` + 1. set `last_update` to the current epoch + +The invariants for updates in both cases are that `m - n >= 0` and `m - n <= pipeline_length`. + +For the active validator set, we store all the active and inactive validators separately with their respective voting power: +```rust,ignore +type VotingPower = u64; + +/// Validator's address with its voting power. +#[derive(PartialEq, Eq, PartialOrd, Ord)] +struct WeightedValidator { + /// The `voting_power` field must be on top, because lexicographic ordering is + /// based on the top-to-bottom declaration order and in the `ValidatorSet` + /// the `WeighedValidator`s these need to be sorted by the `voting_power`. + voting_power: VotingPower, + address: Address, +} + +struct ValidatorSet { + /// Active validator set with maximum size equal to `max_active_validators` + active: BTreeSet, + /// All the other validators that are not active + inactive: BTreeSet, +} + +type ValidatorSets = Epoched; + +/// The sum of all active and inactive validators' voting power +type TotalVotingPower = Epoched; +``` + +When any validator's voting power changes, we attempt to perform the following update on the `ActiveValidatorSet`: + +1. let `validator` be the validator's address, `power_before` and `power_after` be the voting power before and after the change, respectively +1. let `power_delta = power_after - power_before` +1. let `min_active = active.first()` (active validator with lowest voting power) +1. let `max_inactive = inactive.last()` (inactive validator with greatest voting power) +1. find whether the validator is active, let `is_active = power_before >= max_inactive.voting_power` + 1. if `is_active`: + 1. if `power_delta > 0 && power_after > max_inactive.voting_power`, update the validator in `active` set with `voting_power = power_after` + 1. else, remove the validator from `active`, insert it into `inactive` and remove `max_inactive.address` from `inactive` and insert it into `active` + 1. else (`!is_active`): + 1. if `power_delta < 0 && power_after < min_active.voting_power`, update the validator in `inactive` set with `voting_power = power_after` + 1. else, remove the validator from `inactive`, insert it into `active` and remove `min_active.address` from `active` and insert it into `inactive` + +Within each validator's address space, we store public consensus key, state, total bonded token amount and voting power calculated from the total bonded token amount (even though the voting power is stored in the `ValidatorSet`, we also need to have the `voting_power` here because we cannot look it up in the `ValidatorSet` without iterating the whole set): + +```rust,ignore +struct Validator { + consensus_key: Epoched, + state: Epoched, + total_deltas: Epoched, + voting_power: Epoched, +} + +enum ValidatorState { + Inactive, + Pending, + Candidate, +} +``` + +The bonds and unbonds are keyed by their identifier: + +```rust,ignore +type Bonds = HashMap>; +type Unbonds = HashMap>; + +struct BondId { + validator: Address, + /// The delegator adddress for delegations, or the same as the `validator` + /// address for self-bonds. + source: Address, +} + +struct Bond { + /// A key is a the epoch set for the bond. This is used in unbonding, where + // it's needed for slash epoch range check. + deltas: HashMap, +} + +struct Unbond { + /// A key is a pair of the epoch of the bond from which a unbond was created + /// the epoch of unboding. This is needed for slash epoch range check. + deltas: HashMap<(Epoch, Epoch), token::Amount> +} +``` + +For slashes, we store the epoch and block height at which the fault occurred, slash rate and the slash type: + +```rust,ignore +struct Slash { + epoch: Epoch, + block_height: u64, + /// slash token amount ‱ (per ten thousand) + rate: u8, + r#type: SlashType, +} +``` + +## Initialization + +An initial validator set with self-bonded token amounts must be given on system initialization. + +This set is used to pre-compute epochs in the genesis block from epoch `0` to epoch `pipeline_length - 1`. diff --git a/documentation/dev/src/explore/design/summary.png b/documentation/dev/src/explore/design/summary.png new file mode 100644 index 0000000000000000000000000000000000000000..e1d0af7b460e340308d0f6ae189c331f2f42eca7 GIT binary patch literal 149153 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 + +The three main one are async-std, futures and tokio. + +## Tokio + +Tokio is multithreaded, low cost and scalable. It also contains an async tcp & +udp socket and is used in both tendermint and libp2p. + + diff --git a/documentation/dev/src/explore/libraries/cli.md b/documentation/dev/src/explore/libraries/cli.md new file mode 100644 index 0000000000..9ddd50e5ea --- /dev/null +++ b/documentation/dev/src/explore/libraries/cli.md @@ -0,0 +1,19 @@ +# Command-line interface + +Important factors: +- UX +- ease of use +- cross-platform + +The considered libraries: +- clap + +## Clap + + + +Probably the most widely used CLI library in Rust. + +With version 2.x, we'd probably want to use it with [Structops](https://github.com/TeXitoi/structopt) for deriving. + +But we can probably use 3.0, which is not yet stable, but is pretty close . This version comes with deriving attributes and also other new ways to build CLI commands. diff --git a/documentation/dev/src/explore/libraries/db.md b/documentation/dev/src/explore/libraries/db.md new file mode 100644 index 0000000000..71c6827c20 --- /dev/null +++ b/documentation/dev/src/explore/libraries/db.md @@ -0,0 +1,95 @@ +# Database + +Important factors: +- persistent key/value storage +- reliability and efficiency (runtime performance and disk usage) +- thread safety +- ease of use + +The considered DBs: +- LMDB +- LevelDB +- RocksDB +- sled - Rust native + +To watch: +- [sanakirja](https://docs.rs/sanakirja) - too new to be considered for now, but has some [promising initial results](https://pijul.org/posts/2021-02-06-rethinking-sanakirja/) - TLDR. it can *fork tables* efficiently, it beats LMDB in benchmarks and usability + +The current preference is for RocksDB as it's tried and tested. Eventually, we might want to benchmark against other backends for our specific use case. + +## LMDB + + + +A compact and efficient, persistent in-memory (i.e. mmap-based) B+trees database. Reportedly has a great read performance, but not as good at writing. + +Rust bindings: +- +- +- - some [comparison notes](https://github.com/vhbit/lmdb-rs/issues/32#issuecomment-310906601) with danburkert/lmdb-rs +- + +## LevelDB + +Log Structured Merge Tree db. Uses one global lock. Better write performance than LMDB and lower DB size. + +Rust bindings: +- + +## RocksDB + +A fork of LevelDB with different optimizations (supposedly for RAM and flash storage). + +Used in and . + +Rust bindings: +- + +## Sled + +Repo: +Homepage: + +Modern, zero-copy reads, lock-free and many more features. + +--- + +# Merkle tree data structure + +Some popular choices for merkle tree in the industry are AVL(+) tree, Patricia Trie and Sparse Merkle Tree, each with different trade-offs. + +AVL(+) tree is used in e.g. [Cosmos](https://github.com/cosmos/iavl). The advantage of this structure is that key don't need to be hashed prior to insertion/look-up. + +Patricia trie used in e.g. [Ethereum](https://eth.wiki/en/fundamentals/patricia-tree) and [Plebeia for Tezos](https://www.dailambda.jp/blog/2020-05-11-plebeia/) are designed to be more space efficient. + +Sparse Merle tree as described in [Optimizing sparse Merkle trees](https://ethresear.ch/t/optimizing-sparse-merkle-trees/3751) used in e.g. [Plasma Cash](https://ethresear.ch/t/plasma-cash-with-sparse-merkle-trees-bloom-filters-and-probabilistic-transfers/2006) are somewhat similar to Patricia trees, but perhaps conceptually simpler. + +- Compact Sparse Merkle Trees +- Efficient Sparse Merkle Trees (caching) + +Considered libraries: +- merk +- sparse-merkle-tree +- patricia_tree + +## merk + + + +Using AVL tree built on top of RocksDB. It makes it easy to setup Merkle tree storage, but: +- is not yet fully implemented as described (e.g. [concurrent ops](https://github.com/nomic-io/merk/issues/26)) +- benchmarks seem to differ from results in README +- doesn't have past states of the tree, instead [relies on RocksDB snapshot/checkpoint features](https://github.com/nomic-io/merk/blob/develop/docs/algorithms.md#database-representation), which means that it's [strongly coupled](https://github.com/nomic-io/merk/issues/11) +- uses a custom [encoding lib](https://github.com/nomic-io/ed) which is zero-copy, but big-endian everywhere +- there are a `unsafe` usages that are not well described/justified +- uses some experimental dep such as (now deprecated) + +## sparse-merkle-tree + + + +A nice abstraction, albeit not yet declared stable. It allows to plug-in a custom hasher function (which is important for [circuit friendliness](https://github.com/heliaxdev/rd-pm/issues/11)) and storage backend. Has minimal dependencies and support Rust `no_std`. + +## patricia_tree + + diff --git a/documentation/dev/src/explore/libraries/errors.md b/documentation/dev/src/explore/libraries/errors.md new file mode 100644 index 0000000000..388b232840 --- /dev/null +++ b/documentation/dev/src/explore/libraries/errors.md @@ -0,0 +1,36 @@ +# Error handling + +The current preference is to use `thiserror` for most code and `eyre` for reporting errors at the CLI level and the client. + +To make the code robust, we should avoid using code that may panic for errors that recoverable and handle all possible errors explicitly. Two exceptions to this rule are: +- prototyping, where it's fine to use `unwrap`, `expect`, etc. +- in code paths with conditional compilation **only** for development build, where it's preferable to use `expect` in place of `unwrap` to help with debugging + +In case of panics, we should provide an error trace that is helpful for trouble-shooting and debugging. + +A great post on error handling library/application distinction: . + +The considered DBs: +- thiserror +- anyhow +- eyre + +The current preference is to use eyre at the outermost modules to print any encountered errors nicely back to the user and thiserror elsewhere. + +## Thiserror + +- + +Macros for user-derived error types. Commonly used for library code. + +## Anyhow + +- + +Easy error handling helpers. Commonly used for application code. + +## Eyre + +- + +Fork of `anyhow` with custom error reporting. diff --git a/documentation/dev/src/explore/libraries/logging.md b/documentation/dev/src/explore/libraries/logging.md new file mode 100644 index 0000000000..c2a877eab6 --- /dev/null +++ b/documentation/dev/src/explore/libraries/logging.md @@ -0,0 +1,29 @@ +# Logging + +Options to consider: +- env_logger +- slog +- tracing + +The current preference is for tracing in combination with tracing-subscriber (to log collected events and traces), because we have some async and parallelized code. In future, we should also add tracing-appender for rolling file logging. + +## Env_logger + + + +A simple logger used by many Rust tools, configurable by env vars. Usually combined with [pretty-env-logger](https://github.com/seanmonstar/pretty-env-logger). + +## Slog + + + +Composable, structured logger. Many extra libraries with extra functionality, e.g.: +- port of env_logger as a slog-rs drain + +## Tracing + + + +Tracing & logging better suited for concurrent processes and async code. Many extra libraries with extra functionality, e.g.: +- non-blocking log appender +- allows to forward library log statements and to use this in combination with env_logger diff --git a/documentation/dev/src/explore/libraries/network.md b/documentation/dev/src/explore/libraries/network.md new file mode 100644 index 0000000000..dd1c2522e0 --- /dev/null +++ b/documentation/dev/src/explore/libraries/network.md @@ -0,0 +1,22 @@ +# network + +## Libp2p : Peer To Peer network + + + +peer-to-peer framework that takes care of the transport/identity and message +encryption for us. + +## tonic : Client/Server with protobuf (prost) + + + +Generates a client/server from protobuf file. This can be used for a rpc server. + +# network behaviour + +## Gossipsub + + + +Publish/Subscribe protocol, improvement over floodsub. diff --git a/documentation/dev/src/explore/libraries/packaging.md b/documentation/dev/src/explore/libraries/packaging.md new file mode 100644 index 0000000000..43fe60f07f --- /dev/null +++ b/documentation/dev/src/explore/libraries/packaging.md @@ -0,0 +1,27 @@ +# Packaging + +For Rust native code, cargo works great, but we'll need to package stuff from outside of Rust too (e.g. tendermint). The goal is to have a repo that can always build as is (reproducible) and easily portable (having a single command to install all the deps). + +Options to consider: +- [nix packages](https://github.com/NixOS/nixpkgs) +- [guix](https://guix.gnu.org/manual/en/html_node/Package-Management.html) +- docker + +## Cargo + +For Rust dependencies, it would be nice to integrate and use: +- +- +- + +## Nix + +Purely functional package management for reproducible environment. The big drawback is its language. + +## Guix + +Similar package management capability to nix, but using scheme language. + +## Docker + +Not ideal for development, but we'll probably want to provide docker images for users. diff --git a/documentation/dev/src/explore/libraries/serialization.md b/documentation/dev/src/explore/libraries/serialization.md new file mode 100644 index 0000000000..ee807827a2 --- /dev/null +++ b/documentation/dev/src/explore/libraries/serialization.md @@ -0,0 +1,81 @@ +# Serialization libraries + +Because the serialization for the RPC and storage have different priorities, it might be beneficial to use a different library for each. + +## RPC + +Important factors: +- security, e.g.: + - handling of malicious input (buffers should not be trusted) + - secure RPC, if included (e.g. DoS or memory exhaustion vulnerabilities) +- native and cross-language adoption for easy interop +- ease of use +- reasonable performance + +The considered libraries: +- protobuf +- cap'n'proto +- flatbuffers +- serde + +The current preference is for protobuf using the prost library. + +## Storage + +Important factors: +- consistent binary representation for hashing +- preserve ordering (for DB keys) +- ease of use +- reasonable performance + +The considered libraries: +- bincode +- borsh + +## Protobuf + +The most mature and widely adopted option. Usually combined with gRPC framework. The [Tendermint Rust ABCI](https://github.com/tendermint/rust-abci) provides protobuf definitions. + +Implementations: +- - Rust native +- - Rust native +- - [missing features](https://github.com/tafia/quick-protobuf/issues/12) + +[A comparison of the two](https://www.reddit.com/r/rust/comments/czxny2/which_protocol_buffers_crates_to_invest_in/) main competing Rust implementations seems to favor Prost. Prost reportedly generates cleaner (more idiomatic) Rust code (). Prost also has better performance (). It is possible to also add serde derive attributes for e.g. [JSON support](https://github.com/danburkert/prost/issues/75). JSON can be useful for development, requests inspection and web integration. However, to reduce attack surface, we might want to disallow JSON for write requests on mainnet by default. + +gRPC implementations: +- - Rust native, using Prost and Tokio +- - build on C core library +- - not production ready + +## Cap'n'proto + +It avoids serialization altogether, you use the data natively in a representation that is efficient for interchange ("zero-copy"). The other cool feature is its ["time-traveling RPC"](https://capnproto.org/rpc.html). On the other hand concern for this lib is a much lower adoption rate, especially the Rust port which is not as complete. The format is designed to be safe against malicious input (on the both sides of a communication channel), but according to [FAQ](https://capnproto.org/faq.html) the reference impl (C++) has not yet undergone security review. + +Implementations: +- + +## Flatbuffers + +Similar to protobuf, but zero-copy like Cap'n'proto, hence a lot faster. + +Unfortunately, the Rust implementation is [lacking buffer verifiers](https://google.github.io/flatbuffers/flatbuffers_support.html), which is crucial for handling malicious requests gracefully. There is only draft implementation . This most likely rules out this option. + +Implementations: +- + +## Serde + +Serde is Rust native framework with great ergonomics. It supports many [different formats](https://serde.rs/#data-formats) implemented as libraries. It's used in some DBs too. Serde itself gives [no security guarantees](https://github.com/serde-rs/serde/issues/1087), handling of malicious input depends heavily on the used format. Serde can be used in combination with many other formats, like protobuf. + +## Bincode + + + +Built on top of serde. Easy to use. + +## Borsh + + + +Used in the Near protocol, it guarantees consistent representations and has a specification. It is also faster than bincode and is being [implemented in other languages](https://github.com/near/borsh#implementations). diff --git a/documentation/dev/src/explore/libraries/wasm.md b/documentation/dev/src/explore/libraries/wasm.md new file mode 100644 index 0000000000..2a82b9119b --- /dev/null +++ b/documentation/dev/src/explore/libraries/wasm.md @@ -0,0 +1,40 @@ +# WASM runtime + +Considered runtimes: +- wasmer +- wasmi + +A good comparison overview is given in this [thread that discusses replacing wasmi with wasmer](https://forum.holochain.org/t/wasmi-vs-wasmer/1929) and its links. In summary: +- wasmer has native rust closures (simpler code) +- wasmer uses lexical scoping to import functions, wasmi is based on structs and trait impls +- the wasmer org maintains wasmer packages in many languages +- wasmer may be vulnerable to compiler bombs + - this can be mitigated by using [a singlepass wasm compiler](https://lib.rs/crates/wasmer-compiler-singlepass-near) +- gas metering + - wasmi inject calls to the host gas meter from Wasm modules + - wasmer + - uses Middleware which injects the instructions at the parsing stage of the compiler (with inlining) - reduced overhead + - must also consider compiler gas cost and how to handle compiler performance changes + - it's hard to implement gas rules for precompiles +- [nondeterminism concerns](https://github.com/WebAssembly/design/blob/c9db0ebdee28d2f92726314c05cb8ff382701f8e/Nondeterminism.md) + - different wasm versions (e.g. newly added features) have to be handled in both the compiled and interpreted versions + - non-determinism in the source language cannot be made deterministic in complied/interpreted wasm either + - threading - look like it has a long way to go before being usable + - floats/NaN - can be avoided + - SIMD + - environment resources exhaustion +- both are using the same spec, in wasmi words "there shouldn't be a problem migrating to another spec compliant execution engine." and "wasmi should be a good option for initial prototyping" + - of course this is only true if we don't use features that are not yet in the spec + +## wasmer + +Repo: + +Compiled with multiple backends (Singlepass, Cranelift and LLVM). It [support metering](https://github.com/wasmerio/wasmer/blob/3dc537cc49b8034047c3b142a66b3b6180f4447c/examples/metering.rs) via a [Middleware](https://github.com/wasmerio/wasmer/tree/3dc537cc49b8034047c3b142a66b3b6180f4447c/lib/middlewares). + +## wasmi + +Repo: + +Built for blockchain to ensure high degree of correctness (security, determinism). Interpreted, hence slower. + diff --git a/documentation/dev/src/explore/prototypes/README.md b/documentation/dev/src/explore/prototypes/README.md new file mode 100644 index 0000000000..375dd805c0 --- /dev/null +++ b/documentation/dev/src/explore/prototypes/README.md @@ -0,0 +1,23 @@ +# Prototypes + +A prototype should start with a description of its goals. These can include, but are not limited to a proof of concept of novel ideas or alternative approaches, comparing different libraries and gathering feedback. + +To get started on a prototype, please: +- open an issue on this repository +- add a sub-page to this section with a link to the issue + +The page outlines the goals and possibly contains any notes that are not suitable to be added to the prototype source itself, while the issue should track the sub-task, their progress, and assignees. + +The code quality is of lesser importance in prototypes. To put the main focus on the prototype's goals, we don't need to worry much about testing, linting and doc strings. + +## Advancing a successful prototype + +Once the goals of the prototype have been completed, we can assess if we'd like to advance the prototype to a development version. + +In order to advance a prototype, in general we'll want to: +- review & clean-up the code for lint, format and best practices +- enable common Rust lints +- review any new dependencies +- add docs for any public interface (internally public too) +- add automated tests +- if the prototype has diverged from the original design, update these pages diff --git a/documentation/dev/src/explore/prototypes/base-ledger.md b/documentation/dev/src/explore/prototypes/base-ledger.md new file mode 100644 index 0000000000..7443568ba5 --- /dev/null +++ b/documentation/dev/src/explore/prototypes/base-ledger.md @@ -0,0 +1,112 @@ +# Base ledger prototype + +## Version 3 + +tracking issue + + +### Goals + +- various shell and protocol fixes, improvements and additions +- add more crypto support +- WASM improvements +- implement new validity predicates +- storage improvements +- gas & fees +- fixes for issues found in the Feigenbaum testnet +- IBC integration +- Ferveo/ABCI++ integration +- PoS improvements and new features + - testing (unit + integration + e2e) + - storage values refactoring + - use checked arithmetics + - validator VP + - staking rewards + - staking reward VP + - re-delegation + - validator + - deactivation/reactivation + - change consensus key + +## Version 2 + +tracking issue + +### Goals + +- storage + - build key schema for access + - implement dynamic account sub-spaces +- implement more complete support for WASM transactions and validity predicates + - transactions can read/write all storage + - validity predicates receive the set of changes (changed keys or complete write log) and can read their pre/post state +- add basic transaction gas metering +- various other improvements + +## Version 1 + +tracking issue + +### Goals + +- get some hands-on experience with Rust and Tendermint +- initial usable node + client (+ validator?) setup +- provide a base layer for other prototypes that need to build on top of a ledger + +### Components + +The main components are built in a single Cargo project with [shared library code](#shared) and multiple binaries: +- `anoma` - main executable with commands for both the node and the client (`anoma node` and `anoma client`) +- `anoman` - the [node](#node) +- `anomac` - the [client](#client) + +#### Node + +The node is built into `anoman`. + +##### Shell + +The shell is what currently pulls together all the other components in the node. + +When it's ran: +- establish a channel (e.g.`mpsc::channel` - Multi-producer, single-consumer FIFO queue) for communication from tendermint to the shell +- launch tendermint node in another thread with the channel sender + - send tendermint ABCI requests via the channel together with a new channel sender to receive a response +- run shell loop with the channel receiver, which handles ABIC requests: + - [transaction execution](../design/ledger/tx.md) which includes [wasm VM calls](../design/ledger/wasm-vm.md) + +###### Tendermint + +This module handles initializing and running `tendermint` and forwards messages for the ABCI requests via its channel sender. + +##### Storage + +Key-value storage. More details are specified on [Storage page](../design/ledger/storage.md). + +##### CLI + +- `anoma run` to start the node (will initialize (if needed) and launch tendermint under the hood) +- `anoma reset` to delete all the node's state from DB and tendermint's state + +#### Client + +Allows to submit a transaction with an attached wasm code to the node with: + +`anoma tx --code tx.wasm` + +It presents back the received response on stdout. Currently, it waits for both the mempool validation and application in a block. + +#### Shared + +##### Config + +Configuration settings: +- home directory (db storage and tendermint config and data) + +##### Genesis + +The genesis parameters, such as the initial validator set, are used to initialize a chain's genesis block. + +##### RPC types + +The types for data that can be submitted to the node via the client's RPC commands. diff --git a/documentation/dev/src/explore/prototypes/gossip-layer.md b/documentation/dev/src/explore/prototypes/gossip-layer.md new file mode 100644 index 0000000000..b991ca5c68 --- /dev/null +++ b/documentation/dev/src/explore/prototypes/gossip-layer.md @@ -0,0 +1,61 @@ +# Intent Gossip system prototype + +## Version 2 + +tracking issue + +- Separate matchmakers from intent gossiper nodes +- Various fixes and improvements +- fixes for issues found in the Feigenbaum testnet +- Persistent storage +- Intent gossip and matching of complex txs +- multi-party trades (e.g. 10) +- multi-asset trades (FT, NFT) +- NFT swaps +- Benchmarking base load for the entire network +- Incentives +- Docs + +## Version 1 + +tracking issue + +### Goals + +- learning rust +- usable node + client setup : + - intent + - incentive function + - mempool and white list +- basic matchmaker + +### components + +The intent gossip is build conjointly to the ledger and share the same binary. + +#### Node + +The node is built into `anoman`, it runs all the necesarry part, rpc server, +libp2p, intent gossip app. + +##### Intent gossip application + +The intent gossip application + +###### Mempool + +###### Filter + +##### Network behaviour +The network behaviour is the part that react on network event. It creates a +channel (e.g. `tokio::mpsc::channel`) with the intent gossip to communicate all +intent it receive. + +##### Rpc server +If the rpc command line option is set it creates a tonic server that receive +command from a client and send theses through a channel +(e.g. `tokio::mpsc::channel`) to the the intent gossip. + +#### Client +Allow to submit a intent : +`anoma gossip --data "data"` diff --git a/documentation/dev/src/explore/resources/README.md b/documentation/dev/src/explore/resources/README.md new file mode 100644 index 0000000000..7acf64a1b0 --- /dev/null +++ b/documentation/dev/src/explore/resources/README.md @@ -0,0 +1,11 @@ +# Resources + +Please add anything relevant to the project that you'd like to share with others, such as research papers, blog posts or tutorials. If it's not obvious from the title, please add some description. + +## General + +- + +## Rust + +- diff --git a/documentation/dev/src/explore/resources/ide.md b/documentation/dev/src/explore/resources/ide.md new file mode 100644 index 0000000000..9f5f106ba1 --- /dev/null +++ b/documentation/dev/src/explore/resources/ide.md @@ -0,0 +1,133 @@ +# IDE + +## VsCode + +Some handy extensions (output of `code --list-extensions`): + +```shell +aaron-bond.better-comments +be5invis.toml +bodil.file-browser +bungcip.better-toml +DavidAnson.vscode-markdownlint +jacobdufault.fuzzy-search +kahole.magit +matklad.rust-analyzer +oderwat.indent-rainbow +# easy to see if crates are up-to-date and update if not +serayuzgur.crates +streetsidesoftware.code-spell-checker +vscodevim.vim +# this is like https://www.spacemacs.org/ but in VsCode +VSpaceCode.vspacecode +VSpaceCode.whichkey +# org-mode +vscode-org-mode.org-mode +publicus.org-checkbox +``` + +Add these to your settings.json to get rustfmt and clippy with the nightly version that we use: + +```json +"rust-analyzer.checkOnSave.overrideCommand": [ + "cargo", + "+{{#include ../../../../rust-nightly-version}}", + "clippy", + "--workspace", + "--message-format=json", + "--all-targets" +], +"rust-analyzer.rustfmt.overrideCommand": [ + "rustup", + "run", + "{{#include ../../../../rust-nightly-version}}", + "--", + "rustfmt", + "--edition", + "2018", + "--" +], +``` + +When editing the wasms source (i.e. `wasm/wasm_source/src/..`), open the `wasm/wasm_source` as a workspace to get rust-analyzer working (because the crate is excluded from the root cargo workspace) and then active `--all-features` for it in the preferences. + +## Emacs + +two main mode: + +- [rust-mode](https://github.com/rust-lang/rust-mode) + official mode supported by rust dev +- [rustic-mode](https://github.com/brotzeit/rustic) + forked with more option and better integration/default value + +## config example with rustic and use-package + +```elisp + ;; all flycheck not mandatory not mandatory + (use-package flycheck + :commands flycheck-mode + :init (global-flycheck-mode)) + + (use-package flycheck-color-mode-line + :after flycheck + :hook + (flycheck-mode . flycheck-color-mode-line-mode)) + + (use-package flycheck-pos-tip + :after flycheck) + (use-package lsp-mode + :after flycheck + :bind-keymap + ("C-c i" . lsp-command-map) + :hook + (lsp-mode . lsp-enable-which-key-integration) ;; if wichkey installed + :commands (lsp lsp-deferred) + :custom + (lsp-eldoc-render-all t) + (lsp-idle-delay 0.3) + ) + + (use-package lsp-ui + :after lsp-mode + :commands lsp-ui-mode + :custom + (lsp-ui-peek-always-show t) + (lsp-ui-sideline-show-hover t) + (lsp-ui-doc-enable nil) + (lsp-ui-doc-max-height 30) + :hook (lsp-mode . lsp-ui-mode)) + + ;; if ivy installed installed + (use-package lsp-ivy + :after lsp-mode ivy + :commands lsp-ivy-workspace-symbol) + + ;; if company installed + (use-package company-lsp + :after lsp-mode company + :init + (push 'company-lsp company-backend)) + + (use-package rustic + :bind (:map rustic-mode-map + ("M-j" . lsp-ui-imenu) + ("M-?" . lsp-find-references) + ("C-c C-c ?" . lsp-describe-thing-at-point) + ("C-c C-c !" . lsp-execute-code-action) + ("C-c C-c r" . lsp-rename) + ("C-c C-c TAB" . lsp-rust-analyzer-expand-macro) + ("C-c C-c q" . lsp-workspace-restart) + ("C-c C-c Q" . lsp-workspace-shutdown) + ("C-c C-c s" . lsp-rust-analyzer-status) + ("C-c C-c C-a" . rustic-cargo-add) + ("C-c C-c C-d" . rustic-cargo-rm) + ("C-c C-c C-u" . rustic-cargo-upgrade) + ("C-c C-c C-u" . rustic-cargo-outdated)) + :hook + (rustic-mode . lsp-deferred) + :custom + (lsp-rust-analyzer-cargo-watch-command "clippy") + :config + (rustic-doc-mode t) + ) +``` diff --git a/documentation/dev/src/rustdoc-logo.png b/documentation/dev/src/rustdoc-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..e4c8c045cd994d4a033d49cc1cd060d129d22048 GIT binary patch literal 5188 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. + +## Public keys + +A public key is a [Borsh encoded `PublicKey`](encoding.md#publickey). For the Ed25519 scheme, this is 32 bytes of Ed25519 public key, prefixed with `32` in little endian encoding (`[32, 0, 0, 0]` in raw bytes or `20000000` in hex). (TODO this will change with ) + +## Signatures + +A signature in Anoma is a [Borsh encoded `Signature`](encoding.md#signature). For the Ed25519 scheme, this is 64 bytes of Ed25519 signature, prefixed with `64` in little endian encoding (`[64, 0, 0, 0]` in raw bytes or `40000000` in hex). (TODO this will change with ) diff --git a/documentation/dev/src/specs/encoding.md b/documentation/dev/src/specs/encoding.md new file mode 100644 index 0000000000..8b9de70617 --- /dev/null +++ b/documentation/dev/src/specs/encoding.md @@ -0,0 +1,48 @@ +# Encoding + +## The ledger + +Most of the data in Anoma are encoded with [Borsh](#borsh-binary-encoding), except for the outer layer of [transactions](#transactions) that are being passed via Tendermint and therefore are required to be encoded with protobuf. + +### Borsh binary encoding + +The encoding schemas below are described in terms of [Borsh specification](https://github.com/nearprotocol/borsh#specification), following the general principles ([verbatim from Borsh](https://github.com/near/borsh/blob/master/README.md#specification)): + +- integers are little endian; +- sizes of dynamic containers are written before values as `u32`; +- all unordered containers (hashmap/hashset) are ordered in lexicographic order by key (in tie breaker case on value); +- structs are serialized in the order of fields in the struct; +- enums are serialized with using `u8` for the enum ordinal and then storing data inside the enum value (if present). + +Note that "nil" corresponds to unit (`()`) which is encoded as empty bytes (nothing is being written). + + + +{{#include encoding/generated-borsh-spec.md}} + +## Protobuf + +The schemas below are described in terms of [proto3 specification](https://developers.google.com/protocol-buffers/docs/reference/proto3-spec). + +All the data fields are REQUIRED, unless specified otherwise. + +### Transactions + +Transactions MUST be encoded in the format as defined for [`message Tx`](#proto-definitions). + +Note that for the [default transactions](ledger/default-transactions.md), the `data` are [encoded with Borsh](#borsh-binary-encoding). + +| Name | Type | Description | Field Number | +|-----------|---------------------------|------------------------------------------------|--------------| +| code | bytes | Transaction WASM code. | 1 | +| data | optional bytes | Transaction data (OPTIONAL). | 2 | +| timestamp | google.protobuf.Timestamp | Timestamp of when the transaction was created. | 3 | + +## Proto definitions + +``` +{{#include ../../../proto/types.proto}} +``` + + + diff --git a/documentation/dev/src/specs/encoding/.gitignore b/documentation/dev/src/specs/encoding/.gitignore new file mode 100644 index 0000000000..0e44a29082 --- /dev/null +++ b/documentation/dev/src/specs/encoding/.gitignore @@ -0,0 +1 @@ +generated-borsh-spec.md \ No newline at end of file diff --git a/documentation/dev/src/specs/ledger.md b/documentation/dev/src/specs/ledger.md new file mode 100644 index 0000000000..54de087ca1 --- /dev/null +++ b/documentation/dev/src/specs/ledger.md @@ -0,0 +1,284 @@ +# The ledger + +The ledger's main responsibility is to process and apply [transactions](#transactions) over the [distributed ledger's storage](#storage), following the ledger's [protocol](#the-protocol) to reach consensus. + +## Accounts + +The ledger is backed by an account-based system. Each account has a unique [address](#addresses) and exactly one [validity predicate](#validity-predicates-check) and a [dynamic storage sub-space](#dynamic-storage-sub-space). + +### Addresses + +There are two main types of address: transparent and shielded. + +The transparent addresses are the addresses of accounts associated with dynamic storage sub-spaces, where the address of the account is the prefix key segment of its sub-space. + +The shielded addresses are used for private transactions and they are not directly associated with storage sub-spaces. + +#### Transparent addresses + +Furthermore, there are three types of transparent addresses: + +- "implicit" addresses which are derived from [public keys](crypto.md#public-keys) +- "established" addresses which are generated from the current address nonce and hence must be created via a request in the ledger +- "internal" addresses are used for special modules integrated into the ledger such as PoS and IBC. + +The addresses are stored on-chain encoded with [bech32m](https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki), which is an improved version of [bech32](https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki). + +The human-readable prefix (as specified for [bech32](https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#specification)) in the transparent address encoding is: + +- `"a"` for Anoma live network (80 characters in total) +- `"atest"` for test networks (84 characters in total) + +## Transactions + +A transaction has two layers, each wrapped inside [`Tx` type encoded with proto3](./encoding.md#transactions). + +The outer layer is employed for front-running protection following DKG protocol to wrap the inner layer, which remains encrypted before its block order has been committed. The outer layer MUST contain `data` with a [`TxType::Wrapper`](encoding.md#txtype) that has a [`WrapperTx`](encoding.md#wrappertx) inside it. + +The SHA-256 hash of this data [encoded with Borsh](encoding.html#borsh-binary-encoding) MUST be [signed](crypto.md#signatures) by an implicit account's key. The encoded signed data together with the signature should be encoded as a [`SignedTxData`](encoding.md#signedtxdata) and also encoded with Borsh. This data should then be attached to a protobuf encoded transaction's `data` field and the field `code` in this layer MUST be empty. Note that the outer layer's signature is not relevant to the inner layer of the transaction, only itself. + +The fields of a `WrapperTx` are: + +- `fee`: Fee to be payed by the source implicit account for including the tx in a block. +- `pk`: [Public key](crypto.md#public-keys) of the source implicit account. +- `epoch`: The [epoch](#epochs) in which the transaction is being included. This should be queried from a synchronized ledger node before the transaction is fully constructed. + + Note that this is currently not used and so the default value `0` may be used for now (depends on ). + +- `gas_limit`: Maximum amount of gas that can be used when executing the inner transaction +- `inner_tx`: The inner layer of the transaction. This MUST contain a [`Tx` type encoded with proto3](./encoding.md#transactions), encrypted against a public key that should be queried from a synchronized ledger node. + + The inner transaction's `Tx` MUST contain the WASM code to be executed and optionally any `data` (which will be provided to the transaction and any triggered validity predicates when they're invoked) to be executed and applied in a block (for example the [default transactions](ledger/default-transactions.md)). + + Please refer to the [signing of the default transactions](ledger/default-transactions.md#signing-transactions) to learn how to construct inner transaction's signatures which will be accepted by the [default validity predicates](ledger/default-validity-predicates.md). + + Note that currently the key doesn't change and so it stay constant for the duration of a chain and `::G1Affine::prime_subgroup_generator()` may be used to encrypt the inner transaction for now as done by the the [`WrapperTx::new` method](https://dev.anoma.net/master/rustdoc/anoma/types/transaction/wrapper/wrapper_tx/struct.WrapperTx.html#method.new) (depends on ). + +- `tx_hash`: A SHA-256 hash of the inner transaction. This MUST match the hash of decrypted `inner_tx`. + +TODO: wrapper transactions will include replay protection (this is because we can simply check a counter against the source (i.e. gas payer) of the transaction before the transactions order is committed to by the DKG protocol, which could affect the expected counter order for sources with multiple queued transactions) + +## The protocol + +When a tx is added to the [mempool](#mempool) and included in block by a block proposer, the [outer transaction is processed](#outer-transaction-processing) and if valid, its inner transaction is added to a transaction FIFO queue that MUST be in the same order as the outer transactions. + +An inner transaction popped from the queue is applied in a block executed in two main steps: + +1. [Inner transaction execution](#inner-transaction-execution) +1. [Validity predicates check](#validity-predicates-check) + +### Epochs + +An epoch is a range of blocks whose length is determined by the [epoch duration protocol parameter](#protocol-parameters): minimum epoch duration and minimum number of blocks in an epoch. They are identified by consecutive natural numbers starting at 0. The [Borsh encoded `Epoch`](encoding.md#epoch) for the last committed block can be queried via the [RPC](ledger/rpc.md#read-only-queries). + +### Protocol parameters + +The parameters are used to dynamically control certain variables in the protocol. They are implemented as an internal address with a native validity predicate. The current value of [Borsh encoded `Parameters`](encoding.md#parameters) is written into and read from the block storage in the parameters account's sub-space. + +Initial parameters for a chain are set in the genesis configuration. + +#### Epoch duration + +The parameters for [epoch](#epochs) duration are: + +- Minimum number of blocks in an epoch +- Minimum duration of an epoch + +### Mempool + +When a request to add a transaction to the mempool is received, it will only be added it's a [`Tx` encoded with proto3](./encoding.md#transactions). + +### Outer transaction processing + +TODO: describe outer tx fee check and deduction, inner tx decryption, tx queue up to the inner tx execution + +### Inner transaction execution + +For any error encountered in any of the following steps of transaction execution, the protocol MUST charge the gas used by the transaction and discard any storage changes that the transaction attempted to perform. + +1. Charge a base transaction [gas](#gas): + \\( \verb|BASE_TRANSACTION_FEE| \\) +1. Decode the transaction bytes and validate the data. The field `timestamp` is required. +1. Charge WASM compilation gas, proportional to the bytes `length` of the `code` field of the transaction (this is because the WASM code is compiled with a single-pass compiler): + \\( \verb|length| * \verb|COMPILE_GAS_PER_BYTE| \\) +1. [Validate the WASM code](#wasm-validation) from the `code` field of the transaction. +1. Inject a [gas counter](#gas) into the `code`. +1. Inject a [stack height](#stack-height-limiter) limiter into the `code`. +1. Compile the transaction `code` with a single-pass compiler (for example, [the Wasmer runtime single-pass compiler](https://medium.com/wasmer/a-webassembly-compiler-tale-9ef37aa3b537)). The compilation computational complexity MUST be linear in proportion to the `code` size. +1. Initialize the WASM linear memory with descriptor having the initial memory size equal to [`TX_MEMORY_INIT_PAGES`](#wasm-constants) and maximum memory size to [`TX_MEMORY_MAX_PAGES`](#wasm-constants). +1. Instantiate the WASM module with imported [transaction host environment functions](#transaction-host-environment-functions) and the instantiated WASM memory. +1. Write the transaction's `data` into the memory exported from the WASM module instance. +1. Attempt to call the module's entrypoint function. The entrypoint MUST have signature: + + ```wat + func (param i64 i64) + ``` + + The first argument is the offset to the `data` input written into the memory and the second argument is its bytes length. + +If the transaction executed successfully, it is followed [Validity predicates check](#validity-predicates-check). + +### Validity predicates check + +For the transaction to be valid, all the triggered validity predicates must accept it. + +First, the addresses whose validity predicates should be triggered by the transaction are determined: + +1. The addresses set by the transaction (see `insert_verifier` in [transaction host environment functions](#transaction-host-environment-functions)) are included in the verifiers set. +1. The storage keys that were modified by the transaction are inspected for addresses included in the storage key segments and these are also included in the verifiers set. Note that a storage key may contain more than one address, in which case all its addresses are included. This however excludes addresses of established accounts that were initialized in this transaction as they do not exist prior to transaction execution and a validity predicate will be associated with an initialized account only after the transaction is applied and accepted. This is intended as it allows users to initialize their account's storage without a validity predicate check. + +For all these addresses, attempt to read their validity predicate WASM code from the storage. For each validity predicate look-up, charge storage read gas and WASM compilation gas, proportional to the bytes length of the validity predicate. If any of the validity predicates look-ups fails, or any validity rejects the transaction or fails anywhere in the execution, the whole transaction is rejected. If the transaction is rejected, the protocol MUST charge the gas used by the transaction and discard any storage changes that the transaction attempted to perform. + +Execute all validity predicates in parallel as follows: + +1. Charge WASM compilation gas, proportional to the bytes length of the validity predicate (same as for the transaction, WASM code is compiled with a single-pass compiler). +1. Charge WASM compilation gas, proportional to the bytes `length` of the validity predicate (same as for the transaction, WASM code is compiled with a single-pass compiler): \\( \verb|length| * \verb|COMPILE_GAS_PER_BYTE| \\). +1. [Validate the WASM code](#wasm-validation) of the validity predicate. +1. Inject a [gas counter](#gas) into the `code`. +1. Inject a [stack height](#stack-height-limiter) limiter into the `code`. +1. Compile the validity predicate with single-pass compiler. The compilation computational complexity MUST be linear in proportion to its bytes size. +1. Initialize the WASM linear memory with descriptor having the initial memory size equal to [`VP_MEMORY_INIT_PAGES`](#wasm-constants) and maximum memory size to [`VP_MEMORY_MAX_PAGES`](#wasm-constants). +1. Instantiate the WASM module with imported [validity predicate host environment functions](#validity-predicate-host-environment-functions) and the instantiated WASM memory. +1. Write the address of the validity predicate’s owner, the transaction `data`, the modified storage keys encoded with Borsh, and all the triggered validity predicates owners' addresses encoded with Borsh into the memory exported from the WASM module instance. +1. Attempt to call the module's entrypoint function. The entrypoint MUST have signature: + + ```wat + func (param i64 i64 i64 i64 i64 i64 i64 i64) (result i64)) + ``` + + - The first argument is the offset to the owner’s address written into the memory, the second argument is its bytes length + - The third is the offset of the transaction’s `data` and fourth is it’s bytes length + - The fifth is the offset of the modified storage keys and sixth is its bytes length + - The seventh is the offset of the triggered validity predicates owners' addresses and eighth is its bytes length + +### Gas + +#### Gas constants + +The gas constants are currently chosen arbitrarily and are subject to change following gas accounting estimations. + +| Name | Value | +|------------------------|-------| +| `COMPILE_GAS_PER_BYTE` | 1 | +| `BASE_TRANSACTION_FEE` | 2 | +| `PARALLEL_GAS_DIVIDER` | 10 | +| `MIN_STORAGE_GAS` | 1 | + +- TODO describe gas accounting, wasm gas counter, limits, what happens if we go over limits and how gas relates to fees + +### WebAssembly (WASM) + +#### WASM constants + +| Name | Unit | Value | +|--------------------------------------|-------------------|-------| +| `PAGE` (as defined in the WASM spec) | kiB | 64 | +| `TX_MEMORY_INIT_PAGES` | number of `PAGE`s | 100 | +| `TX_MEMORY_MAX_PAGES` | number of `PAGE`s | 200 | +| `VP_MEMORY_INIT_PAGES` | number of `PAGE`s | 100 | +| `VP_MEMORY_MAX_PAGES` | number of `PAGE`s | 200 | +| `WASM_STACK_LIMIT` | stack depth | 65535 | + +The WASM instantiation, the types, instructions, validation and execution of WASM modules MUST conform to the [WebAssembly specification](https://webassembly.github.io/spec/core/intro/index.html). + +#### WASM validation + +The WebAssembly code is REQUIRED to only use deterministic instructions. Furthermore, it MUST NOT use features from any of the following WebAssembly proposals: + +- The reference types proposal +- The multi-value proposal +- The bulk memory operations proposal +- The module linking proposal +- The SIMD proposal +- The threads proposal +- The tail-call proposal +- The multi memory proposal +- The exception handling proposal +- The memory64 proposal + +#### Stack height limiter + +To make stack overflows deterministic, set the upper bound of the stack size to [`WASM_STACK_LIMIT`](#wasm-constants). If the stack height exceeds the limit then execution MUST abort. + + + +#### WASM memory + +- TODO memory read/write gas costs + +#### Transaction host environment functions + +The following functions from the host ledger are made available in transaction's WASM code. They MAY be imported in the WASM module as shown bellow and MUST be provided by the ledger's WASM runtime: + +```wat +(import "env" "gas" (func (param i32))) +(import "env" "anoma_tx_read" (func (param i64 i64) (result i64))) +(import "env" "anoma_tx_result_buffer" (func (param i64))) +(import "env" "anoma_tx_has_key" (func (param i64 i64) (result i64))) +(import "env" "anoma_tx_write" (func (param i64 i64 i64 i64))) +(import "env" "anoma_tx_delete" (func (param i64 i64))) +(import "env" "anoma_tx_iter_prefix" (func (param i64 i64) (result i64))) +(import "env" "anoma_tx_iter_next" (func (param i64) (result i64))) +(import "env" "anoma_tx_insert_verifier" (func (param i64 i64))) +(import "env" "anoma_tx_update_validity_predicate" (func (param i64 i64 i64 i64))) +(import "env" "anoma_tx_init_account" (func (param i64 i64 i64))) +(import "env" "anoma_tx_get_chain_id" (func (param i64))) +(import "env" "anoma_tx_get_block_height" (func (param ) (result i64))) +(import "env" "anoma_tx_get_block_hash" (func (param i64))) +(import "env" "anoma_tx_log_string" (func (param i64 i64))) +``` + +Additionally, the WASM module MUST export its memory as shown: + +```wat +(export "memory" (memory 0)) +``` + +- `anoma_tx_init_account` TODO newly created accounts' validity predicates aren't used until the block is committed (i.e. only the transaction that created the account may write into its storage in the block in which its being applied). +- TODO describe functions in detail + +#### Validity predicate host environment functions + +The following functions from the host ledger are made available in validity predicate's WASM code. They MAY be imported in the WASM module as shown bellow and MUST be provided by the ledger's WASM runtime. + +```wat +(import "env" "gas" (func (param i32))) +(import "env" "anoma_vp_read_pre" (func (param i64 i64) (result i64))) +(import "env" "anoma_vp_read_post" (func (param i64 i64) (result i64))) +(import "env" "anoma_vp_result_buffer" (func (param i64))) +(import "env" "anoma_vp_has_key_pre" (func (param i64 i64) (result i64))) +(import "env" "anoma_vp_has_key_post" (func (param i64 i64) (result i64))) +(import "env" "anoma_vp_iter_prefix" (func (param i64 i64) (result i64))) +(import "env" "anoma_vp_iter_pre_next" (func (param i64) (result i64))) +(import "env" "anoma_vp_iter_post_next" (func (param i64) (result i64))) +(import "env" "anoma_vp_get_chain_id" (func (param i64))) +(import "env" "anoma_vp_get_block_height" (func (param ) (result i64))) +(import "env" "anoma_vp_get_block_hash" (func (param i64))) +(import "env" "anoma_vp_verify_tx_signature" (func (param i64 i64 i64 i64) (result i64))) +(import "env" "anoma_vp_eval" (func (param i64 i64 i64 i64) (result i64))) +``` + +- TODO describe functions in detail + +Additionally, the WASM module MUST export its memory as shown: + +```wat +(export "memory" (memory 0)) +``` + +### Storage + +- TODO dynamic key-value storage paths, encoding agnostic, any ledger native keys such as the VP key +- TODO VPs must be written into the storage as raw bytes without any additional encoding + +#### Storage keys + +- TODO spec the key segments, punct, reserved VP segment `?` and address prefix `#` + +#### Dynamic storage sub-space + +Each account can have an associated dynamic account state in the storage. This +state may be comprised of keys with a format specified above and values of arbitrary user bytes. The first segment of all the keys must be the account's address. diff --git a/documentation/dev/src/specs/ledger/default-transactions.md b/documentation/dev/src/specs/ledger/default-transactions.md new file mode 100644 index 0000000000..78b04ff48d --- /dev/null +++ b/documentation/dev/src/specs/ledger/default-transactions.md @@ -0,0 +1,57 @@ +# Default transactions + +The Anoma client comes with a set of pre-built transactions. Note that the Anoma ledger is agnostic about the format of the transactions beyond the format described in [ledger transaction section](../ledger.md#transactions). + +The [default validity predicates](default-validity-predicates.md) can be used to initialize the network's genesis block. These expect the data in the storage to be encoded with [Borsh](../encoding.md#borsh-binary-encoding) and are fully compatible with the default transactions described below. + +## Rust-to-WASM transactions + +The following transactions are pre-built from Rust code and can be used by clients interacting with the Anoma ledger. + +The pre-built WASM code's raw bytes should be attached to the transaction's `code` field. The transactions expect certain variables to be provided via the transaction's `data` field encoded with [Borsh](../encoding.md#borsh-binary-encoding). + +### tx_init_account + +Initialize a new [established account](../../explore/design/ledger/accounts.md#established-transparent-addresses) on the chain. + +To use this transaction, attach [InitAccount](../encoding.md#initaccount) to the `data`. + +### tx_init_validator + +Initialize a new validator account on the chain. + +Attach [InitValidator](../encoding.md#initvalidator) to the `data`. + +### tx_transfer + +Transparently transfer `amount` of fungible `token` from the `source` to the `target`. + +Attach [Transfer](../encoding.md#transfer) to the `data`. + +### tx_update_vp + +Update a validity predicate of an established account. + +Attach [UpdateVp](../encoding.md#updatevp) to the `data`. + +### tx_bond + +Self-bond `amount` of XAN token from `validator` (without `source`) or delegate to `validator` from `source`. + +Attach [Bond](../encoding.md#bond) to the `data`. + +### tx_unbond + +Unbond self-bonded `amount` of XAN token from the `validator` (without `source`) or unbond delegation from the `source` to the `validator`. + +Attach [Bond](../encoding.md#bond) to the `data`. + +### tx_withdraw + +Withdraw unbonded self-bond from the `validator` (without `source`) or withdraw unbonded delegation from the `source` to the `validator`. + +Attach [Withdraw](../encoding.md#withdraw) to the `data`. + +## Signing transactions + +To sign transactions in format that is understood and thus can be verified by the [default validity predicates](default-validity-predicates.md), the SHA-256 hash of the `data` [encoded with Borsh](../encoding.html#borsh-binary-encoding) MUST be [signed](../crypto.md#signatures) by an implicit or established account's key. The encoded signed data together with the signature should be encoded as a [`SignedTxData`](../encoding.md#signedtxdata) and also encoded with Borsh. This data should then be attached to a protobuf encoded transaction's `data` field. diff --git a/documentation/dev/src/specs/ledger/default-validity-predicates.md b/documentation/dev/src/specs/ledger/default-validity-predicates.md new file mode 100644 index 0000000000..894a5df493 --- /dev/null +++ b/documentation/dev/src/specs/ledger/default-validity-predicates.md @@ -0,0 +1,7 @@ +# Default validity predicates + +The Anoma ledger and client comes with a set of pre-built validity predicates. + +## Rust-to-WASM validity predicates + +TODO diff --git a/documentation/dev/src/specs/ledger/rpc.md b/documentation/dev/src/specs/ledger/rpc.md new file mode 100644 index 0000000000..c536967670 --- /dev/null +++ b/documentation/dev/src/specs/ledger/rpc.md @@ -0,0 +1,45 @@ +# RPC + +The ledger provides an RPC interface for submitting transactions to the mempool, subscribing to their results and queries about the state of the ledger and its storage. + +The RPC interface is provided as [specified](https://github.com/tendermint/spec/tree/4566f1e3028278c5b3eca27b53254a48771b152b/spec/rpc) from Tendermint and most of the requests are routed to the Anoma ledger via ABCI. + +## Transactions + +A [transaction](../ledger.md#transactions) can be submitted to the [mempool](../ledger.md#mempool) via Tendermint's [`BroadCastTxSync`](https://github.com/tendermint/spec/tree/4566f1e3028278c5b3eca27b53254a48771b152b/spec/rpc#broadcasttxsync) or [`BroadCastTxAsync`](https://github.com/tendermint/spec/tree/4566f1e3028278c5b3eca27b53254a48771b152b/spec/rpc#broadcasttxasync). The `CheckTx` result of these requests is success only if the transaction passes [mempool validation rules](../ledger.md#mempool). In case of `BroadCastTxAsync`, the `DeliverTx` is not indicative of the transaction's result, it's merely a result of the transaction being added to the [transaction queue](../ledger.md#outer-transaction-processing). The actual result of the outer transaction and the inner transaction can be found from via the [ABCI events](https://github.com/tendermint/spec/blob/4566f1e3028278c5b3eca27b53254a48771b152b/spec/abci/abci.md#events). + +To find a result of the inner transaction, query for event with `type` equal to `"NewBlock"` and key equal to `"applied.hash"`, where the `value` of the found `Event` will contain `TxResult` pretty-printed as a string (TODO proper encoding depends on ). + +## Read-only queries + +Read-only queries can be requested via [ABCIQuery](https://github.com/tendermint/spec/tree/4566f1e3028278c5b3eca27b53254a48771b152b/spec/rpc#abciquery). The `path` for the query can be one of the following options: + +- `epoch`: Get the [epoch](../ledger.md#epochs) of the last committed block. The response `value` is always known [Borsh encoded `Epoch`](../encoding.md#epoch) +- `dry_run_tx`: Simulate a transaction being applied in a block. The response `code = 0` means that the transaction would be accepted by all the validity predicates that verified its validity. On success, the response `info` contains the `TxResult` pretty-printed as a string (TODO proper encoding depends on ). +- `value/{dynamic}`: Look-up a raw [storage](../ledger.md#storage) value for the given `dynamic` key. When the response `code = 0`, the key is found and the response `value` contains the raw bytes of the value. +- `prefix/{dynamic}`: Iterate a [storage](../ledger.md#storage) key prefix for the given `dynamic` key. When the response `code = 0`, the key is found and the response `value` contains [Borsh encoded `Vec`](../encoding.md#prefixvalue), where each `PrefixValue` contains the `key` and the raw bytes of the `value`. +- `has_key/{dynamic}`: check if the given `dynamic` key is present in the [storage](../ledger.md#storage). The response `value` contains [Borsh encoded](../encoding.md#borsh-binary-encoding) boolean that is `true` if the key has been found. + +For example, to find if an established address exists on-chain, we can submit a query to find if it has a validity predicate at path `has_key/#{established_address}/?`, which is the only storage value required for established addresses (note that `#` is a special storage key segment prefix for bech32m encoded addresses and `?` character is used as the last segment of a validity predicate storage key). + +## PoS + +TODO document response types encoding after + +The Proof-of-Stake queries are built on top of the [read-only queries](#read-only-queries), where all the PoS data are stored under the [internal `PoS` address](../encoding.html#internaladdress), which is governed by its native validity predicate. The bech32m encoded address of the PoS account currently is `"atest1v9hx7w362pex7mmxyphkvgznw3skkefqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqq8ylv7"`, in the storage keys below in place of `PoS`. + +Note that in the query paths below (and in all storage keys in general), addresses are encoded with bech32m and prefixed with `#` character. + +- `#{PoS}/bond/#{validator}/#{validator}`: validator self-bonds, where `validator` is its bech32m encoded address +- `#{PoS}/bond/#{owner}/#{validator}`: delegation bonds, where `owner` is the delegation source and `validator` the delegation target +- `#{PoS}/unbond/#{validator}/#{validator}`: unbonded validator self-bonds, where `validator` is its bech32m encoded address +- `#{PoS}/unbond/#{owner}/#{validator}`: unbonded delegation bonds, where `owner` is the delegation source and `validator` the delegation target +- `#{PoS}/validator/#{validator}/voting_power`: `validator`'s voting power +- `#{PoS}/slash/#{validator}`: slashes applied to the `validator`, if any + +## Default validity predicate storage queries + +The [default validity predicate](default-validity-predicates.md) for the implicit accounts and token accounts enforce a format for the account's storage. This storage can be queried at the following paths: + +- public key +- token balance diff --git a/documentation/dev/src/specs/overview.md b/documentation/dev/src/specs/overview.md new file mode 100644 index 0000000000..2b9c7e15c7 --- /dev/null +++ b/documentation/dev/src/specs/overview.md @@ -0,0 +1,19 @@ +# Overview + +At a high level, Anoma is composed of two main components: the distributed ledger and the intent gossip / matchmaking system. While they are designed to complement each other, they can be operated separately. + +## The ledger + +The [ledger](ledger.md) is a distributed state machine, relying on functionality provided by [Tendermint](https://docs.tendermint.com/master/spec/) such as its BFT consensus algorithm with instant finality, P2P networking capabilities, transaction mempool and more. The ledger state machine is built on top the [ABCI](https://docs.tendermint.com/master/spec/abci/). + +For block validator voting power assignment, the ledger employs a proof-of-stake system. + +The ledger's key-value storage is organized into blocks and user specific state is organized into accounts. The state machine executes transactions, which can apply arbitrary changes to the state that are validated by validity predicates associated with the accounts involved in the transaction. + +To prevent transaction front-running, the ledger employs a DKG scheme as implemented in [Ferveo](https://github.com/anoma/ferveo). Using this scheme, transactions are encrypted before being submitted to the ledger. The encrypted transactions are committed by a block proposer to a specific order in which they must be executed once decrypted. + +- TODO add fractal scaling & protocol upgrade system overview + +## The intent gossip with matchmaking system + +- TODO add an overview diff --git a/documentation/dev/theme/favicon.png b/documentation/dev/theme/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..f34029b97164e824eaf0dd6d37db05e11c5e7a8c GIT binary patch literal 5037 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 DRwPG| literal 0 HcmV?d00001 diff --git a/documentation/dev/theme/favicon.svg b/documentation/dev/theme/favicon.svg new file mode 100644 index 0000000000..d3343977ed --- /dev/null +++ b/documentation/dev/theme/favicon.svg @@ -0,0 +1,6 @@ + + + + + + From 5a3868a924873686d9d22ef8072b57560983069f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zemanovi=C4=8D?= Date: Tue, 2 Aug 2022 18:19:32 +0200 Subject: [PATCH 005/118] docs/dev: remove intent_gossip and prototypes pages --- documentation/dev/src/SUMMARY.md | 11 - .../dev/src/explore/design/gossip.md | 17 - .../explore/design/gossip_process.excalidraw | 966 -------- .../dev/src/explore/design/gossip_process.svg | 16 - .../design/intent_gossip/example.excalidraw | 2202 ----------------- .../explore/design/intent_gossip/example.svg | 16 - .../design/intent_gossip/fungible_token.md | 35 - .../intent_gossip/gossip_process.excalidraw | 966 -------- .../design/intent_gossip/gossip_process.svg | 16 - .../explore/design/intent_gossip/incentive.md | 9 - .../explore/design/intent_gossip/intent.md | 28 - .../design/intent_gossip/intent_gossip.md | 51 - .../intent_life_cycle.excalidraw | 1686 ------------- .../intent_gossip/intent_life_cycle.svg | 16 - .../design/intent_gossip/matchmaker.md | 80 - .../intent_gossip/matchmaker_graph.excalidraw | 1648 ------------ .../design/intent_gossip/matchmaker_graph.png | Bin 156552 -> 0 bytes .../design/intent_gossip/matchmaker_graph.svg | 16 - .../matchmaker_process.excalidraw | 1883 -------------- .../intent_gossip/matchmaker_process.svg | 16 - .../src/explore/design/intent_gossip/topic.md | 11 - .../dev/src/explore/prototypes/README.md | 23 - .../dev/src/explore/prototypes/base-ledger.md | 112 - .../src/explore/prototypes/gossip-layer.md | 61 - 24 files changed, 9885 deletions(-) delete mode 100644 documentation/dev/src/explore/design/gossip.md delete mode 100644 documentation/dev/src/explore/design/gossip_process.excalidraw delete mode 100644 documentation/dev/src/explore/design/gossip_process.svg delete mode 100644 documentation/dev/src/explore/design/intent_gossip/example.excalidraw delete mode 100644 documentation/dev/src/explore/design/intent_gossip/example.svg delete mode 100644 documentation/dev/src/explore/design/intent_gossip/fungible_token.md delete mode 100644 documentation/dev/src/explore/design/intent_gossip/gossip_process.excalidraw delete mode 100644 documentation/dev/src/explore/design/intent_gossip/gossip_process.svg delete mode 100644 documentation/dev/src/explore/design/intent_gossip/incentive.md delete mode 100644 documentation/dev/src/explore/design/intent_gossip/intent.md delete mode 100644 documentation/dev/src/explore/design/intent_gossip/intent_gossip.md delete mode 100644 documentation/dev/src/explore/design/intent_gossip/intent_life_cycle.excalidraw delete mode 100644 documentation/dev/src/explore/design/intent_gossip/intent_life_cycle.svg delete mode 100644 documentation/dev/src/explore/design/intent_gossip/matchmaker.md delete mode 100644 documentation/dev/src/explore/design/intent_gossip/matchmaker_graph.excalidraw delete mode 100644 documentation/dev/src/explore/design/intent_gossip/matchmaker_graph.png delete mode 100644 documentation/dev/src/explore/design/intent_gossip/matchmaker_graph.svg delete mode 100644 documentation/dev/src/explore/design/intent_gossip/matchmaker_process.excalidraw delete mode 100644 documentation/dev/src/explore/design/intent_gossip/matchmaker_process.svg delete mode 100644 documentation/dev/src/explore/design/intent_gossip/topic.md delete mode 100644 documentation/dev/src/explore/prototypes/README.md delete mode 100644 documentation/dev/src/explore/prototypes/base-ledger.md delete mode 100644 documentation/dev/src/explore/prototypes/gossip-layer.md diff --git a/documentation/dev/src/SUMMARY.md b/documentation/dev/src/SUMMARY.md index f0d84c6afa..fee1b6fb27 100644 --- a/documentation/dev/src/SUMMARY.md +++ b/documentation/dev/src/SUMMARY.md @@ -4,14 +4,6 @@ - [Exploration](./explore/README.md) - [Design](./explore/design/README.md) - [Overview](./explore/design/overview.md) - - [Gossip network](./explore/design/gossip.md) - - [Intent gossip](./explore/design/intent_gossip/intent_gossip.md) - - [Intent](./explore/design/intent_gossip/intent.md) - - [Topic](./explore/design/intent_gossip/topic.md) - - [Incentive](./explore/design/intent_gossip/incentive.md) - - [Matchmaker](./explore/design/intent_gossip/matchmaker.md) - - [Fungible token](./explore/design/intent_gossip/fungible_token.md) - - [Distributed key generation gossip](./explore/design/dkg.md) - [The ledger](./explore/design/ledger.md) - [Parameters](./explore/design/ledger/parameters.md) - [Epochs](./explore/design/ledger/epochs.md) @@ -30,9 +22,6 @@ - [Proof of Stake system](./explore/design/pos.md) - [Testnet setup](./explore/design/testnet-setup.md) - [Testnet launch procedure](./explore/design/testnet-launch-procedure/README.md) - - [Prototypes](./explore/prototypes/README.md) - - [Base ledger](./explore/prototypes/base-ledger.md) - - [Gossip layer](./explore/prototypes/gossip-layer.md) - [Libraries & Tools](./explore/libraries/README.md) - [Cryptography]() - [network](./explore/libraries/network.md) diff --git a/documentation/dev/src/explore/design/gossip.md b/documentation/dev/src/explore/design/gossip.md deleted file mode 100644 index 4879363d33..0000000000 --- a/documentation/dev/src/explore/design/gossip.md +++ /dev/null @@ -1,17 +0,0 @@ -# The gossip network - -The gossip network runs in parallel to the ledger network and is used to -propagate off-chain information. The network is based on -[libp2p](https://libp2p.io/) , a peer to peer network system that is implemented -in different languages, has a large user base and an active development. It -allows us to readily implement a network to run our application. - -The gossip network is used to propagate messages of two different applications, -intents for the [intent gossip system](intent_gossip/intent_gossip.md), and message for distributed keys -generation application. - -## Flow diagram: High level overview - -![gossip process](./gossip_process.svg "gossip process") - -[Diagram on Excalidraw](https://excalidraw.com/#room=5d4a2a84ef52cf5f5f96,r4ghl40frJ9putMy-0vyOQ) diff --git a/documentation/dev/src/explore/design/gossip_process.excalidraw b/documentation/dev/src/explore/design/gossip_process.excalidraw deleted file mode 100644 index 3684252693..0000000000 --- a/documentation/dev/src/explore/design/gossip_process.excalidraw +++ /dev/null @@ -1,966 +0,0 @@ -{ - "type": "excalidraw", - "version": 2, - "source": "https://excalidraw.com", - "elements": [ - { - "type": "ellipse", - "version": 603, - "versionNonce": 717195654, - "isDeleted": false, - "id": "9XNyo7y8QCSEp4yAFf5oy", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1156.111111111111, - "y": 164.3333333333334, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 573.6666666666667, - "height": 372.55555555555554, - "seed": 821968881, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [] - }, - { - "type": "arrow", - "version": 1450, - "versionNonce": 941173851, - "isDeleted": false, - "id": "lXNINuf2v3Bas7FefE3LH", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1586.2054115693877, - "y": -370.2728566628903, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 246.73688630955917, - "height": 192.92404363452567, - "seed": 736805503, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "5xDzwVV0gDBlD-WL85LYy", - "focus": 0.18717224637187657, - "gap": 6.459472910604248 - }, - "endBinding": { - "elementId": "xxAsLeElpbNGHmw4QPxMz", - "focus": -0.23250849205562685, - "gap": 13.411672225924079 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -246.73688630955917, - 192.92404363452567 - ] - ] - }, - { - "type": "diamond", - "version": 278, - "versionNonce": 198810363, - "isDeleted": false, - "id": "5xDzwVV0gDBlD-WL85LYy", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1565.6666666666665, - "y": -444.66666666666663, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 127, - "height": 100, - "seed": 563016927, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "lXNINuf2v3Bas7FefE3LH", - "RR6GEDZFWUssCdTAnrDqo" - ] - }, - { - "type": "text", - "version": 253, - "versionNonce": 1818093109, - "isDeleted": false, - "id": "HskYIBtFFYajWD-2Djn1f", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1605.1666666666665, - "y": -409.66666666666663, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 50, - "height": 26, - "seed": 1643469585, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "lXNINuf2v3Bas7FefE3LH" - ], - "fontSize": 20, - "fontFamily": 1, - "text": "client", - "baseline": 18, - "textAlign": "center", - "verticalAlign": "middle" - }, - { - "type": "rectangle", - "version": 432, - "versionNonce": 232368667, - "isDeleted": false, - "id": "5cPSOu9KDeCIp3Nmd546m", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1176, - "y": -287.2222222222222, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 570.0000000000001, - "height": 356.2222222222222, - "seed": 1306655743, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [] - }, - { - "type": "diamond", - "version": 627, - "versionNonce": 1842306310, - "isDeleted": false, - "id": "xxAsLeElpbNGHmw4QPxMz", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1181.3333333333333, - "y": -207.55555555555554, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 209, - "height": 188, - "seed": 1389553521, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "B4iQSfzoi419GYzKlXw5m", - "MPfW6JEUQYoWrzHeI_NxD", - "z6DMUeY7qrwuosEZr9D8K", - "GJPwvquPv4Afa-iz06Txv", - "bleUDuct9nWGxJfhyl_J2", - "V6oy4uJc_J45aC2sNpHvE", - "lXNINuf2v3Bas7FefE3LH", - "OIBiMf6VpPETwJAGERKti", - "J8EUyGyYHRSW895zskWbp" - ] - }, - { - "type": "diamond", - "version": 604, - "versionNonce": 1476920774, - "isDeleted": false, - "id": "dSBMH7Bqm1h_eoLM_yqkZ", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1184.4444444444446, - "y": 264.99999999999994, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 307.888888888889, - "height": 215.66666666666666, - "seed": 1838896927, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "OIBiMf6VpPETwJAGERKti", - "MPfW6JEUQYoWrzHeI_NxD", - "FqT97u9kn8yPY-e9ZEmwX", - "3w6C3S5gFIBLSOSnHrL9p", - "J8EUyGyYHRSW895zskWbp" - ] - }, - { - "type": "text", - "version": 446, - "versionNonce": 2067771125, - "isDeleted": false, - "id": "FOQ3kxQ9jn8r8iZ6-5Kdn", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1227.3333333333333, - "y": -149.55555555555551, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 121, - "height": 52, - "seed": 1118918783, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "Intent \nbroadcaster", - "baseline": 44, - "textAlign": "center", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 346, - "versionNonce": 94289307, - "isDeleted": false, - "id": "wNwxFCvE4WMQV8QLZiqxu", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1272, - "y": 281.99999999999994, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 131, - "height": 78, - "seed": 197177745, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "OIBiMf6VpPETwJAGERKti", - "MPfW6JEUQYoWrzHeI_NxD", - "J8EUyGyYHRSW895zskWbp" - ], - "fontSize": 20, - "fontFamily": 1, - "text": "intent\nbroadcaster \nnetwork", - "baseline": 70, - "textAlign": "center", - "verticalAlign": "top" - }, - { - "type": "arrow", - "version": 1548, - "versionNonce": 1059405510, - "isDeleted": false, - "id": "OIBiMf6VpPETwJAGERKti", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1340.8991464307837, - "y": 256.43457590166764, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 19.424658574333307, - "height": 274.53680436823555, - "seed": 413185503, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "dSBMH7Bqm1h_eoLM_yqkZ", - "focus": 0.06980420648639936, - "gap": 8.455707710143173 - }, - "endBinding": { - "elementId": "xxAsLeElpbNGHmw4QPxMz", - "focus": -0.27643465526659067, - "gap": 24.916176360598527 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -19.424658574333307, - -274.53680436823555 - ] - ] - }, - { - "type": "arrow", - "version": 1783, - "versionNonce": 702656213, - "isDeleted": false, - "id": "MPfW6JEUQYoWrzHeI_NxD", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1225.7890453334985, - "y": -41.97976066319893, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 21.266468152933612, - "height": 381.0875685373966, - "seed": 1670492081, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "xxAsLeElpbNGHmw4QPxMz", - "gap": 23.483962590379445, - "focus": 0.5312629502131418 - }, - "endBinding": { - "elementId": "dSBMH7Bqm1h_eoLM_yqkZ", - "gap": 16.103707014847412, - "focus": -0.8818009263489358 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -21.266468152933612, - 381.0875685373966 - ] - ] - }, - { - "type": "text", - "version": 540, - "versionNonce": 1475775174, - "isDeleted": false, - "id": "InLHuKJiMfsKjnhDLER2S", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1224.6666666666667, - "y": 122.99999999999997, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 88, - "height": 52, - "seed": 1075843217, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "validate \nmsg", - "baseline": 44, - "textAlign": "right", - "verticalAlign": "top" - }, - { - "type": "arrow", - "version": 1384, - "versionNonce": 280535450, - "isDeleted": false, - "id": "J8EUyGyYHRSW895zskWbp", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1386.7368978905408, - "y": 286.51414709947557, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 19.54258711706757, - "height": 343.3666092756827, - "seed": 1500547647, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "dSBMH7Bqm1h_eoLM_yqkZ", - "focus": 0.34597438474774744, - "gap": 10.117038200934843 - }, - "endBinding": { - "elementId": "xxAsLeElpbNGHmw4QPxMz", - "focus": -0.7476913039884736, - "gap": 26.682463765500543 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -19.54258711706757, - -343.3666092756827 - ] - ] - }, - { - "type": "text", - "version": 452, - "versionNonce": 1029595482, - "isDeleted": false, - "id": "3a6V_ozlu_-z813t_fjbn", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1391, - "y": 187.77777777777777, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 156, - "height": 36, - "seed": 15072497, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 28, - "fontFamily": 1, - "text": "libP2P logic", - "baseline": 25, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "diamond", - "version": 365, - "versionNonce": 757518677, - "isDeleted": false, - "id": "hngD3gT8MxLbMtULxwILm", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1204.6111111111113, - "y": -434.0000000000001, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 127, - "height": 100, - "seed": 662285233, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "lXNINuf2v3Bas7FefE3LH", - "V6oy4uJc_J45aC2sNpHvE" - ] - }, - { - "type": "text", - "version": 334, - "versionNonce": 979982971, - "isDeleted": false, - "id": "Tne4ggu_ZDCdoqKD1HVLY", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1244.1111111111113, - "y": -402.0000000000001, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 50, - "height": 26, - "seed": 1728898015, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "lXNINuf2v3Bas7FefE3LH" - ], - "fontSize": 20, - "fontFamily": 1, - "text": "client", - "baseline": 18, - "textAlign": "center", - "verticalAlign": "middle" - }, - { - "type": "arrow", - "version": 1682, - "versionNonce": 1212570555, - "isDeleted": false, - "id": "V6oy4uJc_J45aC2sNpHvE", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1262.664151563201, - "y": -330.8400855354932, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 2.5819871518015134, - "height": 140.4581124311759, - "seed": 1528357951, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "hngD3gT8MxLbMtULxwILm", - "focus": 0.10105347446704833, - "gap": 5.8523740982304915 - }, - "endBinding": { - "elementId": "xxAsLeElpbNGHmw4QPxMz", - "focus": -0.18349209857314347, - "gap": 1 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 2.5819871518015134, - 140.4581124311759 - ] - ] - }, - { - "type": "text", - "version": 377, - "versionNonce": 1391350555, - "isDeleted": false, - "id": "q9mdbiPTZ5bMiHS1pP8Jd", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1267.8333333333333, - "y": -327.77777777777777, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 86, - "height": 26, - "seed": 280036991, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "send msg", - "baseline": 18, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 138, - "versionNonce": 2055493659, - "isDeleted": false, - "id": "JdaaIi8F9pCIbQiuefyHi", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1388.75, - "y": -206.72222222222223, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 180, - "height": 35, - "seed": 476397371, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 28, - "fontFamily": 3, - "text": "Gossip Node", - "baseline": 28, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 419, - "versionNonce": 1035911669, - "isDeleted": false, - "id": "E1bibepZLZFj3VmWghmhk", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1557.1388888888887, - "y": -324.94444444444554, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 86, - "height": 26, - "seed": 1482472437, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "send msg", - "baseline": 18, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "diamond", - "version": 629, - "versionNonce": 251582106, - "isDeleted": false, - "id": "JaiST4fQ2FlodcbDsHGRd", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1525.611111111111, - "y": -178.99999999999997, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 209, - "height": 188, - "seed": 1161636571, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "B4iQSfzoi419GYzKlXw5m", - "MPfW6JEUQYoWrzHeI_NxD", - "z6DMUeY7qrwuosEZr9D8K", - "GJPwvquPv4Afa-iz06Txv", - "bleUDuct9nWGxJfhyl_J2", - "RR6GEDZFWUssCdTAnrDqo", - "yZ1sDbO9UxZw6Yw7d8BGk", - "sofyhfQ6yAERl8W7igqud", - "98jHSy6KgIgI-kigPhATL", - "Jj-F4u_NSjuW-tVWK6ErH" - ] - }, - { - "type": "text", - "version": 477, - "versionNonce": 320811829, - "isDeleted": false, - "id": "yE8obB-cq-eO9tpUS_PcA", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1575.611111111111, - "y": -117.99999999999994, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 121, - "height": 52, - "seed": 413385813, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "DKG \nbroadcaster", - "baseline": 44, - "textAlign": "center", - "verticalAlign": "top" - }, - { - "type": "arrow", - "version": 115, - "versionNonce": 808640859, - "isDeleted": false, - "id": "RR6GEDZFWUssCdTAnrDqo", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1660.0572555330295, - "y": -366.9575940330065, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 24.665187381169744, - "height": 183.91639038865497, - "seed": 45437883, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "5xDzwVV0gDBlD-WL85LYy", - "focus": -0.5447225569886008, - "gap": 1.5967808146620044 - }, - "endBinding": { - "elementId": "JaiST4fQ2FlodcbDsHGRd", - "focus": -0.07528645180716763, - "gap": 6.5362537154315845 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -24.665187381169744, - 183.91639038865497 - ] - ] - }, - { - "type": "diamond", - "version": 596, - "versionNonce": 1248600538, - "isDeleted": false, - "id": "sJFOeRzApKjnkoavWYSOm", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1415.6666666666667, - "y": 270.6666666666667, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 292.8888888888888, - "height": 207.6666666666666, - "seed": 3834485, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "OIBiMf6VpPETwJAGERKti", - "MPfW6JEUQYoWrzHeI_NxD", - "FqT97u9kn8yPY-e9ZEmwX", - "3w6C3S5gFIBLSOSnHrL9p", - "J8EUyGyYHRSW895zskWbp", - "yZ1sDbO9UxZw6Yw7d8BGk", - "sofyhfQ6yAERl8W7igqud", - "98jHSy6KgIgI-kigPhATL", - "Jj-F4u_NSjuW-tVWK6ErH" - ] - }, - { - "type": "text", - "version": 354, - "versionNonce": 339994458, - "isDeleted": false, - "id": "ERwB6OfVxtsDLuZO1G4dn", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1507.2222222222224, - "y": 292.6666666666667, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 131, - "height": 78, - "seed": 410831707, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "OIBiMf6VpPETwJAGERKti", - "MPfW6JEUQYoWrzHeI_NxD", - "yZ1sDbO9UxZw6Yw7d8BGk" - ], - "fontSize": 20, - "fontFamily": 1, - "text": "DKG\nbroadcaster \nnetwork", - "baseline": 70, - "textAlign": "center", - "verticalAlign": "top" - }, - { - "type": "arrow", - "version": 432, - "versionNonce": 855557126, - "isDeleted": false, - "id": "yZ1sDbO9UxZw6Yw7d8BGk", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1613.2645903010791, - "y": 5.6816480400971585, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 32.37650849922488, - "height": 267.8739593512054, - "seed": 978571771, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "JaiST4fQ2FlodcbDsHGRd", - "focus": 0.056328322376417134, - "gap": 8.799318498256582 - }, - "endBinding": { - "elementId": "ERwB6OfVxtsDLuZO1G4dn", - "focus": 0.016268660508214034, - "gap": 19.11105927536414 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -32.37650849922488, - 267.8739593512054 - ] - ] - }, - { - "type": "arrow", - "version": 398, - "versionNonce": 2067988678, - "isDeleted": false, - "id": "Jj-F4u_NSjuW-tVWK6ErH", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1623.0089473868802, - "y": 304.406818117378, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 33.75764899556157, - "height": 307.2241654227815, - "seed": 398843163, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "sJFOeRzApKjnkoavWYSOm", - "focus": 0.3632505836483008, - "gap": 7.699251414567215 - }, - "endBinding": { - "elementId": "JaiST4fQ2FlodcbDsHGRd", - "focus": -0.3414897328591685, - "gap": 9.04048516465393 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 33.75764899556157, - -307.2241654227815 - ] - ] - }, - { - "type": "text", - "version": 554, - "versionNonce": 720882453, - "isDeleted": false, - "id": "kXVNso4ItXnAMFArYHbYk", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1486.1111111111115, - "y": 109.99999999999997, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 88, - "height": 52, - "seed": 1662723835, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "validate \nmsg", - "baseline": 44, - "textAlign": "right", - "verticalAlign": "top" - } - ], - "appState": { - "gridSize": null, - "viewBackgroundColor": "#ffffff" - } -} \ No newline at end of file diff --git a/documentation/dev/src/explore/design/gossip_process.svg b/documentation/dev/src/explore/design/gossip_process.svg deleted file mode 100644 index 32a046a1ac..0000000000 --- a/documentation/dev/src/explore/design/gossip_process.svg +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - clientIntent broadcasterintentbroadcaster networkvalidate msglibP2P logicclientsend msgGossip Nodesend msgDKG broadcasterDKGbroadcaster networkvalidate msg \ No newline at end of file diff --git a/documentation/dev/src/explore/design/intent_gossip/example.excalidraw b/documentation/dev/src/explore/design/intent_gossip/example.excalidraw deleted file mode 100644 index 876d8a453b..0000000000 --- a/documentation/dev/src/explore/design/intent_gossip/example.excalidraw +++ /dev/null @@ -1,2202 +0,0 @@ -{ - "type": "excalidraw", - "version": 2, - "source": "https://excalidraw.com", - "elements": [ - { - "type": "text", - "version": 686, - "versionNonce": 1681340216, - "isDeleted": false, - "id": "8-d43siu84Jr4CoHQ4O3h", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 87.4761904761906, - "y": 120.73809523809535, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 188, - "height": 120, - "seed": 454219117, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 16, - "fontFamily": 3, - "text": "- 400 < X < 1000 USD\n- rate USD to EUR: \n >= 1.5 EUR/USD\n- rate USD to CZK:\n >= 10 USD/CZK\n- in less than 20 mn", - "baseline": 116, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 196, - "versionNonce": 124057672, - "isDeleted": false, - "id": "pMCzM8kGspun9xkTr6k5d", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 61.95238095238085, - "y": 83.64285714285725, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 94, - "height": 25, - "seed": 1950434275, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 3, - "text": "- DATA: ", - "baseline": 20, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "rectangle", - "version": 295, - "versionNonce": 1203474488, - "isDeleted": false, - "id": "2p7QI8-lBoSz4ic4BK3eT", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 44.61904761904748, - "y": 43.0714285714287, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 284.3809523809525, - "height": 245.90476190476187, - "seed": 1582276557, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "oYCojvs3_Pz8ZGLg2mw3V", - "954BBr80PqUI9uJuWnFsM", - "uKTSmBiHZULyjH127gePI", - "Czhwb2CjT6al5-6rCgR97" - ] - }, - { - "type": "text", - "version": 156, - "versionNonce": 1336848200, - "isDeleted": false, - "id": "h9Y3DYl2lfuXh9QZLoKSa", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 63.39285714285711, - "y": 255.0476190476184, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 152, - "height": 25, - "seed": 668258179, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 3, - "text": "- timestamp T", - "baseline": 20, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "rectangle", - "version": 448, - "versionNonce": 1263323448, - "isDeleted": false, - "id": "UiaZM4EJyss7ILeYlY9LS", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 75.14285714285711, - "y": 118.35714285714295, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 247.28571428571422, - "height": 129.47619047619048, - "seed": 138681901, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "oYCojvs3_Pz8ZGLg2mw3V", - "bMCs-OrsKdLPqnA1PVwiv", - "954BBr80PqUI9uJuWnFsM" - ] - }, - { - "type": "text", - "version": 255, - "versionNonce": 1940489800, - "isDeleted": false, - "id": "MBhNEXU9Gx54BPICMfGTq", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 66.14285714285711, - "y": 47.3333333333334, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 217, - "height": 52, - "seed": 607512355, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "oYCojvs3_Pz8ZGLg2mw3V", - "954BBr80PqUI9uJuWnFsM" - ], - "fontSize": 20, - "fontFamily": 1, - "text": "intent from account A\n", - "baseline": 44, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "arrow", - "version": 1706, - "versionNonce": 441377336, - "isDeleted": false, - "id": "HBiEEEb8ounDRLLN9wXKf", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 797.2148759236247, - "y": 300.28571428571433, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 82.58839012004557, - "height": 92.74093504094964, - "seed": 1181817966, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "UXXI91T9S5l9KHt7Wp0ZV", - "gap": 1, - "focus": -0.6432089438320445 - }, - "endBinding": { - "elementId": "Vva_ZJK0PzeOvHwKtR1hx", - "gap": 4.782874482859853, - "focus": 0.22336105149411092 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -82.58839012004557, - 92.74093504094964 - ] - ] - }, - { - "type": "arrow", - "version": 1822, - "versionNonce": 540114248, - "isDeleted": false, - "id": "oYCojvs3_Pz8ZGLg2mw3V", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 492.80297633357, - "y": 292.13629393845633, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 30.182646679681625, - "height": 92.45738907898789, - "seed": 1847628014, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "hf7oNcONr_HxLhhGRiJqE", - "gap": 10.279151081313444, - "focus": 0.38338854643484865 - }, - "endBinding": { - "elementId": "Vva_ZJK0PzeOvHwKtR1hx", - "gap": 13.215840792079547, - "focus": -0.011602561064372598 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 30.182646679681625, - 92.45738907898789 - ] - ] - }, - { - "type": "rectangle", - "version": 315, - "versionNonce": 1403378488, - "isDeleted": false, - "id": "UXXI91T9S5l9KHt7Wp0ZV", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -2.309523809529537, - "y": -69.04761904761892, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 1041.3809523809525, - "height": 368.33333333333326, - "seed": 1810420256, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "oYCojvs3_Pz8ZGLg2mw3V", - "HBiEEEb8ounDRLLN9wXKf" - ] - }, - { - "type": "arrow", - "version": 941, - "versionNonce": 111318088, - "isDeleted": false, - "id": "Swcv4ZXJejaz5TYfHeDMu", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 876.138834695055, - "y": -424.07142857142946, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 9.184895705945564, - "height": 459.29069763915254, - "seed": 936098418, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "usikQRBWwYKM-qybe0fQH", - "gap": 2, - "focus": -0.255388727353868 - }, - "endBinding": { - "elementId": "swYlyjktS4gIwsiQLSPjZ", - "gap": 9.066445217991259, - "focus": 0.15984810321549953 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -9.184895705945564, - 459.29069763915254 - ] - ] - }, - { - "type": "rectangle", - "version": 310, - "versionNonce": 431338552, - "isDeleted": false, - "id": "usikQRBWwYKM-qybe0fQH", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 774.0119047619048, - "y": -530.0714285714295, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 164, - "height": 104, - "seed": 354374066, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "Swcv4ZXJejaz5TYfHeDMu", - "ol2AB4uLuMEYj138srSeF" - ] - }, - { - "type": "rectangle", - "version": 312, - "versionNonce": 1289276232, - "isDeleted": false, - "id": "swYlyjktS4gIwsiQLSPjZ", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 700, - "y": 44.285714285714334, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 282.8571428571426, - "height": 236, - "seed": 345326578, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "HBiEEEb8ounDRLLN9wXKf", - "Swcv4ZXJejaz5TYfHeDMu" - ] - }, - { - "type": "text", - "version": 268, - "versionNonce": 576875832, - "isDeleted": false, - "id": "wXWmmm8mpOqmxFuLw0x-V", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 798.0119047619048, - "y": -481.07142857142946, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 101, - "height": 26, - "seed": 992734510, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "account C", - "baseline": 18, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 171, - "versionNonce": 2100306504, - "isDeleted": false, - "id": "XDW5IfPRFhlKsj3a1RbYD", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 553.8333333333278, - "y": 327.61904761904776, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 127, - "height": 26, - "seed": 1564124704, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "fetch intents", - "baseline": 18, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "arrow", - "version": 1247, - "versionNonce": 1192232504, - "isDeleted": false, - "id": "954BBr80PqUI9uJuWnFsM", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 522.3067180843871, - "y": -423.5118681617779, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 5.583297287089863, - "height": 443.7930802552394, - "seed": 467951874, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "bDFsD9RIYPQQrHIWUfc_E", - "focus": 0.21113172608583025, - "gap": 6.8690842191745105 - }, - "endBinding": { - "elementId": "hf7oNcONr_HxLhhGRiJqE", - "focus": 0.002175851518750341, - "gap": 15.671168858919486 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -5.583297287089863, - 443.7930802552394 - ] - ] - }, - { - "type": "text", - "version": 399, - "versionNonce": 1988401480, - "isDeleted": false, - "id": "dYXMYP8IeZ5hPB8hDXUkx", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 488.66666666666674, - "y": -491.04761904761915, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 99, - "height": 26, - "seed": 1024864898, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "account B", - "baseline": 18, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 167, - "versionNonce": 1546793032, - "isDeleted": false, - "id": "Z7BWkND-NitKxr9Ih4Ie2", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 389.80952380952374, - "y": 76.52380952380958, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 94, - "height": 25, - "seed": 469053826, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 3, - "text": "- DATA: ", - "baseline": 20, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "rectangle", - "version": 268, - "versionNonce": 1534974008, - "isDeleted": false, - "id": "hf7oNcONr_HxLhhGRiJqE", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 372.47619047619037, - "y": 35.95238095238102, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 284.3809523809525, - "height": 245.90476190476187, - "seed": 25601394, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "oYCojvs3_Pz8ZGLg2mw3V", - "954BBr80PqUI9uJuWnFsM" - ] - }, - { - "type": "text", - "version": 459, - "versionNonce": 102033224, - "isDeleted": false, - "id": "oRS3euY4VEuk2SgUKpr1L", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 718.5714285714287, - "y": 138.8095238095238, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 188, - "height": 80, - "seed": 655184434, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 16, - "fontFamily": 3, - "text": "- 0 < X < 0.05 BTC \n- rate BTC to EUR: \n >= 0.00001 BTC/USD\n- in less than 1 mn", - "baseline": 76, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 182, - "versionNonce": 1065750840, - "isDeleted": false, - "id": "XrVgeTerY-7DS-ka0p0Em", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 716.5, - "y": 242.59523809523824, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 176, - "height": 25, - "seed": 1477693777, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 3, - "text": "- timestamp T''", - "baseline": 20, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 128, - "versionNonce": 1888009800, - "isDeleted": false, - "id": "d8WVAhFQ2zo-3HuEkCg6h", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 391.25, - "y": 247.9285714285707, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 164, - "height": 25, - "seed": 204593966, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 3, - "text": "- timestamp T'", - "baseline": 20, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "rectangle", - "version": 426, - "versionNonce": 1210001976, - "isDeleted": false, - "id": "Nkvl_WfjngjOTgW9Zbs2_", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 390, - "y": 111.2380952380953, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 247.28571428571422, - "height": 129.47619047619048, - "seed": 1239365918, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "oYCojvs3_Pz8ZGLg2mw3V", - "bMCs-OrsKdLPqnA1PVwiv", - "954BBr80PqUI9uJuWnFsM" - ] - }, - { - "type": "rectangle", - "version": 337, - "versionNonce": 745125192, - "isDeleted": false, - "id": "LxE-VPfS6ezu0mmzjr8F1", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 712.8571428571429, - "y": 130.2380952380953, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 237.2857142857145, - "height": 105.47619047619037, - "seed": 423857246, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [] - }, - { - "type": "text", - "version": 530, - "versionNonce": 640619320, - "isDeleted": false, - "id": "Hk5l9iiBugHCCPMbYtU63", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 12.624999999999886, - "y": 1537.291666666666, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 410, - "height": 250, - "seed": 212882431, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 3, - "text": "if someone takes between\ntx.DATA.A.low to tx.DATA.A.high \ntx.DATA.A.output_asset \nfrom my account,\nit has to credit\nat least tx.DATA.A.min_rate \nthe amount in tx.DATA.A.input_asset\n and to be before\n (tx.DATA.A.timestamp\n + tx.DATA.A.TTL)", - "baseline": 245, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 645, - "versionNonce": 1326697544, - "isDeleted": false, - "id": "EygNVoDyqnn-JbFybEbGe", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 287.5238095238093, - "y": 660.2380952380953, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 281, - "height": 350, - "seed": 2012467634, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 3, - "text": "- STATE FUNCTION : \n - 1/ src: A\n dest: C\n amount: 466.6 USD\n - 2/ src: C\n dest: B\n amount: 800 EUR\n - 3/ src: B \n dest: A\n amount: 0.017 BTC\n- DATA\n - 1/ intent A\n - 2/ intent B\n - 3/ intent C", - "baseline": 345, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "rectangle", - "version": 378, - "versionNonce": 1618836792, - "isDeleted": false, - "id": "0XL0H0k8apgsdhnJ1t5ab", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": -3.9166666666667425, - "y": 1448.4999999999995, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 447.08333333333337, - "height": 377.9166666666665, - "seed": 124501362, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "Zd243WE5eHC_WR8epiEAk", - "bMcnnlJo1LpwISJChgmKB", - "69EnjeqAfSHRFsprrsmiO", - "5qf0tF76bMQXA21Z0jkWa", - "cnhSr0ikLZ2glzJteomgZ", - "Jo906mQj2gE8MfU639rAz", - "ubXW8sd3hkMXVly_O_ZOm", - "8R2CEj2oEGuvX1dqJ8gCY" - ] - }, - { - "type": "arrow", - "version": 858, - "versionNonce": 2126699080, - "isDeleted": false, - "id": "Jo906mQj2gE8MfU639rAz", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 468.4392508864622, - "y": 1386.951149425287, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 197.84511112482477, - "height": 37.33444576972829, - "seed": 1746017906, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "VvkwdNT_ReB6o1cn6jyZr", - "focus": -0.3762898352769947, - "gap": 2.034482758620584 - }, - "endBinding": { - "elementId": "0XL0H0k8apgsdhnJ1t5ab", - "focus": -0.8806478681490097, - "gap": 24.21440480498427 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -197.84511112482477, - 37.33444576972829 - ] - ] - }, - { - "type": "text", - "version": 241, - "versionNonce": 1174694472, - "isDeleted": false, - "id": "rDu3FdPNopgW6z9PCoHab", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 480.66666666666674, - "y": 1342.1666666666663, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 96, - "height": 26, - "seed": 1492486702, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "check VPs", - "baseline": 18, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "rectangle", - "version": 357, - "versionNonce": 2070927672, - "isDeleted": false, - "id": "TsHuKC9fQpBlBOzMikQ_z", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 305.83333333333326, - "y": 1874.75, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 442.4999999999999, - "height": 382.91666666666646, - "seed": 1984398894, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "y1ij4QN5do9jfy8-88ASN", - "MmzmsyscAAK-oBSzk0-T_", - "tjHofHebcS4-4X76vqi0M" - ] - }, - { - "type": "arrow", - "version": 1601, - "versionNonce": 108809784, - "isDeleted": false, - "id": "GN1g4nPawR3Tizbo7OUxq", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 438.53788770476547, - "y": 517.4917358318999, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 1.8992073358202788, - "height": 90.2497092278901, - "seed": 471491378, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": null, - "endBinding": { - "elementId": "VEHFhWJtyqbM7CEJvy1OY", - "gap": 6.496650178305457, - "focus": -0.2974579993705736 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -1.8992073358202788, - 90.2497092278901 - ] - ] - }, - { - "type": "rectangle", - "version": 371, - "versionNonce": 1915086408, - "isDeleted": false, - "id": "VEHFhWJtyqbM7CEJvy1OY", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 268, - "y": 606.2380952380953, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 471.19047619047615, - "height": 412.00000000000006, - "seed": 465481138, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "GN1g4nPawR3Tizbo7OUxq", - "9m0lD6nkNLEEuDZhOAFaq" - ] - }, - { - "type": "rectangle", - "version": 541, - "versionNonce": 793102136, - "isDeleted": false, - "id": "Vva_ZJK0PzeOvHwKtR1hx", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 193.7142857142859, - "y": 397.8095238095238, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 721.2857142857143, - "height": 138.52380952380955, - "seed": 926229486, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "oYCojvs3_Pz8ZGLg2mw3V", - "HBiEEEb8ounDRLLN9wXKf", - "GN1g4nPawR3Tizbo7OUxq", - "Czhwb2CjT6al5-6rCgR97" - ] - }, - { - "type": "text", - "version": 295, - "versionNonce": 642213960, - "isDeleted": false, - "id": "1nPK7swUFkn2ZECAVz_c2", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 466.71428571428567, - "y": 399.7142857142857, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 201, - "height": 46, - "seed": 985887602, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "GN1g4nPawR3Tizbo7OUxq", - "oYCojvs3_Pz8ZGLg2mw3V", - "HBiEEEb8ounDRLLN9wXKf" - ], - "fontSize": 36, - "fontFamily": 1, - "text": "matchmaker", - "baseline": 32, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 227, - "versionNonce": 1383604280, - "isDeleted": false, - "id": "-G2iBkHpCw0y563oTofms", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 394, - "y": 40.21428571428572, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 218, - "height": 52, - "seed": 1376390450, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "oYCojvs3_Pz8ZGLg2mw3V", - "954BBr80PqUI9uJuWnFsM" - ], - "fontSize": 20, - "fontFamily": 1, - "text": "intent from account B\n", - "baseline": 44, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 161, - "versionNonce": 1220747080, - "isDeleted": false, - "id": "HA5fUOkkjum0HgfnMlIBG", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 733, - "y": 60.95238095238096, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 220, - "height": 26, - "seed": 1992833394, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "intent from account C", - "baseline": 18, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 153, - "versionNonce": 1878481208, - "isDeleted": false, - "id": "nBttw1DAeptrX2lVgvsY7", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 720.7142857142857, - "y": 95.95238095238096, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 82, - "height": 25, - "seed": 1251151454, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 3, - "text": "- DATA:", - "baseline": 20, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "arrow", - "version": 896, - "versionNonce": 407405112, - "isDeleted": false, - "id": "9m0lD6nkNLEEuDZhOAFaq", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 508.568121346975, - "y": 1021.1321908520348, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 3.1429313226068984, - "height": 312.2365395554883, - "seed": 1155072110, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "VEHFhWJtyqbM7CEJvy1OY", - "focus": -0.01207639830586925, - "gap": 2.894095613939328 - }, - "endBinding": { - "elementId": "VvkwdNT_ReB6o1cn6jyZr", - "focus": -0.14754250955099754, - "gap": 2.381269592476542 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 3.1429313226068984, - 312.2365395554883 - ] - ] - }, - { - "type": "text", - "version": 299, - "versionNonce": 580155464, - "isDeleted": false, - "id": "hiykXkLOlmLVWGgrQKtH8", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 532.9999999999999, - "y": 1144.9999999999998, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 265, - "height": 26, - "seed": 2146825074, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "send transaction to ledger", - "baseline": 18, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 212, - "versionNonce": 1497632824, - "isDeleted": false, - "id": "7Ng3PQpN63cbVPHR8aHrn", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 46.66666666666663, - "y": 1475.7499999999995, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 51, - "height": 26, - "seed": 983757230, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "A VP:", - "baseline": 18, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 271, - "versionNonce": 1492004680, - "isDeleted": false, - "id": "AuP1LD1e9BIzr9fnDJADl", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 324.58333333333326, - "y": 1904.5, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 52, - "height": 26, - "seed": 1592796398, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "B VP:", - "baseline": 18, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "rectangle", - "version": 309, - "versionNonce": 1344396616, - "isDeleted": false, - "id": "VvkwdNT_ReB6o1cn6jyZr", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 433.16666666666674, - "y": 1335.7499999999998, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 185, - "height": 49.166666666666735, - "seed": 1653182898, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "9m0lD6nkNLEEuDZhOAFaq", - "Jo906mQj2gE8MfU639rAz", - "tjHofHebcS4-4X76vqi0M", - "o8vZWSYePDHs1bN3foTMP" - ] - }, - { - "type": "arrow", - "version": 981, - "versionNonce": 846653512, - "isDeleted": false, - "id": "tjHofHebcS4-4X76vqi0M", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 513.8848064154693, - "y": 1386.951149425287, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 2.1447670720162932, - "height": 467.54798651113333, - "seed": 572567090, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "VvkwdNT_ReB6o1cn6jyZr", - "focus": 0.12853479300213336, - "gap": 2.034482758620584 - }, - "endBinding": { - "elementId": "TsHuKC9fQpBlBOzMikQ_z", - "focus": -0.045390860814372345, - "gap": 20.250864063579456 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 2.1447670720162932, - 467.54798651113333 - ] - ] - }, - { - "type": "text", - "version": 349, - "versionNonce": 540359496, - "isDeleted": false, - "id": "0L6p1qM6u_tVfVgCK_FDY", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 333.14285714285734, - "y": 623.5238095238096, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 307, - "height": 24, - "seed": 2092627950, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 2, - "text": "TRANSACTION from matchmaker ", - "baseline": 17, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "ellipse", - "version": 643, - "versionNonce": 356842808, - "isDeleted": false, - "id": "PcxdOS9NrJhMOgUW0faBx", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -165.8333333333394, - "y": -331.6666666666668, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 1361.333333333333, - "height": 1437.3809523809525, - "seed": 2083480096, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [] - }, - { - "type": "text", - "version": 218, - "versionNonce": 192844360, - "isDeleted": false, - "id": "A6kNrvnIcbKPUZ5GodYoX", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 353.2142857142801, - "y": -291.6666666666665, - "strokeColor": "#364fc7", - "backgroundColor": "transparent", - "width": 364, - "height": 92, - "seed": 389688288, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 36, - "fontFamily": 1, - "text": "Intent broadcaster \nnetwork", - "baseline": 78, - "textAlign": "center", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 158, - "versionNonce": 1595971128, - "isDeleted": false, - "id": "nVSCWf4TYONMAlK6r7v7u", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 607.1666666666612, - "y": -49.71428571428561, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 193, - "height": 36, - "seed": 1611512800, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 28, - "fontFamily": 1, - "text": "global mempool", - "baseline": 25, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 635, - "versionNonce": 293931336, - "isDeleted": false, - "id": "HVqr4I6oVLiB-7Smz4WBL", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 264.6904761904701, - "y": 450.04761904761926, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 584, - "height": 78, - "seed": 644801056, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "GN1g4nPawR3Tizbo7OUxq" - ], - "fontSize": 19.896103896103885, - "fontFamily": 1, - "text": "The matchmacker chooses values for the transaction that\n he thinks will be accepted by the ledger (the validity\npredicate of each account).", - "baseline": 70, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "ellipse", - "version": 452, - "versionNonce": 2052606792, - "isDeleted": false, - "id": "0ilp60kgFqvYZ-R-LlZ_8", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -241.6666666666722, - "y": 1238.6666666666663, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 1547.3333333333326, - "height": 1465.0000000000002, - "seed": 312942560, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [] - }, - { - "type": "text", - "version": 369, - "versionNonce": 781905208, - "isDeleted": false, - "id": "gwJeBcdO_DYmasftBcHif", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 537.8333333333277, - "y": 1261.1666666666665, - "strokeColor": "#364fc7", - "backgroundColor": "transparent", - "width": 258, - "height": 46, - "seed": 721258016, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 36, - "fontFamily": 1, - "text": "ledger network", - "baseline": 32, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 683, - "versionNonce": 1321181768, - "isDeleted": false, - "id": "jU8TxFoAubCE7Tws_-GtR", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 321.8333333333276, - "y": 1954.5, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 410, - "height": 250, - "seed": 1682625504, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 3, - "text": "if someone takes between\ntx.DATA.B.amount \ntx.DATA.B.output_asset \nfrom my account,\nit has to credit\nat least tx.DATA.B.min_rate \nthe amount in tx.DATA.B.input_asset\n and to be before\n (tx.DATA.B.timestamp \n + tx.DATA.C.TTL)", - "baseline": 245, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "arrow", - "version": 1227, - "versionNonce": 385840712, - "isDeleted": false, - "id": "MmzmsyscAAK-oBSzk0-T_", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 537.0941616654786, - "y": 2275.9127064518443, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 0.8399583165244167, - "height": 211.42062688148872, - "seed": 331186144, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "TsHuKC9fQpBlBOzMikQ_z", - "focus": -0.041338956392506655, - "gap": 18.246039785178027 - }, - "endBinding": { - "elementId": "OLiV9Yr0v-YQNJbhTqcuZ", - "focus": 0.664082386729967, - "gap": 1 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 0.8399583165244167, - 211.42062688148872 - ] - ] - }, - { - "type": "text", - "version": 379, - "versionNonce": 884140088, - "isDeleted": false, - "id": "OLiV9Yr0v-YQNJbhTqcuZ", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 508.83333333332746, - "y": 2488.333333333333, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 35, - "height": 25, - "seed": 258550752, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "cnhSr0ikLZ2glzJteomgZ", - "MmzmsyscAAK-oBSzk0-T_", - "r3K74Ft73zYbYmn37KM_a", - "8R2CEj2oEGuvX1dqJ8gCY", - "xfJTcfqB9FHSZl9nnr-SE" - ], - "fontSize": 20, - "fontFamily": 3, - "text": "...", - "baseline": 20, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 172, - "versionNonce": 1265089080, - "isDeleted": false, - "id": "bnfip1RTsFRJNftw4HckK", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 470.8809523809465, - "y": 574.2857142857144, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 175, - "height": 26, - "seed": 111981536, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "craft transaction", - "baseline": 18, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "rectangle", - "version": 370, - "versionNonce": 1269966152, - "isDeleted": false, - "id": "bDFsD9RIYPQQrHIWUfc_E", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 458.49999999999466, - "y": -534.3809523809524, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 164, - "height": 104, - "seed": 1802037792, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "Swcv4ZXJejaz5TYfHeDMu", - "ol2AB4uLuMEYj138srSeF", - "954BBr80PqUI9uJuWnFsM" - ] - }, - { - "type": "text", - "version": 336, - "versionNonce": 467907384, - "isDeleted": false, - "id": "xzml5UDbVyEJKPO3if06i", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 816.5273034941135, - "y": -372.08003798021025, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 43, - "height": 26, - "seed": 806763701, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "send", - "baseline": 18, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 385, - "versionNonce": 1271807048, - "isDeleted": false, - "id": "X0SNHo6dQnl8irYcF3Ubf", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 529.5273034941135, - "y": -385.08003798021025, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 43, - "height": 26, - "seed": 207870843, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "send", - "baseline": 18, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 448, - "versionNonce": 1282968632, - "isDeleted": false, - "id": "TVJpZzxoPMIinWFy_aK1i", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 212.9761904761957, - "y": -498.9599810098948, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 98, - "height": 52, - "seed": 505781699, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "account A\n", - "baseline": 44, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "rectangle", - "version": 415, - "versionNonce": 1045394248, - "isDeleted": false, - "id": "E7FV6AEnvxE7fX_r3_TzW", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 182.80952380952374, - "y": -542.2933143432281, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 164, - "height": 104, - "seed": 1994281965, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "Swcv4ZXJejaz5TYfHeDMu", - "ol2AB4uLuMEYj138srSeF", - "954BBr80PqUI9uJuWnFsM", - "uKTSmBiHZULyjH127gePI" - ] - }, - { - "type": "text", - "version": 429, - "versionNonce": 654984504, - "isDeleted": false, - "id": "l3RrMlLKlU9laipGh-WIb", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 253.8368273036425, - "y": -392.9923999424859, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 43, - "height": 26, - "seed": 735243619, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "send", - "baseline": 18, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "arrow", - "version": 247, - "versionNonce": 1502726728, - "isDeleted": false, - "id": "uKTSmBiHZULyjH127gePI", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 254.78140471240346, - "y": -433.642857142857, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 18.07520040340512, - "height": 446.8986715332853, - "seed": 1473743181, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "E7FV6AEnvxE7fX_r3_TzW", - "focus": 0.14647529307932466, - "gap": 4.650457200371079 - }, - "endBinding": { - "elementId": "2p7QI8-lBoSz4ic4BK3eT", - "focus": 0.6266906023232607, - "gap": 29.815614181000413 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 18.07520040340512, - 446.8986715332853 - ] - ] - }, - { - "type": "arrow", - "version": 214, - "versionNonce": 419225144, - "isDeleted": false, - "id": "Czhwb2CjT6al5-6rCgR97", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 251.88178381509215, - "y": 291.02380952380963, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 52.803167627033986, - "height": 104.42857142857144, - "seed": 1533710979, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "2p7QI8-lBoSz4ic4BK3eT", - "gap": 2.047619047619051, - "focus": 0.017984625714246562 - }, - "endBinding": { - "elementId": "Vva_ZJK0PzeOvHwKtR1hx", - "gap": 2.3571428571426907, - "focus": -0.5394946080216643 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 52.803167627033986, - 104.42857142857144 - ] - ] - }, - { - "type": "text", - "version": 439, - "versionNonce": 1127503672, - "isDeleted": false, - "id": "mgtimTjmkfFageE4a_ALC", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 401.95238095238096, - "y": 117.14285714285734, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 188, - "height": 80, - "seed": 1741274855, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 16, - "fontFamily": 3, - "text": "- 800 EUR\n- rate EUR to BTC: \n >= 47058 EUR/BTC\n- in less than 10 mn", - "baseline": 76, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "rectangle", - "version": 349, - "versionNonce": 859410232, - "isDeleted": false, - "id": "n8qBdtjdYuoZicswHAM8Z", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 605.3690476190475, - "y": 1444.017857142857, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 442.4999999999999, - "height": 382.91666666666646, - "seed": 1102897255, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "tjHofHebcS4-4X76vqi0M", - "y1ij4QN5do9jfy8-88ASN", - "MmzmsyscAAK-oBSzk0-T_", - "o8vZWSYePDHs1bN3foTMP", - "r3K74Ft73zYbYmn37KM_a", - "xfJTcfqB9FHSZl9nnr-SE" - ] - }, - { - "type": "text", - "version": 268, - "versionNonce": 554150456, - "isDeleted": false, - "id": "kEAF_yIT_4cO4uX63467_", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 624.1190476190475, - "y": 1473.767857142857, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 54, - "height": 26, - "seed": 1833762185, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "C VP:", - "baseline": 18, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 691, - "versionNonce": 340342088, - "isDeleted": false, - "id": "LgtU9c20p3iojrteT7TOy", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 621.3690476190416, - "y": 1523.767857142857, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 410, - "height": 250, - "seed": 405945223, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 3, - "text": "if someone takes between\ntx.DATA.C.low to tx.DATA.C. high \ntx.DATA.C.output_asset \nfrom my account,\nit has to credit\nat least tx.DATA.C.min_rate \nthe amount in tx.DATA.C.input_asset\n and to be before\n (tx.DATA.C.timestamp\n + tx.DATA.C.TTL)", - "baseline": 245, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "arrow", - "version": 341, - "versionNonce": 1631355976, - "isDeleted": false, - "id": "o8vZWSYePDHs1bN3foTMP", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 622.3113514729953, - "y": 1387.3092905570172, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 131.8668164720766, - "height": 50.16689991917315, - "seed": 1895758345, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "VvkwdNT_ReB6o1cn6jyZr", - "focus": -0.16380407789917548, - "gap": 4.1446848063285415 - }, - "endBinding": { - "elementId": "n8qBdtjdYuoZicswHAM8Z", - "focus": 0.6183687597387931, - "gap": 6.5416666666667425 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 131.8668164720766, - 50.16689991917315 - ] - ] - }, - { - "id": "8R2CEj2oEGuvX1dqJ8gCY", - "type": "arrow", - "x": 166.28016609367018, - "y": 1833.6428571428573, - "width": 333.2772811594371, - "height": 669.3349011418622, - "angle": 0, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "round", - "seed": 973478472, - "version": 390, - "versionNonce": 235803208, - "isDeleted": false, - "boundElementIds": null, - "points": [ - [ - 0, - 0 - ], - [ - 61.005548192043705, - 588.333333333333 - ], - [ - 333.2772811594371, - 669.3349011418622 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "0XL0H0k8apgsdhnJ1t5ab", - "focus": 0.3030726950488866, - "gap": 7.226190476191277 - }, - "endBinding": { - "elementId": "OLiV9Yr0v-YQNJbhTqcuZ", - "focus": -0.5710015327583038, - "gap": 9.275886080220175 - }, - "startArrowhead": null, - "endArrowhead": "arrow" - }, - { - "type": "arrow", - "version": 540, - "versionNonce": 1649680456, - "isDeleted": false, - "id": "xfJTcfqB9FHSZl9nnr-SE", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 875.4506366524696, - "y": 1845.3095238095234, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 316.498255700089, - "height": 653.299399447023, - "seed": 253988936, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "n8qBdtjdYuoZicswHAM8Z", - "focus": -0.2859002709985485, - "gap": 18.374999999999773 - }, - "endBinding": { - "elementId": "OLiV9Yr0v-YQNJbhTqcuZ", - "focus": 0.4400244271235751, - "gap": 15.119047619053163 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -53.16492236675572, - 571.6666666666665 - ], - [ - -316.498255700089, - 653.299399447023 - ] - ] - } - ], - "appState": { - "gridSize": null, - "viewBackgroundColor": "#ffffff" - } -} \ No newline at end of file diff --git a/documentation/dev/src/explore/design/intent_gossip/example.svg b/documentation/dev/src/explore/design/intent_gossip/example.svg deleted file mode 100644 index 9a5a48a38c..0000000000 --- a/documentation/dev/src/explore/design/intent_gossip/example.svg +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - 400 < X < 1000 USD- rate USD to EUR: >= 1.5 EUR/USD- rate USD to CZK: >= 10 USD/CZK- in less than 20 mn- DATA: - timestamp Tintent from account Aaccount Cfetch intentsaccount B- DATA: - 0 < X < 0.05 BTC - rate BTC to EUR: >= 0.00001 BTC/USD- in less than 1 mn- timestamp T''- timestamp T'if someone takes betweentx.DATA.A.low to tx.DATA.A.high tx.DATA.A.output_asset from my account,it has to creditat least tx.DATA.A.min_rate the amount in tx.DATA.A.input_asset and to be before (tx.DATA.A.timestamp + tx.DATA.A.TTL)- STATE FUNCTION : - 1/ src: A dest: C amount: 466.6 USD - 2/ src: C dest: B amount: 800 EUR - 3/ src: B dest: A amount: 0.017 BTC- DATA - 1/ intent A - 2/ intent B - 3/ intent Ccheck VPsmatchmakerintent from account Bintent from account C- DATA:send transaction to ledgerA VP:B VP:TRANSACTION from matchmaker Intent broadcaster networkglobal mempoolThe matchmacker chooses values for the transaction that he thinks will be accepted by the ledger (the validitypredicate of each account).ledger networkif someone takes betweentx.DATA.B.amount tx.DATA.B.output_asset from my account,it has to creditat least tx.DATA.B.min_rate the amount in tx.DATA.B.input_asset and to be before (tx.DATA.B.timestamp + tx.DATA.C.TTL)...craft transactionsendsendaccount Asend- 800 EUR- rate EUR to BTC: >= 47058 EUR/BTC- in less than 10 mnC VP:if someone takes betweentx.DATA.C.low to tx.DATA.C. high tx.DATA.C.output_asset from my account,it has to creditat least tx.DATA.C.min_rate the amount in tx.DATA.C.input_asset and to be before (tx.DATA.C.timestamp + tx.DATA.C.TTL) \ No newline at end of file diff --git a/documentation/dev/src/explore/design/intent_gossip/fungible_token.md b/documentation/dev/src/explore/design/intent_gossip/fungible_token.md deleted file mode 100644 index 43a34c5c94..0000000000 --- a/documentation/dev/src/explore/design/intent_gossip/fungible_token.md +++ /dev/null @@ -1,35 +0,0 @@ -# Fungible token encoding and template - -The Heliax team implemented an intent encoding, a filter program template, and a -matchmaker program template that can be used to exchange fungible tokens between -any number of participants. - -## Intent encoding -The intent encoding allows the expression of a desire to participate in an asset -exchange. The encoding is defined as follows : - -```protobuf -message FungibleToken { - string address = 1; - string token_sell = 2; - int64 max_sell = 3; - int64 rate_min = 4; - string token_buy = 5; - int64 min_buy = 6; - google.protobuf.Timestamp expire = 7; -} -``` - -## Matchmaker program - -The filter program attempts to decode the intent and if successful, checks -that it's not yet expired and that the account address has enough funds for the -intended token to be sold. - -The main program can match intents for exchanging assets. It does that by -creating a graph from all intents. When a cycle is found then it removes all -intents from that cycle of the mempool and crafts a transaction based on all the -removed intents. - -![matchmaker](matchmaker_graph.svg) -[excalidraw link](https://excalidraw.com/#room=1db86ba6d5f0ccb7447c,2vvRd4X2Y3HDWHihJmy9zw) diff --git a/documentation/dev/src/explore/design/intent_gossip/gossip_process.excalidraw b/documentation/dev/src/explore/design/intent_gossip/gossip_process.excalidraw deleted file mode 100644 index 3684252693..0000000000 --- a/documentation/dev/src/explore/design/intent_gossip/gossip_process.excalidraw +++ /dev/null @@ -1,966 +0,0 @@ -{ - "type": "excalidraw", - "version": 2, - "source": "https://excalidraw.com", - "elements": [ - { - "type": "ellipse", - "version": 603, - "versionNonce": 717195654, - "isDeleted": false, - "id": "9XNyo7y8QCSEp4yAFf5oy", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1156.111111111111, - "y": 164.3333333333334, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 573.6666666666667, - "height": 372.55555555555554, - "seed": 821968881, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [] - }, - { - "type": "arrow", - "version": 1450, - "versionNonce": 941173851, - "isDeleted": false, - "id": "lXNINuf2v3Bas7FefE3LH", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1586.2054115693877, - "y": -370.2728566628903, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 246.73688630955917, - "height": 192.92404363452567, - "seed": 736805503, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "5xDzwVV0gDBlD-WL85LYy", - "focus": 0.18717224637187657, - "gap": 6.459472910604248 - }, - "endBinding": { - "elementId": "xxAsLeElpbNGHmw4QPxMz", - "focus": -0.23250849205562685, - "gap": 13.411672225924079 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -246.73688630955917, - 192.92404363452567 - ] - ] - }, - { - "type": "diamond", - "version": 278, - "versionNonce": 198810363, - "isDeleted": false, - "id": "5xDzwVV0gDBlD-WL85LYy", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1565.6666666666665, - "y": -444.66666666666663, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 127, - "height": 100, - "seed": 563016927, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "lXNINuf2v3Bas7FefE3LH", - "RR6GEDZFWUssCdTAnrDqo" - ] - }, - { - "type": "text", - "version": 253, - "versionNonce": 1818093109, - "isDeleted": false, - "id": "HskYIBtFFYajWD-2Djn1f", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1605.1666666666665, - "y": -409.66666666666663, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 50, - "height": 26, - "seed": 1643469585, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "lXNINuf2v3Bas7FefE3LH" - ], - "fontSize": 20, - "fontFamily": 1, - "text": "client", - "baseline": 18, - "textAlign": "center", - "verticalAlign": "middle" - }, - { - "type": "rectangle", - "version": 432, - "versionNonce": 232368667, - "isDeleted": false, - "id": "5cPSOu9KDeCIp3Nmd546m", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1176, - "y": -287.2222222222222, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 570.0000000000001, - "height": 356.2222222222222, - "seed": 1306655743, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [] - }, - { - "type": "diamond", - "version": 627, - "versionNonce": 1842306310, - "isDeleted": false, - "id": "xxAsLeElpbNGHmw4QPxMz", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1181.3333333333333, - "y": -207.55555555555554, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 209, - "height": 188, - "seed": 1389553521, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "B4iQSfzoi419GYzKlXw5m", - "MPfW6JEUQYoWrzHeI_NxD", - "z6DMUeY7qrwuosEZr9D8K", - "GJPwvquPv4Afa-iz06Txv", - "bleUDuct9nWGxJfhyl_J2", - "V6oy4uJc_J45aC2sNpHvE", - "lXNINuf2v3Bas7FefE3LH", - "OIBiMf6VpPETwJAGERKti", - "J8EUyGyYHRSW895zskWbp" - ] - }, - { - "type": "diamond", - "version": 604, - "versionNonce": 1476920774, - "isDeleted": false, - "id": "dSBMH7Bqm1h_eoLM_yqkZ", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1184.4444444444446, - "y": 264.99999999999994, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 307.888888888889, - "height": 215.66666666666666, - "seed": 1838896927, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "OIBiMf6VpPETwJAGERKti", - "MPfW6JEUQYoWrzHeI_NxD", - "FqT97u9kn8yPY-e9ZEmwX", - "3w6C3S5gFIBLSOSnHrL9p", - "J8EUyGyYHRSW895zskWbp" - ] - }, - { - "type": "text", - "version": 446, - "versionNonce": 2067771125, - "isDeleted": false, - "id": "FOQ3kxQ9jn8r8iZ6-5Kdn", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1227.3333333333333, - "y": -149.55555555555551, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 121, - "height": 52, - "seed": 1118918783, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "Intent \nbroadcaster", - "baseline": 44, - "textAlign": "center", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 346, - "versionNonce": 94289307, - "isDeleted": false, - "id": "wNwxFCvE4WMQV8QLZiqxu", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1272, - "y": 281.99999999999994, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 131, - "height": 78, - "seed": 197177745, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "OIBiMf6VpPETwJAGERKti", - "MPfW6JEUQYoWrzHeI_NxD", - "J8EUyGyYHRSW895zskWbp" - ], - "fontSize": 20, - "fontFamily": 1, - "text": "intent\nbroadcaster \nnetwork", - "baseline": 70, - "textAlign": "center", - "verticalAlign": "top" - }, - { - "type": "arrow", - "version": 1548, - "versionNonce": 1059405510, - "isDeleted": false, - "id": "OIBiMf6VpPETwJAGERKti", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1340.8991464307837, - "y": 256.43457590166764, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 19.424658574333307, - "height": 274.53680436823555, - "seed": 413185503, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "dSBMH7Bqm1h_eoLM_yqkZ", - "focus": 0.06980420648639936, - "gap": 8.455707710143173 - }, - "endBinding": { - "elementId": "xxAsLeElpbNGHmw4QPxMz", - "focus": -0.27643465526659067, - "gap": 24.916176360598527 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -19.424658574333307, - -274.53680436823555 - ] - ] - }, - { - "type": "arrow", - "version": 1783, - "versionNonce": 702656213, - "isDeleted": false, - "id": "MPfW6JEUQYoWrzHeI_NxD", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1225.7890453334985, - "y": -41.97976066319893, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 21.266468152933612, - "height": 381.0875685373966, - "seed": 1670492081, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "xxAsLeElpbNGHmw4QPxMz", - "gap": 23.483962590379445, - "focus": 0.5312629502131418 - }, - "endBinding": { - "elementId": "dSBMH7Bqm1h_eoLM_yqkZ", - "gap": 16.103707014847412, - "focus": -0.8818009263489358 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -21.266468152933612, - 381.0875685373966 - ] - ] - }, - { - "type": "text", - "version": 540, - "versionNonce": 1475775174, - "isDeleted": false, - "id": "InLHuKJiMfsKjnhDLER2S", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1224.6666666666667, - "y": 122.99999999999997, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 88, - "height": 52, - "seed": 1075843217, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "validate \nmsg", - "baseline": 44, - "textAlign": "right", - "verticalAlign": "top" - }, - { - "type": "arrow", - "version": 1384, - "versionNonce": 280535450, - "isDeleted": false, - "id": "J8EUyGyYHRSW895zskWbp", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1386.7368978905408, - "y": 286.51414709947557, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 19.54258711706757, - "height": 343.3666092756827, - "seed": 1500547647, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "dSBMH7Bqm1h_eoLM_yqkZ", - "focus": 0.34597438474774744, - "gap": 10.117038200934843 - }, - "endBinding": { - "elementId": "xxAsLeElpbNGHmw4QPxMz", - "focus": -0.7476913039884736, - "gap": 26.682463765500543 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -19.54258711706757, - -343.3666092756827 - ] - ] - }, - { - "type": "text", - "version": 452, - "versionNonce": 1029595482, - "isDeleted": false, - "id": "3a6V_ozlu_-z813t_fjbn", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1391, - "y": 187.77777777777777, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 156, - "height": 36, - "seed": 15072497, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 28, - "fontFamily": 1, - "text": "libP2P logic", - "baseline": 25, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "diamond", - "version": 365, - "versionNonce": 757518677, - "isDeleted": false, - "id": "hngD3gT8MxLbMtULxwILm", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1204.6111111111113, - "y": -434.0000000000001, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 127, - "height": 100, - "seed": 662285233, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "lXNINuf2v3Bas7FefE3LH", - "V6oy4uJc_J45aC2sNpHvE" - ] - }, - { - "type": "text", - "version": 334, - "versionNonce": 979982971, - "isDeleted": false, - "id": "Tne4ggu_ZDCdoqKD1HVLY", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1244.1111111111113, - "y": -402.0000000000001, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 50, - "height": 26, - "seed": 1728898015, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "lXNINuf2v3Bas7FefE3LH" - ], - "fontSize": 20, - "fontFamily": 1, - "text": "client", - "baseline": 18, - "textAlign": "center", - "verticalAlign": "middle" - }, - { - "type": "arrow", - "version": 1682, - "versionNonce": 1212570555, - "isDeleted": false, - "id": "V6oy4uJc_J45aC2sNpHvE", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1262.664151563201, - "y": -330.8400855354932, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 2.5819871518015134, - "height": 140.4581124311759, - "seed": 1528357951, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "hngD3gT8MxLbMtULxwILm", - "focus": 0.10105347446704833, - "gap": 5.8523740982304915 - }, - "endBinding": { - "elementId": "xxAsLeElpbNGHmw4QPxMz", - "focus": -0.18349209857314347, - "gap": 1 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 2.5819871518015134, - 140.4581124311759 - ] - ] - }, - { - "type": "text", - "version": 377, - "versionNonce": 1391350555, - "isDeleted": false, - "id": "q9mdbiPTZ5bMiHS1pP8Jd", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1267.8333333333333, - "y": -327.77777777777777, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 86, - "height": 26, - "seed": 280036991, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "send msg", - "baseline": 18, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 138, - "versionNonce": 2055493659, - "isDeleted": false, - "id": "JdaaIi8F9pCIbQiuefyHi", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1388.75, - "y": -206.72222222222223, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 180, - "height": 35, - "seed": 476397371, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 28, - "fontFamily": 3, - "text": "Gossip Node", - "baseline": 28, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 419, - "versionNonce": 1035911669, - "isDeleted": false, - "id": "E1bibepZLZFj3VmWghmhk", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1557.1388888888887, - "y": -324.94444444444554, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 86, - "height": 26, - "seed": 1482472437, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "send msg", - "baseline": 18, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "diamond", - "version": 629, - "versionNonce": 251582106, - "isDeleted": false, - "id": "JaiST4fQ2FlodcbDsHGRd", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1525.611111111111, - "y": -178.99999999999997, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 209, - "height": 188, - "seed": 1161636571, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "B4iQSfzoi419GYzKlXw5m", - "MPfW6JEUQYoWrzHeI_NxD", - "z6DMUeY7qrwuosEZr9D8K", - "GJPwvquPv4Afa-iz06Txv", - "bleUDuct9nWGxJfhyl_J2", - "RR6GEDZFWUssCdTAnrDqo", - "yZ1sDbO9UxZw6Yw7d8BGk", - "sofyhfQ6yAERl8W7igqud", - "98jHSy6KgIgI-kigPhATL", - "Jj-F4u_NSjuW-tVWK6ErH" - ] - }, - { - "type": "text", - "version": 477, - "versionNonce": 320811829, - "isDeleted": false, - "id": "yE8obB-cq-eO9tpUS_PcA", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1575.611111111111, - "y": -117.99999999999994, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 121, - "height": 52, - "seed": 413385813, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "DKG \nbroadcaster", - "baseline": 44, - "textAlign": "center", - "verticalAlign": "top" - }, - { - "type": "arrow", - "version": 115, - "versionNonce": 808640859, - "isDeleted": false, - "id": "RR6GEDZFWUssCdTAnrDqo", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1660.0572555330295, - "y": -366.9575940330065, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 24.665187381169744, - "height": 183.91639038865497, - "seed": 45437883, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "5xDzwVV0gDBlD-WL85LYy", - "focus": -0.5447225569886008, - "gap": 1.5967808146620044 - }, - "endBinding": { - "elementId": "JaiST4fQ2FlodcbDsHGRd", - "focus": -0.07528645180716763, - "gap": 6.5362537154315845 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -24.665187381169744, - 183.91639038865497 - ] - ] - }, - { - "type": "diamond", - "version": 596, - "versionNonce": 1248600538, - "isDeleted": false, - "id": "sJFOeRzApKjnkoavWYSOm", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1415.6666666666667, - "y": 270.6666666666667, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 292.8888888888888, - "height": 207.6666666666666, - "seed": 3834485, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "OIBiMf6VpPETwJAGERKti", - "MPfW6JEUQYoWrzHeI_NxD", - "FqT97u9kn8yPY-e9ZEmwX", - "3w6C3S5gFIBLSOSnHrL9p", - "J8EUyGyYHRSW895zskWbp", - "yZ1sDbO9UxZw6Yw7d8BGk", - "sofyhfQ6yAERl8W7igqud", - "98jHSy6KgIgI-kigPhATL", - "Jj-F4u_NSjuW-tVWK6ErH" - ] - }, - { - "type": "text", - "version": 354, - "versionNonce": 339994458, - "isDeleted": false, - "id": "ERwB6OfVxtsDLuZO1G4dn", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1507.2222222222224, - "y": 292.6666666666667, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 131, - "height": 78, - "seed": 410831707, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "OIBiMf6VpPETwJAGERKti", - "MPfW6JEUQYoWrzHeI_NxD", - "yZ1sDbO9UxZw6Yw7d8BGk" - ], - "fontSize": 20, - "fontFamily": 1, - "text": "DKG\nbroadcaster \nnetwork", - "baseline": 70, - "textAlign": "center", - "verticalAlign": "top" - }, - { - "type": "arrow", - "version": 432, - "versionNonce": 855557126, - "isDeleted": false, - "id": "yZ1sDbO9UxZw6Yw7d8BGk", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1613.2645903010791, - "y": 5.6816480400971585, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 32.37650849922488, - "height": 267.8739593512054, - "seed": 978571771, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "JaiST4fQ2FlodcbDsHGRd", - "focus": 0.056328322376417134, - "gap": 8.799318498256582 - }, - "endBinding": { - "elementId": "ERwB6OfVxtsDLuZO1G4dn", - "focus": 0.016268660508214034, - "gap": 19.11105927536414 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -32.37650849922488, - 267.8739593512054 - ] - ] - }, - { - "type": "arrow", - "version": 398, - "versionNonce": 2067988678, - "isDeleted": false, - "id": "Jj-F4u_NSjuW-tVWK6ErH", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1623.0089473868802, - "y": 304.406818117378, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 33.75764899556157, - "height": 307.2241654227815, - "seed": 398843163, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "sJFOeRzApKjnkoavWYSOm", - "focus": 0.3632505836483008, - "gap": 7.699251414567215 - }, - "endBinding": { - "elementId": "JaiST4fQ2FlodcbDsHGRd", - "focus": -0.3414897328591685, - "gap": 9.04048516465393 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 33.75764899556157, - -307.2241654227815 - ] - ] - }, - { - "type": "text", - "version": 554, - "versionNonce": 720882453, - "isDeleted": false, - "id": "kXVNso4ItXnAMFArYHbYk", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1486.1111111111115, - "y": 109.99999999999997, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 88, - "height": 52, - "seed": 1662723835, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "validate \nmsg", - "baseline": 44, - "textAlign": "right", - "verticalAlign": "top" - } - ], - "appState": { - "gridSize": null, - "viewBackgroundColor": "#ffffff" - } -} \ No newline at end of file diff --git a/documentation/dev/src/explore/design/intent_gossip/gossip_process.svg b/documentation/dev/src/explore/design/intent_gossip/gossip_process.svg deleted file mode 100644 index 9129d9eea7..0000000000 --- a/documentation/dev/src/explore/design/intent_gossip/gossip_process.svg +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - clientIntent broadcasterintentbroadcaster networkvalidate msglibP2P magicclientsend msgGossip Nodesend msgDKG broadcasterDKGbroadcaster networkvalidate msg \ No newline at end of file diff --git a/documentation/dev/src/explore/design/intent_gossip/incentive.md b/documentation/dev/src/explore/design/intent_gossip/incentive.md deleted file mode 100644 index 51905d457f..0000000000 --- a/documentation/dev/src/explore/design/intent_gossip/incentive.md +++ /dev/null @@ -1,9 +0,0 @@ -# Incentive - -[Tracking Issue](https://github.com/anoma/anoma/issues/37) - ---- - -TODO -- describe incentive function -- describe logic to ensure matchmaker can't cheat intent gossip service diff --git a/documentation/dev/src/explore/design/intent_gossip/intent.md b/documentation/dev/src/explore/design/intent_gossip/intent.md deleted file mode 100644 index 62bffedbe0..0000000000 --- a/documentation/dev/src/explore/design/intent_gossip/intent.md +++ /dev/null @@ -1,28 +0,0 @@ -# Intents - -An intent is a way of expressing a user's desire. It is defined as arbitrary -data and an optional address for a schema. The data is as arbitrary as possible -to allow the users to express any sort of intent. It could range from defining a -selling order for a specific token to offering piano lessons or even proposing a -green tax for shoes’ manufacturers. - -An intent is written using an encoding, or data schema. The encoding exists -either on-chain or off-chain. It must be known by users that want to express -similar intents. It also must be understood by some matchmaker. Otherwise, it -possibly won’t be matched. The user can define its own schema and inform either -off-chain or on-chain. Having it on-chain allows it to easily share it with other -participants. Please refer to [data schema](./../ledger/storage/data-schema.md) for more -information about the usage of on-chain schema. - ---- - -There is only a single intent type that is composed of arbitrary data and a -possible schema definition. - -```rust -struct Intent { - schema: Option, - data: Vec, - timestamp: Timestamp -} -``` diff --git a/documentation/dev/src/explore/design/intent_gossip/intent_gossip.md b/documentation/dev/src/explore/design/intent_gossip/intent_gossip.md deleted file mode 100644 index f9342a0181..0000000000 --- a/documentation/dev/src/explore/design/intent_gossip/intent_gossip.md +++ /dev/null @@ -1,51 +0,0 @@ -# Intent gossip network - -The intent gossip network enables counterparty discovery for bartering. The -users can express any sort of intents that might be matched and transformed into -a transaction that fulfills the intents on the Anoma ledger. - -An [intent](./intent.md) describes the desire of a user, from asset exchange to a -green tax percent for selling shoes. These intents are picked up by a matchmaker -that composes them into transactions to send to the ledger network. A matchmaker -is optionally included in the intent gossip node. - -Each node connects to a specified intent gossip network, either a public or a -private one. Anyone can create their own network where they decide all aspects -of it: which type of intents is propagated, which nodes can participate, the -matchmaker logic, etc. It is possible, for example, to run the intent gossip system -over bluetooth to have it off-line. - -An intent gossip node is a peer in the intent gossip network that has the role -of propagating intents to all other connected nodes. - -The network uses the -[gossipsub](https://github.com/libp2p/specs/tree/512accdd81e35480911499cea14e7d7ea019f71b/pubsub/gossipsub) -network behaviour. This system aggregates nodes around topics of interest. Each -node subscribes to a set of topics and connects to other nodes that are also -subscribed to the same topics. A topic defines a sub-network for a defined -interest, e.g. “asset_exchange”. see -[gossipsub](https://github.com/libp2p/specs/tree/512accdd81e35480911499cea14e7d7ea019f71b/pubsub/gossipsub) -for more information on the network topology. - -Each node has an incentive to propagate intents and will obtain a small portion -of the fees if the intent is settled. (TODO: update when logic is found) See -[incentive](./incentive.md) for more information. - -### Flow diagram: asset exchange - -This example shows three intents matched together by the intent gossip network. -These three intents express user desires to exchange assets. - -![intent gossip and ledger network -interaction](./example.svg "intent gossip network") -[Diagram on Excalidraw](https://excalidraw.com/#room=257e44f4b4b5867bf541,XDEKyGVIpqCrfq55bRqKug) - -# Flow diagram: life cycle of intent and global process - -This diagram shows the process flow for intents, from users expressing their -desire to the ledger executing the validity predicate to check the crafted -transaction. - -![intent life cycle](./intent_life_cycle.svg "intent life -cycle") -[Diagram on Excalidraw](https://excalidraw.com/#room=7ac107b3757c64049003,cdMInfvdLtjaGWSZWEKrhw) diff --git a/documentation/dev/src/explore/design/intent_gossip/intent_life_cycle.excalidraw b/documentation/dev/src/explore/design/intent_gossip/intent_life_cycle.excalidraw deleted file mode 100644 index 83b9eced85..0000000000 --- a/documentation/dev/src/explore/design/intent_gossip/intent_life_cycle.excalidraw +++ /dev/null @@ -1,1686 +0,0 @@ -{ - "type": "excalidraw", - "version": 2, - "source": "https://excalidraw.com", - "elements": [ - { - "type": "text", - "version": 588, - "versionNonce": 594523952, - "isDeleted": false, - "id": "1u_2wBZI6b8qbCpHVN6MP", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -298.6003582724815, - "y": 1338.2754110612868, - "strokeColor": "#1864ab", - "backgroundColor": "transparent", - "width": 85.4456709210074, - "height": 21.78026905829601, - "seed": 71443719, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 16.75405312176615, - "fontFamily": 1, - "text": "add intent", - "baseline": 14.78026905829601, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 454, - "versionNonce": 786627024, - "isDeleted": false, - "id": "2Wc5lEY411C5Gl9LSu5pY", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -410.91401048972233, - "y": 1360.7731689088182, - "strokeColor": "#c92a2a", - "backgroundColor": "transparent", - "width": 88, - "height": 18, - "seed": 1334554569, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "yk9tRH45JFldlow2BsTQc", - "IfZHk6DCJHzdGQSleRzVY", - "3M7y36XaiPpkZdYFa6HL0" - ], - "fontSize": 13.677130044843086, - "fontFamily": 3, - "text": "filter.wasm", - "baseline": 14, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "arrow", - "version": 2279, - "versionNonce": 1948716336, - "isDeleted": false, - "id": "3M7y36XaiPpkZdYFa6HL0", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -305.31404973574377, - "y": 1369.1513491711225, - "strokeColor": "#1864ab", - "backgroundColor": "transparent", - "width": 105.04325514724303, - "height": 0.1273972078367933, - "seed": 94578119, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "MA9plWdw54jKf3dPF231d", - "focus": 0.11381802003862611, - "gap": 4.5029253777944405 - }, - "endBinding": { - "elementId": "J3PIpIxWftxjM5b3onaa_", - "focus": -1.823336288291325, - "gap": 9.453089222814356 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 105.04325514724303, - 0.1273972078367933 - ] - ] - }, - { - "type": "rectangle", - "version": 628, - "versionNonce": 1926825424, - "isDeleted": false, - "id": "jTa_ZQSjZQ_9wK0AxfkKq", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -200.54779225354866, - "y": 1340.590433482808, - "strokeColor": "#1864ab", - "backgroundColor": "transparent", - "width": 125.3736920777284, - "height": 59.495515695067446, - "seed": 1482668551, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "Q4yHCPe8MjqsFcGPSqmAZ", - "3M7y36XaiPpkZdYFa6HL0", - "9rmYOU060-nUE-om6NWFg", - "dAdWOUfpjNuXJyfO475fP" - ] - }, - { - "type": "rectangle", - "version": 504, - "versionNonce": 1614695216, - "isDeleted": false, - "id": "MA9plWdw54jKf3dPF231d", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -416.8923363492138, - "y": 1350.6808669656184, - "strokeColor": "#1864ab", - "backgroundColor": "transparent", - "width": 107.07536123567559, - "height": 33.48318385650231, - "seed": 186308295, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "IolhdtZMlJt05RE7PSeqH", - "3M7y36XaiPpkZdYFa6HL0" - ] - }, - { - "type": "arrow", - "version": 1314, - "versionNonce": 44918064, - "isDeleted": false, - "id": "IolhdtZMlJt05RE7PSeqH", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -297.62941465804636, - "y": 1305.067079818005, - "strokeColor": "#1864ab", - "backgroundColor": "transparent", - "width": 35.4136526564796, - "height": 41.1911597898536, - "seed": 580979783, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "vMWskj1YJao4q8Szni_9g", - "focus": 0.2739809180363499, - "gap": 3.4310135063774396 - }, - "endBinding": { - "elementId": "MA9plWdw54jKf3dPF231d", - "focus": 0.17835547552991876, - "gap": 4.422627357759893 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -35.4136526564796, - 41.1911597898536 - ] - ] - }, - { - "type": "text", - "version": 630, - "versionNonce": 701297456, - "isDeleted": false, - "id": "J3PIpIxWftxjM5b3onaa_", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -193.70922723112722, - "y": 1346.0612855007478, - "strokeColor": "#c92a2a", - "backgroundColor": "transparent", - "width": 112.83632286995548, - "height": 16.412556053811695, - "seed": 856985703, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "9rmYOU060-nUE-om6NWFg", - "Q4yHCPe8MjqsFcGPSqmAZ", - "MOjksoKslfp16-Y701zlH", - "3M7y36XaiPpkZdYFa6HL0" - ], - "fontSize": 13.67713004484308, - "fontFamily": 2, - "text": "matchmaker.wasm", - "baseline": 11.412556053811695, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "rectangle", - "version": 629, - "versionNonce": 2084073754, - "isDeleted": false, - "id": "AfmJxEIuWj5_62161GQ01", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -326.2723811922641, - "y": 1440.665545590435, - "strokeColor": "#1864ab", - "backgroundColor": "transparent", - "width": 176.69394618834113, - "height": 56.203662182361796, - "seed": 337914215, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "9rmYOU060-nUE-om6NWFg", - "mlM1pmVM-052hahaRXJQR", - "ttC9xH3eOGzQ_k5DLzmBu" - ] - }, - { - "type": "text", - "version": 642, - "versionNonce": 1534794758, - "isDeleted": false, - "id": "TzqXubskSAjo2ZuvkxkCC", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -293.94129001139663, - "y": 1468.2503736920773, - "strokeColor": "#1864ab", - "backgroundColor": "transparent", - "width": 112, - "height": 18, - "seed": 647873609, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "ttC9xH3eOGzQ_k5DLzmBu", - "9rmYOU060-nUE-om6NWFg" - ], - "fontSize": 13.67713004484309, - "fontFamily": 3, - "text": "tx.wawm + data", - "baseline": 14, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "arrow", - "version": 2292, - "versionNonce": 1408723920, - "isDeleted": false, - "id": "9rmYOU060-nUE-om6NWFg", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -147.6356968299097, - "y": 1408.7716634080846, - "strokeColor": "#1864ab", - "backgroundColor": "transparent", - "width": 66.68074390630872, - "height": 23.556734178462648, - "seed": 798702697, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "jTa_ZQSjZQ_9wK0AxfkKq", - "gap": 8.685714230208873, - "focus": -0.6781834884379211 - }, - "endBinding": { - "elementId": "AfmJxEIuWj5_62161GQ01", - "gap": 8.337148003887705, - "focus": -0.47373449663638795 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -66.68074390630872, - 23.556734178462648 - ] - ] - }, - { - "type": "text", - "version": 507, - "versionNonce": 260021712, - "isDeleted": false, - "id": "He6AuKTKQxKmk5B38hWHj", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -176.69016893516272, - "y": 1368.6692825112111, - "strokeColor": "#1864ab", - "backgroundColor": "transparent", - "width": 75.90807174887914, - "height": 17.780269058296007, - "seed": 836533545, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 13.677130044843084, - "fontFamily": 1, - "text": "craft data", - "baseline": 11.780269058296007, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "arrow", - "version": 1796, - "versionNonce": 1407883056, - "isDeleted": false, - "id": "ttC9xH3eOGzQ_k5DLzmBu", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -245.0771506636562, - "y": 1508.714667199035, - "strokeColor": "#1864ab", - "backgroundColor": "transparent", - "width": 0.6776858655143201, - "height": 347.40968967814, - "seed": 187206441, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "AfmJxEIuWj5_62161GQ01", - "gap": 11.845459426238218, - "focus": 0.08178190315132251 - }, - "endBinding": { - "elementId": "SehQ2WycVyCQCB-DbZfI1", - "gap": 3.963620241223044, - "focus": -0.07279835372456127 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 0.6776858655143201, - 347.40968967814 - ] - ] - }, - { - "type": "ellipse", - "version": 410, - "versionNonce": 51621680, - "isDeleted": false, - "id": "SehQ2WycVyCQCB-DbZfI1", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -329.5040702804547, - "y": 1859.9240159441954, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 183.84491778774336, - "height": 121.63153961136064, - "seed": 1448762345, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "ttC9xH3eOGzQ_k5DLzmBu" - ] - }, - { - "type": "text", - "version": 374, - "versionNonce": 1588809350, - "isDeleted": false, - "id": "zERziwpui3gX_VflZl-6H", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -294.7738759605737, - "y": 1914.3163926258123, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 102.57847533632317, - "height": 17.780269058296007, - "seed": 1122418569, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 13.677130044843079, - "fontFamily": 1, - "text": "Ledger network", - "baseline": 11.780269058296007, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 349, - "versionNonce": 996390352, - "isDeleted": false, - "id": "95Wz9icO-OmtvwP5kKKfo", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -231.3882257363585, - "y": 1743.2290732436484, - "strokeColor": "#1864ab", - "backgroundColor": "transparent", - "width": 29.405829596412616, - "height": 17.780269058296007, - "seed": 1438218537, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 13.677130044843071, - "fontFamily": 1, - "text": "send", - "baseline": 11.780269058296007, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 236, - "versionNonce": 2057635802, - "isDeleted": false, - "id": "1o37i1BlUHSA_I1CYSHoq", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -369.98077680761, - "y": 1306.2222222222215, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 43.986547085201835, - "height": 24.30835496813786, - "seed": 365688905, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "IolhdtZMlJt05RE7PSeqH" - ], - "fontSize": 18.520651404295513, - "fontFamily": 1, - "text": "apply", - "baseline": 17.30835496813786, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "arrow", - "version": 1479, - "versionNonce": 442628400, - "isDeleted": false, - "id": "dAdWOUfpjNuXJyfO475fP", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -92.3069277739813, - "y": 1403.7229079845479, - "strokeColor": "#1864ab", - "backgroundColor": "transparent", - "width": 9.276809968310843, - "height": 353.05286013400246, - "seed": 203795395, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "jTa_ZQSjZQ_9wK0AxfkKq", - "focus": -0.7039148076260963, - "gap": 3.636958806672169 - }, - "endBinding": { - "elementId": "xA7xWASKaJXAE1SQjNFQ2", - "focus": 0.2211669756965918, - "gap": 14.492622357918698 - }, - "lastCommittedPoint": null, - "startArrowhead": "arrow", - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 9.276809968310843, - 353.05286013400246 - ] - ] - }, - { - "type": "ellipse", - "version": 494, - "versionNonce": 12155910, - "isDeleted": false, - "id": "xA7xWASKaJXAE1SQjNFQ2", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -144.08927207417597, - "y": 1770.7329347284497, - "strokeColor": "#1864ab", - "backgroundColor": "transparent", - "width": 101.89461883408097, - "height": 60.17937219730958, - "seed": 833498093, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "dAdWOUfpjNuXJyfO475fP" - ] - }, - { - "type": "text", - "version": 413, - "versionNonce": 1448457242, - "isDeleted": false, - "id": "Mh7caG46B4Id7Rt9mZVK0", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -78.91214202933338, - "y": 1692.8943697060292, - "strokeColor": "#1864ab", - "backgroundColor": "transparent", - "width": 90, - "height": 19, - "seed": 1753782275, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "dAdWOUfpjNuXJyfO475fP" - ], - "fontSize": 13.677130044843079, - "fontFamily": 1, - "text": "read storage", - "baseline": 13, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 411, - "versionNonce": 706916998, - "isDeleted": false, - "id": "3Nb-sNCg1mpGbUpGqPC6x", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -127.67671602036424, - "y": 1788.5132037867468, - "strokeColor": "#1864ab", - "backgroundColor": "transparent", - "width": 75.22421524663697, - "height": 17.780269058296007, - "seed": 1638966797, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 13.677130044843079, - "fontFamily": 1, - "text": "ledger node", - "baseline": 11.780269058296007, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "rectangle", - "version": 162, - "versionNonce": 137567834, - "isDeleted": false, - "id": "vMWskj1YJao4q8Szni_9g", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -294.2777777777778, - "y": 1243.3333333333333, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 86, - "height": 61, - "seed": 1736645018, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "IolhdtZMlJt05RE7PSeqH", - "MODmRH_Ai_h7eca-aYe9A", - "mHbM0I-2cMJHDQh1moe77" - ] - }, - { - "type": "diamond", - "version": 389, - "versionNonce": 416087686, - "isDeleted": false, - "id": "mBiwqFRC0vttSdLSnsU30", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -445.2777777777778, - "y": 1092.6666666666667, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 406.66666666666674, - "height": 525.6666666666669, - "seed": 476615706, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "9rmYOU060-nUE-om6NWFg", - "dAdWOUfpjNuXJyfO475fP" - ] - }, - { - "type": "ellipse", - "version": 352, - "versionNonce": 1356395824, - "isDeleted": false, - "id": "JwMrnB618nsHGBBcf92Nk", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -763.2777777777765, - "y": 874.9999999999998, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 763.3333333333335, - "height": 772.6666666666669, - "seed": 2052937478, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "ttC9xH3eOGzQ_k5DLzmBu" - ] - }, - { - "type": "text", - "version": 170, - "versionNonce": 1019110864, - "isDeleted": false, - "id": "tKzpFkSzFkhgxKS4-AVGh", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -502.944444444443, - "y": 895.6666666666666, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 190, - "height": 52, - "seed": 1397120794, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "node connected to \ntopic X", - "baseline": 44, - "textAlign": "center", - "verticalAlign": "top" - }, - { - "type": "ellipse", - "version": 443, - "versionNonce": 988924208, - "isDeleted": false, - "id": "jLWO7OrtG_BOPVeKMiwwN", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -473.44444444444264, - "y": 870.3333333333328, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 738.6666666666667, - "height": 779.0000000000005, - "seed": 1658325702, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "ttC9xH3eOGzQ_k5DLzmBu" - ] - }, - { - "type": "text", - "version": 46, - "versionNonce": 39391066, - "isDeleted": false, - "id": "GyEOsmqW1Zbdi7mCavkOe", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -302.44444444444275, - "y": 1444, - "strokeColor": "#1864ab", - "backgroundColor": "transparent", - "width": 134, - "height": 21, - "seed": 734861702, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 16, - "fontFamily": 1, - "text": "wrap transaction", - "baseline": 15, - "textAlign": "center", - "verticalAlign": "top" - }, - { - "type": "arrow", - "version": 364, - "versionNonce": 770571728, - "isDeleted": false, - "id": "MODmRH_Ai_h7eca-aYe9A", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "dashed", - "roughness": 0, - "opacity": 100, - "angle": 0, - "x": -479.5404756662694, - "y": 1107.858463582872, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 182.87979526759636, - "height": 175.27063591985802, - "seed": 1217671632, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "KwgaEOt8AQFLzGPvhESKA", - "focus": -0.46643591145185553, - "gap": 6.200069247495527 - }, - "endBinding": { - "elementId": "vMWskj1YJao4q8Szni_9g", - "focus": -0.7361561089573266, - "gap": 2.3829026208952087 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 182.87979526759636, - 175.27063591985802 - ] - ] - }, - { - "type": "diamond", - "version": 778, - "versionNonce": 595069744, - "isDeleted": false, - "id": "1aiocLnc3sR_lZQoFdB-y", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -704.777777777776, - "y": 1239.6666666666663, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 234.6666666666666, - "height": 309.6666666666667, - "seed": 344958598, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "9rmYOU060-nUE-om6NWFg", - "dAdWOUfpjNuXJyfO475fP", - "MODmRH_Ai_h7eca-aYe9A" - ] - }, - { - "type": "text", - "version": 1103, - "versionNonce": 2017820624, - "isDeleted": false, - "id": "50lEI8L3qiqHPIwEeJjSw", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": -633.4444444444428, - "y": 1277.4999999999993, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 88, - "height": 42, - "seed": 2055761114, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 16, - "fontFamily": 1, - "text": "intent\ngossip node", - "baseline": 36, - "textAlign": "center", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 196, - "versionNonce": 951002416, - "isDeleted": false, - "id": "zoKUQOZpsx3bSrQmlje2Y", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -518.4444444444428, - "y": 1209.5, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 13, - "height": 21, - "seed": 1744336198, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 16, - "fontFamily": 1, - "text": "...", - "baseline": 15, - "textAlign": "center", - "verticalAlign": "top" - }, - { - "type": "rectangle", - "version": 235, - "versionNonce": 73640752, - "isDeleted": false, - "id": "l4h4jtqh4lQ5ChrRu_d_W", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -534.9444444444428, - "y": 1211, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 45, - "height": 24.000000000000004, - "seed": 1561834950, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "NbiyFfs9_Zj9QLzFL8qHm", - "sZ8QrMhPhFBK7IsremLwb", - "B6B0y6Mtp0UrJDdAOrL4y" - ] - }, - { - "type": "arrow", - "version": 1093, - "versionNonce": 1896727504, - "isDeleted": false, - "id": "B6B0y6Mtp0UrJDdAOrL4y", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "dashed", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -548.3104597282063, - "y": 1368.7777417215675, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 24.520420568205054, - "height": 124.27733365833865, - "seed": 733305606, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "kfmygtSSHmjQGgRHYzhpm", - "focus": 0.25664643293730066, - "gap": 10.318970816658975 - }, - "endBinding": { - "elementId": "l4h4jtqh4lQ5ChrRu_d_W", - "focus": 0.285651344839639, - "gap": 9.50040806322886 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 24.520420568205054, - -124.27733365833865 - ] - ] - }, - { - "type": "arrow", - "version": 732, - "versionNonce": 138725840, - "isDeleted": false, - "id": "sZ8QrMhPhFBK7IsremLwb", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "dashed", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -519.0071422289418, - "y": 1208, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 4.665799248315011, - "height": 60.764495548789455, - "seed": 1445654746, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "l4h4jtqh4lQ5ChrRu_d_W", - "focus": -0.2310245718703419, - "gap": 3 - }, - "endBinding": { - "elementId": "KwgaEOt8AQFLzGPvhESKA", - "focus": -0.06849615152086622, - "gap": 6.783169732481319 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -4.665799248315011, - -60.764495548789455 - ] - ] - }, - { - "type": "text", - "version": 854, - "versionNonce": 557904688, - "isDeleted": false, - "id": "y-BT1d_fUjOriE9fXDJL5", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": -600.8876146788973, - "y": 1384.7289755351683, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 72, - "height": 57, - "seed": 277391514, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 14.403669724770648, - "fontFamily": 1, - "text": "gossipsub \nintent\nmempool", - "baseline": 51, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "rectangle", - "version": 371, - "versionNonce": 434353968, - "isDeleted": false, - "id": "kfmygtSSHmjQGgRHYzhpm", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -611.9444444444428, - "y": 1379.0967125382265, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 86, - "height": 61, - "seed": 405227014, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "IolhdtZMlJt05RE7PSeqH", - "MODmRH_Ai_h7eca-aYe9A", - "B6B0y6Mtp0UrJDdAOrL4y", - "jNcNZ79jIqf8USX6XWVfL" - ] - }, - { - "type": "diamond", - "version": 51, - "versionNonce": 1683064986, - "isDeleted": false, - "id": "SHqk2AS-Tf7dKA-jlraJy", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -642.9444444444428, - "y": 1809, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 126, - "height": 138, - "seed": 111487686, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "jNcNZ79jIqf8USX6XWVfL" - ] - }, - { - "type": "text", - "version": 61, - "versionNonce": 1776051718, - "isDeleted": false, - "id": "4KWmIOGgA881gCSC5JHPR", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -605.4444444444428, - "y": 1867.5, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 45, - "height": 21, - "seed": 1914582042, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 16, - "fontFamily": 1, - "text": "Client", - "baseline": 15, - "textAlign": "center", - "verticalAlign": "top" - }, - { - "type": "arrow", - "version": 583, - "versionNonce": 1443824080, - "isDeleted": false, - "id": "jNcNZ79jIqf8USX6XWVfL", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -579.5237129692832, - "y": 1804.7181399798692, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 5.784969773188777, - "height": 354.7181399798692, - "seed": 338257542, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "SHqk2AS-Tf7dKA-jlraJy", - "focus": -0.012292118582791034, - "gap": 4.302480703755165 - }, - "endBinding": { - "elementId": "kfmygtSSHmjQGgRHYzhpm", - "focus": 0.09507177161013172, - "gap": 9.903287461773516 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 5.784969773188777, - -354.7181399798692 - ] - ] - }, - { - "type": "text", - "version": 75, - "versionNonce": 1051571526, - "isDeleted": false, - "id": "2KyLbsA0pYg-9FlG-TXOS", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -550.9444444444428, - "y": 1763.5, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 86, - "height": 21, - "seed": 436422490, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 16, - "fontFamily": 1, - "text": "send intent", - "baseline": 15, - "textAlign": "center", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 134, - "versionNonce": 1446470608, - "isDeleted": false, - "id": "_iAmT5vekaBL78IeOELHk", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -616.4444444444428, - "y": 1474.5, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 29, - "height": 21, - "seed": 472650778, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 16, - "fontFamily": 1, - "text": "add", - "baseline": 15, - "textAlign": "center", - "verticalAlign": "top" - }, - { - "type": "diamond", - "version": 649, - "versionNonce": 2130147290, - "isDeleted": false, - "id": "zO0p-uresSJTDL1fIuJzV", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -425.7777777777761, - "y": 1051.6666666666663, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 135.66666666666674, - "height": 118.66666666666676, - "seed": 112661018, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "9rmYOU060-nUE-om6NWFg", - "dAdWOUfpjNuXJyfO475fP", - "MODmRH_Ai_h7eca-aYe9A", - "NbiyFfs9_Zj9QLzFL8qHm", - "sZ8QrMhPhFBK7IsremLwb", - "mHbM0I-2cMJHDQh1moe77", - "ixAHiLZKgPdknMrEKL8E0" - ] - }, - { - "type": "arrow", - "version": 273, - "versionNonce": 2086180304, - "isDeleted": false, - "id": "mHbM0I-2cMJHDQh1moe77", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "dashed", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -349.6653716829509, - "y": 1166.225689032409, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 50.06401310624267, - "height": 82.14785148842725, - "seed": 1712918342, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "zO0p-uresSJTDL1fIuJzV", - "focus": 0.3763418967402116, - "gap": 2.3589356079478208 - }, - "endBinding": { - "elementId": "vMWskj1YJao4q8Szni_9g", - "focus": -0.5326929819465109, - "gap": 5.323580798930379 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 50.06401310624267, - 82.14785148842725 - ] - ] - }, - { - "type": "diamond", - "version": 680, - "versionNonce": 992396592, - "isDeleted": false, - "id": "KwgaEOt8AQFLzGPvhESKA", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -600.7777777777761, - "y": 1027.6666666666667, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 135.66666666666674, - "height": 118.66666666666676, - "seed": 1672626970, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "9rmYOU060-nUE-om6NWFg", - "dAdWOUfpjNuXJyfO475fP", - "MODmRH_Ai_h7eca-aYe9A", - "NbiyFfs9_Zj9QLzFL8qHm", - "sZ8QrMhPhFBK7IsremLwb", - "mHbM0I-2cMJHDQh1moe77" - ] - }, - { - "type": "diamond", - "version": 103, - "versionNonce": 1529867034, - "isDeleted": false, - "id": "5G2DYWMgIW2-Eyu0jHu5M", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -333.94444444444275, - "y": 634.75, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 126, - "height": 138, - "seed": 856516186, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "jNcNZ79jIqf8USX6XWVfL", - "ixAHiLZKgPdknMrEKL8E0" - ] - }, - { - "type": "text", - "version": 111, - "versionNonce": 1461469830, - "isDeleted": false, - "id": "3n5h8veTQO-lECAC8FTbh", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -296.44444444444275, - "y": 693.25, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 45, - "height": 21, - "seed": 1537623110, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 16, - "fontFamily": 1, - "text": "Client", - "baseline": 15, - "textAlign": "center", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 175, - "versionNonce": 288331846, - "isDeleted": false, - "id": "m_iuhNYFucnv5uwttXCPa", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -281.94444444444275, - "y": 819.25, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 86, - "height": 21, - "seed": 1275300634, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 16, - "fontFamily": 1, - "text": "send intent", - "baseline": 15, - "textAlign": "center", - "verticalAlign": "top" - }, - { - "type": "arrow", - "version": 79, - "versionNonce": 1108019504, - "isDeleted": false, - "id": "ixAHiLZKgPdknMrEKL8E0", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -269.94444444444275, - "y": 777, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 84, - "height": 274, - "seed": 1390808730, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "5G2DYWMgIW2-Eyu0jHu5M", - "focus": -0.37232070443749277, - "gap": 3.604130291018784 - }, - "endBinding": { - "elementId": "zO0p-uresSJTDL1fIuJzV", - "focus": -0.21219892752739253, - "gap": 3.135288841647885 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -84, - 274 - ] - ] - }, - { - "type": "text", - "version": 1136, - "versionNonce": 408089904, - "isDeleted": false, - "id": "Wj0MHJ1dtfAoF25CFCBfi", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": -576.9444444444428, - "y": 1060.2499999999998, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 88, - "height": 42, - "seed": 960837584, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 16, - "fontFamily": 1, - "text": "intent\ngossip node", - "baseline": 36, - "textAlign": "center", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 1149, - "versionNonce": 1606676272, - "isDeleted": false, - "id": "TXaHYoLoaZlRQaR766TLH", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": -400.94444444444275, - "y": 1083.2500000000002, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 88, - "height": 42, - "seed": 1165581104, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 16, - "fontFamily": 1, - "text": "intent\ngossip node", - "baseline": 36, - "textAlign": "center", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 1227, - "versionNonce": 1197055440, - "isDeleted": false, - "id": "9hZsHGB4M9tFJZIfi6Ao_", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": -305.94444444444275, - "y": 1134.2499999999998, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 128, - "height": 63, - "seed": 1645861840, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 16, - "fontFamily": 1, - "text": "intent\ngossip node\nwith matchmaker", - "baseline": 57, - "textAlign": "center", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 210, - "versionNonce": 346021168, - "isDeleted": false, - "id": "26K0-MZ5xxu4N_zB_HZRa", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -164.94444444444275, - "y": 890.2499999999999, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 190, - "height": 52, - "seed": 1266445616, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "node connected to \ntopic Y", - "baseline": 44, - "textAlign": "center", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 913, - "versionNonce": 915376944, - "isDeleted": false, - "id": "ENHebue9f6lfx-kznKF5G", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": -285.94444444444275, - "y": 1243.7500000000002, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 72, - "height": 57, - "seed": 2113192912, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 14.403669724770648, - "fontFamily": 1, - "text": "gossipsub \nintent\nmempool", - "baseline": 51, - "textAlign": "left", - "verticalAlign": "top" - } - ], - "appState": { - "gridSize": null, - "viewBackgroundColor": "#ffffff" - } -} \ No newline at end of file diff --git a/documentation/dev/src/explore/design/intent_gossip/intent_life_cycle.svg b/documentation/dev/src/explore/design/intent_gossip/intent_life_cycle.svg deleted file mode 100644 index 7295dd3431..0000000000 --- a/documentation/dev/src/explore/design/intent_gossip/intent_life_cycle.svg +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - add intentfilter.wasmmatchmaker.wasmtx.wawm + datacraft dataLedger networksendapplyread storageledger nodenode connected to topic Xwrap transactionintentgossip node...gossipsub intentmempoolClientsend intentaddClientsend intentintentgossip nodeintentgossip nodeintentgossip nodewith matchmakernode connected to topic Ygossipsub intentmempool \ No newline at end of file diff --git a/documentation/dev/src/explore/design/intent_gossip/matchmaker.md b/documentation/dev/src/explore/design/intent_gossip/matchmaker.md deleted file mode 100644 index ce2cace5bd..0000000000 --- a/documentation/dev/src/explore/design/intent_gossip/matchmaker.md +++ /dev/null @@ -1,80 +0,0 @@ -# Matchmaker - -The matchmaker is a specific actor in the intent gossip network that tries to -match intents together. When intents are matched together, the matchmaker crafts -a transaction from them and sends it to the ledger network. - -A matchmaker is an intent gossip node started with additional parameters: a -ledger address and a list of sub-matchmakers. A sub-matchmaker is defined with a -topics list, a main program path, a filter program path, and a transaction code. - -The main and filter programs are wasm compiled code. Each has a defined -entrypoint and their own set of environment functions that they can call. - -When the matchmaker receives a new intent from the network it calls the -corresponding sub-matchmaker, the one that has the intent’s topic in their -topics list. A sub-matchmaker first checks if the intent is accepted by the -filter, before adding it to that sub-matchmaker database. Then the main program -is called with the intent and current state. - -## Sub-matchmaker topics' list - -A sub-matchmaker is defined to work with only a subset of encoding. Each intent -propagated to the corresponding topic will be process by this sub-matchmaker. - -Having a topics list instead of a unique topic allows a matchmaker to match -intents from different encodings. For example, when an updated version of an -encoding is out, the matchmaker could match intents from both versions if they -don’t diverge too much. - -## Sub-matchmaker database and state (name TBD) - -Each sub-matchmaker has a database and an arbitrary state. - -The database contains intents received by the node from the topics list that -passed the filter. - -The state is arbitrary data that is managed by the main program. That state is -given to all calls in the main program. - -The database is persistent but the state is not. When a node is started the -state is recovered by giving all intents from the database to the main program. -The invariant that the current state is equal to the state if the node is -restarted is not enforced and is the responsibility of the main program. - -## Filter program - -The filter is an optional wasm program given in parameters. This filter is used -to check each intent received by that sub-matchmaker. If it's not defined, -intents are directly passed to the main program. - - The entrypoint `filter_intent` takes an intent and returns a boolean. The -filter has the ability to query the state of the ledger for any given key. - -## Main program - -The main program is a mandatory wasm program given in parameters. The main -program must match together intents. - -The main program entrypoint `match_intent` takes the current state, a new intent -data and its id. The main program also has the ability to query the state of the -ledger. It also has functions `remove` and `get` to interact with the matchmaker -mempool. When a main matchmaker program finds a match it sends a transaction to -the ledger composed of the code template given in the matchmaker parameter and -the data given to this function. Finally the matchmaker must update its state so -the next run will have up to date values. - -The main program is called on two specific occasion; when intent gossip node is -started, on all intent from database and whenever a new intent is received from -the p2p network and the RPC endpoint, if enabled. - -## Transaction - -The transaction code given in parameters is used when the main program matches a -group of intents. The main program returns arbitrary data that is attached to -the transaction which is then injected into a ledger node. - -## Flow diagram: Matchmaker process -![matchmaker process](./matchmaker_process.svg "matchmaker process") - -[excalidraw link](https://excalidraw.com/#room=92b291c13cfab8fb22a4,OvHfWIrL0jeDzPI-EFZMaw) diff --git a/documentation/dev/src/explore/design/intent_gossip/matchmaker_graph.excalidraw b/documentation/dev/src/explore/design/intent_gossip/matchmaker_graph.excalidraw deleted file mode 100644 index 8d2d29fc95..0000000000 --- a/documentation/dev/src/explore/design/intent_gossip/matchmaker_graph.excalidraw +++ /dev/null @@ -1,1648 +0,0 @@ -{ - "type": "excalidraw", - "version": 2, - "source": "https://excalidraw.com", - "elements": [ - { - "type": "ellipse", - "version": 304, - "versionNonce": 732978925, - "isDeleted": false, - "id": "0kpaYctW0QC41GkaU0Fnm", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 788, - "y": 448, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 142.99999999999994, - "height": 63.000000000000014, - "seed": 1594329571, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "YebzbhwZPZJG7VeGK6buO", - "x5FlGy9vo-0WFWlvTLxRB" - ] - }, - { - "type": "text", - "version": 66, - "versionNonce": 1832587875, - "isDeleted": false, - "id": "VGy1X1kAYasab67GT_3Vp", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 815, - "y": 464, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 86, - "height": 26, - "seed": 1391569133, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "Intent A", - "baseline": 18, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "ellipse", - "version": 357, - "versionNonce": 1055790499, - "isDeleted": false, - "id": "ipca-2U6Ichp5KRWeBGiU", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1019.5, - "y": 553.5, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 142.99999999999994, - "height": 63.000000000000014, - "seed": 961566285, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "YebzbhwZPZJG7VeGK6buO", - "jrzBVVdi5EqY0mYYzI-qC", - "vUyB6nADBS51AWp7XW9EQ" - ] - }, - { - "type": "text", - "version": 103, - "versionNonce": 2128726541, - "isDeleted": false, - "id": "sh9VeUsrJu8zyMqC4wTTn", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1046.5, - "y": 569.5, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 88, - "height": 26, - "seed": 54575363, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "Intent B", - "baseline": 18, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "ellipse", - "version": 443, - "versionNonce": 813787459, - "isDeleted": false, - "id": "mWM2JyFPRcVz5-LPE35xW", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 912.5, - "y": 728.5, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 142.99999999999994, - "height": 63.000000000000014, - "seed": 1522729677, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "jrzBVVdi5EqY0mYYzI-qC", - "jL-ZuiaA7Yepo4Ood8hh4" - ] - }, - { - "type": "text", - "version": 189, - "versionNonce": 563544173, - "isDeleted": false, - "id": "mkyAaMiHp_aflaPNTUS4h", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 939.5, - "y": 744.5, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 86, - "height": 26, - "seed": 1761418371, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "Intent C", - "baseline": 18, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "ellipse", - "version": 602, - "versionNonce": 665405667, - "isDeleted": false, - "id": "8Kq9uOVih2T18r283qOW_", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 625.8084194993482, - "y": 740.257842502465, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 143.34456240942814, - "height": 63.15180022233556, - "seed": 1558060547, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "jL-ZuiaA7Yepo4Ood8hh4", - "hKuG4FbIRTd9ZuXgsPwJH", - "B-ARwwElkcqpEnbbGinI1" - ] - }, - { - "type": "text", - "version": 336, - "versionNonce": 2031512269, - "isDeleted": false, - "id": "jPnOeECE_YTxUJl_u56s4", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 652.8734767374922, - "y": 756.2963949398833, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 89.21444793314066, - "height": 26.062647710805145, - "seed": 2115827629, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20.048190546773174, - "fontFamily": 1, - "text": "Intent D", - "baseline": 18.062647710805145, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "ellipse", - "version": 596, - "versionNonce": 1193323555, - "isDeleted": false, - "id": "eYMWKEiFVFlYbjiPgu_c4", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1300.5, - "y": 552.5, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 142.99999999999994, - "height": 63.000000000000014, - "seed": 1785759373, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "vUyB6nADBS51AWp7XW9EQ", - "Tz4cdqtGreDIsYuudDs1x" - ] - }, - { - "type": "text", - "version": 347, - "versionNonce": 967433101, - "isDeleted": false, - "id": "rHC_PRTjElJ0lMKCObfnb", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1327.5, - "y": 568.5, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 87, - "height": 26, - "seed": 397063363, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "Intent E", - "baseline": 18, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "ellipse", - "version": 652, - "versionNonce": 590894061, - "isDeleted": false, - "id": "1MaFQq1C6f_KmXrCju5x4", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1084.5, - "y": 873.5, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 142.99999999999994, - "height": 63.000000000000014, - "seed": 1794271469, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "ZVBhabk31rzDP8O9ZI07b", - "wkpAIY8WXU4_DhUYO1aB9" - ] - }, - { - "type": "text", - "version": 393, - "versionNonce": 1012982253, - "isDeleted": false, - "id": "DLt_4JJLkufDMzrR-McEC", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1111.5, - "y": 889.5, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 85, - "height": 26, - "seed": 1115072611, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "Intent F", - "baseline": 18, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "arrow", - "version": 39, - "versionNonce": 1611153251, - "isDeleted": false, - "id": "YebzbhwZPZJG7VeGK6buO", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 933, - "y": 485, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 96, - "height": 76, - "seed": 1699820525, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "0kpaYctW0QC41GkaU0Fnm", - "focus": -0.8133458878104184, - "gap": 2.90910614687202 - }, - "endBinding": { - "elementId": "ipca-2U6Ichp5KRWeBGiU", - "focus": -0.38721567770808374, - "gap": 6.84867663170747 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 96, - 76 - ] - ] - }, - { - "type": "arrow", - "version": 42, - "versionNonce": 858266701, - "isDeleted": false, - "id": "jrzBVVdi5EqY0mYYzI-qC", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1080, - "y": 624, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 40, - "height": 103, - "seed": 1343642477, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "ipca-2U6Ichp5KRWeBGiU", - "focus": -0.05715042949410481, - "gap": 7.857427983505644 - }, - "endBinding": { - "elementId": "mWM2JyFPRcVz5-LPE35xW", - "focus": 0.5953281273765297, - "gap": 12.01223971985118 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -40, - 103 - ] - ] - }, - { - "type": "arrow", - "version": 257, - "versionNonce": 137386755, - "isDeleted": false, - "id": "jL-ZuiaA7Yepo4Ood8hh4", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 909.4582871700171, - "y": 767.0701354272285, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 133.9560247707435, - "height": 0.9487028688702139, - "seed": 520169987, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "mWM2JyFPRcVz5-LPE35xW", - "focus": -0.21904362566296393, - "gap": 4.520486328322136 - }, - "endBinding": { - "elementId": "8Kq9uOVih2T18r283qOW_", - "focus": -0.10330406547410168, - "gap": 6.7389193162100725 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -133.9560247707435, - 0.9487028688702139 - ] - ] - }, - { - "type": "arrow", - "version": 39, - "versionNonce": 366545581, - "isDeleted": false, - "id": "vUyB6nADBS51AWp7XW9EQ", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1165, - "y": 592, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 129, - "height": 9, - "seed": 1771476173, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "ipca-2U6Ichp5KRWeBGiU", - "focus": 0.381367937500731, - "gap": 3.8982105359317814 - }, - "endBinding": { - "elementId": "eYMWKEiFVFlYbjiPgu_c4", - "focus": 0.2019864602059321, - "gap": 6.524513889047455 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 129, - -9 - ] - ] - }, - { - "type": "arrow", - "version": 58, - "versionNonce": 403964579, - "isDeleted": false, - "id": "x5FlGy9vo-0WFWlvTLxRB", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 630.6120629006252, - "y": 483.8482760775462, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 151.38793709937477, - "height": 3.1517239224538116, - "seed": 625380429, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": null, - "endBinding": { - "elementId": "0kpaYctW0QC41GkaU0Fnm", - "focus": -0.28899374373966724, - "gap": 7.345010020824645 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 151.38793709937477, - 3.1517239224538116 - ] - ] - }, - { - "type": "arrow", - "version": 257, - "versionNonce": 677492291, - "isDeleted": false, - "id": "B-ARwwElkcqpEnbbGinI1", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 620.2972122415217, - "y": 767.8259116200478, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 105.25300037055923, - "height": 3.00722858201598, - "seed": 1445768771, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "8Kq9uOVih2T18r283qOW_", - "focus": 0.19635383025160105, - "gap": 5.918038308672706 - }, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -105.25300037055923, - 3.00722858201598 - ] - ] - }, - { - "type": "arrow", - "version": 96, - "versionNonce": 1349387117, - "isDeleted": false, - "id": "Tz4cdqtGreDIsYuudDs1x", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1367, - "y": 622, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 3, - "height": 106, - "seed": 1860965379, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "eYMWKEiFVFlYbjiPgu_c4", - "focus": 0.054884241524747655, - "gap": 6.574103558846954 - }, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -3, - 106 - ] - ] - }, - { - "type": "arrow", - "version": 376, - "versionNonce": 1294704067, - "isDeleted": false, - "id": "ZVBhabk31rzDP8O9ZI07b", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 4.670616178776941, - "x": 959.5453473034307, - "y": 783.1973748150889, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 7.812955781063806, - "height": 238.3078431598483, - "seed": 447610179, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": null, - "endBinding": { - "elementId": "1MaFQq1C6f_KmXrCju5x4", - "focus": 0.1315115545982045, - "gap": 10.746558995595109 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -7.812955781063806, - 238.3078431598483 - ] - ] - }, - { - "type": "arrow", - "version": 246, - "versionNonce": 1817294669, - "isDeleted": false, - "id": "wkpAIY8WXU4_DhUYO1aB9", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1263.104260686975, - "y": 902.4835510585458, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 110.99401075709227, - "height": 3.577325516939027, - "seed": 891868547, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "e1dMmNfjngeSZQw9Q_6bR", - "focus": 1.9182906115878682, - "gap": 15.4835510585458 - }, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 110.99401075709227, - 3.577325516939027 - ] - ] - }, - { - "type": "text", - "version": 60, - "versionNonce": 1709523331, - "isDeleted": false, - "id": "Y_SmrpIdN0Bw5qAuumOQq", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 988, - "y": 482, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 78, - "height": 26, - "seed": 1670115203, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "0.1 BTC", - "baseline": 18, - "textAlign": "center", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 84, - "versionNonce": 1194052653, - "isDeleted": false, - "id": "wBU3MwS8Tev8OyGNWq1F6", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1083.5, - "y": 663, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 101, - "height": 26, - "seed": 1534790019, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "1000 XTZ", - "baseline": 18, - "textAlign": "center", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 176, - "versionNonce": 1801984291, - "isDeleted": false, - "id": "oPeSCDN2RaQLZlMs4lwHW", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 786.3493583868772, - "y": 791.9373522891948, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 147, - "height": 26, - "seed": 1663457027, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20.04819054677318, - "fontFamily": 1, - "text": "Give 2.3k ADA", - "baseline": 18, - "textAlign": "center", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 258, - "versionNonce": 35546349, - "isDeleted": false, - "id": "ECtAtkhrh6wCcSpTFeh6_", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 488.2084241147941, - "y": 793.8867522150837, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 192, - "height": 26, - "seed": 812495341, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20.048190546773178, - "fontFamily": 1, - "text": "Give max 3.5k EUR", - "baseline": 18, - "textAlign": "center", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 208, - "versionNonce": 18377827, - "isDeleted": false, - "id": "9ciMh63J68g-vSTAGOaJH", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 609.5, - "y": 437, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 171, - "height": 26, - "seed": 1942912995, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "Want min 3k USD", - "baseline": 18, - "textAlign": "center", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 111, - "versionNonce": 1985072557, - "isDeleted": false, - "id": "o0sItaNu9BXqe7GFjkfGK", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1185.5, - "y": 533, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 75, - "height": 26, - "seed": 1598303939, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "1.3 ETH", - "baseline": 18, - "textAlign": "center", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 158, - "versionNonce": 717025187, - "isDeleted": false, - "id": "eY178tj8K8fiCB25oqtHg", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1382, - "y": 647, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 198, - "height": 26, - "seed": 650001315, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "Give max 15K DOGE", - "baseline": 18, - "textAlign": "center", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 316, - "versionNonce": 181323661, - "isDeleted": false, - "id": "IsXt4dgTY7mgH6itytb74", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 872.5, - "y": 859, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 165, - "height": 26, - "seed": 403581795, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "Want min 3 DOT", - "baseline": 18, - "textAlign": "center", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 210, - "versionNonce": 2078831715, - "isDeleted": false, - "id": "e1dMmNfjngeSZQw9Q_6bR", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1244, - "y": 861, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 198, - "height": 26, - "seed": 842009251, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "wkpAIY8WXU4_DhUYO1aB9" - ], - "fontSize": 20, - "fontFamily": 1, - "text": "Give max 0.20 BNB", - "baseline": 18, - "textAlign": "center", - "verticalAlign": "top" - }, - { - "type": "rectangle", - "version": 197, - "versionNonce": 495152091, - "isDeleted": false, - "id": "wti3vXhEzdwXVYSSC_Yg4", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 919.75, - "y": 1297.75, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 573.6995798319325, - "height": 340.49999999999994, - "seed": 1080165805, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [] - }, - { - "type": "text", - "version": 194, - "versionNonce": 2141066069, - "isDeleted": false, - "id": "NJGQKI0Bu-BSAQWAGkvs0", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1049.9411764705899, - "y": 1313.487394957982, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 301.8718487394957, - "height": 37.19747899159662, - "seed": 1527490595, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 28.61344537815124, - "fontFamily": 1, - "text": "Crafted transaction ", - "baseline": 26.19747899159662, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 402, - "versionNonce": 1602173051, - "isDeleted": false, - "id": "VZPj77ZO7kpLohrkLcsaq", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 946.9327731092449, - "y": 1363.5609243697459, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 380.55882352941154, - "height": 260.3823529411763, - "seed": 245832803, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 28.613445378151237, - "fontFamily": 1, - "text": "- transfers: \n - A -- 0.1 BTC --> B\n - B -- 1k XTZ --> C\n - C -- 2.3k ADA --> D\n - D -- 3.3k EUR --> G\n - G -- 3.9 USD --> A\n- Intent A, B, C, D, G", - "baseline": 249.3823529411763, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "line", - "version": 131, - "versionNonce": 282971573, - "isDeleted": false, - "id": "dDR0rbGDKpRDhHVnEbj1j", - "fillStyle": "hachure", - "strokeWidth": 4, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 423.7733438086325, - "y": 1030.9922277551025, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 1217.4922266087865, - "height": 0.6666331686519698, - "seed": 1295070381, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 1217.4922266087865, - -0.6666331686519698 - ] - ] - }, - { - "type": "ellipse", - "version": 756, - "versionNonce": 1167558477, - "isDeleted": false, - "id": "Y1Mwn-VLiFFNqjTIzDdGi", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 971.395787942603, - "y": 1084.75, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 142.99999999999994, - "height": 63.000000000000014, - "seed": 803447789, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "wn9QHNTxewgA6oWR_jL0I", - "HtZRI-FNYskH4xD-NSUP7" - ] - }, - { - "type": "text", - "version": 491, - "versionNonce": 1766483021, - "isDeleted": false, - "id": "F7Vff6Hn-nwKWlHga6GEW", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 998.395787942603, - "y": 1100.75, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 87, - "height": 26, - "seed": 1821023587, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "Intent E", - "baseline": 18, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "arrow", - "version": 602, - "versionNonce": 1139487939, - "isDeleted": false, - "id": "wn9QHNTxewgA6oWR_jL0I", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 838.2662361154958, - "y": 1115.6051125581707, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 127.08332287156463, - "height": 3.5588919032202284, - "seed": 1515770947, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "GhbNF28zPBdmlEAk4sj4B", - "focus": 0.24968415527183857, - "gap": 10.417486034576314 - }, - "endBinding": { - "elementId": "Y1Mwn-VLiFFNqjTIzDdGi", - "focus": 0.20198646020593047, - "gap": 6.48230359390098 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 127.08332287156463, - -3.5588919032202284 - ] - ] - }, - { - "type": "arrow", - "version": 537, - "versionNonce": 1389208675, - "isDeleted": false, - "id": "HtZRI-FNYskH4xD-NSUP7", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1119.895787942603, - "y": 1112.25, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 158.02664733117444, - "height": 1.6298954558747027, - "seed": 1000247245, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "Y1Mwn-VLiFFNqjTIzDdGi", - "focus": -0.1521545689608934, - "gap": 5.9061722485449195 - }, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 158.02664733117444, - 1.6298954558747027 - ] - ] - }, - { - "type": "text", - "version": 284, - "versionNonce": 2018617933, - "isDeleted": false, - "id": "N9A9cOEizfeHChb2jpWZz", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 853.395787942603, - "y": 1068.25, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 75, - "height": 26, - "seed": 1106624845, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "1.3 ETH", - "baseline": 18, - "textAlign": "center", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 319, - "versionNonce": 1565357325, - "isDeleted": false, - "id": "zd6CqXgDZCINde5uj4yN1", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1109.895787942603, - "y": 1068.25, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 198, - "height": 26, - "seed": 1379632643, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "Give max 15K DOGE", - "baseline": 18, - "textAlign": "center", - "verticalAlign": "top" - }, - { - "type": "ellipse", - "version": 488, - "versionNonce": 519207363, - "isDeleted": false, - "id": "GhbNF28zPBdmlEAk4sj4B", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 685.5, - "y": 1078.5, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 142.99999999999994, - "height": 63.000000000000014, - "seed": 1312450381, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "YebzbhwZPZJG7VeGK6buO", - "jrzBVVdi5EqY0mYYzI-qC", - "vUyB6nADBS51AWp7XW9EQ", - "wn9QHNTxewgA6oWR_jL0I", - "KdMOyTpK2hvtrVnL6DNUk" - ] - }, - { - "type": "text", - "version": 229, - "versionNonce": 1476996579, - "isDeleted": false, - "id": "WJ9wOt80gJsxizloGLxfL", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 712.5, - "y": 1094.5, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 88, - "height": 26, - "seed": 377241603, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "Intent B", - "baseline": 18, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "ellipse", - "version": 765, - "versionNonce": 949274637, - "isDeleted": false, - "id": "nADlxrdq_B6PfDfo-HQQG", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 666.2871222634944, - "y": 1200.75, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 142.99999999999994, - "height": 63.000000000000014, - "seed": 1679328365, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "Tv4Heajn0ixll9tSaFYAV", - "gSSopQezSVkjkU58H15H_" - ] - }, - { - "type": "text", - "version": 502, - "versionNonce": 720585923, - "isDeleted": false, - "id": "mX16fM9A-0VWPNNJUyNpS", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 693.2871222634944, - "y": 1216.75, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 85, - "height": 26, - "seed": 1794245859, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "Intent F", - "baseline": 18, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "arrow", - "version": 622, - "versionNonce": 935737251, - "isDeleted": false, - "id": "Tv4Heajn0ixll9tSaFYAV", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 4.670616178776941, - "x": 541.3324695669255, - "y": 1110.447374815089, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 7.812955781063806, - "height": 238.3078431598483, - "seed": 2026335949, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": null, - "endBinding": { - "elementId": "nADlxrdq_B6PfDfo-HQQG", - "focus": 0.07219246840230681, - "gap": 9.727127096910678 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -7.812955781063806, - 238.3078431598483 - ] - ] - }, - { - "type": "arrow", - "version": 492, - "versionNonce": 1577405251, - "isDeleted": false, - "id": "gSSopQezSVkjkU58H15H_", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 844.8913829504695, - "y": 1229.7335510585458, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 110.99401075709227, - "height": 3.577325516939027, - "seed": 1824878723, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "2ga4PRzeyXVKa442XCN2Y", - "focus": 1.9182906115878662, - "gap": 15.4835510585458 - }, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 110.99401075709227, - 3.577325516939027 - ] - ] - }, - { - "type": "text", - "version": 434, - "versionNonce": 1228568397, - "isDeleted": false, - "id": "g4OJ4hTt8EHD2ib5qCNue", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 454.2871222634972, - "y": 1186.25, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 165, - "height": 26, - "seed": 1089080621, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "Want min 3 DOT", - "baseline": 18, - "textAlign": "center", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 323, - "versionNonce": 1748647533, - "isDeleted": false, - "id": "2ga4PRzeyXVKa442XCN2Y", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 825.7871222634944, - "y": 1188.25, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 198, - "height": 26, - "seed": 610953251, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "gSSopQezSVkjkU58H15H_" - ], - "fontSize": 20, - "fontFamily": 1, - "text": "Give max 0.20 BNB", - "baseline": 18, - "textAlign": "center", - "verticalAlign": "top" - }, - { - "type": "arrow", - "version": 658, - "versionNonce": 1450766733, - "isDeleted": false, - "id": "KdMOyTpK2hvtrVnL6DNUk", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 4.670616178776941, - "x": 559.906477890532, - "y": 993.9852887975298, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 7.812955781063806, - "height": 238.3078431598483, - "seed": 398907139, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": null, - "endBinding": { - "elementId": "GhbNF28zPBdmlEAk4sj4B", - "focus": -0.05450706234283051, - "gap": 10.753265054089042 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -7.812955781063806, - 238.3078431598483 - ] - ] - }, - { - "type": "text", - "version": 497, - "versionNonce": 1079658179, - "isDeleted": false, - "id": "aM2wnnRNQ8hdsJNJ-zvH6", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 458.36113058710646, - "y": 1069.7879139824408, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 194, - "height": 26, - "seed": 1308118701, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "Want min 0.09 BTC", - "baseline": 18, - "textAlign": "center", - "verticalAlign": "top" - } - ], - "appState": { - "gridSize": null, - "viewBackgroundColor": "#ffffff" - } -} \ No newline at end of file diff --git a/documentation/dev/src/explore/design/intent_gossip/matchmaker_graph.png b/documentation/dev/src/explore/design/intent_gossip/matchmaker_graph.png deleted file mode 100644 index ab284b0e70511ec0e8e40a0aa5c2bd6c4ed2ec12..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 156552 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:HJZpaSnO`Nr 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 - - - - - - Intent AIntent BIntent CIntent DIntent EIntent F0.1 BTC1000 XTZGive 2.3k ADAGive max 3.5k EURWant min 3k USD1.3 ETHGive max 15K DOGEWant min 3 DOTGive max 0.20 BNBCrafted transaction - transfers: - A -- 0.1 BTC --> B - B -- 1k XTZ --> C - C -- 2.3k ADA --> D - D -- 3.3k EUR --> G - G -- 3.9 USD --> A- Intent A, B, C, D, GIntent E1.3 ETHGive max 15K DOGEIntent BIntent FWant min 3 DOTGive max 0.20 BNBWant min 0.09 BTC \ No newline at end of file diff --git a/documentation/dev/src/explore/design/intent_gossip/matchmaker_process.excalidraw b/documentation/dev/src/explore/design/intent_gossip/matchmaker_process.excalidraw deleted file mode 100644 index dcb48040f9..0000000000 --- a/documentation/dev/src/explore/design/intent_gossip/matchmaker_process.excalidraw +++ /dev/null @@ -1,1883 +0,0 @@ -{ - "type": "excalidraw", - "version": 2, - "source": "https://excalidraw.com", - "elements": [ - { - "type": "text", - "version": 250, - "versionNonce": 477786094, - "isDeleted": false, - "id": "-fWwS7rt9LYqEFNzDaOFL", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1334.071428571429, - "y": 1108.4285714285713, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 115, - "height": 70, - "seed": 1676859603, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "yBtnqGclgLrHk5_Ql7cuO" - ], - "fontSize": 28, - "fontFamily": 3, - "text": "send_tx\n(data)", - "baseline": 63, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "ellipse", - "version": 178, - "versionNonce": 1385647602, - "isDeleted": false, - "id": "-AUKbp8i4Y0O6x-LjVldd", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 297, - "y": 132, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 1587.8571428571427, - "height": 1546, - "seed": 2049426387, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [] - }, - { - "type": "text", - "version": 102, - "versionNonce": 1069695534, - "isDeleted": false, - "id": "8SDYqin0B7kut0s8YSY5Z", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 870, - "y": 178, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 355, - "height": 46, - "seed": 1891888509, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 36, - "fontFamily": 1, - "text": "Matchmaker process", - "baseline": 32, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "arrow", - "version": 666, - "versionNonce": 1176289202, - "isDeleted": false, - "id": "9rcJtdHxvs9duQVcmN6pg", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1018.4827638040854, - "y": -498.6392023935267, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 221.76726681910736, - "height": 784.1206838750081, - "seed": 395336627, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "u-ME94nrrlTlc6E3cTspG", - "focus": 0.5186114360714434, - "gap": 14.860797606473284 - }, - "endBinding": { - "elementId": "20SyJveLAUi7KoBBp_oDS", - "focus": 0.14947349178376995, - "gap": 4.518518518518533 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -221.76726681910736, - 784.1206838750081 - ] - ] - }, - { - "type": "rectangle", - "version": 296, - "versionNonce": 1188416622, - "isDeleted": false, - "id": "20SyJveLAUi7KoBBp_oDS", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 670, - "y": 290, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 201, - "height": 61, - "seed": 1788635837, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "9rcJtdHxvs9duQVcmN6pg", - "EV9g4uNJem7yTF0HdehQG", - "coek_IDR9PRlSqn_xuBfH" - ] - }, - { - "type": "text", - "version": 126, - "versionNonce": 328071538, - "isDeleted": false, - "id": "u-ME94nrrlTlc6E3cTspG", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 983, - "y": -549.5, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 197, - "height": 36, - "seed": 1618827037, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "9rcJtdHxvs9duQVcmN6pg", - "MQZgoJ0QZeyWyyOlwsTJ7", - "wX2vQSP79rzqU32fALRHb" - ], - "fontSize": 28, - "fontFamily": 1, - "text": "gossip mempool", - "baseline": 25, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 194, - "versionNonce": 796790446, - "isDeleted": false, - "id": "CcRIOeocsp5wp09s5Cald", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 683, - "y": 298.5, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "width": 176, - "height": 36, - "seed": 1367059613, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 28, - "fontFamily": 1, - "text": "Filter_1.wasm", - "baseline": 25, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "rectangle", - "version": 343, - "versionNonce": 439483186, - "isDeleted": false, - "id": "q87Hkm0Sw3bVVd3Wg6HND", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 996.5, - "y": 276.5, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 201, - "height": 61, - "seed": 903521971, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "9rcJtdHxvs9duQVcmN6pg", - "wX2vQSP79rzqU32fALRHb" - ] - }, - { - "type": "rectangle", - "version": 386, - "versionNonce": 1449396462, - "isDeleted": false, - "id": "pF6B18evRJlwUi2JcmQxA", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1352.5, - "y": 275.5, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 201, - "height": 61, - "seed": 2098314525, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "9rcJtdHxvs9duQVcmN6pg", - "MQZgoJ0QZeyWyyOlwsTJ7", - "quXd_TqwuN2CmoyI_vXkX", - "tQlObdUcJ4e-eO1KrOatP", - "AFE8t2QPl0MtqNC64Ktcv" - ] - }, - { - "type": "text", - "version": 268, - "versionNonce": 946849010, - "isDeleted": false, - "id": "dLtlrcEEya8xcYfwZhZia", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1365, - "y": 287, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "width": 185, - "height": 36, - "seed": 2000393875, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "quXd_TqwuN2CmoyI_vXkX" - ], - "fontSize": 28, - "fontFamily": 1, - "text": "Filter_n.wasm", - "baseline": 25, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 160, - "versionNonce": 454081326, - "isDeleted": false, - "id": "B5qXjcTYw3uMpWIOVJW6r", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1077.5, - "y": 289, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "width": 23, - "height": 36, - "seed": 1953378803, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 28, - "fontFamily": 1, - "text": "...", - "baseline": 25, - "textAlign": "center", - "verticalAlign": "middle" - }, - { - "type": "arrow", - "version": 452, - "versionNonce": 1741575858, - "isDeleted": false, - "id": "MQZgoJ0QZeyWyyOlwsTJ7", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1154.9140472935462, - "y": -501.5, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 207.63095361581804, - "height": 762.5, - "seed": 52989821, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "u-ME94nrrlTlc6E3cTspG", - "focus": -0.63125, - "gap": 12 - }, - "endBinding": { - "elementId": "pF6B18evRJlwUi2JcmQxA", - "focus": -0.718727980147667, - "gap": 14.5 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 207.63095361581804, - 762.5 - ] - ] - }, - { - "type": "arrow", - "version": 398, - "versionNonce": 65873262, - "isDeleted": false, - "id": "wX2vQSP79rzqU32fALRHb", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1089.7329110152689, - "y": -503.5, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 0.6477652019841571, - "height": 777.5, - "seed": 858158013, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "u-ME94nrrlTlc6E3cTspG", - "focus": -0.08333333333333333, - "gap": 10 - }, - "endBinding": { - "elementId": "q87Hkm0Sw3bVVd3Wg6HND", - "focus": -0.06557377049180328, - "gap": 2.5 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 0.6477652019841571, - 777.5 - ] - ] - }, - { - "type": "rectangle", - "version": 251, - "versionNonce": 1492430962, - "isDeleted": false, - "id": "Qby63QOrxFMccQD3d2c92", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 584.4285714285714, - "y": 892.8571428571428, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 305, - "height": 129.8571428571429, - "seed": 906153683, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "EV9g4uNJem7yTF0HdehQG", - "yBtnqGclgLrHk5_Ql7cuO", - "Wb12KbhuRcEHH5IclCfjz" - ] - }, - { - "type": "text", - "version": 175, - "versionNonce": 1648510894, - "isDeleted": false, - "id": "EU8SONkJD9g8GszHushxg", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 613.4285714285714, - "y": 905.3571428571428, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "width": 264, - "height": 34, - "seed": 711796221, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 28, - "fontFamily": 2, - "text": "matchmaker_1.wasm", - "baseline": 24, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "arrow", - "version": 882, - "versionNonce": 262787634, - "isDeleted": false, - "id": "EV9g4uNJem7yTF0HdehQG", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 739.6354774988769, - "y": 363.8196459125622, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 2.694775060113102, - "height": 59.792753760100425, - "seed": 589900403, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "20SyJveLAUi7KoBBp_oDS", - "focus": 0.32213015232123915, - "gap": 12.81964591256218 - }, - "endBinding": { - "elementId": "NUXnLdbMG_fQSEDQtu2Ik", - "focus": -0.4632754266251567, - "gap": 9.81617175590884 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 2.694775060113102, - 59.792753760100425 - ] - ] - }, - { - "type": "rectangle", - "version": 313, - "versionNonce": 1983455726, - "isDeleted": false, - "id": "02X_kZ6WrMz4xBI8cgnGg", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1349.9285714285716, - "y": 894.7857142857143, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 305, - "height": 148.42857142857147, - "seed": 1614285181, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "EV9g4uNJem7yTF0HdehQG", - "quXd_TqwuN2CmoyI_vXkX", - "Q1Ij1-SrX5G6sFDtWRjZD" - ] - }, - { - "type": "text", - "version": 233, - "versionNonce": 2127870962, - "isDeleted": false, - "id": "zwDG2KxyuTcJmWoH5zXjV", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1378.9285714285716, - "y": 907.2857142857143, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "width": 264, - "height": 34, - "seed": 1715804371, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 28, - "fontFamily": 2, - "text": "matchmaker_n.wasm", - "baseline": 24, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "rectangle", - "version": 260, - "versionNonce": 612134322, - "isDeleted": false, - "id": "qFSA3c0L_Ds7pnNR9vyEk", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 988.4285714285716, - "y": 1605.7142857142858, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 221.00000000000006, - "height": 55, - "seed": 1486037725, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "KdQIFFwY0Q-VCyIjJLjqc", - "RuPyouXclWRd1e2Onhfm4", - "tqejUpWw7UdRQgeKJx1Qs", - "jfK56lesWGBAsc29YGxXx" - ] - }, - { - "type": "text", - "version": 175, - "versionNonce": 1108344430, - "isDeleted": false, - "id": "CWmX8zj_7xHE5WtGuwcr9", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1025.4285714285716, - "y": 1615.2142857142858, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 159, - "height": 36, - "seed": 1565496083, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 28, - "fontFamily": 1, - "text": "Tx Channel", - "baseline": 25, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 173, - "versionNonce": 1909000873, - "isDeleted": false, - "id": "NUXnLdbMG_fQSEDQtu2Ik", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 717.9285714285712, - "y": 433.42857142857144, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 97, - "height": 36, - "seed": 335380755, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "EV9g4uNJem7yTF0HdehQG", - "Wb12KbhuRcEHH5IclCfjz", - "AzA1FaOgPEa4cFOKIb_XI" - ], - "fontSize": 28, - "fontFamily": 1, - "text": "is valid", - "baseline": 25, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "rectangle", - "version": 323, - "versionNonce": 1795041586, - "isDeleted": false, - "id": "QmaxQnRFTdOUnNNcMPy7X", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 524.4999999999995, - "y": 1261.9285714285713, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 537.8571428571428, - "height": 67, - "seed": 1680157853, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "EV9g4uNJem7yTF0HdehQG", - "RuPyouXclWRd1e2Onhfm4", - "yBtnqGclgLrHk5_Ql7cuO", - "tqejUpWw7UdRQgeKJx1Qs" - ] - }, - { - "type": "text", - "version": 333, - "versionNonce": 1782168302, - "isDeleted": false, - "id": "NUM8zAtLsxNcBlfW4Jj7Q", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 541.4999999999995, - "y": 1278.4285714285713, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 492, - "height": 35, - "seed": 1032271795, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "yBtnqGclgLrHk5_Ql7cuO" - ], - "fontSize": 28, - "fontFamily": 3, - "text": "tx_wrapper(data:Vec) -> Tx", - "baseline": 28, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "arrow", - "version": 836, - "versionNonce": 998650610, - "isDeleted": false, - "id": "yBtnqGclgLrHk5_Ql7cuO", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 745.9085294063941, - "y": 1042.550408585807, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 0.5420749370830436, - "height": 221.1355590894077, - "seed": 1278179069, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "Qby63QOrxFMccQD3d2c92", - "focus": -0.05746246854310238, - "gap": 19.836122871521297 - }, - "endBinding": { - "elementId": "NUM8zAtLsxNcBlfW4Jj7Q", - "focus": -0.16651713537544344, - "gap": 14.742603753356661 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 0.5420749370830436, - 221.1355590894077 - ] - ] - }, - { - "type": "rectangle", - "version": 405, - "versionNonce": 1298148654, - "isDeleted": false, - "id": "ZJr3NtMIhOWJfBQVo_6Fv", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1195.7857142857133, - "y": 1253.6428571428569, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 534.9999999999999, - "height": 67, - "seed": 422192253, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "EV9g4uNJem7yTF0HdehQG", - "yBtnqGclgLrHk5_Ql7cuO", - "KdQIFFwY0Q-VCyIjJLjqc", - "jfK56lesWGBAsc29YGxXx" - ] - }, - { - "type": "text", - "version": 372, - "versionNonce": 1508312242, - "isDeleted": false, - "id": "HCJ2WIORw1W3_N60QE3F-", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1224.7857142857133, - "y": 1266.1428571428569, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 492, - "height": 35, - "seed": 22425043, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "Q1Ij1-SrX5G6sFDtWRjZD" - ], - "fontSize": 28, - "fontFamily": 3, - "text": "tx_wrapper(data:Vec) -> Tx", - "baseline": 28, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 280, - "versionNonce": 533175922, - "isDeleted": false, - "id": "-Bpweaa_yHbmmzQ8Fbx5I", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 786.7142857142856, - "y": 1113.2142857142856, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 115, - "height": 70, - "seed": 194669533, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "yBtnqGclgLrHk5_Ql7cuO" - ], - "fontSize": 28, - "fontFamily": 3, - "text": "send_tx\n(data)", - "baseline": 63, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 170, - "versionNonce": 1490893230, - "isDeleted": false, - "id": "W9zv5kY3tnQEBVzDDO4N6", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 600.1428571428569, - "y": 947.142857142857, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 220, - "height": 72, - "seed": 876039485, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 28, - "fontFamily": 1, - "text": "tries to match\nasset exchange", - "baseline": 61, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 233, - "versionNonce": 435093554, - "isDeleted": false, - "id": "6hdBGIrkrZ5cxGEvo-GL2", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1366.1428571428569, - "y": 957.7142857142857, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 203, - "height": 72, - "seed": 1851337181, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "Q1Ij1-SrX5G6sFDtWRjZD" - ], - "fontSize": 28, - "fontFamily": 1, - "text": "tries to match\nbid for NFT", - "baseline": 61, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "arrow", - "version": 735, - "versionNonce": 10867694, - "isDeleted": false, - "id": "Q1Ij1-SrX5G6sFDtWRjZD", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1475.9494785236807, - "y": 1045.8571428571422, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 0.4267578776036771, - "height": 208.23402295192489, - "seed": 1632703357, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "6hdBGIrkrZ5cxGEvo-GL2", - "focus": -0.08283125635170244, - "gap": 16.14285714285637 - }, - "endBinding": { - "elementId": "HCJ2WIORw1W3_N60QE3F-", - "focus": 0.019007158541393378, - "gap": 12.051691333789677 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -0.4267578776036771, - 208.23402295192489 - ] - ] - }, - { - "type": "text", - "version": 192, - "versionNonce": 444084334, - "isDeleted": false, - "id": "bQlxAsWkDvgA9E8xnJtCS", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 929.2857142857142, - "y": 1434.2857142857142, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 57, - "height": 36, - "seed": 288110269, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 28, - "fontFamily": 1, - "text": "push", - "baseline": 25, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 240, - "versionNonce": 213112178, - "isDeleted": false, - "id": "oCUz5xIu6AGXHaNP05Lz-", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1232.7857142857142, - "y": 1418.2857142857142, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 57, - "height": 36, - "seed": 18964637, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 28, - "fontFamily": 1, - "text": "push", - "baseline": 25, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "diamond", - "version": 171, - "versionNonce": 125953897, - "isDeleted": false, - "id": "K_xcNPiBXE-cXJS9zVPXW", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1359.2857142857142, - "y": 1675.6428571428573, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 530, - "height": 522.8571428571429, - "seed": 1923266557, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [] - }, - { - "type": "text", - "version": 353, - "versionNonce": 394354599, - "isDeleted": false, - "id": "-b3XUoKQR2HkQtxmLNJ8P", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1460.7857142857144, - "y": 1770.2857142857142, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 341, - "height": 340, - "seed": 307253395, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 28, - "fontFamily": 2, - "text": "intent type \n\n\n- Asset Exchange V1,... ,Vn\n\n- NFT Bid V1, ....,Vm\n\n- Proposal tax rate\n\n- ...", - "baseline": 330, - "textAlign": "center", - "verticalAlign": "top" - }, - { - "type": "arrow", - "version": 321, - "versionNonce": 1380748402, - "isDeleted": false, - "id": "tqejUpWw7UdRQgeKJx1Qs", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 737.3862781852455, - "y": 1337.5000000000002, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 361.4616837725865, - "height": 256, - "seed": 519759858, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "QmaxQnRFTdOUnNNcMPy7X", - "focus": 0.36506890309214235, - "gap": 8.571428571428896 - }, - "endBinding": { - "elementId": "qFSA3c0L_Ds7pnNR9vyEk", - "focus": 0.3749733951794426, - "gap": 12.214285714285552 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 361.4616837725865, - 256 - ] - ] - }, - { - "type": "arrow", - "version": 309, - "versionNonce": 767591918, - "isDeleted": false, - "id": "jfK56lesWGBAsc29YGxXx", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1464.4663097459384, - "y": 1327.5000000000002, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 304.9230901746971, - "height": 266.0000000000002, - "seed": 1704766194, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "ZJr3NtMIhOWJfBQVo_6Fv", - "focus": -0.15595141865445492, - "gap": 6.857142857143344 - }, - "endBinding": { - "elementId": "qFSA3c0L_Ds7pnNR9vyEk", - "focus": 0.10624312511016634, - "gap": 12.214285714285552 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -304.9230901746971, - 266.0000000000002 - ] - ] - }, - { - "type": "diamond", - "version": 308, - "versionNonce": 1298647335, - "isDeleted": false, - "id": "NgADSumoY4-dLkgWi5N4Z", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 897.9285714285716, - "y": 455.1071428571429, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 425, - "height": 386.99999999999994, - "seed": 335028978, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "EV9g4uNJem7yTF0HdehQG", - "AzA1FaOgPEa4cFOKIb_XI" - ] - }, - { - "type": "text", - "version": 217, - "versionNonce": 1471444327, - "isDeleted": false, - "id": "MvTHemdF09EZ6oXZkE1jc", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1018.9285714285716, - "y": 531.1071428571429, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 170, - "height": 46, - "seed": 724442674, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 36, - "fontFamily": 1, - "text": "database", - "baseline": 32, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "arrow", - "version": 757, - "versionNonce": 1293338825, - "isDeleted": false, - "id": "AzA1FaOgPEa4cFOKIb_XI", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 820.3073244931843, - "y": 471.5118365287101, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 108.81143098291295, - "height": 175.18267082955458, - "seed": 360610866, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "NUXnLdbMG_fQSEDQtu2Ik", - "gap": 5.768100034460303, - "focus": -0.6938097555601055 - }, - "endBinding": { - "elementId": "18SWFQMli2cPThvdOpuoo", - "gap": 7.798248129571567, - "focus": -0.6635324351244143 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 108.81143098291295, - 175.18267082955458 - ] - ] - }, - { - "type": "arrow", - "version": 30, - "versionNonce": 1985069938, - "isDeleted": false, - "id": "coek_IDR9PRlSqn_xuBfH", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 668.9285714285716, - "y": 354.1071428571429, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 68, - "height": 62, - "seed": 1014756974, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "20SyJveLAUi7KoBBp_oDS", - "focus": 0.48309968177517726, - "gap": 3.1071428571428896 - }, - "endBinding": { - "elementId": "7tbyhZRSlrMMeTwNPcbDl", - "focus": -0.14152410575427682, - "gap": 6 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -68, - 62 - ] - ] - }, - { - "type": "text", - "version": 27, - "versionNonce": 590603438, - "isDeleted": false, - "id": "7tbyhZRSlrMMeTwNPcbDl", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 540.9285714285716, - "y": 422.1071428571429, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 74, - "height": 46, - "seed": 1767538158, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "coek_IDR9PRlSqn_xuBfH" - ], - "fontSize": 36, - "fontFamily": 1, - "text": "drop", - "baseline": 32, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "arrow", - "version": 32, - "versionNonce": 1173128498, - "isDeleted": false, - "id": "Wb12KbhuRcEHH5IclCfjz", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 774.9285714285716, - "y": 474.1071428571429, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 8, - "height": 406, - "seed": 939628210, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "NUXnLdbMG_fQSEDQtu2Ik", - "focus": -0.1831322697972629, - "gap": 4.678571428571445 - }, - "endBinding": { - "elementId": "Qby63QOrxFMccQD3d2c92", - "focus": 0.1851313721138299, - "gap": 12.749999999999886 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -8, - 406 - ] - ] - }, - { - "type": "text", - "version": 13, - "versionNonce": 1089412846, - "isDeleted": false, - "id": "jEi03IUAXxK1nj2Y42B7G", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 800.9285714285716, - "y": 624.1071428571429, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 53, - "height": 46, - "seed": 665121458, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 36, - "fontFamily": 1, - "text": "run", - "baseline": 32, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 26, - "versionNonce": 1615400690, - "isDeleted": false, - "id": "lI0I06cVAOlfanFTA8Ffo", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 612.9285714285716, - "y": 574.1071428571429, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 65, - "height": 46, - "seed": 752657582, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 36, - "fontFamily": 1, - "text": "add", - "baseline": 32, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "arrow", - "version": 976, - "versionNonce": 1550157735, - "isDeleted": false, - "id": "tQlObdUcJ4e-eO1KrOatP", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1459.3837617831516, - "y": 349.05652363076683, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 1.1844667472269066, - "height": 55.55587604189577, - "seed": 1629950318, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "pF6B18evRJlwUi2JcmQxA", - "focus": -0.0721870437439987, - "gap": 12.556523630766833 - }, - "endBinding": { - "elementId": "i-tn-ZhFtCTs742XKlQ71", - "focus": -0.29298735309248414, - "gap": 9.81617175590884 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -1.1844667472269066, - 55.55587604189577 - ] - ] - }, - { - "type": "text", - "version": 209, - "versionNonce": 435052722, - "isDeleted": false, - "id": "i-tn-ZhFtCTs742XKlQ71", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1423.428571428571, - "y": 414.42857142857144, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 97, - "height": 36, - "seed": 1973388402, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "tQlObdUcJ4e-eO1KrOatP", - "ho8uhQaYopUXmE-cOb5Oy", - "-aa5R0cDAH1OKloselZA3" - ], - "fontSize": 28, - "fontFamily": 1, - "text": "is valid", - "baseline": 25, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "arrow", - "version": 801, - "versionNonce": 1290356583, - "isDeleted": false, - "id": "ho8uhQaYopUXmE-cOb5Oy", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1438.8508824450746, - "y": 460.6001539378572, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 160.01481739098062, - "height": 177.3752734807801, - "seed": 652742126, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "i-tn-ZhFtCTs742XKlQ71", - "gap": 10.171582509285766, - "focus": 0.08985472450032943 - }, - "endBinding": { - "elementId": "zBxeCe2V0Axk5Bu9Z7zb_", - "focus": 0.10695154534385387, - "gap": 3.009196397424489 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -160.01481739098062, - 177.3752734807801 - ] - ] - }, - { - "type": "arrow", - "version": 309, - "versionNonce": 214916146, - "isDeleted": false, - "id": "AFE8t2QPl0MtqNC64Ktcv", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1553.1148808294615, - "y": 349.7631332623532, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 91.75609240578751, - "height": 126.39460265738433, - "seed": 635080690, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "pF6B18evRJlwUi2JcmQxA", - "focus": -0.5572753230194984, - "gap": 13.263133262353222 - }, - "endBinding": { - "elementId": "SW06q84zYJLMiyPVkQ1xY", - "focus": 0.049091461638458705, - "gap": 8.949406937405342 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 91.75609240578751, - 126.39460265738433 - ] - ] - }, - { - "type": "text", - "version": 129, - "versionNonce": 1871263726, - "isDeleted": false, - "id": "SW06q84zYJLMiyPVkQ1xY", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1628.4285714285716, - "y": 485.1071428571429, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 74, - "height": 46, - "seed": 650911790, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "AFE8t2QPl0MtqNC64Ktcv" - ], - "fontSize": 36, - "fontFamily": 1, - "text": "drop", - "baseline": 32, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "arrow", - "version": 116, - "versionNonce": 314115570, - "isDeleted": false, - "id": "-aa5R0cDAH1OKloselZA3", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1480.4285714285716, - "y": 455.1071428571429, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 8, - "height": 406, - "seed": 329761202, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": { - "elementId": "i-tn-ZhFtCTs742XKlQ71", - "focus": -0.18313226979726524, - "gap": 4.678571428571445 - }, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -8, - 406 - ] - ] - }, - { - "type": "text", - "version": 44, - "versionNonce": 1438124590, - "isDeleted": false, - "id": "cl7vkyLcyLB5BfJMeXjQw", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1506.4285714285716, - "y": 605.1071428571429, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 53, - "height": 46, - "seed": 754182766, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 36, - "fontFamily": 1, - "text": "run", - "baseline": 32, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "text", - "version": 200, - "versionNonce": 155678642, - "isDeleted": false, - "id": "DF_4GrKBdi7IsRviOYf09", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1306.4285714285716, - "y": 487.1071428571429, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 65, - "height": 46, - "seed": 1013496690, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 36, - "fontFamily": 1, - "text": "add", - "baseline": 32, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "diamond", - "version": 500, - "versionNonce": 1653880585, - "isDeleted": false, - "id": "18SWFQMli2cPThvdOpuoo", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 921.4285714285716, - "y": 614.6071428571429, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 110, - "height": 99.00000000000001, - "seed": 1872566985, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "tQlObdUcJ4e-eO1KrOatP", - "ho8uhQaYopUXmE-cOb5Oy", - "AzA1FaOgPEa4cFOKIb_XI" - ] - }, - { - "id": "bvMzoIc6JDXbDVYJF9Ibg", - "type": "text", - "x": 941.9285714285716, - "y": 654.6071428571429, - "width": 76, - "height": 26, - "angle": 0, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 1926098473, - "version": 27, - "versionNonce": 1791601191, - "isDeleted": false, - "boundElementIds": null, - "text": "table 1 ", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "left", - "verticalAlign": "top", - "baseline": 18 - }, - { - "id": "r0pIVYRB3ZOSkyTYj3h2g", - "type": "text", - "x": 1212.9285714285716, - "y": 649.1071428571429, - "width": 70, - "height": 26, - "angle": 0, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 1775138089, - "version": 27, - "versionNonce": 1051956679, - "isDeleted": false, - "boundElementIds": null, - "text": "table n", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18 - }, - { - "type": "diamond", - "version": 524, - "versionNonce": 1186891401, - "isDeleted": false, - "id": "zBxeCe2V0Axk5Bu9Z7zb_", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1193.9285714285716, - "y": 615.1071428571429, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 110, - "height": 99.00000000000001, - "seed": 748894505, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "tQlObdUcJ4e-eO1KrOatP", - "ho8uhQaYopUXmE-cOb5Oy", - "AzA1FaOgPEa4cFOKIb_XI" - ] - } - ], - "appState": { - "gridSize": null, - "viewBackgroundColor": "#ffffff" - } -} \ No newline at end of file diff --git a/documentation/dev/src/explore/design/intent_gossip/matchmaker_process.svg b/documentation/dev/src/explore/design/intent_gossip/matchmaker_process.svg deleted file mode 100644 index 226afae23b..0000000000 --- a/documentation/dev/src/explore/design/intent_gossip/matchmaker_process.svg +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - send_tx(data)Matchmaker processgossip mempoolFilter_1.wasmFilter_n.wasm...matchmaker_1.wasmmatchmaker_n.wasmTx Channelis validtx_wrapper(data:Vec<u8>) -> Txtx_wrapper(data:Vec<u8>) -> Txsend_tx(data)tries to matchasset exchangetries to matchbid for NFTpushpushintent type - Asset Exchange V1,... ,Vn- NFT Bid V1, ....,Vm- Proposal tax rate- ...databasedroprunaddis validdroprunaddtable 1 table n \ No newline at end of file diff --git a/documentation/dev/src/explore/design/intent_gossip/topic.md b/documentation/dev/src/explore/design/intent_gossip/topic.md deleted file mode 100644 index 08a6465d07..0000000000 --- a/documentation/dev/src/explore/design/intent_gossip/topic.md +++ /dev/null @@ -1,11 +0,0 @@ -# Topic - -A topic is string and an encoding that describes this sub-network. In a topic -all intents use the exact same encoding. That encoding is known by matchmakers -so it can decode them to find matches. Whenever a node subscribes to a new topic -it informs all connected nodes and each of them propagate it. With this it’s -easy to create new topics in the intent gossip network and inform others. - -Other nodes can choose to subscribe to a new topic with the help of a -filter. This filter is defined as a combination of a whitelist, a regex -expression, and a maximum limit. diff --git a/documentation/dev/src/explore/prototypes/README.md b/documentation/dev/src/explore/prototypes/README.md deleted file mode 100644 index 375dd805c0..0000000000 --- a/documentation/dev/src/explore/prototypes/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# Prototypes - -A prototype should start with a description of its goals. These can include, but are not limited to a proof of concept of novel ideas or alternative approaches, comparing different libraries and gathering feedback. - -To get started on a prototype, please: -- open an issue on this repository -- add a sub-page to this section with a link to the issue - -The page outlines the goals and possibly contains any notes that are not suitable to be added to the prototype source itself, while the issue should track the sub-task, their progress, and assignees. - -The code quality is of lesser importance in prototypes. To put the main focus on the prototype's goals, we don't need to worry much about testing, linting and doc strings. - -## Advancing a successful prototype - -Once the goals of the prototype have been completed, we can assess if we'd like to advance the prototype to a development version. - -In order to advance a prototype, in general we'll want to: -- review & clean-up the code for lint, format and best practices -- enable common Rust lints -- review any new dependencies -- add docs for any public interface (internally public too) -- add automated tests -- if the prototype has diverged from the original design, update these pages diff --git a/documentation/dev/src/explore/prototypes/base-ledger.md b/documentation/dev/src/explore/prototypes/base-ledger.md deleted file mode 100644 index 7443568ba5..0000000000 --- a/documentation/dev/src/explore/prototypes/base-ledger.md +++ /dev/null @@ -1,112 +0,0 @@ -# Base ledger prototype - -## Version 3 - -tracking issue - - -### Goals - -- various shell and protocol fixes, improvements and additions -- add more crypto support -- WASM improvements -- implement new validity predicates -- storage improvements -- gas & fees -- fixes for issues found in the Feigenbaum testnet -- IBC integration -- Ferveo/ABCI++ integration -- PoS improvements and new features - - testing (unit + integration + e2e) - - storage values refactoring - - use checked arithmetics - - validator VP - - staking rewards - - staking reward VP - - re-delegation - - validator - - deactivation/reactivation - - change consensus key - -## Version 2 - -tracking issue - -### Goals - -- storage - - build key schema for access - - implement dynamic account sub-spaces -- implement more complete support for WASM transactions and validity predicates - - transactions can read/write all storage - - validity predicates receive the set of changes (changed keys or complete write log) and can read their pre/post state -- add basic transaction gas metering -- various other improvements - -## Version 1 - -tracking issue - -### Goals - -- get some hands-on experience with Rust and Tendermint -- initial usable node + client (+ validator?) setup -- provide a base layer for other prototypes that need to build on top of a ledger - -### Components - -The main components are built in a single Cargo project with [shared library code](#shared) and multiple binaries: -- `anoma` - main executable with commands for both the node and the client (`anoma node` and `anoma client`) -- `anoman` - the [node](#node) -- `anomac` - the [client](#client) - -#### Node - -The node is built into `anoman`. - -##### Shell - -The shell is what currently pulls together all the other components in the node. - -When it's ran: -- establish a channel (e.g.`mpsc::channel` - Multi-producer, single-consumer FIFO queue) for communication from tendermint to the shell -- launch tendermint node in another thread with the channel sender - - send tendermint ABCI requests via the channel together with a new channel sender to receive a response -- run shell loop with the channel receiver, which handles ABIC requests: - - [transaction execution](../design/ledger/tx.md) which includes [wasm VM calls](../design/ledger/wasm-vm.md) - -###### Tendermint - -This module handles initializing and running `tendermint` and forwards messages for the ABCI requests via its channel sender. - -##### Storage - -Key-value storage. More details are specified on [Storage page](../design/ledger/storage.md). - -##### CLI - -- `anoma run` to start the node (will initialize (if needed) and launch tendermint under the hood) -- `anoma reset` to delete all the node's state from DB and tendermint's state - -#### Client - -Allows to submit a transaction with an attached wasm code to the node with: - -`anoma tx --code tx.wasm` - -It presents back the received response on stdout. Currently, it waits for both the mempool validation and application in a block. - -#### Shared - -##### Config - -Configuration settings: -- home directory (db storage and tendermint config and data) - -##### Genesis - -The genesis parameters, such as the initial validator set, are used to initialize a chain's genesis block. - -##### RPC types - -The types for data that can be submitted to the node via the client's RPC commands. diff --git a/documentation/dev/src/explore/prototypes/gossip-layer.md b/documentation/dev/src/explore/prototypes/gossip-layer.md deleted file mode 100644 index b991ca5c68..0000000000 --- a/documentation/dev/src/explore/prototypes/gossip-layer.md +++ /dev/null @@ -1,61 +0,0 @@ -# Intent Gossip system prototype - -## Version 2 - -tracking issue - -- Separate matchmakers from intent gossiper nodes -- Various fixes and improvements -- fixes for issues found in the Feigenbaum testnet -- Persistent storage -- Intent gossip and matching of complex txs -- multi-party trades (e.g. 10) -- multi-asset trades (FT, NFT) -- NFT swaps -- Benchmarking base load for the entire network -- Incentives -- Docs - -## Version 1 - -tracking issue - -### Goals - -- learning rust -- usable node + client setup : - - intent - - incentive function - - mempool and white list -- basic matchmaker - -### components - -The intent gossip is build conjointly to the ledger and share the same binary. - -#### Node - -The node is built into `anoman`, it runs all the necesarry part, rpc server, -libp2p, intent gossip app. - -##### Intent gossip application - -The intent gossip application - -###### Mempool - -###### Filter - -##### Network behaviour -The network behaviour is the part that react on network event. It creates a -channel (e.g. `tokio::mpsc::channel`) with the intent gossip to communicate all -intent it receive. - -##### Rpc server -If the rpc command line option is set it creates a tonic server that receive -command from a client and send theses through a channel -(e.g. `tokio::mpsc::channel`) to the the intent gossip. - -#### Client -Allow to submit a intent : -`anoma gossip --data "data"` From 4060f2eaa1ce70f17b211252cb915a467edc9226 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zemanovi=C4=8D?= Date: Tue, 2 Aug 2022 18:19:52 +0200 Subject: [PATCH 006/118] docs/dev: update mdbook-admonish assets to v2 --- documentation/dev/assets/mdbook-admonish.css | 36 ++++++++++++++++++++ documentation/dev/book.toml | 2 +- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/documentation/dev/assets/mdbook-admonish.css b/documentation/dev/assets/mdbook-admonish.css index 5d83c334d6..5e360387df 100644 --- a/documentation/dev/assets/mdbook-admonish.css +++ b/documentation/dev/assets/mdbook-admonish.css @@ -1,3 +1,4 @@ +@charset "UTF-8"; :root { --md-admonition-icon--note: url("data:image/svg+xml;charset=utf-8,"); @@ -23,6 +24,8 @@ url("data:image/svg+xml;charset=utf-8,"); --md-admonition-icon--quote: url("data:image/svg+xml;charset=utf-8,"); + --md-details-icon: + url("data:image/svg+xml;charset=utf-8,"); } :is(.admonition) { @@ -56,12 +59,21 @@ html :is(.admonition) > :last-child { margin-bottom: 1.2rem; } +a.admonition-anchor-link { + display: none; + position: absolute; + left: -1.2rem; + padding-right: 1rem; +} a.admonition-anchor-link:link, a.admonition-anchor-link:visited { color: var(--fg); } a.admonition-anchor-link:link:hover, a.admonition-anchor-link:visited:hover { text-decoration: none; } +a.admonition-anchor-link::before { + content: "§"; +} :is(.admonition-title, summary) { position: relative; @@ -94,6 +106,30 @@ html :is(.admonition-title, summary):last-child { -webkit-mask-size: contain; content: ""; } +:is(.admonition-title, summary):hover a.admonition-anchor-link { + display: initial; +} + +details.admonition > summary.admonition-title::after { + position: absolute; + top: 0.625em; + inset-inline-end: 1.6rem; + height: 2rem; + width: 2rem; + background-color: currentcolor; + mask-image: var(--md-details-icon); + -webkit-mask-image: var(--md-details-icon); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-size: contain; + content: ""; + transform: rotate(0deg); + transition: transform 0.25s; +} +details[open].admonition > summary.admonition-title::after { + transform: rotate(90deg); +} :is(.admonition):is(.note) { border-color: #448aff; diff --git a/documentation/dev/book.toml b/documentation/dev/book.toml index 585a0875b2..a1728506b9 100644 --- a/documentation/dev/book.toml +++ b/documentation/dev/book.toml @@ -29,4 +29,4 @@ renderer = ["html"] [preprocessor.admonish] command = "mdbook-admonish" -assets_version = "1.0.0" # do not edit: managed by `mdbook-admonish install` +assets_version = "2.0.0" # do not edit: managed by `mdbook-admonish install` From 3874b7b73c9a31b3aee02189ee977c2eb32e41d3 Mon Sep 17 00:00:00 2001 From: Tomas Zemanovic Date: Thu, 11 Aug 2022 10:16:01 +0200 Subject: [PATCH 007/118] Apply suggestions from code review --- documentation/dev/book.toml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/documentation/dev/book.toml b/documentation/dev/book.toml index a1728506b9..f1b171cd24 100644 --- a/documentation/dev/book.toml +++ b/documentation/dev/book.toml @@ -2,13 +2,14 @@ authors = ["Heliax R&D Team"] language = "en" multilingual = false -site-url = "https://docs.anoma.network/master/" +# This book is currently not being hosted +# site-url = "https://docs.anoma.network/master/" src = "src" title = "Anoma - DOCS" [output.html] -edit-url-template = "https://github.com/anoma/anoma/edit/master/docs/{path}" -git-repository-url = "https://github.com/anoma/anoma" +edit-url-template = "https://github.com/anoma/namada/edit/master/documentation/dev/{path}" +git-repository-url = "https://github.com/anoma/namada" additional-css = ["assets/custom.css", "assets/mdbook-admonish.css"] additional-js = ["assets/mermaid.min.js", "assets/mermaid-init.js"] mathjax-support = true From 1de31626af013d0467c2f76ca94f13b9e1c3424e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zemanovi=C4=8D?= Date: Wed, 17 Aug 2022 08:30:36 +0200 Subject: [PATCH 008/118] docs/dev: s/anoma/namada --- documentation/dev/README.md | 7 +---- documentation/dev/src/README.md | 14 ++++------ documentation/dev/src/explore/README.md | 2 +- .../dev/src/explore/design/actors.md | 6 ++-- .../dev/src/explore/design/ledger.md | 14 ++++++---- .../src/explore/design/ledger/governance.md | 28 ++++++++++--------- .../explore/design/ledger/pos-integration.md | 8 +++++- .../dev/src/explore/design/ledger/storage.md | 12 +++++--- .../dev/src/explore/design/testnet-setup.md | 2 +- documentation/dev/src/specs/README.md | 4 +-- documentation/dev/src/specs/crypto.md | 6 ++-- documentation/dev/src/specs/encoding.md | 2 +- documentation/dev/src/specs/ledger.md | 2 +- .../src/specs/ledger/default-transactions.md | 4 +-- .../ledger/default-validity-predicates.md | 2 +- documentation/dev/src/specs/ledger/rpc.md | 2 +- documentation/dev/src/specs/overview.md | 2 +- 17 files changed, 63 insertions(+), 54 deletions(-) diff --git a/documentation/dev/README.md b/documentation/dev/README.md index 99d845411c..319003497a 100644 --- a/documentation/dev/README.md +++ b/documentation/dev/README.md @@ -1,11 +1,6 @@ See the [Introduction](./src/). In short: + - `make dev-deps` install dependencies - `make serve` open the rendered mdBook in your default browser - -Using Nix: - -```bash -nix develop ..#anoma-docs -c make serve -``` diff --git a/documentation/dev/src/README.md b/documentation/dev/src/README.md index b44651e303..3108c65cdb 100644 --- a/documentation/dev/src/README.md +++ b/documentation/dev/src/README.md @@ -1,10 +1,10 @@ # Introduction -Welcome to Anoma's docs! +Welcome to Namada's docs! -## About Anoma +## About Namada -[Anoma](https://anoma.network/) is a sovereign, proof-of-stake blockchain protocol that enables private, asset-agnostic cash and private bartering among any number of parties. To learn more about the protocol, we recommend the following resources: +Namada is a sovereign, proof-of-stake blockchain protocol that enables private, asset-agnostic cash and private bartering among any number of parties. To learn more about the protocol, we recommend the following resources: - [Introduction to Anoma Medium article](https://medium.com/anomanetwork/introducing-anoma-a-blockchain-for-private-asset-agnostic-bartering-dcc47ac42d9f) - [Anoma's Whitepaper](https://anoma.network/papers/whitepaper.pdf) @@ -16,14 +16,12 @@ Welcome to Anoma's docs! The two main sections of this book are: -- [Exploration](./explore): documents the process of exploring the design and implementation space for Anoma +- [Exploration](./explore): documents the process of exploring the design and implementation space for Namada - [Specifications](./specs): implementation independent technical specifications -The Anoma user guide and networks documentation can be found at . - ### The source -This book is written using [mdBook](https://rust-lang.github.io/mdBook/) with [mdbook-mermaid](https://github.com/badboy/mdbook-mermaid) for diagrams, it currently lives in the [Anoma repo](https://github.com/anoma/anoma). +This book is written using [mdBook](https://rust-lang.github.io/mdBook/) with [mdbook-mermaid](https://github.com/badboy/mdbook-mermaid) for diagrams, it currently lives in the [Namada repo](https://github.com/anoma/namada). To get started quickly, in the `docs` directory one can: @@ -37,4 +35,4 @@ make serve The mermaid diagrams docs can be found at . -[Contributions](https://github.com/anoma/anoma/issues) to the contents and the structure of this book (nothing is set in stone) should be made via pull requests. Code changes that diverge from the spec should also update this book. +[Contributions](https://github.com/anoma/namada/issues) to the contents and the structure of this book (nothing is set in stone) should be made via pull requests. Code changes that diverge from the spec should also update this book. diff --git a/documentation/dev/src/explore/README.md b/documentation/dev/src/explore/README.md index fc5b5117cf..3614c61542 100644 --- a/documentation/dev/src/explore/README.md +++ b/documentation/dev/src/explore/README.md @@ -1,5 +1,5 @@ # Exploration -This section documents the process of exploring the design and implementation space for Anoma. Ideally, the captured information should provide an overview of the explored space and help to guide further decisions. +This section documents the process of exploring the design and implementation space for Namada. Ideally, the captured information should provide an overview of the explored space and help to guide further decisions. The content of this section is more free-form. This is largely a cross-over of both the implementation details and the design of implementation-independent specifications. diff --git a/documentation/dev/src/explore/design/actors.md b/documentation/dev/src/explore/design/actors.md index d742097db7..88e26f3d64 100644 --- a/documentation/dev/src/explore/design/actors.md +++ b/documentation/dev/src/explore/design/actors.md @@ -1,10 +1,10 @@ # Actors and Incentives -Anoma consists of various actors fulfilling various roles in the network. They are all incentivized to act for the good of the network. The native Anoma token `XAN` is used to settle transaction fees and pay for the incentives in Anoma. +Namada consists of various actors fulfilling various roles in the network. They are all incentivized to act for the good of the network. The native Namada token `XAN` is used to settle transaction fees and pay for the incentives in Namada. ## Fees associated with a transaction -Users of Anoma can +Users of Namada can - transfer private assets they hold to other users and - barter assets with other users. @@ -20,7 +20,7 @@ Each transaction may be associated with the following fees, paid in `XAN`: | Actor | Responsibilities | Incentives | Bond in escrow | May also be | |---|---|---|---|---| -| User | Make offers or send transactions | Features of Anoma | X | Anyone | +| User | Make offers or send transactions | Features of Namada | X | Anyone | | Signer | Generate key shards | portions of init_f, exe_f | ✓ | Validator | | Validator | Validate | portions of init_f, exe_f |✓ | Signer | | Submitter | Submit orders & pay init_f | successful orders get init_f back plus bonus | X | | diff --git a/documentation/dev/src/explore/design/ledger.md b/documentation/dev/src/explore/design/ledger.md index 3c3fd8ce25..25b32ee4e7 100644 --- a/documentation/dev/src/explore/design/ledger.md +++ b/documentation/dev/src/explore/design/ledger.md @@ -1,6 +1,6 @@ # The ledger -The ledger depends on [Tendermint node](https://github.com/tendermint/tendermint). Running the Anoma node will also initialize and run Tendermint node. Anoma communicates with Tendermint via the ABCI. +The ledger depends on [Tendermint node](https://github.com/tendermint/tendermint). Running the Namada node will also initialize and run Tendermint node. Namada communicates with Tendermint via the ABCI. ## Overview @@ -22,11 +22,13 @@ Configuration for threads usage can be changed via environment variables: We are using the Tendermint state-machine replication engine via ABCI. It provides many useful things, such as a BFT consensus protocol, P2P layer with peer exchange, block sync and mempool layer. Useful resources: + - Tendermint ABCI - Tendermint RPC reference - Awesome collection Rust ABCI implementations: + - - the future update planned for this crate is to add async support - longer term the goal is to be able to [seamlessly switch from Go Tendermint @@ -39,14 +41,14 @@ Rust ABCI implementations: ### ABCI Integration -The ledger wraps the Tendermint node inside the Anoma node. The Tendermint node -communicates with the Anoma shell via four layers as illustrated below. +The ledger wraps the Tendermint node inside the Namada node. The Tendermint node +communicates with the Namada shell via four layers as illustrated below. ```mermaid flowchart LR C[Client] --- R - subgraph Anoma Node - S((Anoma Shell)) + subgraph Namada Node + S((Namada Shell)) subgraph Tendermint ABCI R[RPC] === T{Tendermint} T --- TC[Consensus] @@ -62,6 +64,7 @@ flowchart LR ``` The *consensus* connection allows the shell to: + - initialize genesis on start-up - begin a block - apply a transaction(s) in a block @@ -74,6 +77,7 @@ the transaction is either new, when it has not been validated before, or to be re-checked when it has been validated at some previous level. The *query* connection is used for: + - the Tendermint node asks the last known state from the shell to determine if it needs to replay any blocks - relay client queries for some state at a given path to the shell diff --git a/documentation/dev/src/explore/design/ledger/governance.md b/documentation/dev/src/explore/design/ledger/governance.md index d518b99ae8..21fdc55da1 100644 --- a/documentation/dev/src/explore/design/ledger/governance.md +++ b/documentation/dev/src/explore/design/ledger/governance.md @@ -1,14 +1,16 @@ # Governance -Anoma introduce a governance mechanism to propose and apply protocol changes with and without the need for an hard fork. Anyone holding some M1T will be able to prosose some changes to which delegators and validator will cast their yay or nay votes. Governance on Anoma supports both signaling and voting mechanism. The difference between the the two, is that the former is needed when the changes require an hard fork. In cases where the chain is not able to produce blocks anymore, Anoma relies an off chain signaling mechanism to agree on a common strategy. +Namada introduce a governance mechanism to propose and apply protocol changes with and without the need for an hard fork. Anyone holding some M1T will be able to prosose some changes to which delegators and validator will cast their yay or nay votes. Governance on Namada supports both signaling and voting mechanism. The difference between the the two, is that the former is needed when the changes require an hard fork. In cases where the chain is not able to produce blocks anymore, Namada relies an off chain signaling mechanism to agree on a common strategy. ## Governance & Treasury addresses Governance introduce two internal address with their corresponding native vps: + - Governance address, which is in charge of validating on-chain proposals and votes - Treasury address, which is in charge of holding treasury funds Also, it introduces some protocol parameters: + - `min_proposal_fund` - `max_proposal_code_size` - `min_proposal_period` @@ -19,6 +21,7 @@ Also, it introduces some protocol parameters: ## On-chain proposals On-chain proposals are created under the `governance_address` storage space and, by default, this storage space is initialized with following storage keys: + ``` /$GovernanceAddress/counter: u64 /$GovernanceAddress/min_proposal_fund: u64 @@ -30,6 +33,7 @@ On-chain proposals are created under the `governance_address` storage space and, ``` In order to create a valid proposal, a transaction need to modify these storage keys: + ``` /$GovernanceAddress/proposal/$id/content : Vec /$GovernanceAddress/proposal/$id/author : Address @@ -41,18 +45,19 @@ In order to create a valid proposal, a transaction need to modify these storage ``` and follow these rules: + - `$id` must be equal to `counter + 1`. - `startEpoch` must: - - be grater than `currentEpoch`, where current epoch is the epoch in which the transaction is executed and included in a block - - be a multiple of `min_proposal_period`. + - be grater than `currentEpoch`, where current epoch is the epoch in which the transaction is executed and included in a block + - be a multiple of `min_proposal_period`. - `endEpoch` must: - - be at least `min_proposal_period` epoch greater than `startEpoch` - - be a multiple of `min_proposal_period` + - be at least `min_proposal_period` epoch greater than `startEpoch` + - be a multiple of `min_proposal_period` - `graceEpoch` must: - - be at least `min_grace_epoch` epochs greater than `endEpoch` + - be at least `min_grace_epoch` epochs greater than `endEpoch` - `proposalCode` can be empty and must be a valid transaction with size less than `max_proposal_code_size` kibibytes. - `funds` must be equal to `min_proposal_fund` and should be moved to the `governance_address`. -- `content` should follow the `Anoma Improvement Proposal schema` and must be less than `max_proposal_content_size` kibibytes. +- `content` should follow the `Namada Improvement Proposal schema` and must be less than `max_proposal_content_size` kibibytes. - `author` must be a valid address on-chain A proposal gets accepted if, at least 2/3 of the total voting power (computed at the epoch definied in the `startEpoch` field) vote `yay`. If the proposal is accepted, the locked funds are returned to the address definied in the `proposal_author` field, otherwise are moved to the treasury address. @@ -62,7 +67,7 @@ The `proposal_code` field can execute arbitrary code in the form of a wasm trans Proposal can be submitted by any address as long as the above rules are respected. Votes can be casted only by active validators and delegator (at epoch `startEpoch` or less). Moreover, validator can vote only during the first 2/3 of the voting period (from `startEpoch` and 2/3 of `endEpoch` - `startEpoch`). -The preferred content template (`Anoma Improvement Proposal schema`) is the following: +The preferred content template (`Namada Improvement Proposal schema`) is the following: ```json { @@ -79,6 +84,7 @@ The preferred content template (`Anoma Improvement Proposal schema`) is the foll ``` In order to vote a proposal, a transaction should modify the following storage key: + ``` /$GovernanceAddress/proposal/$id/vote/$validator_address/$voter_address: ProposalVote ``` @@ -86,6 +92,7 @@ In order to vote a proposal, a transaction should modify the following storage k where ProposalVote is a borsh encoded string containing either `yay` or `nay`, `$validator_address` is the delegation validator address and the `$voter_address` is the address of who is voting. A voter can be cast for each delegation. Vote is valid if it follow this rules: + - vote can be sent only by validator or delegators - validator can vote only during the first 2/3 of the total voting period, delegator can vote for the whole voting period @@ -93,12 +100,7 @@ The outcome of a proposal is compute at the epoch specific in the `endEpoch` fie A proposal is accepted only if more than 2/3 of the voting power vote `yay`. If a proposal gets accepted, the locked funds will be reimbursed to the author. In case it gets rejected, the locked funds will be moved to treasury. - ## Off-chain proposal In case where its not possibile to run a proposal online (for example, when the chain is halted), an offline mechanism can be used. The ledger offers the possibility to create and sign proposal which are verified against a specific chain epoch. - - - - diff --git a/documentation/dev/src/explore/design/ledger/pos-integration.md b/documentation/dev/src/explore/design/ledger/pos-integration.md index bf6b0f6952..992a9b043d 100644 --- a/documentation/dev/src/explore/design/ledger/pos-integration.md +++ b/documentation/dev/src/explore/design/ledger/pos-integration.md @@ -1,6 +1,7 @@ # PoS integration -The [PoS system](../pos.md) is integrated into Anoma ledger at 3 different layers: +The [PoS system](../pos.md) is integrated into Namada ledger at 3 different layers: + - base ledger that performs genesis initialization, validator set updates on new epoch and applies slashes when they are received from ABCI - an account with an internal address and a [native VP](vp.md#native-vps) that validates any changes applied by transactions to the PoS account state - transaction WASMs to perform various PoS actions, also available as a library code for custom made transactions @@ -153,6 +154,7 @@ In the following description, "pre-state" is the state prior to transaction exec Any changes to PoS epoched data are checked to update the structure as described in [epoched data storage](../pos.md#storage). Because some key changes are expected to relate to others, the VP also accumulates some values that are checked for validity after key specific logic: + - `balance_delta: token::Change` - `bond_delta: HashMap` - `unbond_delta: HashMap` @@ -173,6 +175,7 @@ For any updated epoched data, the `last_update` field must be set to the current The validity predicate triggers a validation logic based on the storage keys modified by a transaction: - `validator/{validator_address}/consensus_key`: + ```rust,ignore match (pre_state, post_state) { (None, Some(post)) => { @@ -188,7 +191,9 @@ The validity predicate triggers a validation logic based on the storage keys mod _ => false, } ``` + - `validator/{validator_address}/state`: + ```rust,ignore match (pre_state, post_state) { (None, Some(post)) => { @@ -207,6 +212,7 @@ The validity predicate triggers a validation logic based on the storage keys mod _ => false, } ``` + - `validator/{validator_address}/total_deltas`: - find the difference between the pre-state and post-state values and add it to the `total_deltas` accumulator and update `total_stake_by_epoch`, `expected_voting_power_by_epoch` and `expected_total_voting_power_delta_by_epoch` - `validator/{validator_address}/voting_power`: diff --git a/documentation/dev/src/explore/design/ledger/storage.md b/documentation/dev/src/explore/design/ledger/storage.md index 7186dd00a3..e441cbb2d0 100644 --- a/documentation/dev/src/explore/design/ledger/storage.md +++ b/documentation/dev/src/explore/design/ledger/storage.md @@ -53,6 +53,7 @@ It's very likely that different settings for immutable storage will be provided We'd like to have easily reproducible benchmarks for the whole database integration that should be filled over time with pre-generated realistic data. This should enable us to tune and compare different hashing functions, backends, data structures, memory layouts, etc. ### Criteria + - in-memory - writes (insert, update, delete) - possibly also concurrent writes, pending on the approach taken for concurrent transaction execution @@ -71,25 +72,27 @@ The considered options for a DB backend are given in [Libraries & Tools / Databa A committed block is not immediately persisted on RocksDB. When the block is committed, a set of key-value pairs which compose the block is written to the memtable on RocksDB. For the efficient sequential write, a flush is executed to persist the data on the memtable to the disk as a file when the size of the memtable is getting big (the threshold is one of the tuning parameters). -We can disable write-ahead log(WAL) which protects these data on the memtable from a crash by persisting the write logs to the disk. Disabling WAL helps reduce the write amplification. That's because WAL isn't required for Anoma because other nodes have the block. The blocks which have not been persisted to the disk by flush can be recovered even if an Anoma node crashes. +We can disable write-ahead log(WAL) which protects these data on the memtable from a crash by persisting the write logs to the disk. Disabling WAL helps reduce the write amplification. That's because WAL isn't required for Namada because other nodes have the block. The blocks which have not been persisted to the disk by flush can be recovered even if an Namada node crashes. ## Implementation ### `storage` module -This is the main interface for interacting with storage in Anoma. +This is the main interface for interacting with storage in Namada. This module and its sub-modules should implement the in-memory storage (and/or a cache layer) with Merkle tree (however, the interface should be agnostic to the choice of vector commitment scheme or whether or not there even is one, we may want non-Merklised storage) and the persistent DB. The in-memory storage holds chain's metadata and current block's storage. Its public API should allow/provide: + - get the Merkle root and Merkle tree proofs - read-only storage API for ledger's metadata to be accessible for transactions' code, VPs and the RPC - with public types of all the stored metadata - unless specified otherwise, read the state from the current block -An API made visible only to the shell module (e.g. `pub ( in SimplePath )` - https://doc.rust-lang.org/reference/visibility-and-privacy.html) should allow the shell to: +An API made visible only to the shell module (e.g. `pub ( in SimplePath )` - ) should allow the shell to: + - load state from DB for latest persisted block or initialize a new storage if none found - begin a new block - within a block: @@ -100,6 +103,7 @@ An API made visible only to the shell module (e.g. `pub ( in SimplePath )` - htt - commit the current block (persist to storage) ### `storage/merkle_tree` module + It consists of one Sparse Merkle Tree (base tree) and multiple Sparse Merkle Trees (subtrees). The base tree stores the store type and the root of each subtree as a key-value pair. Each subtree has the hashed key-value pairs for each data. ```mermaid @@ -143,4 +147,4 @@ The persistent DB implementation (e.g. RocksDB). ### DB keys -The DB keys are composed of key segments. A key segment can be an `Address` which starts with `#` (there can be multiple addresses involved in a key) or any user defined non-empty utf-8 string (maybe limited to only alphanumerical characters). Also, `/` and `?` are reserved. `/` is used as a separator for segments. `?` is reserved for a validity predicate and the key segment `?` can be specified only by the specific API. \ No newline at end of file +The DB keys are composed of key segments. A key segment can be an `Address` which starts with `#` (there can be multiple addresses involved in a key) or any user defined non-empty utf-8 string (maybe limited to only alphanumerical characters). Also, `/` and `?` are reserved. `/` is used as a separator for segments. `?` is reserved for a validity predicate and the key segment `?` can be specified only by the specific API. diff --git a/documentation/dev/src/explore/design/testnet-setup.md b/documentation/dev/src/explore/design/testnet-setup.md index c0bbff99f6..a936aa7b65 100644 --- a/documentation/dev/src/explore/design/testnet-setup.md +++ b/documentation/dev/src/explore/design/testnet-setup.md @@ -6,7 +6,7 @@ Starting from a release branch, we configure the network that will run on this r Prepare a genesis configuration file. You can start from one of the source files in the [anoma-network-config repo](https://github.com/heliaxdev/anoma-network-config/tree/master/src) or the source files inside the `genesis` directory in this repository, or start from scratch. Note that in this file, for any account for which you don't specify address and/or keys, they will be automatically generated in the next step and saved in wallet(s) in the network "setup" directory. -Additionally, for validator accounts you should also specify their `net_address`. Note that for each validator node we're using up to 5 ports (3 for the ledger and 2 for the intent gossip), so if multiple validators are running behind the same public IP, their ports should be increments of 5 (e.g. `26656`, `26661`, ...). A port supplied in the `net_address` will be used for the node's P2P address. The ledger's RPC address address is its `{port + 1}` and the Anoma ledger's port is `{port + 2}`. The intent gossip will run on `{port + 3}` and its RPC server at `{post + 4}`. +Additionally, for validator accounts you should also specify their `net_address`. Note that for each validator node we're using up to 5 ports (3 for the ledger and 2 for the intent gossip), so if multiple validators are running behind the same public IP, their ports should be increments of 5 (e.g. `26656`, `26661`, ...). A port supplied in the `net_address` will be used for the node's P2P address. The ledger's RPC address address is its `{port + 1}` and the Namada ledger's port is `{port + 2}`. The intent gossip will run on `{port + 3}` and its RPC server at `{post + 4}`. In the genesis file, also set the `genesis_time` in [RFC3339](https://www.ietf.org/rfc/rfc3339.txt) format, e.g. `2021-09-30T10:00:00Z`. It's the time the blockchain started or will start. If nodes are started before this time they will sit idle until the time specified. diff --git a/documentation/dev/src/specs/README.md b/documentation/dev/src/specs/README.md index 2140ea906e..d6095a56ce 100644 --- a/documentation/dev/src/specs/README.md +++ b/documentation/dev/src/specs/README.md @@ -1,7 +1,7 @@ # Specifications -[Anoma](https://anoma.network/papers/whitepaper.pdf) is a sovereign, proof-of-stake blockchain protocol that enables private, asset-agnostic cash and private bartering among any number of parties. +Namada is a sovereign, proof-of-stake blockchain protocol that enables private, asset-agnostic cash and private bartering among any number of parties. -This specification defines the Anoma ledger's protocol and its components and the intent gossip and matchmaking system. +This specification defines the Namada ledger's protocol and its components. The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC-2119](https://www.rfc-editor.org/rfc/rfc2119). diff --git a/documentation/dev/src/specs/crypto.md b/documentation/dev/src/specs/crypto.md index 577b048b44..e2879790bb 100644 --- a/documentation/dev/src/specs/crypto.md +++ b/documentation/dev/src/specs/crypto.md @@ -1,11 +1,11 @@ # Cryptographic schemes -Anoma currently supports Ed25519 signatures with more to be added: +Namada currently supports Ed25519 signatures with more to be added: - [`Secp256k1`](https://github.com/anoma/anoma/issues/162) - [`Sr25519`](https://github.com/anoma/anoma/issues/646) -Please note that the Anoma's crypto public API and encoding is currently undergoing some breaking changes with . +Please note that the Namada's crypto public API and encoding is currently undergoing some breaking changes with . ## Public keys @@ -13,4 +13,4 @@ A public key is a [Borsh encoded `PublicKey`](encoding.md#publickey). For the Ed ## Signatures -A signature in Anoma is a [Borsh encoded `Signature`](encoding.md#signature). For the Ed25519 scheme, this is 64 bytes of Ed25519 signature, prefixed with `64` in little endian encoding (`[64, 0, 0, 0]` in raw bytes or `40000000` in hex). (TODO this will change with ) +A signature in Namada is a [Borsh encoded `Signature`](encoding.md#signature). For the Ed25519 scheme, this is 64 bytes of Ed25519 signature, prefixed with `64` in little endian encoding (`[64, 0, 0, 0]` in raw bytes or `40000000` in hex). (TODO this will change with ) diff --git a/documentation/dev/src/specs/encoding.md b/documentation/dev/src/specs/encoding.md index 8b9de70617..728390c153 100644 --- a/documentation/dev/src/specs/encoding.md +++ b/documentation/dev/src/specs/encoding.md @@ -2,7 +2,7 @@ ## The ledger -Most of the data in Anoma are encoded with [Borsh](#borsh-binary-encoding), except for the outer layer of [transactions](#transactions) that are being passed via Tendermint and therefore are required to be encoded with protobuf. +Most of the data in Namada are encoded with [Borsh](#borsh-binary-encoding), except for the outer layer of [transactions](#transactions) that are being passed via Tendermint and therefore are required to be encoded with protobuf. ### Borsh binary encoding diff --git a/documentation/dev/src/specs/ledger.md b/documentation/dev/src/specs/ledger.md index 54de087ca1..de6ff37f98 100644 --- a/documentation/dev/src/specs/ledger.md +++ b/documentation/dev/src/specs/ledger.md @@ -26,7 +26,7 @@ The addresses are stored on-chain encoded with [bech32m](https://github.com/bitc The human-readable prefix (as specified for [bech32](https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#specification)) in the transparent address encoding is: -- `"a"` for Anoma live network (80 characters in total) +- `"a"` for Namada live network (80 characters in total) - `"atest"` for test networks (84 characters in total) ## Transactions diff --git a/documentation/dev/src/specs/ledger/default-transactions.md b/documentation/dev/src/specs/ledger/default-transactions.md index 78b04ff48d..78ed5b2098 100644 --- a/documentation/dev/src/specs/ledger/default-transactions.md +++ b/documentation/dev/src/specs/ledger/default-transactions.md @@ -1,12 +1,12 @@ # Default transactions -The Anoma client comes with a set of pre-built transactions. Note that the Anoma ledger is agnostic about the format of the transactions beyond the format described in [ledger transaction section](../ledger.md#transactions). +The Namada client comes with a set of pre-built transactions. Note that the Namada ledger is agnostic about the format of the transactions beyond the format described in [ledger transaction section](../ledger.md#transactions). The [default validity predicates](default-validity-predicates.md) can be used to initialize the network's genesis block. These expect the data in the storage to be encoded with [Borsh](../encoding.md#borsh-binary-encoding) and are fully compatible with the default transactions described below. ## Rust-to-WASM transactions -The following transactions are pre-built from Rust code and can be used by clients interacting with the Anoma ledger. +The following transactions are pre-built from Rust code and can be used by clients interacting with the Namada ledger. The pre-built WASM code's raw bytes should be attached to the transaction's `code` field. The transactions expect certain variables to be provided via the transaction's `data` field encoded with [Borsh](../encoding.md#borsh-binary-encoding). diff --git a/documentation/dev/src/specs/ledger/default-validity-predicates.md b/documentation/dev/src/specs/ledger/default-validity-predicates.md index 894a5df493..6a52fb1f65 100644 --- a/documentation/dev/src/specs/ledger/default-validity-predicates.md +++ b/documentation/dev/src/specs/ledger/default-validity-predicates.md @@ -1,6 +1,6 @@ # Default validity predicates -The Anoma ledger and client comes with a set of pre-built validity predicates. +The Namada ledger and client comes with a set of pre-built validity predicates. ## Rust-to-WASM validity predicates diff --git a/documentation/dev/src/specs/ledger/rpc.md b/documentation/dev/src/specs/ledger/rpc.md index c536967670..d0b6c37b6b 100644 --- a/documentation/dev/src/specs/ledger/rpc.md +++ b/documentation/dev/src/specs/ledger/rpc.md @@ -2,7 +2,7 @@ The ledger provides an RPC interface for submitting transactions to the mempool, subscribing to their results and queries about the state of the ledger and its storage. -The RPC interface is provided as [specified](https://github.com/tendermint/spec/tree/4566f1e3028278c5b3eca27b53254a48771b152b/spec/rpc) from Tendermint and most of the requests are routed to the Anoma ledger via ABCI. +The RPC interface is provided as [specified](https://github.com/tendermint/spec/tree/4566f1e3028278c5b3eca27b53254a48771b152b/spec/rpc) from Tendermint and most of the requests are routed to the Namada ledger via ABCI. ## Transactions diff --git a/documentation/dev/src/specs/overview.md b/documentation/dev/src/specs/overview.md index 2b9c7e15c7..43a4db2ee2 100644 --- a/documentation/dev/src/specs/overview.md +++ b/documentation/dev/src/specs/overview.md @@ -1,6 +1,6 @@ # Overview -At a high level, Anoma is composed of two main components: the distributed ledger and the intent gossip / matchmaking system. While they are designed to complement each other, they can be operated separately. +At a high level, Namada is composed of two main components: the distributed ledger and the intent gossip / matchmaking system. While they are designed to complement each other, they can be operated separately. ## The ledger From dc92f735a54a1c1f24ccbca1f45eb2ee6a72f769 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zemanovi=C4=8D?= Date: Wed, 27 Apr 2022 10:47:05 +0200 Subject: [PATCH 009/118] docs/pos: format md --- documentation/dev/src/explore/design/pos.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/documentation/dev/src/explore/design/pos.md b/documentation/dev/src/explore/design/pos.md index 55a2d91794..8b1d75d67d 100644 --- a/documentation/dev/src/explore/design/pos.md +++ b/documentation/dev/src/explore/design/pos.md @@ -7,6 +7,7 @@ An epoch is a range of blocks or time that is defined by the base ledger and mad ### Epoched data Epoched data are data associated with a specific epoch that are set in advance. The data relevant to the PoS system in the ledger's state are epoched. Each data can be uniquely identified. These are: + - [System parameters](#system-parameters). A single value for each epoch. - [Active validator set](#active-validator-set). A single value for each epoch. - Total voting power. A sum of all active and inactive validators' voting power. A single value for each epoch. @@ -27,6 +28,7 @@ Additionally, any account may submit evidence for [a slashable misbehaviour](#sl A validator must have a public consensus key. Additionally, it may also specify optional metadata fields (TBA). A validator may be in one of the following states: + - *inactive*: A validator is not being considered for block creation and cannot receive any new delegations. - *pending*: @@ -126,6 +128,7 @@ type Validators = HashMap; ``` Epoched data are stored in the following structure: + ```rust,ignore struct Epoched { /// The epoch in which this data was last updated @@ -180,6 +183,7 @@ To update a value in `Epoched` data with delta values in epoch `n` with value `d The invariants for updates in both cases are that `m - n >= 0` and `m - n <= pipeline_length`. For the active validator set, we store all the active and inactive validators separately with their respective voting power: + ```rust,ignore type VotingPower = u64; From fb762937ed35c41d382cf6dabad1ce97ea4a5ef8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zemanovi=C4=8D?= Date: Wed, 27 Apr 2022 11:03:19 +0200 Subject: [PATCH 010/118] docs/pos: `s/max_active_validators/max_validator_slots` --- documentation/dev/src/explore/design/pos.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/documentation/dev/src/explore/design/pos.md b/documentation/dev/src/explore/design/pos.md index 8b1d75d67d..972b7fdb2e 100644 --- a/documentation/dev/src/explore/design/pos.md +++ b/documentation/dev/src/explore/design/pos.md @@ -57,7 +57,7 @@ For each validator (in any state), the system also tracks total bonded tokens as #### Active validator set -From all the *candidate* validators, in each epoch the ones with the most voting power limited up to the `max_active_validators` [parameter](#system-parameters) are selected for the active validator set. The active validator set selected in epoch `n` is set for epoch `n + pipeline_length`. +From all the *candidate* validators, in each epoch the ones with the most voting power limited up to the `max_validator_slots` [parameter](#system-parameters) are selected for the active validator set. The active validator set selected in epoch `n` is set for epoch `n + pipeline_length`. ### Delegator @@ -198,7 +198,7 @@ struct WeightedValidator { } struct ValidatorSet { - /// Active validator set with maximum size equal to `max_active_validators` + /// Active validator set with maximum size equal to `max_validator_slots` active: BTreeSet, /// All the other validators that are not active inactive: BTreeSet, From 13510428229c32770b2ab93a54df6049ef456de6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zemanovi=C4=8D?= Date: Wed, 27 Apr 2022 11:09:03 +0200 Subject: [PATCH 011/118] docs/pos: Note explicitly that token withdrawal is not epoched --- documentation/dev/src/explore/design/pos.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/documentation/dev/src/explore/design/pos.md b/documentation/dev/src/explore/design/pos.md index 972b7fdb2e..93e9b42147 100644 --- a/documentation/dev/src/explore/design/pos.md +++ b/documentation/dev/src/explore/design/pos.md @@ -90,6 +90,8 @@ Any unbonds created in epoch `n` decrements the bond's validator's total bonded An "unbond" with epoch set to `n` may be withdrawn by the bond's source address in or any time after the epoch `n`. Once withdrawn, the unbond is deleted and the tokens are credited to the source account. +Note that unlike bonding and unbonding where token changes are delayed to some future epochs (pipeline or unbonding offset), the token withdrawal applies immediately. This because when the tokens are withdrawable, they are already "unlocked" from the PoS system and do not contribute to voting power. + ### Staking rewards To a validator who proposed a block, the system rewards tokens based on the `block_proposer_reward` [system parameter](#system-parameters) and each validator that voted on a block receives `block_vote_reward`. From e4e663d8c16cae6a5365a979eca630ff856a78fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zemanovi=C4=8D?= Date: Wed, 27 Apr 2022 11:17:44 +0200 Subject: [PATCH 012/118] docs/pos-integration: add unbond epochs --- documentation/dev/src/explore/design/ledger/pos-integration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/dev/src/explore/design/ledger/pos-integration.md b/documentation/dev/src/explore/design/ledger/pos-integration.md index 992a9b043d..dcaeb1ee9a 100644 --- a/documentation/dev/src/explore/design/ledger/pos-integration.md +++ b/documentation/dev/src/explore/design/ledger/pos-integration.md @@ -76,7 +76,7 @@ The validator transactions are assumed to be applied with an account address `va - let `pre_unbond = read(unbond/{validator_address}/{validator_address}/delta)` - if `total(bond) - total(pre_unbond) < amount`, panic - decrement the `bond` deltas starting from the rightmost value (a bond in a future-most epoch) until whole `amount` is decremented - - for each decremented `bond` value write a new `unbond` with the key set to the epoch of the source value + - for each decremented `bond` value write a new `unbond` in epoch `n + unbonding_length` with the start epoch set to the epoch of the source value and end epoch `n + unbonding_length` - decrement the `amount` from `validator/{validator_address}/total_deltas` in epoch `n + unbonding_length` - update the `validator/{validator_address}/voting_power` in epoch `n + unbonding_length` - update the `total_voting_power` in epoch `n + unbonding_length` From 4da91ee5f4cb4fb46b34c86396fe495a027e8811 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zemanovi=C4=8D?= Date: Wed, 27 Apr 2022 13:45:14 +0200 Subject: [PATCH 013/118] docs/pos-integration: more explicit unbonding deltas order --- documentation/dev/src/explore/design/ledger/pos-integration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/dev/src/explore/design/ledger/pos-integration.md b/documentation/dev/src/explore/design/ledger/pos-integration.md index dcaeb1ee9a..8e3c1dfed2 100644 --- a/documentation/dev/src/explore/design/ledger/pos-integration.md +++ b/documentation/dev/src/explore/design/ledger/pos-integration.md @@ -75,7 +75,7 @@ The validator transactions are assumed to be applied with an account address `va - if `bond` doesn't exist, panic - let `pre_unbond = read(unbond/{validator_address}/{validator_address}/delta)` - if `total(bond) - total(pre_unbond) < amount`, panic - - decrement the `bond` deltas starting from the rightmost value (a bond in a future-most epoch) until whole `amount` is decremented + - decrement the `bond` deltas starting from the rightmost value (a bond in a future-most epoch at the unbonding offset) until whole `amount` is decremented - for each decremented `bond` value write a new `unbond` in epoch `n + unbonding_length` with the start epoch set to the epoch of the source value and end epoch `n + unbonding_length` - decrement the `amount` from `validator/{validator_address}/total_deltas` in epoch `n + unbonding_length` - update the `validator/{validator_address}/voting_power` in epoch `n + unbonding_length` From 6f083997d88bb4495dba828fa81f203c92baee26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zemanovi=C4=8D?= Date: Wed, 27 Apr 2022 13:47:34 +0200 Subject: [PATCH 014/118] docs/pos: add reference to reasoning for pipeline_len = 2 --- documentation/dev/src/explore/design/pos.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/dev/src/explore/design/pos.md b/documentation/dev/src/explore/design/pos.md index 93e9b42147..6af1723a3c 100644 --- a/documentation/dev/src/explore/design/pos.md +++ b/documentation/dev/src/explore/design/pos.md @@ -111,7 +111,7 @@ The invariant is that the sum of amounts that may be withdrawn from a misbehavin The default values that are relative to epoch duration assume that an epoch last about 24 hours. - `max_validator_slots`: Maximum active validators, default `128` -- `pipeline_len`: Pipeline length in number of epochs, default `2` +- `pipeline_len`: Pipeline length in number of epochs, default `2` (see ) - `unboding_len`: Unbonding duration in number of epochs, default `6` - `votes_per_token`: Used in validators' voting power calculation, default 100‱ (1 voting power unit per 1000 tokens) - `block_proposer_reward`: Amount of tokens rewarded to a validator for proposing a block From 98e153c0e8950fe9eb5863cc6d1201d489567aac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zemanovi=C4=8D?= Date: Wed, 27 Apr 2022 13:49:19 +0200 Subject: [PATCH 015/118] docs/pos: validator total deltas don't subtract unbonds Unbonds get subtracted from bonds when applied, so we should subtract again to find total deltas. --- documentation/dev/src/explore/design/pos.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/dev/src/explore/design/pos.md b/documentation/dev/src/explore/design/pos.md index 6af1723a3c..3cacc83246 100644 --- a/documentation/dev/src/explore/design/pos.md +++ b/documentation/dev/src/explore/design/pos.md @@ -36,7 +36,7 @@ A validator may be in one of the following states: - *candidate*: A validator is considered for block creation and can receive delegations. -For each validator (in any state), the system also tracks total bonded tokens as a sum of the tokens in their self-bonds and delegated bonds, less any unbonded tokens. The total bonded tokens determine their voting voting power by multiplication by the `votes_per_token` [parameter](#system-parameters). The voting power is used for validator selection for block creation and is used in governance related activities. +For each validator (in any state), the system also tracks total bonded tokens as a sum of the tokens in their self-bonds and delegated bonds. The total bonded tokens determine their voting voting power by multiplication by the `votes_per_token` [parameter](#system-parameters). The voting power is used for validator selection for block creation and is used in governance related activities. #### Validator actions From b73861f39265b36b90b95384e6815c00ac0463e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zemanovi=C4=8D?= Date: Wed, 27 Apr 2022 14:10:03 +0200 Subject: [PATCH 016/118] docs/pos: remove validator "pending" state --- .../src/explore/design/ledger/pos-integration.md | 13 ++++++------- documentation/dev/src/explore/design/pos.md | 9 +++------ 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/documentation/dev/src/explore/design/ledger/pos-integration.md b/documentation/dev/src/explore/design/ledger/pos-integration.md index 8e3c1dfed2..578eec65ee 100644 --- a/documentation/dev/src/explore/design/ledger/pos-integration.md +++ b/documentation/dev/src/explore/design/ledger/pos-integration.md @@ -56,11 +56,11 @@ The validator transactions are assumed to be applied with an account address `va - `become_validator(consensus_key, staking_reward_address)`: - creates a record in `validator/{validator_address}/consensus_key` in epoch `n + pipeline_length` - creates a record in `validator/{validator_address}/staking_reward_address` - - sets `validator/{validator_address}/state` for to `pending` in the current epoch and `candidate` in epoch `n + pipeline_length` + - sets `validator/{validator_address}/state` to `candidate` in epoch `n + pipeline_length` - `deactivate`: - - sets `validator/{validator_address}/state` for to `inactive` in epoch `n + pipeline_length` + - sets `validator/{validator_address}/state` to `inactive` in epoch `n + pipeline_length` - `reactivate`: - - sets `validator/{validator_address}/state` for to `pending` in the current epoch and `candidate` in epoch `n + pipeline_length` + - sets `validator/{validator_address}/state` to `candidate` in epoch `n + pipeline_length` - `self_bond(amount)`: - let `bond = read(bond/{validator_address}/{validator_address}/delta)` - if `bond` exist, update it with the new bond amount in epoch `n + pipeline_length` @@ -199,15 +199,14 @@ The validity predicate triggers a validation logic based on the storage keys mod (None, Some(post)) => { // - check that all other required validator fields have been initialized // - check that the `post` state is set correctly: - // - the state should be set to `pending` in the current epoch and `candidate` at pipeline offset + // - the state should be set to `candidate` at pipeline offset // - insert into or update `new_validators` accumulator }, (Some(pre), Some(post)) => { // - check that a validator has been correctly deactivated or reactivated // - the `state` should only be changed at `pipeline_length` offset - // - if the `state` becomes `inactive`, it must have been `pending` or `candidate` - // - if the `state` becomes `pending`, it must have been `inactive` - // - if the `state` becomes `candidate`, it must have been `pending` or `inactive` + // - if the `state` becomes `inactive`, it must have been `candidate` + // - if the `state` becomes `candidate`, it must have been `inactive` }, _ => false, } diff --git a/documentation/dev/src/explore/design/pos.md b/documentation/dev/src/explore/design/pos.md index 3cacc83246..141ccbc6e4 100644 --- a/documentation/dev/src/explore/design/pos.md +++ b/documentation/dev/src/explore/design/pos.md @@ -31,8 +31,6 @@ A validator may be in one of the following states: - *inactive*: A validator is not being considered for block creation and cannot receive any new delegations. -- *pending*: - A validator has requested to become a *candidate*. - *candidate*: A validator is considered for block creation and can receive delegations. @@ -41,11 +39,11 @@ For each validator (in any state), the system also tracks total bonded tokens as #### Validator actions - *become validator*: - Any account that is not a validator already and that doesn't have any delegations may request to become a validator. It is required to provide a public consensus key and staking reward address. For the action applied in epoch `n`, the validator's state will be immediately set to *pending*, it will be set to *candidate* for epoch `n + pipeline_length` and the consensus key is set for epoch `n + pipeline_length`. + Any account that is not a validator already and that doesn't have any delegations may request to become a validator. It is required to provide a public consensus key and staking reward address. For the action applied in epoch `n`, the validator's state will be set to *candidate* for epoch `n + pipeline_length` and the consensus key is set for epoch `n + pipeline_length`. - *deactivate*: - Only a *pending* or *candidate* validator account may *deactivate*. For this action applied in epoch `n`, the validator's account is set to become *inactive* in the epoch `n + pipeline_length`. + Only a validator whose state at or before the `pipeline_length` offset is *candidate* account may *deactivate*. For this action applied in epoch `n`, the validator's account is set to become *inactive* in the epoch `n + pipeline_length`. - *reactivate*: - Only an *inactive* validator may *reactivate*. Similarly to *become validator* action, for this action applied in epoch `n`, the validator's state will be immediately set to *pending* and it will be set to *candidate* for epoch `n + pipeline_length`. + Only an *inactive* validator may *reactivate*. Similarly to *become validator* action, for this action applied in epoch `n`, the validator's state will be set to *candidate* for epoch `n + pipeline_length`. - *self-bond*: A validator may lock-up tokens into a [bond](#bonds) only for its own validator's address. - *unbond*: @@ -238,7 +236,6 @@ struct Validator { enum ValidatorState { Inactive, - Pending, Candidate, } ``` From c1ac299f4aed34bc83d1d3e00a1e2a0a06032a93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zemanovi=C4=8D?= Date: Wed, 27 Apr 2022 14:27:14 +0200 Subject: [PATCH 017/118] changelog: add #1070 --- .changelog/unreleased/docs/1070-pos-spec-updates.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .changelog/unreleased/docs/1070-pos-spec-updates.md diff --git a/.changelog/unreleased/docs/1070-pos-spec-updates.md b/.changelog/unreleased/docs/1070-pos-spec-updates.md new file mode 100644 index 0000000000..016cae8b88 --- /dev/null +++ b/.changelog/unreleased/docs/1070-pos-spec-updates.md @@ -0,0 +1,2 @@ +- Applied various fixes and updates to the PoS system spec and integration spec + ([#1070](https://github.com/anoma/anoma/pull/1070)) \ No newline at end of file From 242f1e483725735db76cf61c40f312cfd62d1b3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zemanovi=C4=8D?= Date: Fri, 5 Aug 2022 19:00:38 +0200 Subject: [PATCH 018/118] docs/dev: remove PoS spec and link to spec page instead --- documentation/dev/src/SUMMARY.md | 1 - .../explore/design/ledger/pos-integration.md | 8 +- documentation/dev/src/explore/design/pos.md | 285 ------------------ 3 files changed, 4 insertions(+), 290 deletions(-) delete mode 100644 documentation/dev/src/explore/design/pos.md diff --git a/documentation/dev/src/SUMMARY.md b/documentation/dev/src/SUMMARY.md index fee1b6fb27..62f2ccd1c6 100644 --- a/documentation/dev/src/SUMMARY.md +++ b/documentation/dev/src/SUMMARY.md @@ -19,7 +19,6 @@ - [PoS integration](./explore/design/ledger/pos-integration.md) - [Crypto primitives](./explore/design/crypto-primitives.md) - [Actors](./explore/design/actors.md) - - [Proof of Stake system](./explore/design/pos.md) - [Testnet setup](./explore/design/testnet-setup.md) - [Testnet launch procedure](./explore/design/testnet-launch-procedure/README.md) - [Libraries & Tools](./explore/libraries/README.md) diff --git a/documentation/dev/src/explore/design/ledger/pos-integration.md b/documentation/dev/src/explore/design/ledger/pos-integration.md index 578eec65ee..d441e5ddca 100644 --- a/documentation/dev/src/explore/design/ledger/pos-integration.md +++ b/documentation/dev/src/explore/design/ledger/pos-integration.md @@ -1,6 +1,6 @@ # PoS integration -The [PoS system](../pos.md) is integrated into Namada ledger at 3 different layers: +The [PoS system](https://specs.namada.net/economics/proof-of-stake/bonding-mechanism.html) is integrated into Namada ledger at 3 different layers: - base ledger that performs genesis initialization, validator set updates on new epoch and applies slashes when they are received from ABCI - an account with an internal address and a [native VP](vp.md#native-vps) that validates any changes applied by transactions to the PoS account state @@ -8,7 +8,7 @@ The [PoS system](../pos.md) is integrated into Namada ledger at 3 different laye The `votes_per_token` PoS system parameter must be chosen to satisfy the [Tendermint requirement](https://github.com/tendermint/spec/blob/60395941214439339cc60040944c67893b5f8145/spec/abci/apps.md#validator-updates) of `MaxTotalVotingPower = MaxInt64 / 8`. -All [the data relevant to the PoS system](../pos.md#storage) are stored under the PoS account's storage sub-space, with the following key schema (the PoS address prefix is omitted for clarity): +All [the data relevant to the PoS system](https://specs.namada.net/economics/proof-of-stake/bonding-mechanism.html#storage) are stored under the PoS account's storage sub-space, with the following key schema (the PoS address prefix is omitted for clarity): - `params` (required): the system parameters - for any validator, all the following fields are required: @@ -45,7 +45,7 @@ All the fees that are charged in a transaction execution (DKG transaction wrappe ## Transactions -The transactions are assumed to be applied in epoch `n`. Any transaction that modifies [epoched data](../pos.md#epoched-data) updates the structure as described in [epoched data storage](../pos.md#storage). +The transactions are assumed to be applied in epoch `n`. Any transaction that modifies [epoched data](https://specs.namada.net/economics/proof-of-stake/bonding-mechanism.html#epoched-data) updates the structure as described in [epoched data storage](https://specs.namada.net/economics/proof-of-stake/bonding-mechanism.html#storage). For slashing tokens, we implement a [PoS slash pool account](vp.md#pos-slash-pool-vp). Slashed tokens should be credited to this account and, for now, no tokens can be be debited by anyone. @@ -151,7 +151,7 @@ Evidence for byzantine behaviour is received from Tendermint ABCI on `BeginBlock In the following description, "pre-state" is the state prior to transaction execution and "post-state" is the state posterior to it. -Any changes to PoS epoched data are checked to update the structure as described in [epoched data storage](../pos.md#storage). +Any changes to PoS epoched data are checked to update the structure as described in [epoched data storage](https://specs.namada.net/economics/proof-of-stake/bonding-mechanism.html#storage). Because some key changes are expected to relate to others, the VP also accumulates some values that are checked for validity after key specific logic: diff --git a/documentation/dev/src/explore/design/pos.md b/documentation/dev/src/explore/design/pos.md deleted file mode 100644 index 141ccbc6e4..0000000000 --- a/documentation/dev/src/explore/design/pos.md +++ /dev/null @@ -1,285 +0,0 @@ -# Proof of Stake (PoS) system - -## Epoch - -An epoch is a range of blocks or time that is defined by the base ledger and made available to the PoS system. This document assumes that epochs are identified by consecutive natural numbers. All the data relevant to PoS are [associated with epochs](#epoched-data). - -### Epoched data - -Epoched data are data associated with a specific epoch that are set in advance. The data relevant to the PoS system in the ledger's state are epoched. Each data can be uniquely identified. These are: - -- [System parameters](#system-parameters). A single value for each epoch. -- [Active validator set](#active-validator-set). A single value for each epoch. -- Total voting power. A sum of all active and inactive validators' voting power. A single value for each epoch. -- [Validators' consensus key, state and total bonded tokens](#validator). Identified by the validator's address. -- [Bonds](#bonds) are created by self-bonding and delegations. They are identified by the pair of source address and the validator's address. - -Changes to the epoched data do not take effect immediately. Instead, changes in epoch `n` are queued to take effect in the epoch `n + pipeline_length` for most cases and `n + unboding_length` for [unbonding](#unbond) actions. Should the same validator's data or same bonds (i.e. with the same identity) be updated more than once in the same epoch, the later update overrides the previously queued-up update. For bonds, the token amounts are added up. Once the epoch `n` has ended, the queued-up updates for epoch `n + pipeline_length` are final and the values become immutable. - -## Entities - -- [Validator](#validator): An account with a public consensus key, which may participate in producing blocks and governance activities. A validator may not also be a delegator. -- [Delegator](#delegator): An account that delegates some tokens to a validator. A delegator may not also be a validator. - -Additionally, any account may submit evidence for [a slashable misbehaviour](#slashing). - -### Validator - -A validator must have a public consensus key. Additionally, it may also specify optional metadata fields (TBA). - -A validator may be in one of the following states: - -- *inactive*: - A validator is not being considered for block creation and cannot receive any new delegations. -- *candidate*: - A validator is considered for block creation and can receive delegations. - -For each validator (in any state), the system also tracks total bonded tokens as a sum of the tokens in their self-bonds and delegated bonds. The total bonded tokens determine their voting voting power by multiplication by the `votes_per_token` [parameter](#system-parameters). The voting power is used for validator selection for block creation and is used in governance related activities. - -#### Validator actions - -- *become validator*: - Any account that is not a validator already and that doesn't have any delegations may request to become a validator. It is required to provide a public consensus key and staking reward address. For the action applied in epoch `n`, the validator's state will be set to *candidate* for epoch `n + pipeline_length` and the consensus key is set for epoch `n + pipeline_length`. -- *deactivate*: - Only a validator whose state at or before the `pipeline_length` offset is *candidate* account may *deactivate*. For this action applied in epoch `n`, the validator's account is set to become *inactive* in the epoch `n + pipeline_length`. -- *reactivate*: - Only an *inactive* validator may *reactivate*. Similarly to *become validator* action, for this action applied in epoch `n`, the validator's state will be set to *candidate* for epoch `n + pipeline_length`. -- *self-bond*: - A validator may lock-up tokens into a [bond](#bonds) only for its own validator's address. -- *unbond*: - Any self-bonded tokens may be partially or fully [unbonded](#unbond). -- *withdraw unbonds*: - Unbonded tokens may be withdrawn in or after the [unbond's epoch](#unbond). -- *change consensus key*: - Set the new consensus key. When applied in epoch `n`, the key is set for epoch `n + pipeline_length`. - -#### Active validator set - -From all the *candidate* validators, in each epoch the ones with the most voting power limited up to the `max_validator_slots` [parameter](#system-parameters) are selected for the active validator set. The active validator set selected in epoch `n` is set for epoch `n + pipeline_length`. - -### Delegator - -A delegator may have any number of delegations to any number of validators. Delegations are stored in [bonds](#bonds). - -#### Delegator actions - -- *delegate*: - An account which is not a validator may delegate tokens to any number of validators. This will lock-up tokens into a [bond](#bonds). -- *undelegate*: - Any delegated tokens may be partially or fully [unbonded](#unbond). -- *withdraw unbonds*: - Unbonded tokens may be withdrawn in or after the [unbond's epoch](#unbond). - -## Bonds - -A bond locks-up tokens from validators' self-bonding and delegators' delegations. For self-bonding, the source address is equal to the validator's address. Only validators can self-bond. For a bond created from a delegation, the bond's source is the delegator's account. - -For each epoch, bonds are uniquely identified by the pair of source and validator's addresses. A bond created in epoch `n` is written into epoch `n + pipeline_length`. If there already is a bond in the epoch `n + pipeline_length` for this pair of source and validator's addresses, its tokens are incremented by the newly bonded amount. - -Any bonds created in epoch `n` increment the bond's validator's total bonded tokens by the bond's token amount and update the voting power for epoch `n + pipeline_length`. - -The tokens put into a bond are immediately deducted from the source account. - -### Unbond - -An unbonding action (validator *unbond* or delegator *undelegate*) requested by the bond's source account in epoch `n` creates an "unbond" with epoch set to `n + unbounding_length`. We also store the epoch of the bond(s) from which the unbond is created in order to determine if the unbond should be slashed if a fault occurred within the range of bond epoch (inclusive) and unbond epoch (exclusive). - -Any unbonds created in epoch `n` decrements the bond's validator's total bonded tokens by the bond's token amount and update the voting power for epoch `n + unbonding_length`. - -An "unbond" with epoch set to `n` may be withdrawn by the bond's source address in or any time after the epoch `n`. Once withdrawn, the unbond is deleted and the tokens are credited to the source account. - -Note that unlike bonding and unbonding where token changes are delayed to some future epochs (pipeline or unbonding offset), the token withdrawal applies immediately. This because when the tokens are withdrawable, they are already "unlocked" from the PoS system and do not contribute to voting power. - -### Staking rewards - -To a validator who proposed a block, the system rewards tokens based on the `block_proposer_reward` [system parameter](#system-parameters) and each validator that voted on a block receives `block_vote_reward`. - -### Slashing - -Instead of absolute values, validators' total bonded token amounts and bonds' and unbonds' token amounts are stored as their deltas (i.e. the change of quantity from a previous epoch) to allow distinguishing changes for different epoch, which is essential for determining whether tokens should be slashed. However, because slashes for a fault that occurred in epoch `n` may only be applied before the beginning of epoch `n + unbonding_length`, in epoch `m` we can sum all the deltas of total bonded token amounts and bonds and unbond with the same source and validator for epoch equal or less than `m - unboding_length` into a single total bonded token amount, single bond and single unbond record. This is to keep the total number of total bonded token amounts for a unique validator and bonds and unbonds for a unique pair of source and validator bound to a maximum number (equal to `unbonding_length`). - -To disincentivize validators misbehaviour in the PoS system a validator may be slashed for any fault that it has done. An evidence of misbehaviour may be submitted by any account for a fault that occurred in epoch `n` anytime before the beginning of epoch `n + unbonding_length`. - -A valid evidence reduces the validator's total bonded token amount by the slash rate in and before the epoch in which the fault occurred. The validator's voting power must also be adjusted to the slashed total bonded token amount. Additionally, a slash is stored with the misbehaving validator's address and the relevant epoch in which the fault occurred. When an unbond is being withdrawn, we first look-up if any slash occurred within the range of epochs in which these were active and if so, reduce its token amount by the slash rate. Note that bonds and unbonds amounts are not slashed until their tokens are withdrawn. - -The invariant is that the sum of amounts that may be withdrawn from a misbehaving validator must always add up to the total bonded token amount. - -## System parameters - -The default values that are relative to epoch duration assume that an epoch last about 24 hours. - -- `max_validator_slots`: Maximum active validators, default `128` -- `pipeline_len`: Pipeline length in number of epochs, default `2` (see ) -- `unboding_len`: Unbonding duration in number of epochs, default `6` -- `votes_per_token`: Used in validators' voting power calculation, default 100‱ (1 voting power unit per 1000 tokens) -- `block_proposer_reward`: Amount of tokens rewarded to a validator for proposing a block -- `block_vote_reward`: Amount of tokens rewarded to each validator that voted on a block proposal -- `duplicate_vote_slash_rate`: Portion of validator's stake that should be slashed on a duplicate vote -- `light_client_attack_slash_rate`: Portion of validator's stake that should be slashed on a light client attack - -## Storage - -The [system parameters](#system-parameters) are written into the storage to allow for their changes. Additionally, each validator may record a new parameters value under their sub-key that they wish to change to, which would override the systems parameters when more than 2/3 voting power are in agreement on all the parameters values. - -The validators' data are keyed by the their addresses, conceptually: - -```rust,ignore -type Validators = HashMap; -``` - -Epoched data are stored in the following structure: - -```rust,ignore -struct Epoched { - /// The epoch in which this data was last updated - last_update: Epoch, - /// Dynamically sized vector in which the head is the data for epoch in which - /// the `last_update` was performed and every consecutive array element is the - /// successor epoch of the predecessor array element. For system parameters, - /// validator's consensus key and state, `LENGTH = pipeline_length + 1`. - /// For all others, `LENGTH = unbonding_length + 1`. - data: Vec> -} -``` - -Note that not all epochs will have data set, only the ones in which some changes occurred. - -To try to look-up a value for `Epoched` data with independent values in each epoch (such as the active validator set) in the current epoch `n`: - -1. let `index = min(n - last_update, pipeline_length)` -1. read the `data` field at `index`: - 1. if there's a value at `index` return it - 1. else if `index == 0`, return `None` - 1. else decrement `index` and repeat this sub-step from 1. - -To look-up a value for `Epoched` data with delta values in the current epoch `n`: - -1. let `end = min(n - last_update, pipeline_length) + 1` -1. sum all the values that are not `None` in the `0 .. end` range bounded inclusively below and exclusively above - -To update a value in `Epoched` data with independent values in epoch `n` with value `new` for epoch `m`: - -1. let `shift = min(n - last_update, pipeline_length)` -1. if `shift == 0`: - 1. `data[m - n] = new` -1. else: - 1. for `i in 0 .. shift` range bounded inclusively below and exclusively above, set `data[i] = None` - 1. rotate `data` left by `shift` - 1. set `data[m - n] = new` - 1. set `last_update` to the current epoch - -To update a value in `Epoched` data with delta values in epoch `n` with value `delta` for epoch `m`: - -1. let `shift = min(n - last_update, pipeline_length)` -1. if `shift == 0`: - 1. set `data[m - n] = data[m - n].map_or_else(delta, |last_delta| last_delta + delta)` (add the `delta` to the previous value, if any, otherwise use the `delta` as the value) -1. else: - 1. let `sum` to be equal to the sum of all delta values in the `i in 0 .. shift` range bounded inclusively below and exclusively above and set `data[i] = None` - 1. rotate `data` left by `shift` - 1. set `data[0] = data[0].map_or_else(sum, |last_delta| last_delta + sum)` - 1. set `data[m - n] = delta` - 1. set `last_update` to the current epoch - -The invariants for updates in both cases are that `m - n >= 0` and `m - n <= pipeline_length`. - -For the active validator set, we store all the active and inactive validators separately with their respective voting power: - -```rust,ignore -type VotingPower = u64; - -/// Validator's address with its voting power. -#[derive(PartialEq, Eq, PartialOrd, Ord)] -struct WeightedValidator { - /// The `voting_power` field must be on top, because lexicographic ordering is - /// based on the top-to-bottom declaration order and in the `ValidatorSet` - /// the `WeighedValidator`s these need to be sorted by the `voting_power`. - voting_power: VotingPower, - address: Address, -} - -struct ValidatorSet { - /// Active validator set with maximum size equal to `max_validator_slots` - active: BTreeSet, - /// All the other validators that are not active - inactive: BTreeSet, -} - -type ValidatorSets = Epoched; - -/// The sum of all active and inactive validators' voting power -type TotalVotingPower = Epoched; -``` - -When any validator's voting power changes, we attempt to perform the following update on the `ActiveValidatorSet`: - -1. let `validator` be the validator's address, `power_before` and `power_after` be the voting power before and after the change, respectively -1. let `power_delta = power_after - power_before` -1. let `min_active = active.first()` (active validator with lowest voting power) -1. let `max_inactive = inactive.last()` (inactive validator with greatest voting power) -1. find whether the validator is active, let `is_active = power_before >= max_inactive.voting_power` - 1. if `is_active`: - 1. if `power_delta > 0 && power_after > max_inactive.voting_power`, update the validator in `active` set with `voting_power = power_after` - 1. else, remove the validator from `active`, insert it into `inactive` and remove `max_inactive.address` from `inactive` and insert it into `active` - 1. else (`!is_active`): - 1. if `power_delta < 0 && power_after < min_active.voting_power`, update the validator in `inactive` set with `voting_power = power_after` - 1. else, remove the validator from `inactive`, insert it into `active` and remove `min_active.address` from `active` and insert it into `inactive` - -Within each validator's address space, we store public consensus key, state, total bonded token amount and voting power calculated from the total bonded token amount (even though the voting power is stored in the `ValidatorSet`, we also need to have the `voting_power` here because we cannot look it up in the `ValidatorSet` without iterating the whole set): - -```rust,ignore -struct Validator { - consensus_key: Epoched, - state: Epoched, - total_deltas: Epoched, - voting_power: Epoched, -} - -enum ValidatorState { - Inactive, - Candidate, -} -``` - -The bonds and unbonds are keyed by their identifier: - -```rust,ignore -type Bonds = HashMap>; -type Unbonds = HashMap>; - -struct BondId { - validator: Address, - /// The delegator adddress for delegations, or the same as the `validator` - /// address for self-bonds. - source: Address, -} - -struct Bond { - /// A key is a the epoch set for the bond. This is used in unbonding, where - // it's needed for slash epoch range check. - deltas: HashMap, -} - -struct Unbond { - /// A key is a pair of the epoch of the bond from which a unbond was created - /// the epoch of unboding. This is needed for slash epoch range check. - deltas: HashMap<(Epoch, Epoch), token::Amount> -} -``` - -For slashes, we store the epoch and block height at which the fault occurred, slash rate and the slash type: - -```rust,ignore -struct Slash { - epoch: Epoch, - block_height: u64, - /// slash token amount ‱ (per ten thousand) - rate: u8, - r#type: SlashType, -} -``` - -## Initialization - -An initial validator set with self-bonded token amounts must be given on system initialization. - -This set is used to pre-compute epochs in the genesis block from epoch `0` to epoch `pipeline_length - 1`. From 9114cc46a4a720aeb6012300c67a015a82ecf1d3 Mon Sep 17 00:00:00 2001 From: Marco Granelli Date: Thu, 9 Jun 2022 11:40:35 +0200 Subject: [PATCH 019/118] Fixes typos. Updates comment on `clap` --- documentation/dev/src/explore/libraries/cli.md | 4 +--- documentation/dev/src/explore/libraries/errors.md | 4 ++-- documentation/dev/src/explore/libraries/network.md | 4 ++-- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/documentation/dev/src/explore/libraries/cli.md b/documentation/dev/src/explore/libraries/cli.md index 9ddd50e5ea..9cf708d299 100644 --- a/documentation/dev/src/explore/libraries/cli.md +++ b/documentation/dev/src/explore/libraries/cli.md @@ -14,6 +14,4 @@ The considered libraries: Probably the most widely used CLI library in Rust. -With version 2.x, we'd probably want to use it with [Structops](https://github.com/TeXitoi/structopt) for deriving. - -But we can probably use 3.0, which is not yet stable, but is pretty close . This version comes with deriving attributes and also other new ways to build CLI commands. +With version 2.x, we'd probably want to update clap to 3.x: this version comes with deriving attributes and also other new ways to build CLI commands (previously, deriving was only provided by [StructOpt](https://github.com/TeXitoi/structopt), which is now in maintenance mode). diff --git a/documentation/dev/src/explore/libraries/errors.md b/documentation/dev/src/explore/libraries/errors.md index 388b232840..32a943ffe8 100644 --- a/documentation/dev/src/explore/libraries/errors.md +++ b/documentation/dev/src/explore/libraries/errors.md @@ -2,7 +2,7 @@ The current preference is to use `thiserror` for most code and `eyre` for reporting errors at the CLI level and the client. -To make the code robust, we should avoid using code that may panic for errors that recoverable and handle all possible errors explicitly. Two exceptions to this rule are: +To make the code robust, we should avoid using code that may panic for errors that are recoverable and handle all possible errors explicitly. Two exceptions to this rule are: - prototyping, where it's fine to use `unwrap`, `expect`, etc. - in code paths with conditional compilation **only** for development build, where it's preferable to use `expect` in place of `unwrap` to help with debugging @@ -10,7 +10,7 @@ In case of panics, we should provide an error trace that is helpful for trouble- A great post on error handling library/application distinction: . -The considered DBs: +The considered libraries: - thiserror - anyhow - eyre diff --git a/documentation/dev/src/explore/libraries/network.md b/documentation/dev/src/explore/libraries/network.md index dd1c2522e0..bc3fd39432 100644 --- a/documentation/dev/src/explore/libraries/network.md +++ b/documentation/dev/src/explore/libraries/network.md @@ -1,4 +1,4 @@ -# network +# Network ## Libp2p : Peer To Peer network @@ -13,7 +13,7 @@ encryption for us. Generates a client/server from protobuf file. This can be used for a rpc server. -# network behaviour +# Network behaviour ## Gossipsub From ab22bff8d881c02f25e1d6f829de4af90f3a9797 Mon Sep 17 00:00:00 2001 From: Marco Granelli Date: Thu, 9 Jun 2022 12:02:28 +0200 Subject: [PATCH 020/118] Removes mention to clap version --- documentation/dev/src/explore/libraries/cli.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/dev/src/explore/libraries/cli.md b/documentation/dev/src/explore/libraries/cli.md index 9cf708d299..6099837042 100644 --- a/documentation/dev/src/explore/libraries/cli.md +++ b/documentation/dev/src/explore/libraries/cli.md @@ -14,4 +14,4 @@ The considered libraries: Probably the most widely used CLI library in Rust. -With version 2.x, we'd probably want to update clap to 3.x: this version comes with deriving attributes and also other new ways to build CLI commands (previously, deriving was only provided by [StructOpt](https://github.com/TeXitoi/structopt), which is now in maintenance mode). +Comes with deriving attributes and also other new ways to build CLI commands (previously, deriving was only provided by [StructOpt](https://github.com/TeXitoi/structopt), which is now in maintenance mode). From f13bc246e1baf96a832c9c6b8bc401d3de901c3c Mon Sep 17 00:00:00 2001 From: Marco Granelli Date: Thu, 9 Jun 2022 17:34:35 +0200 Subject: [PATCH 021/118] Updates changelog --- .changelog/unreleased/docs/1143-update-libraries-docs.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .changelog/unreleased/docs/1143-update-libraries-docs.md diff --git a/.changelog/unreleased/docs/1143-update-libraries-docs.md b/.changelog/unreleased/docs/1143-update-libraries-docs.md new file mode 100644 index 0000000000..6e9eee6948 --- /dev/null +++ b/.changelog/unreleased/docs/1143-update-libraries-docs.md @@ -0,0 +1,2 @@ +- Fixes libraries doc typos and correct comment on the clap crate + ([#1143](https://github.com/anoma/anoma/pull/1143)) \ No newline at end of file From 7c41b0a128f26c35a68cfc5a5a2decf4e4486c93 Mon Sep 17 00:00:00 2001 From: James Hiew Date: Thu, 9 Jun 2022 14:50:24 +0200 Subject: [PATCH 022/118] crypto.md: remove references to closed issue --- documentation/dev/src/specs/crypto.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/documentation/dev/src/specs/crypto.md b/documentation/dev/src/specs/crypto.md index e2879790bb..1730920199 100644 --- a/documentation/dev/src/specs/crypto.md +++ b/documentation/dev/src/specs/crypto.md @@ -5,12 +5,10 @@ Namada currently supports Ed25519 signatures with more to be added: - [`Secp256k1`](https://github.com/anoma/anoma/issues/162) - [`Sr25519`](https://github.com/anoma/anoma/issues/646) -Please note that the Namada's crypto public API and encoding is currently undergoing some breaking changes with . - ## Public keys -A public key is a [Borsh encoded `PublicKey`](encoding.md#publickey). For the Ed25519 scheme, this is 32 bytes of Ed25519 public key, prefixed with `32` in little endian encoding (`[32, 0, 0, 0]` in raw bytes or `20000000` in hex). (TODO this will change with ) +A public key is a [Borsh encoded `PublicKey`](encoding.md#publickey). For the Ed25519 scheme, this is 32 bytes of Ed25519 public key, prefixed with `32` in little endian encoding (`[32, 0, 0, 0]` in raw bytes or `20000000` in hex). ## Signatures -A signature in Namada is a [Borsh encoded `Signature`](encoding.md#signature). For the Ed25519 scheme, this is 64 bytes of Ed25519 signature, prefixed with `64` in little endian encoding (`[64, 0, 0, 0]` in raw bytes or `40000000` in hex). (TODO this will change with ) +A signature in Namada is a [Borsh encoded `Signature`](encoding.md#signature). For the Ed25519 scheme, this is 64 bytes of Ed25519 signature, prefixed with `64` in little endian encoding (`[64, 0, 0, 0]` in raw bytes or `40000000` in hex). From 9a3ec2aa9aa76be778b19b2becd2f5fae00467e9 Mon Sep 17 00:00:00 2001 From: James Hiew Date: Fri, 8 Jul 2022 10:34:08 +0100 Subject: [PATCH 023/118] crypto.md: remove outdated encoding descriptions --- documentation/dev/src/specs/crypto.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/documentation/dev/src/specs/crypto.md b/documentation/dev/src/specs/crypto.md index 1730920199..289280b895 100644 --- a/documentation/dev/src/specs/crypto.md +++ b/documentation/dev/src/specs/crypto.md @@ -7,8 +7,8 @@ Namada currently supports Ed25519 signatures with more to be added: ## Public keys -A public key is a [Borsh encoded `PublicKey`](encoding.md#publickey). For the Ed25519 scheme, this is 32 bytes of Ed25519 public key, prefixed with `32` in little endian encoding (`[32, 0, 0, 0]` in raw bytes or `20000000` in hex). +A public key is a [Borsh encoded `PublicKey`](encoding.md#publickey). ## Signatures -A signature in Namada is a [Borsh encoded `Signature`](encoding.md#signature). For the Ed25519 scheme, this is 64 bytes of Ed25519 signature, prefixed with `64` in little endian encoding (`[64, 0, 0, 0]` in raw bytes or `40000000` in hex). +A signature in Namada is a [Borsh encoded `Signature`](encoding.md#signature). From 291b24240f4efbdcfdfb385e09ae9346345118bd Mon Sep 17 00:00:00 2001 From: James Hiew Date: Fri, 8 Jul 2022 10:41:48 +0100 Subject: [PATCH 024/118] crypto.md: add context for signatures --- documentation/dev/src/specs/crypto.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/dev/src/specs/crypto.md b/documentation/dev/src/specs/crypto.md index 289280b895..c3ba21c15a 100644 --- a/documentation/dev/src/specs/crypto.md +++ b/documentation/dev/src/specs/crypto.md @@ -1,6 +1,6 @@ # Cryptographic schemes -Namada currently supports Ed25519 signatures with more to be added: +Namada currently supports Ed25519 for signing transactions or any other arbitrary data, with support for more signature schemes to be added: - [`Secp256k1`](https://github.com/anoma/anoma/issues/162) - [`Sr25519`](https://github.com/anoma/anoma/issues/646) From 7c1340447fbb4e69fc957f8614d65b5510f634f8 Mon Sep 17 00:00:00 2001 From: brentstone Date: Tue, 9 Aug 2022 00:53:47 -0400 Subject: [PATCH 025/118] Initial info on Secp256k1 keys and zeroizing secret keys --- documentation/dev/src/specs/crypto.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/documentation/dev/src/specs/crypto.md b/documentation/dev/src/specs/crypto.md index c3ba21c15a..9025c5c1bb 100644 --- a/documentation/dev/src/specs/crypto.md +++ b/documentation/dev/src/specs/crypto.md @@ -1,14 +1,19 @@ # Cryptographic schemes -Namada currently supports Ed25519 for signing transactions or any other arbitrary data, with support for more signature schemes to be added: +Namada currently supports both Ed25519 and Secp256k1 (currently in [development](https://github.com/anoma/namada/pulls/278)) for signing transactions or any other arbitrary data, with support for more signature schemes to be added: -- [`Secp256k1`](https://github.com/anoma/anoma/issues/162) - [`Sr25519`](https://github.com/anoma/anoma/issues/646) +The implementation of the Ed25519 scheme makes use of the `ed25519_consensus` crate, while the `libsecp256k1` crate is used for Secp256k1 keys. + ## Public keys -A public key is a [Borsh encoded `PublicKey`](encoding.md#publickey). +A public key is a [Borsh encoded](encoding.md) `PublicKey`. + +## Secret Keys + +A secret key is a [Borsh encoded](encoding.md) `SecretKey`. In order to prevent leaks of sensitive information, the contents of a secret key are zeroized. Sometimes the Rust compiler can optimize away the action of zeroing the bytes of data corresponding to an object dropped from scope. For secret keys, this data in memory is directly zeroed after the keys are no longer needed. ## Signatures -A signature in Namada is a [Borsh encoded `Signature`](encoding.md#signature). +A signature in Namada is a [Borsh encoded](encoding.md) `Signature`. From 7c937046fa23e32619030b34c5df161c03fd8184 Mon Sep 17 00:00:00 2001 From: brentstone Date: Tue, 9 Aug 2022 00:54:22 -0400 Subject: [PATCH 026/118] change string to valid path --- encoding_spec/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/encoding_spec/src/main.rs b/encoding_spec/src/main.rs index 8877ff3e77..db65f24667 100644 --- a/encoding_spec/src/main.rs +++ b/encoding_spec/src/main.rs @@ -32,7 +32,7 @@ use namada::types::{token, transaction}; /// This generator will write output into this `docs` file. const OUTPUT_PATH: &str = - "documentation/docs/src/specs/encoding/generated-borsh-spec.md"; + "documentation/dev/src/specs/encoding/generated-borsh-spec.md"; lazy_static! { /// Borsh types may be used by declarations. These are displayed differently in the [`md_fmt_type`]. From 19b454e357f4192330c57a5d3f9d12775338ab07 Mon Sep 17 00:00:00 2001 From: James Hiew Date: Fri, 17 Jun 2022 10:04:10 +0100 Subject: [PATCH 027/118] .gitignore: make some patterns relative to repo root This avoid some potential conflicts with actual files we want to track eg apps/src/bin/anoma-client/main.rs --- .gitignore | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 8092b5afd8..5f835e6405 100644 --- a/.gitignore +++ b/.gitignore @@ -7,8 +7,8 @@ debug/ target/ # Release packages -anoma-*/ -anoma-*.tar.gz +/anoma-*/ +/anoma-*.tar.gz # These are backup files generated by rustfmt **/*.rs.bk @@ -26,4 +26,4 @@ anoma-*.tar.gz wasm/*.wasm # app version string file -apps/version.rs +/apps/version.rs From 8593febefea9046bd6a88e9d9bb36ce9d94bdc36 Mon Sep 17 00:00:00 2001 From: James Hiew Date: Fri, 17 Jun 2022 10:07:55 +0100 Subject: [PATCH 028/118] Add changelog --- .changelog/unreleased/miscellaneous/1158-gitignore-anoma.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .changelog/unreleased/miscellaneous/1158-gitignore-anoma.md diff --git a/.changelog/unreleased/miscellaneous/1158-gitignore-anoma.md b/.changelog/unreleased/miscellaneous/1158-gitignore-anoma.md new file mode 100644 index 0000000000..79e551d436 --- /dev/null +++ b/.changelog/unreleased/miscellaneous/1158-gitignore-anoma.md @@ -0,0 +1,2 @@ +- Make some .gitignore patterns relative to repo root + ([#1158](https://github.com/anoma/anoma/pull/1158)) \ No newline at end of file From 5bdc7029122d1a0f8c131acd52a8b0ae8b566a80 Mon Sep 17 00:00:00 2001 From: James Hiew Date: Fri, 17 Jun 2022 10:04:10 +0100 Subject: [PATCH 029/118] .gitignore: make some patterns relative to repo root This avoid some potential conflicts with actual files we want to track eg apps/src/bin/anoma-client/main.rs --- .gitignore | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 8092b5afd8..5f835e6405 100644 --- a/.gitignore +++ b/.gitignore @@ -7,8 +7,8 @@ debug/ target/ # Release packages -anoma-*/ -anoma-*.tar.gz +/anoma-*/ +/anoma-*.tar.gz # These are backup files generated by rustfmt **/*.rs.bk @@ -26,4 +26,4 @@ anoma-*.tar.gz wasm/*.wasm # app version string file -apps/version.rs +/apps/version.rs From 07876b1f8be00531da22c217f5ec36b2ffad1773 Mon Sep 17 00:00:00 2001 From: James Hiew Date: Fri, 17 Jun 2022 10:07:55 +0100 Subject: [PATCH 030/118] Add changelog --- .changelog/unreleased/miscellaneous/1158-gitignore-anoma.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .changelog/unreleased/miscellaneous/1158-gitignore-anoma.md diff --git a/.changelog/unreleased/miscellaneous/1158-gitignore-anoma.md b/.changelog/unreleased/miscellaneous/1158-gitignore-anoma.md new file mode 100644 index 0000000000..79e551d436 --- /dev/null +++ b/.changelog/unreleased/miscellaneous/1158-gitignore-anoma.md @@ -0,0 +1,2 @@ +- Make some .gitignore patterns relative to repo root + ([#1158](https://github.com/anoma/anoma/pull/1158)) \ No newline at end of file From e0b5c4648e0d2412eae90c58fd13461c60ade039 Mon Sep 17 00:00:00 2001 From: James Hiew Date: Fri, 1 Jul 2022 12:31:41 +0100 Subject: [PATCH 031/118] Add specs/openapi.yml --- specs/openapi.yml | 130 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 specs/openapi.yml diff --git a/specs/openapi.yml b/specs/openapi.yml new file mode 100644 index 0000000000..7533c14431 --- /dev/null +++ b/specs/openapi.yml @@ -0,0 +1,130 @@ +openapi: 3.0.3 +info: + title: Anoma + description: Interacting with an Anoma blockchain via Tendermint RPC + version: 0.6.1 +servers: + - url: http://127.0.0.1:26657 + description: Tendermint RPC endpoint for an Anoma ledger +paths: + /: + post: + summary: Interact with the Anoma blockchain via Tendermint RPC + operationId: abci_query + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + id: + description: Should be unique between requests + type: integer + example: 58392 + method: + description: The Tendermint RPC method being called which in this case should always be abci_query + type: string + enum: + - "abci_query" + params: + type: object + required: + - path + properties: + path: + description: Path as will be recognized by the ledger + oneOf: + - type: string + enum: + - "epoch" + - "dry_run_tx" + description: > + * `epoch` - Epoch at the given block height + * `dry_run_tx` - Dry run a transaction + - type: string + description: Read a storage value with exact storage key + pattern: r"^value\/(\w|\/)+$" + - type: string + description: Read a range of storage values with a matching key prefix + pattern: r"^prefix\/(\w|\/)+$" + - type: string + description: Check if the given storage key exists + pattern: r"^has_key\/(\w|\/)+$" + data: + description: Optional data to go along with the query (base64-encoded if necessary) + type: string + example: "abcd" + default: "" + height: + description: Height as a base64 encoded integer (0 means latest) + type: string + example: "1" + default: "0" + prove: + description: Include proofs of the transaction's inclusion in the block + type: boolean + example: true + default: false + examples: + epoch_latest: + summary: Get the latest epoch + value: + { + "id": 2, + "method": "abci_query", + "params": { "path": "epoch" }, + } + epoch_at_height: + summary: Get the epoch at a given height + value: + { + "id": 2, + "method": "abci_query", + "params": { "path": "epoch", "height": 2 }, + } + responses: + "200": + description: Response of the submitted query + content: + application/json: + schema: + $ref: "https://docs.tendermint.com/v0.34/rpc/openapi.yaml#/components/schemas/ABCIQueryResponse" + examples: + epoch_latest: + value: + { + "jsonrpc": "2.0", + "id": 2, + "result": + { + "response": + { + "code": 0, + "log": "", + "info": "", + "index": "0", + "key": null, + "value": "lQAAAAAAAAA=", + "proofOps": null, + "height": "0", + "codespace": "", + }, + }, + } + "500": + description: Error + content: + application/json: + schema: + $ref: "https://docs.tendermint.com/v0.34/rpc/openapi.yaml#/components/schemas/ErrorResponse" + example: + { + "jsonrpc": "2.0", + "error": + { + "code": -32700, + "message": "Parse error. Invalid JSON", + "data": "error unmarshaling request: invalid character 'd' after object key:value pair", + }, + } From 42bfb42d5d79af1fc0ad8fceecc45343d26599c8 Mon Sep 17 00:00:00 2001 From: James Hiew Date: Fri, 8 Jul 2022 15:13:23 +0100 Subject: [PATCH 032/118] A key can contain any ASCII, not just alphabetical characters --- specs/openapi.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/specs/openapi.yml b/specs/openapi.yml index 7533c14431..e8bf5259d3 100644 --- a/specs/openapi.yml +++ b/specs/openapi.yml @@ -44,13 +44,13 @@ paths: * `dry_run_tx` - Dry run a transaction - type: string description: Read a storage value with exact storage key - pattern: r"^value\/(\w|\/)+$" + pattern: r"^value\/([\x00-\x7F]|\/)+$" - type: string description: Read a range of storage values with a matching key prefix - pattern: r"^prefix\/(\w|\/)+$" + pattern: r"^prefix\/([\x00-\x7F]|\/)+$" - type: string description: Check if the given storage key exists - pattern: r"^has_key\/(\w|\/)+$" + pattern: r"^has_key\/([\x00-\x7F]|\/)+$" data: description: Optional data to go along with the query (base64-encoded if necessary) type: string From a374fd2bb5f8985273b4e7dceff8d507307e74e7 Mon Sep 17 00:00:00 2001 From: James Hiew Date: Fri, 8 Jul 2022 15:13:34 +0100 Subject: [PATCH 033/118] Add example for getting an account's public key --- specs/openapi.yml | 48 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/specs/openapi.yml b/specs/openapi.yml index e8bf5259d3..52acc7fab5 100644 --- a/specs/openapi.yml +++ b/specs/openapi.yml @@ -83,6 +83,18 @@ paths: "method": "abci_query", "params": { "path": "epoch", "height": 2 }, } + get_account_public_key: + summary: Get the public key for an account which has been initialized with a validity predicate, with proof + value: + { + "id": 2, + "method": "abci_query", + "params": + { + "path": "value/#atest1v4ehgw36g4pyg3j9x3qnjd3cxgmyz3fk8qcrys3hxdp5xwfnx3zyxsj9xgunxsfjg5u5xvzyzrrqtn/public_key", + "prove": true, + }, + } responses: "200": description: Response of the submitted query @@ -112,6 +124,42 @@ paths: }, }, } + get_account_public_key: + value: + { + "jsonrpc": "2.0", + "id": 2, + "result": + { + "response": + { + "code": 0, + "log": "", + "info": "", + "index": "0", + "key": null, + "value": "ABdruiwJLZ4w4Z/MoD+aW3fH4vkc9+QhGOCGmDr1oVz+", + "proofOps": + { + "ops": + [ + { + "type": "ics23_CommitmentProof", + "key": "I2F0ZXN0MXY0ZWhndzM2ZzRweWczajl4M3FuamQzY3hnbXl6M2ZrOHFjcnlzM2h4ZHA1eHdmbngzenl4c2o5eGd1bnhzZmpnNXU1eHZ6eXpycnF0bi9wdWJsaWNfa2V5", + "data": "Cu0CCmAjYXRlc3QxdjRlaGd3MzZnNHB5ZzNqOXgzcW5qZDNjeGdteXozZms4cWNyeXMzaHhkcDV4d2ZueDN6eXhzajl4Z3VueHNmamc1dTV4dnp5enJycXRuL3B1YmxpY19rZXkSIQAXa7osCS2eMOGfzKA/mlt3x+L5HPfkIRjghpg69aFc/hooCAEQARgBKiAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACIkCAESIOQIgEOVb0Hv2eOTmYDks2uP4L4gs0RgmV2wUisInkbQIiQIARog04WfgQqfT2X9aD9qhA/fWy6LS6JjdmkpmUfkK9hoKOwiJAgBEiB+tFAPUElWCcCpAL4khjoihfs19F7tfdagbWWE44kCESIkCAEaIBtq2MVGbblK4zgD3h5vxQNKiCU+dmaHLQSpzWvBT3lwIiQIARogwl8LV3ECHOBxasQriaEAE/dgSZnKZ6vBm6Zm7vTED0Y=", + }, + { + "type": "ics23_CommitmentProof", + "key": "I2F0ZXN0MXY0ZWhndzM2ZzRweWczajl4M3FuamQzY3hnbXl6M2ZrOHFjcnlzM2h4ZHA1eHdmbngzenl4c2o5eGd1bnhzZmpnNXU1eHZ6eXpycnF0bi9wdWJsaWNfa2V5", + "data": "CnkKB2FjY291bnQSIMMIWmruLiaYEqu6LGhBd6QS74N0WncwSIe+tIux4F+BGiYIARABKiAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACIkCAESIG3BkVXL0ICjUIY1bV7YSPruEfFZLIB2vlL7lpwQ3ycX", + }, + ], + }, + "height": "0", + "codespace": "", + }, + }, + } "500": description: Error content: From ce036b0a8459c2a0b6b0bd9272afb42e273fd447 Mon Sep 17 00:00:00 2001 From: James Hiew Date: Fri, 8 Jul 2022 15:16:32 +0100 Subject: [PATCH 034/118] Add invalid storage key error response example --- specs/openapi.yml | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/specs/openapi.yml b/specs/openapi.yml index 52acc7fab5..40b15751f0 100644 --- a/specs/openapi.yml +++ b/specs/openapi.yml @@ -97,7 +97,7 @@ paths: } responses: "200": - description: Response of the submitted query + description: Response of the submitted query, which may have been successful or may have errored at the application level. content: application/json: schema: @@ -160,8 +160,29 @@ paths: }, }, } + invalid_storage_key: + value: + { + "jsonrpc": "2.0", + "id": 2, + "result": + { + "response": + { + "code": 1, + "log": "", + "info": "RPC error: Invalid storage key: Error parsing address: Error decoding address from Bech32m: invalid length", + "index": "0", + "key": null, + "value": null, + "proofOps": null, + "height": "0", + "codespace": "", + }, + }, + } "500": - description: Error + description: Tendermint-level error content: application/json: schema: From 4efd4613a98ed39c594cf14bf2efa2ad2cfada80 Mon Sep 17 00:00:00 2001 From: James Hiew Date: Tue, 19 Jul 2022 12:05:17 +0100 Subject: [PATCH 035/118] Storage key regexes should permit any UTF-8 string --- specs/openapi.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/specs/openapi.yml b/specs/openapi.yml index 40b15751f0..f7f2f53e0c 100644 --- a/specs/openapi.yml +++ b/specs/openapi.yml @@ -44,13 +44,13 @@ paths: * `dry_run_tx` - Dry run a transaction - type: string description: Read a storage value with exact storage key - pattern: r"^value\/([\x00-\x7F]|\/)+$" + pattern: r"^value\/.+$" - type: string description: Read a range of storage values with a matching key prefix - pattern: r"^prefix\/([\x00-\x7F]|\/)+$" + pattern: r"^prefix\/.+$" - type: string description: Check if the given storage key exists - pattern: r"^has_key\/([\x00-\x7F]|\/)+$" + pattern: r"^has_key\/.+$" data: description: Optional data to go along with the query (base64-encoded if necessary) type: string From 959737d1046fa9086c3b68da7cb841bcab5cd3d3 Mon Sep 17 00:00:00 2001 From: James Date: Tue, 19 Jul 2022 12:14:34 +0100 Subject: [PATCH 036/118] Apply suggestions from code review Co-authored-by: Tomas Zemanovic --- specs/openapi.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/openapi.yml b/specs/openapi.yml index f7f2f53e0c..d207b42a11 100644 --- a/specs/openapi.yml +++ b/specs/openapi.yml @@ -40,7 +40,7 @@ paths: - "epoch" - "dry_run_tx" description: > - * `epoch` - Epoch at the given block height + * `epoch` - Get the epoch of the last block (the height argument is not yet supported ) * `dry_run_tx` - Dry run a transaction - type: string description: Read a storage value with exact storage key From d758b1ba12077f367a7877a9ef86173263d0ff5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zemanovi=C4=8D?= Date: Wed, 17 Aug 2022 08:53:50 +0200 Subject: [PATCH 037/118] docs: move and link to openAPI spec from Ledger RPC --- {specs => documentation/dev/src/specs/ledger}/openapi.yml | 0 documentation/dev/src/specs/ledger/rpc.md | 4 ++++ 2 files changed, 4 insertions(+) rename {specs => documentation/dev/src/specs/ledger}/openapi.yml (100%) diff --git a/specs/openapi.yml b/documentation/dev/src/specs/ledger/openapi.yml similarity index 100% rename from specs/openapi.yml rename to documentation/dev/src/specs/ledger/openapi.yml diff --git a/documentation/dev/src/specs/ledger/rpc.md b/documentation/dev/src/specs/ledger/rpc.md index d0b6c37b6b..2a839ce886 100644 --- a/documentation/dev/src/specs/ledger/rpc.md +++ b/documentation/dev/src/specs/ledger/rpc.md @@ -4,6 +4,10 @@ The ledger provides an RPC interface for submitting transactions to the mempool, The RPC interface is provided as [specified](https://github.com/tendermint/spec/tree/4566f1e3028278c5b3eca27b53254a48771b152b/spec/rpc) from Tendermint and most of the requests are routed to the Namada ledger via ABCI. +## OpenAPI spec + +The [OpenAPI specification](./openapi.yml) is provided. + ## Transactions A [transaction](../ledger.md#transactions) can be submitted to the [mempool](../ledger.md#mempool) via Tendermint's [`BroadCastTxSync`](https://github.com/tendermint/spec/tree/4566f1e3028278c5b3eca27b53254a48771b152b/spec/rpc#broadcasttxsync) or [`BroadCastTxAsync`](https://github.com/tendermint/spec/tree/4566f1e3028278c5b3eca27b53254a48771b152b/spec/rpc#broadcasttxasync). The `CheckTx` result of these requests is success only if the transaction passes [mempool validation rules](../ledger.md#mempool). In case of `BroadCastTxAsync`, the `DeliverTx` is not indicative of the transaction's result, it's merely a result of the transaction being added to the [transaction queue](../ledger.md#outer-transaction-processing). The actual result of the outer transaction and the inner transaction can be found from via the [ABCI events](https://github.com/tendermint/spec/blob/4566f1e3028278c5b3eca27b53254a48771b152b/spec/abci/abci.md#events). From 881e5ca41405f307b942cb34fea8f52bd206fe38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zemanovi=C4=8D?= Date: Wed, 17 Aug 2022 08:57:12 +0200 Subject: [PATCH 038/118] changelog: add #322 --- .changelog/unreleased/docs/322-openapi-spec.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 .changelog/unreleased/docs/322-openapi-spec.md diff --git a/.changelog/unreleased/docs/322-openapi-spec.md b/.changelog/unreleased/docs/322-openapi-spec.md new file mode 100644 index 0000000000..9af416a990 --- /dev/null +++ b/.changelog/unreleased/docs/322-openapi-spec.md @@ -0,0 +1 @@ +- Added OpenAPI spec ([#322](https://github.com/anoma/namada/pull/322)) \ No newline at end of file From 339858ca19345f5bf8c219795d0c327d71877d67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zemanovi=C4=8D?= Date: Wed, 17 Aug 2022 09:00:02 +0200 Subject: [PATCH 039/118] update relative paths in dev docs --- documentation/dev/src/explore/resources/ide.md | 4 ++-- documentation/dev/src/specs/encoding.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/documentation/dev/src/explore/resources/ide.md b/documentation/dev/src/explore/resources/ide.md index 9f5f106ba1..b7e2232bb9 100644 --- a/documentation/dev/src/explore/resources/ide.md +++ b/documentation/dev/src/explore/resources/ide.md @@ -31,7 +31,7 @@ Add these to your settings.json to get rustfmt and clippy with the nightly versi ```json "rust-analyzer.checkOnSave.overrideCommand": [ "cargo", - "+{{#include ../../../../rust-nightly-version}}", + "+{{#include ../../../../../rust-nightly-version}}", "clippy", "--workspace", "--message-format=json", @@ -40,7 +40,7 @@ Add these to your settings.json to get rustfmt and clippy with the nightly versi "rust-analyzer.rustfmt.overrideCommand": [ "rustup", "run", - "{{#include ../../../../rust-nightly-version}}", + "{{#include ../../../../../rust-nightly-version}}", "--", "rustfmt", "--edition", diff --git a/documentation/dev/src/specs/encoding.md b/documentation/dev/src/specs/encoding.md index 728390c153..40e4b79b3c 100644 --- a/documentation/dev/src/specs/encoding.md +++ b/documentation/dev/src/specs/encoding.md @@ -41,7 +41,7 @@ Note that for the [default transactions](ledger/default-transactions.md), the `d ## Proto definitions ``` -{{#include ../../../proto/types.proto}} +{{#include ../../../../proto/types.proto}} ``` From 8c1a9a4baee686aebf9fe51349465aa15f646565 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zemanovi=C4=8D?= Date: Wed, 17 Aug 2022 09:06:17 +0200 Subject: [PATCH 040/118] update links to user guide docs --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 939653c596..323bc5e9b8 100644 --- a/README.md +++ b/README.md @@ -38,10 +38,10 @@ make install After installation, the main `anoma` executable will be available on path. -To find how to use it, check out the [User Guide section of the docs](https://docs.anoma.net/user-guide/). +To find how to use it, check out the [User Guide section of the docs](https://docs.namada.net/user-guide/index.html). For more detailed instructions and more install options, see the [Install -section](https://docs.anoma.net/user-guide/install.html) of the User +section](https://docs.namada.net/user-guide/install.html) of the User Guide. ## ⚙️ Development From dea735d0fddeb53277c8bf9b808178f99b382179 Mon Sep 17 00:00:00 2001 From: Adrian Brink Date: Thu, 14 Jul 2022 13:42:42 +0200 Subject: [PATCH 041/118] Update config files --- documentation/docs/book.toml | 4 ++-- documentation/docs/src/README.md | 18 +----------------- 2 files changed, 3 insertions(+), 19 deletions(-) diff --git a/documentation/docs/book.toml b/documentation/docs/book.toml index d1a55fe006..cef6122f68 100644 --- a/documentation/docs/book.toml +++ b/documentation/docs/book.toml @@ -1,10 +1,10 @@ [book] -authors = ["Heliax R&D Team"] +authors = ["Heliax AG"] language = "en" multilingual = false site-url = "https://docs.namada.net/" src = "src" -title = "Namada Docs" +title = "Namada Documentation" [output.html] edit-url-template = "https://github.com/anoma/namada/documentation/docs/edit/main/{path}" diff --git a/documentation/docs/src/README.md b/documentation/docs/src/README.md index ff487e04e4..3e1330b24c 100644 --- a/documentation/docs/src/README.md +++ b/documentation/docs/src/README.md @@ -4,25 +4,9 @@ Welcome to Namada's docs! ## About Namada -[Namada](https://namada.net/) is a sovereign proof-of-stake blockchain, using Tendermint BFT consensus, that enables multi-asset private transfers for any native or non-native asset using a multi-asset shielded pool derived from the Sapling circuit. +[Namada](https://namada.net/) is a sovereign proof-of-stake blockchain, using Tendermint BFT consensus, that enables multi-asset private transfers for any native or non-native asset using a multi-asset shielded pool derived from the Sapling circuit. To learn more about the protocol, we recommend the following resources: - [Introducing Namada: Shielded Transfers with Any Assets](https://medium.com/anomanetwork/introducing-namada-shielded-transfers-with-any-assets-dce2e579384c) - [Namada's specifications](https://specs.namada.net) - -### The source - -This book is written using [mdBook](https://rust-lang.github.io/mdBook/), it currently lives in the [Namada repo](https://github.com/anoma/namada/documentation/docs). - -To get started quickly, in the `docs` directory one can: - -```shell -# Install dependencies -make dev-deps - -# This will open the book in your default browser and rebuild on changes -make serve -``` - -[Contributions](https://github.com/anoma/namada/issues) to the contents and the structure of this book should be made via pull requests. From 742f94c550b416cc24ce5835027b34b7394d2d67 Mon Sep 17 00:00:00 2001 From: Adrian Brink Date: Thu, 14 Jul 2022 13:45:08 +0200 Subject: [PATCH 042/118] Replace anoma with namada in quickstart --- documentation/docs/src/quick-start.md | 28 +++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/documentation/docs/src/quick-start.md b/documentation/docs/src/quick-start.md index d29cae9ffd..41a45c7158 100644 --- a/documentation/docs/src/quick-start.md +++ b/documentation/docs/src/quick-start.md @@ -11,11 +11,11 @@ This guide is aimed at people interested in running a validator node and assumes ## Install Namada -See [the install guide](user-guide/install.md) for details on installing the Namada binaries. Commands in this guide will assume you have the Namada binaries (`anoma`, `anoman`, `anomaw`, `anomac`) on your path. +See [the install guide](user-guide/install.md) for details on installing the Namada binaries. Commands in this guide will assume you have the Namada binaries (`namada`, `namadan`, `namadaw`, `namadac`) on your path. ## Joining a network -See [the testnets page](testnets) for details of how to join a testnet. The rest of this guide will assume you have joined a testnet chain using the `anomac utils join-network` command. +See [the testnets page](testnets) for details of how to join a testnet. The rest of this guide will assume you have joined a testnet chain using the `namadac utils join-network` command. ## Run a ledger node @@ -26,7 +26,7 @@ tmux # inside the tmux/or not -anoma ledger +namada ledger # can detach the tmux (Ctrl-B then D) ``` @@ -39,9 +39,9 @@ Generate a local key on disk ```shell # first, we make a keypair and the implicit account associated with it -# anomaw address gen instead of key gen. Preferred because they both make a keypair but the former stores the implicit address for it too +# namadaw address gen instead of key gen. Preferred because they both make a keypair but the former stores the implicit address for it too -anomaw address gen \ +namadaw address gen \ --alias example-implicit ➜ Enter encryption password: @@ -53,7 +53,7 @@ Successfully added a key and an address with alias: "example-implicit" To initialize an account operator on chain under the alias "example-established": ```shell -anomac init-account \ +namadac init-account \ --source example-implicit \ --public-key example-implicit \ --alias example-established @@ -79,7 +79,7 @@ The transaction initialized 1 new account Let's transfer ourselves 1000 NAM from the faucet with the same alias using: ```shell -anomac transfer \ +namadac transfer \ --source faucet \ --target example-established \ --token NAM \ @@ -104,7 +104,7 @@ Transaction applied with result: { To get the balance of your account "example-established": ```shell -anomac balance \ +namadac balance \ --owner example-established ``` @@ -113,7 +113,7 @@ anomac balance \ Initialize a validator account under any alias - in this example, "example-validator": ```shell -anomac init-validator \ +namadac init-validator \ --alias example-validator \ --source example-established @@ -148,7 +148,7 @@ The validator's addresses and keys were stored in the wallet: The ledger node has been setup to use this validator's address and consensus key. ``` -Once the `init-validator` transaction is applied in the block and the on-chain generated validator's address is stored in your wallet, you MUST restart the `anoma ledger` node to start the node as a validator that you've just created. +Once the `init-validator` transaction is applied in the block and the on-chain generated validator's address is stored in your wallet, you MUST restart the `namada ledger` node to start the node as a validator that you've just created. When you restart the node, you might notice log message "This node is not a validator" from Tendermint. This is expected, because your validator doesn't yet have any stake in the [PoS system](./user-guide/ledger/pos.md). @@ -157,7 +157,7 @@ We will now add some stake to your validator account. Transfer 1000 NAM to your validator account ("example-validator"): ```shell -anomac transfer \ +namadac transfer \ --source example-established \ --target example-validator \ --token NAM \ @@ -181,7 +181,7 @@ Transaction applied with result: { Bond the 1000 NAM to "example-validator" using: ```shell -anomac bond \ +namadac bond \ --validator example-validator \ --amount 1000 @@ -203,7 +203,7 @@ Transaction applied with result: { Check your bond: ```shell -anomac bonds \ +namadac bonds \ --validator example-validator ➜ Jan 06 22:30:42.798 INFO anoma_apps::cli::context: Chain ID: anoma-testnet-1.2.bf0181d9f7e0 @@ -216,7 +216,7 @@ Bonds total: 1000 Check the voting power - this will be 0 until the active-from epoch is reached (in this case `22395`): ```shell -anomac voting-power \ +namadac voting-power \ --validator example-validator ➜ Jan 06 22:31:24.908 INFO anoma_apps::cli::context: Chain ID: anoma-testnet-1.2.bf0181d9f7e0 From 98fe44420f7d4adee45c0995d63f4e2062a3315d Mon Sep 17 00:00:00 2001 From: Adrian Brink Date: Thu, 14 Jul 2022 16:39:49 +0200 Subject: [PATCH 043/118] update outer readme --- documentation/README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/documentation/README.md b/documentation/README.md index a740b8d387..63dec3bdea 100644 --- a/documentation/README.md +++ b/documentation/README.md @@ -1,8 +1,6 @@ # Documentation -- `docs` contains user and operator documentation. - -- `dev` contains developer documentation for building on top of Namada. +- `docs` contains user, operator and developer documentation. - `spec` contains the specifications for Namada. From 346945288be75dd25ad85f96cf3e2e32ef1f42b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zemanovi=C4=8D?= Date: Wed, 17 Aug 2022 13:07:57 +0200 Subject: [PATCH 044/118] re-add `dev` docs section --- documentation/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/documentation/README.md b/documentation/README.md index 63dec3bdea..7ba9592ede 100644 --- a/documentation/README.md +++ b/documentation/README.md @@ -2,6 +2,8 @@ - `docs` contains user, operator and developer documentation. +- `dev` contains developer documentation for building on top of Namada. + - `spec` contains the specifications for Namada. To build any of these, in its subdirectory: From 2e683c7e371f3e31e5779d3ee45133a400b8ba81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zemanovi=C4=8D?= Date: Wed, 17 Aug 2022 13:19:56 +0200 Subject: [PATCH 045/118] doc/docs: s/anoma/namada --- documentation/docs/src/testnets/README.md | 5 +- .../docs/src/testnets/internal-testnet-1.md | 64 +++++++++---------- .../src/user-guide/genesis-validator-setup.md | 12 ++-- .../docs/src/user-guide/getting-started.md | 27 ++++---- documentation/docs/src/user-guide/install.md | 10 +-- documentation/docs/src/user-guide/ledger.md | 4 +- .../docs/src/user-guide/ledger/governance.md | 22 +++---- .../docs/src/user-guide/ledger/masp.md | 37 ++++++++++- .../docs/src/user-guide/ledger/pos.md | 42 ++++++------ documentation/docs/src/user-guide/wallet.md | 34 +++++----- 10 files changed, 148 insertions(+), 109 deletions(-) diff --git a/documentation/docs/src/testnets/README.md b/documentation/docs/src/testnets/README.md index 23e3a88887..6299cc839c 100644 --- a/documentation/docs/src/testnets/README.md +++ b/documentation/docs/src/testnets/README.md @@ -2,11 +2,12 @@ This section describes how to connect to the various testnets and to test selected features. -You may need to be using `anoma` binaries built from a specific commit in order to interact with specific testnets. Use the below command with the chain ID of the testnet you want to join. +You may need to be using `namada` binaries built from a specific commit in order to interact with specific testnets. Use the below command with the chain ID of the testnet you want to join. ```shell -anoma client utils join-network --chain-id=$NAMADA_CHAIN_ID +namada client utils join-network --chain-id=$NAMADA_CHAIN_ID ``` ## Current testnets + - [Namada Close Quarters Testnet 1](./namada-close-quarters-testnet-1.md) diff --git a/documentation/docs/src/testnets/internal-testnet-1.md b/documentation/docs/src/testnets/internal-testnet-1.md index 37af29fc5f..d4ad45adb6 100644 --- a/documentation/docs/src/testnets/internal-testnet-1.md +++ b/documentation/docs/src/testnets/internal-testnet-1.md @@ -16,14 +16,14 @@ You can install Namada by following the instructions from the [Install User Guid ## Setting up Namada -At this point, depending on your installation choice, we will assume that the `anoma` binaries are available on path and built from the latest testnet branch. +At this point, depending on your installation choice, we will assume that the `namada` binaries are available on path and built from the latest testnet branch. ### Join a network To join the current testnet, you need to download the configuration files. This can be done easily with: ```shell -anomac utils join-network --chain-id $NAMADA_TESTNET_CHAIN_ID +namadac utils join-network --chain-id $NAMADA_TESTNET_CHAIN_ID ``` It should output something like this where the chain id might differ: @@ -67,7 +67,7 @@ tar -xvf masp-params.tar.gz ~/Library/Application\ Support/MASPParams/ At this point, you are ready to start your Namada node with: ```shell -anoma ledger +namada ledger ``` To keep your node running after closing your terminal, you can optionally use a terminal multiplexer like `tmux`. @@ -84,9 +84,9 @@ To try out shielded transfers, you will first need an ordinary transparent account with some token balance. Example commands for that: ``` -anomaw address gen --alias my-implicit -anomac init-account --source my-implicit --public-key my-implicit --alias my-established -anomac transfer --token btc --amount 1000 --source faucet --target my-established --signer my-established +namadaw address gen --alias my-implicit +namadac init-account --source my-implicit --public-key my-implicit --alias my-established +namadac transfer --token btc --amount 1000 --source faucet --target my-established --signer my-established ``` The testnet tokens which the faucet can provide you are named `NAM`, @@ -102,7 +102,7 @@ you could randomly generate one with e.g. `openssl rand -hex 32`. The wallet does not yet support spending keys, so make a note of yours somewhere. -Shielded transfers work with the `anomac transfer` command, but either +Shielded transfers work with the `namadac transfer` command, but either `--source`, `--target`, or both are replaced. `--source` may be replaced with `--spending-key` to spend a shielded balance, but if you are following along, you don't have a shielded balance to spend yet. @@ -112,7 +112,7 @@ balance. To create a payment address from your spending key, use: ```shell -anomaw masp gen-payment-addr --spending-key [your spending key] +namadaw masp gen-payment-addr --spending-key [your spending key] ``` This will generate a different payment address each time you run it. @@ -123,14 +123,14 @@ Once you have a payment address, transfer a balance from your transparent account to your shielded spending key with something like: ```shell -anomac transfer --source my-established --payment-address [your payment address] --token btc --amount 100 +namadac transfer --source my-established --payment-address [your payment address] --token btc --amount 100 ``` Once this transfer goes through, you can view your spending key's balance: ```shell -anomac balance --spending-key [your spending key] +namadac balance --spending-key [your spending key] ``` However, your spending key is the secret key to all your shielded @@ -138,24 +138,24 @@ balances, and you may not want to use it just to view balances. For this purpose, you can derive the viewing key: ```shell -anomaw masp derive-view-key --spending-key [your spending key] -anomac balance --viewing-key [your viewing key] +namadaw masp derive-view-key --spending-key [your spending key] +namadac balance --viewing-key [your viewing key] ``` The viewing key can also be used to generate payment addresses, with -e.g. `anomaw masp gen-payment-addr --viewing-key [your viewing key]`. +e.g. `namadaw masp gen-payment-addr --viewing-key [your viewing key]`. Now that you have a shielded balance, it can either be transferred to a different shielded payment address (shielded to shielded): ```shell -anomac transfer --spending-key [your spending key] --payment-address [someone's payment address] --token btc --amount 50 --signer my-established +namadac transfer --spending-key [your spending key] --payment-address [someone's payment address] --token btc --amount 50 --signer my-established ``` or to a transparent account (shielded to transparent): ```shell -anomac transfer --spending-key [your spending key] --target [some transparent account] --token btc --amount 50 --signer my-established +namadac transfer --spending-key [your spending key] --target [some transparent account] --token btc --amount 50 --signer my-established ``` Note that for both of these types of transfer, `--signer` must be @@ -178,21 +178,21 @@ make build-wasm-scripts-docker If you get the following log, it means that Tendermint is not installed properly on your machine or not available on path. To solve this issue, install Tendermint by following the [Install User Guide](../user-guide/install.md). ```shell -2022-03-30T07:21:09.212187Z INFO anoma_apps::cli::context: Chain ID: anoma-masp-0.3.51d2f83a8412b95 -2022-03-30T07:21:09.213968Z INFO anoma_apps::node::ledger: Available logical cores: 8 -2022-03-30T07:21:09.213989Z INFO anoma_apps::node::ledger: Using 4 threads for Rayon. -2022-03-30T07:21:09.213994Z INFO anoma_apps::node::ledger: Using 4 threads for Tokio. -2022-03-30T07:21:09.217867Z INFO anoma_apps::node::ledger: VP WASM compilation cache size not configured, using 1/6 of available memory. -2022-03-30T07:21:09.218908Z INFO anoma_apps::node::ledger: Available memory: 15.18 GiB -2022-03-30T07:21:09.218934Z INFO anoma_apps::node::ledger: VP WASM compilation cache size: 2.53 GiB -2022-03-30T07:21:09.218943Z INFO anoma_apps::node::ledger: Tx WASM compilation cache size not configured, using 1/6 of available memory. -2022-03-30T07:21:09.218947Z INFO anoma_apps::node::ledger: Tx WASM compilation cache size: 2.53 GiB -2022-03-30T07:21:09.218954Z INFO anoma_apps::node::ledger: Block cache size not configured, using 1/3 of available memory. -2022-03-30T07:21:09.218959Z INFO anoma_apps::node::ledger: RocksDB block cache size: 5.06 GiB -2022-03-30T07:21:09.218996Z INFO anoma_apps::node::ledger::storage::rocksdb: Using 2 compactions threads for RocksDB. -2022-03-30T07:21:09.219196Z INFO anoma_apps::node::ledger: Tendermint node is no longer running. -2022-03-30T07:21:09.232544Z INFO anoma::ledger::storage: No state could be found -2022-03-30T07:21:09.232709Z INFO anoma_apps::node::ledger: Tendermint has exited, shutting down... -2022-03-30T07:21:09.232794Z INFO anoma_apps::node::ledger: Anoma ledger node started. -2022-03-30T07:21:09.232849Z INFO anoma_apps::node::ledger: Anoma ledger node has shut down. +2022-03-30T07:21:09.212187Z INFO namada_apps::cli::context: Chain ID: anoma-masp-0.3.51d2f83a8412b95 +2022-03-30T07:21:09.213968Z INFO namada_apps::node::ledger: Available logical cores: 8 +2022-03-30T07:21:09.213989Z INFO namada_apps::node::ledger: Using 4 threads for Rayon. +2022-03-30T07:21:09.213994Z INFO namada_apps::node::ledger: Using 4 threads for Tokio. +2022-03-30T07:21:09.217867Z INFO namada_apps::node::ledger: VP WASM compilation cache size not configured, using 1/6 of available memory. +2022-03-30T07:21:09.218908Z INFO namada_apps::node::ledger: Available memory: 15.18 GiB +2022-03-30T07:21:09.218934Z INFO namada_apps::node::ledger: VP WASM compilation cache size: 2.53 GiB +2022-03-30T07:21:09.218943Z INFO namada_apps::node::ledger: Tx WASM compilation cache size not configured, using 1/6 of available memory. +2022-03-30T07:21:09.218947Z INFO namada_apps::node::ledger: Tx WASM compilation cache size: 2.53 GiB +2022-03-30T07:21:09.218954Z INFO namada_apps::node::ledger: Block cache size not configured, using 1/3 of available memory. +2022-03-30T07:21:09.218959Z INFO namada_apps::node::ledger: RocksDB block cache size: 5.06 GiB +2022-03-30T07:21:09.218996Z INFO namada_apps::node::ledger::storage::rocksdb: Using 2 compactions threads for RocksDB. +2022-03-30T07:21:09.219196Z INFO namada_apps::node::ledger: Tendermint node is no longer running. +2022-03-30T07:21:09.232544Z INFO namada::ledger::storage: No state could be found +2022-03-30T07:21:09.232709Z INFO namada_apps::node::ledger: Tendermint has exited, shutting down... +2022-03-30T07:21:09.232794Z INFO namada_apps::node::ledger: Anoma ledger node started. +2022-03-30T07:21:09.232849Z INFO namada_apps::node::ledger: Anoma ledger node has shut down. ``` diff --git a/documentation/docs/src/user-guide/genesis-validator-setup.md b/documentation/docs/src/user-guide/genesis-validator-setup.md index dd65d453b4..ae04bd123d 100644 --- a/documentation/docs/src/user-guide/genesis-validator-setup.md +++ b/documentation/docs/src/user-guide/genesis-validator-setup.md @@ -15,7 +15,7 @@ You must also provide a static `{IP:port}` to the `--net-address` argument of yo ```shell export ALIAS="1337-validator" -anoma client utils init-genesis-validator \ +namada client utils init-genesis-validator \ --alias $ALIAS \ --net-address 1.2.3.4:26656 ``` @@ -35,17 +35,17 @@ Note that the wallet containing your private keys will also be written into this Once the network is finalized, a new chain ID will be created and released on [anoma-network-config/releases](https://github.com/heliaxdev/anoma-network-config/releases) (a custom configs URL can be used instead with `ANOMA_NETWORK_CONFIGS_SERVER` env var). You can use it to setup your genesis validator node for the `--chain-id` argument in the command below. ```shell -anoma client utils join-network \ +namada client utils join-network \ --chain-id $CHAIN_ID \ --genesis-validator $ALIAS ``` -This command will use your pre-genesis wallet for the given chain and take care of setting up Anoma with Tendermint. +This command will use your pre-genesis wallet for the given chain and take care of setting up Namada with Tendermint. -If you run this command in the same directory that you ran `anoma client utils init-genesis-validator`, it should find the pre-genesis wallet for you, otherwise you can pass the path to the pre-genesis directory using `--pre-genesis-path`. e.g. +If you run this command in the same directory that you ran `namada client utils init-genesis-validator`, it should find the pre-genesis wallet for you, otherwise you can pass the path to the pre-genesis directory using `--pre-genesis-path`. e.g. ```shell -anoma client utils join-network \ +namada client utils join-network \ --chain-id $CHAIN_ID \ --pre-genesis-path workspace/.anoma/pre-genesis/$ALIAS ``` @@ -53,7 +53,7 @@ anoma client utils join-network \ Once setup, you can start the ledger as usual with e.g.: ```shell -anoma ledger +namada ledger ``` ## Required keys diff --git a/documentation/docs/src/user-guide/getting-started.md b/documentation/docs/src/user-guide/getting-started.md index 8e31897206..6f2ce00e30 100644 --- a/documentation/docs/src/user-guide/getting-started.md +++ b/documentation/docs/src/user-guide/getting-started.md @@ -2,34 +2,35 @@ This guide assumes that the Namada binaries are [installed](./install.md) and available on path. These are: -- `anoma`: The main binary that can be used to interact with all the components of Namada -- `anoman`: The ledger and intent gossiper node -- `anomac`: The client -- `anomaw`: The wallet +- `namada`: The main binary that can be used to interact with all the components of Namada +- `namadan`: The ledger and intent gossiper node +- `namadac`: The client +- `namadaw`: The wallet -The main binary `anoma` has sub-commands for all of the other binaries: +The main binary `namada` has sub-commands for all of the other binaries: -- `anoma client = anomac` -- `anoma node = anoman` -- `anoma wallet = anomaw` +- `namada client = namadac` +- `namada node = namadan` +- `namada wallet = namadaw` To explore the command-line interface, add `--help` argument at any sub-command level to find out any possible sub-commands and/or arguments. - - ## Join a network After you installed Namada, you will need to join a live network (e.g. testnet) to be able to interact with a chain and execute most available commands. You can join a network with the following command: + ``` -anoma client utils join-network --chain-id= -``` +namada client utils join-network --chain-id= +``` + To join a testnet, head over to the [testnets](../testnets) section for details on how to do this. ## Start your node As soon as you are connected to a network, you can start your local node with: + ``` -anoma ledger +namada ledger ``` Learn more about the configuration of the Ledger in [The Ledger](./ledger.md) section diff --git a/documentation/docs/src/user-guide/install.md b/documentation/docs/src/user-guide/install.md index dcf6966cb4..1b491f881b 100644 --- a/documentation/docs/src/user-guide/install.md +++ b/documentation/docs/src/user-guide/install.md @@ -16,8 +16,9 @@ This section covers the minimum and recommended hardware requirements for engagi | RAM | 16GB DDR4 | | Storage | at least 60GB SSD (NVMe SSD is recommended. HDD will be enough for localnet only) | -There are different ways to install Namada: -- [From Source](#from-source) +There are different ways to install Namada: + +- [From Source](#from-source) - [From Binaries](#from-binaries) - [From Docker](#from-docker) @@ -74,7 +75,7 @@ Let's install Tendermint. You can either follow the instructions on the [Tendermint guide](https://docs.tendermint.com/master/introduction/install.html) or download the `get_tendermint.sh` script from the [Namada repository](https://github.com/anoma/namada/blob/master/scripts/install/get_tendermint.sh) and execute it (will ask you for `root` access): ```shell -curl -LO https://raw.githubusercontent.com/anoma/anoma/master/scripts/install/get_tendermint.sh +curl -LO https://raw.githubusercontent.com/namada/anoma/main/scripts/install/get_tendermint.sh chmod +x get_tendermint.sh ./get_tendermint.sh ``` @@ -90,6 +91,7 @@ Finally, you should have GLIBC `v2.29` or higher. Now, that you have all dependencies installed you can download the latest binary release from our [releases page](https://github.com/anoma/namada/releases) by choosing the appropriate architecture. [fixme]: <> (update docker config as soon as Anoma is transferred fully to Namada) + ## From Docker -Go to [heliaxdev dockerhub account](https://hub.docker.com/r/heliaxdev/anoma) and pull the image. \ No newline at end of file +Go to [heliaxdev dockerhub account](https://hub.docker.com/r/heliaxdev/anoma) and pull the image. diff --git a/documentation/docs/src/user-guide/ledger.md b/documentation/docs/src/user-guide/ledger.md index 747cb8ebca..e51da998aa 100644 --- a/documentation/docs/src/user-guide/ledger.md +++ b/documentation/docs/src/user-guide/ledger.md @@ -3,7 +3,7 @@ To start a local Namada ledger node, run: ```shell -anoma ledger +namada ledger ``` Note that you need to have [joined a network](./getting-started.md) before you start the ledger. It throws an error if no network has been configured. @@ -24,4 +24,4 @@ option `p2p_pex` in `[ledger.tendermint]` can be set by `ANOMA_LEDGER__TENDERMINT__P2P_PEX=true|false` or `ANOMA_LEDGER.TENDERMINT.P2P_PEX=true|false` in the environment (Note: only the double underscore form can be used in Bash, because Bash doesn't allow dots in -environment variable names). \ No newline at end of file +environment variable names). diff --git a/documentation/docs/src/user-guide/ledger/governance.md b/documentation/docs/src/user-guide/ledger/governance.md index 3fe70edf35..22a84755ed 100644 --- a/documentation/docs/src/user-guide/ledger/governance.md +++ b/documentation/docs/src/user-guide/ledger/governance.md @@ -14,7 +14,7 @@ There are two different mechanism to create a proposal: Assuming you have an account with at least 500 NAM token (in this example we are going to use `my-new-acc`), lets get the corresponding address ```shell -anoma wallet address find --alias `my-new-acc` +namada wallet address find --alias `my-new-acc` ``` Now, we need to create a json file `proposal.json` holding the content of our proposal. Copy the below text into a json file. @@ -51,19 +51,19 @@ You should change the value of: As soon as your `proposal.json` file is ready, you can submit the proposal with (making sure to be in the same directory as the `proposal.json` file): ```shell -anoma client init-proposal --data-path proposal.json +namada client init-proposal --data-path proposal.json ``` The transaction should have been accepted. You can query all the proposals with: ```shell -anoma client query-proposal +namada client query-proposal ``` or a single proposal with ```shell -anoma client query-proposal --proposal-id 0 +namada client query-proposal --proposal-id 0 ``` where `0` is the proposal id. @@ -73,7 +73,7 @@ where `0` is the proposal id. Only validators and delegators can vote. Assuming you have a validator or a delegator account (in this example we are going to use `validator`), you can send a vote with the following command: ```shell -anoma client vote-proposal \ +namada client vote-proposal \ --proposal-id 0 \ --vote yay \ --signer validator @@ -86,25 +86,25 @@ where `--vote` can be either `yay` or `nay`. As soon as the ledger reaches epoch definied in the json as `voting_end_epoch`, you can no longer vote. The code definied in `proposal_code` json field will be executed at the beginning of `grace_epoch` epoch. You can use the following commands to check the status of a proposal: ```shell -anoma client query-proposal --proposal-id 0 +namada client query-proposal --proposal-id 0 ``` or to just check the result: ```shell -anoma client query-proposal-result --proposal-id 0 +namada client query-proposal-result --proposal-id 0 ``` ## Off-chain proposals -If for any reason issuing an on-chain proposal is not adequate to your needs, you still have the option to create an off-chain proposal. +If for any reason issuing an on-chain proposal is not adequate to your needs, you still have the option to create an off-chain proposal. ### Create proposal Create the same json file as in the on-chain proposal and use the following command: ```shell -anoma client init-proposal \ +namada client init-proposal \ --data-path proposal.json \ --offline ``` @@ -116,7 +116,7 @@ This command will create a `proposal` file same directory where the command was To vote an offline proposal use the following command: ```shell -anoma client vote-proposal --data-path proposal \ +namada client vote-proposal --data-path proposal \ --vote yay \ --signer validator \ --offline @@ -136,7 +136,7 @@ All those files will have to be in a folder (lets call it `offline-proposal`). Now you can use the following command: ```shell -anoma client query-proposal-result \ +namada client query-proposal-result \ --offline \ --data-path `offline-proposal` ``` diff --git a/documentation/docs/src/user-guide/ledger/masp.md b/documentation/docs/src/user-guide/ledger/masp.md index fb866dcf49..0c50995e81 100644 --- a/documentation/docs/src/user-guide/ledger/masp.md +++ b/documentation/docs/src/user-guide/ledger/masp.md @@ -1,9 +1,11 @@ # Private transfers + In Namada, private transfers are enabled by the Multi-Asset Shielded Pool (MASP). The MASP is a zero-knowledge circuit (zk-SNARK) that extends the Zcash Sapling circuit to add support for sending arbitrary assets. All assets in the pool share the same anonymity set, this means that the more transactions are issued to MASP, the stronger are the privacity guarantees. ## Using MASP If you are familiar to Zcash, the set of interactions you can execute with the MASP are similar: + - [**Shielding transfers:** transparent to shielded addresses](#shielding-transfers) - [**Shielded transfers:** shielded to shielded addresses](#shielded-transfers) - [**Deshielding transfers:** shielded to transparent addresses](#deshielding-tranfers) @@ -21,16 +23,20 @@ transparent account with some token balance. #### Create your transparent account Generate an implicit account: + ```shell namadaw address gen --alias [your-implicit-account-alias] ``` + Then, create an established account on chain using the implicit account you've just generated: + ```shell namadac init-account \ --source [your-implicit-account-alias] \ --public-key [your-implicit-account-alias] \ --alias [your-established-account-alias] ``` + #### Get tokens from the Testnet Faucet ```admonish info "Testnet Faucet Tokens" @@ -53,7 +59,8 @@ Now that you have a transparent account with some tokens, you can generate a Spe #### Generate your Spending Key You can randomly generate a new Spending Key with: -```shell + +```shell namadaw masp gen-key --alias [your-spending-key-alias] ``` @@ -128,7 +135,9 @@ namadac transfer \ ``` ### Shielded Address/Key Generation + #### Spending Key Generation + The client should be able to generate a spending key and automatically derive a viewing key for it. The spending key should be usable as the source of a transfer. The viewing key should be usable to determine the @@ -136,31 +145,41 @@ total unspent notes that the spending key is authorized to spend. It should not be possible to directly or indirectly use the viewing key to spend funds. Below is an example of how spending keys should be generated: + ``` namadaw --masp gen-key --alias my-sk ``` + #### Payment Address Generation + The client should be able to generate a payment address from a spending key or viewing key. This payment address should be usable to send notes to the originating spending key. It should not be directly or indirectly usable to either spend notes or view shielded balances. Below are examples of how payment addresses should be generated: + ``` namadaw masp gen-addr --alias my-pa1 --key my-sk namadaw masp gen-addr --alias my-pa2 --key my-vk ``` + #### Manual Key/Address Addition + The client should be able to directly add raw spending keys, viewing keys, and payment addresses. Below are examples of how these objects should be added: + ``` namadaw masp add --alias my-sk --value xsktest1qqqqqqqqqqqqqq9v0sls5r5de7njx8ehu49pqgmqr9ygelg87l5x8y4s9r0pjlvu69au6gn3su5ewneas486hdccyayx32hxvt64p3d0hfuprpgcgv2q9gdx3jvxrn02f0nnp3jtdd6f5vwscfuyum083cvfv4jun75ak5sdgrm2pthzj3sflxc0jx0edrakx3vdcngrfjmru8ywkguru8mxss2uuqxdlglaz6undx5h8w7g70t2es850g48xzdkqay5qs0yw06rtxcvedhsv namadaw masp add --alias my-vk --value xfvktest1qqqqqqqqqqqqqqpagte43rsza46v55dlz8cffahv0fnr6eqacvnrkyuf9lmndgal7erg38awgq60r259csg3lxeeyy5355f5nj3ywpeqgd2guqd73uxz46645d0ayt9em88wflka0vsrq29u47x55psw93ly80lvftzdr5ccrzuuedtf6fala4r4nnazm9y9hq5yu6pq24arjskmpv4mdgfn3spffxxv8ugvym36kmnj45jcvvmm227vqjm5fq8882yhjsq97p7xrwqt7n63v namadaw masp add --alias my-pa --value patest10qy6fuwef9leccl6dfm7wwlyd336x4y32hz62cnrvlrl6r5yk0jnw80kus33x34a5peg2xc4csn ``` + ### Making Shielded Transactions + #### Shielding Transactions + The client should be able to make shielding transactions by providing a transparent source address and a shielded payment address. The main transparent effect of such a transaction should be a deduction of @@ -170,10 +189,13 @@ gas fee is charged to the source address. Once the transaction is completed, the spending key that was used to generate the payment address will have the authority to spend the amount that was send. Below is an example of how a shielding transacion should be made: + ``` namadac transfer --source Bertha --amount 50 --token BTC --target my-pa ``` + #### Unshielding Transactions + The client should be able to make unshielding transactions by providing a shielded spending key and a transparent target address. The main transparent effect of such a transaction should be a deduction of the @@ -183,10 +205,13 @@ is charged to the signer's address (which should default to the target address). Once the transaction is complete, the spending key will no longer be able to spend the transferred amount. Below is an example of how an unshielding transaction should be made: + ``` namadac transfer --target Bertha --amount 45 --token BTC --source my-sk ``` + #### Shielded Transactions + The client should be able to make shielded transactions by providing a shielded spending key and a shielded payment address. There should be no change in the transparent balance of the MASP validity predicate's @@ -195,10 +220,13 @@ transaction is complete, the spending key will no longer be able to spend the transferred amount, but the spending key that was used to (directly or indirectly) generate the payment address will. Below is an example of how a shielded transaction should be made: + ``` namadac transfer --source my-sk --amount 5 --token BTC --target your-pa ``` + ### Viewing Shielded Balances + The client should be able to view shielded balances. The most general output should be a list of pairs, each denoting a token type and the unspent amount of that token present at each shielded @@ -206,26 +234,33 @@ address whose viewing key is represented in the wallet. Note that it should be possible to restrict the balance query to check only a specific viewing key or for a specific token type. Below are examples of how balance queries should be made: + ``` namadac balance namadac balance --owner my-key namadac balance --owner my-key --token BTC namadac balance --token BTC ``` + ### Listing Shielded Keys/Addresses + The wallet should be able to list all the spending keys, viewing keys, and payment addresses that it stores. Below are examples of how the wallet's storage should be queried: + ``` namadaw masp list-keys namadaw masp list-keys --unsafe-show-secret namadaw masp list-keys --unsafe-show-secret --decrypt namadaw masp list-addrs ``` + ### Finding Shielded Keys/Addresses + The wallet should be able to find any spending key, viewing key or payment address when given its alias. Below are examples of how the wallet's storage should be queried: + ``` namadaw masp find --alias my-alias namadaw masp find --alias my-alias --unsafe-show-secret diff --git a/documentation/docs/src/user-guide/ledger/pos.md b/documentation/docs/src/user-guide/ledger/pos.md index f0ffff9f05..2407fee0d2 100644 --- a/documentation/docs/src/user-guide/ledger/pos.md +++ b/documentation/docs/src/user-guide/ledger/pos.md @@ -2,12 +2,12 @@ The Namada Proof of Stake system uses the NAM token as the staking token. It features delegation to any number of validators and customizable validator validity predicates. -## PoS Validity Predicate +## PoS Validity Predicate The PoS system is implemented as an account with the [PoS Validity Predicate](https://github.com/anoma/namada/blob/namada/shared/src/ledger/pos/vp.rs) that governs the rules of the system. You can find its address in your wallet: ```shell -anoma wallet address find --alias PoS +namada wallet address find --alias PoS ``` ## Epochs @@ -17,7 +17,7 @@ The system relies on the concept of epochs. An epoch is a range of consecutive b To query the current epoch: ```shell -anoma client epoch +namada client epoch ``` ## Delegating @@ -27,7 +27,7 @@ You can delegate to any number of validators at any time. When you delegate toke To submit a delegation that bonds tokens from the source address to a validator with alias `validator-1`: ```shell -anoma client bond \ +namada client bond \ --source my-new-acc \ --validator validator-1 \ --amount 12.34 @@ -36,7 +36,7 @@ anoma client bond \ You can query your delegations: ```shell -anoma client bonds --owner my-new-acc +namada client bonds --owner my-new-acc ``` The result of this query will inform the epoch from which your delegations will be active. @@ -44,7 +44,7 @@ The result of this query will inform the epoch from which your delegations will Because the PoS system is just an account, you can query its balance, which is the sum of all staked tokens: ```shell -anoma client balance --owner PoS +namada client balance --owner PoS ``` ### Slashes @@ -52,7 +52,7 @@ anoma client balance --owner PoS Should a validator exhibit punishable behavior, the delegations towards this validator are also liable for slashing. Only the delegations that were active in the epoch in which the fault occurred will be slashed by the slash rate of the fault type. If any of your delegations have been slashed, this will be displayed in the `bonds` query. You can also find all the slashes applied with: ```shell -anoma client slashes +namada client slashes ``` ### Unbounding @@ -62,7 +62,7 @@ While your tokens are being delegated, they are locked-in the PoS system and hen To submit an unbonding of a delegation of tokens from a source address to the validator: ```shell -anoma client unbond \ +namada client unbond \ --source my-new-acc \ --validator validator-1 \ --amount 1.2 @@ -71,13 +71,13 @@ anoma client unbond \ When you unbond tokens, you won't be able to withdraw them immediately. Instead, tokens unbonded in the epoch `n` will be withdrawable starting from the epoch `n + 6` (the literal `6` is set by PoS parameter `unbonding_len`). After you unbond some tokens, you will be able to see when you can withdraw them via `bonds` query: ```shell -anoma client bonds --owner my-new-acc +namada client bonds --owner my-new-acc ``` When the chain reaches the epoch in which you can withdraw the tokens (or anytime after), you can submit a withdrawal of unbonded delegation of tokens back to your account: ```shell -anoma client withdraw \ +namada client withdraw \ --source my-new-acc \ --validator validator-1 ``` @@ -89,7 +89,7 @@ Upon success, the withdrawn tokens will be credited back your account and debite To see all validators and their voting power, you can query: ```shell -anoma client voting-power +namada client voting-power ``` With this command, you can specify `--epoch` to find the voting powers at some future epoch. Note that only the voting powers for the current and the next epoch are final. @@ -101,7 +101,7 @@ With this command, you can specify `--epoch` to find the voting powers at some f To register a new validator account, run: ```shell -anoma client init-validator \ +namada client init-validator \ --alias my-validator \ --source my-new-acc ``` @@ -120,7 +120,7 @@ Then, it submits a transaction to the ledger that generates two new accounts wit These keys and aliases of the addresses will be saved in your wallet. Your local ledger node will also be setup to run this validator, you just have to shut it down with e.g. `Ctrl + C`, then start it again with the same command: ```shell -anoma ledger +namada ledger ``` The ledger will then use the validator consensus key to sign blocks, should your validator account acquire enough voting power to be included in the active validator set. The size of the active validator set is limited to `128` (the limit is set by the PoS `max_validator_slots` parameter). @@ -128,22 +128,22 @@ The ledger will then use the validator consensus key to sign blocks, should your Note that the balance of NAM tokens that is in your validator account does not count towards your validator's stake and voting power: ```shell -anoma client balance --owner my-validator --token NAM +namada client balance --owner my-validator --token NAM ``` That is, the balance of your account's address is a regular liquid balance that you can transfer using your validator account key, depending on the rules of the validator account's validity predicate. The default validity predicate allows you to transfer it with a signed transaction and/or stake it in the PoS system. -### Self-bonding +### Self-bonding You can submit a self-bonding transaction of tokens from a validator account to the PoS system with: ```shell -anoma client bond \ +namada client bond \ --validator my-validator \ --amount 3.3 ``` -### Determine your voting power +### Determine your voting power A validator's voting power is determined by the sum of all their active self-bonds and delegations of tokens, with slashes applied, if any, divided by `1000` (PoS `votes_per_token` parameter, with the current value set to `10‱` in parts per ten thousand). @@ -151,12 +151,12 @@ The same rules apply to delegations. When you self-bond tokens, the bonded amoun While your tokens are being self-bonded, they are locked-in the PoS system and hence are not liquid until you withdraw them. To do that, you first need to send a transaction to “unbond” your tokens. You can unbond any amount, up to the sum of all your self-bonds, even before they become active. -### Self-unbounding +### Self-unbounding To submit an unbonding of self-bonded tokens from your validator: ```shell -anoma client unbond \ +namada client unbond \ --validator my-validator \ --amount 0.3 ``` @@ -164,11 +164,11 @@ anoma client unbond \ Again, when you unbond tokens, you won't be able to withdraw them immediately. Instead, tokens unbonded in the epoch `n` will be withdrawable starting from the epoch `n + 6`. After you unbond some tokens, you will be able to see when you can withdraw them via `bonds` query: ```shell -anoma client bonds --validator my-validator +namada client bonds --validator my-validator ``` When the chain reaches the epoch in which you can withdraw the tokens (or anytime after), you can submit a withdrawal of unbonded tokens back to your validator account: ```shell -anoma client withdraw --validator my-validator +namada client withdraw --validator my-validator ``` diff --git a/documentation/docs/src/user-guide/wallet.md b/documentation/docs/src/user-guide/wallet.md index 23421a3044..6f0366784e 100644 --- a/documentation/docs/src/user-guide/wallet.md +++ b/documentation/docs/src/user-guide/wallet.md @@ -3,6 +3,7 @@ This document describes the different wallet concepts and options that are available to users of Namada who want to be able to [send, receive and interact](#send-and-receive-nam-tokens) with NAM tokens on the Namada blockchain. Check out the different options to generate a wallet: + - File System Wallet - Web Wallet - Paper Wallet @@ -15,7 +16,7 @@ Namada uses ed25519 keypairs for signing cryptographic operations on the blockch To manage your keys, various sub-commands are available under: ```shell -anoma wallet key +namada wallet key ``` ### Generate a keypair @@ -23,17 +24,17 @@ anoma wallet key Generate a keypair with a given alias and derive the implicit address from its public key: ```shell -anoma wallet key gen --alias my-key +namada wallet key gen --alias my-key ``` ```admonish note -The derived implicit address shares the same `my-key` alias. The previous command has the same effect as `anoma wallet address gen --alias my-key`. +The derived implicit address shares the same `my-key` alias. The previous command has the same effect as `namada wallet address gen --alias my-key`. ``` ### List all known keys ```shell -anoma wallet key list +namada wallet key list ``` ## Manage addresses @@ -49,31 +50,31 @@ There are currently 3 types of account addresses: To manage addresses, similar to keys, various sub-commands are available: ```shell -anoma wallet address +namada wallet address ``` ### Generate an implicit address ```shell -anoma wallet address gen --alias my-account +namada wallet address gen --alias my-account ``` ```admonish note -Note that this will also generate and save a key from which the address was derived and save it under the same `my-account` alias. Thus, this command has the same effect as `anoma wallet key gen --alias my-account`. +Note that this will also generate and save a key from which the address was derived and save it under the same `my-account` alias. Thus, this command has the same effect as `namada wallet key gen --alias my-account`. ``` ### List all known addresses ```shell -anoma wallet address list +namada wallet address list ``` ## File System Wallet -By default, the Namada Wallet is stored under `.anoma/{chain_id}/wallet.toml` where keys are stored encrypted. You can change the default base directory path with `--base-dir` and you can allow the storage of unencrypted keypairs with the flag `--unsafe-dont-encrypt`. +By default, the Namada Wallet is stored under `.anoma/{chain_id}/wallet.toml` where keys are stored encrypted. You can change the default base directory path with `--base-dir` and you can allow the storage of unencrypted keypairs with the flag `--unsafe-dont-encrypt`. -If the wallet doesn't already exist, it will be created for you as soon as you run a command that tries to access the wallet. A newly created wallet will be pre-loaded with some internal addresses like `pos`, `pos_slash_pool`, `masp` and more. +If the wallet doesn't already exist, it will be created for you as soon as you run a command that tries to access the wallet. A newly created wallet will be pre-loaded with some internal addresses like `pos`, `pos_slash_pool`, `masp` and more. Currently, the Namada client can load the password via: @@ -83,7 +84,7 @@ Currently, the Namada client can load the password via: ## Web Wallet -The Web Wallet for Namada is currently in closed beta. +The Web Wallet for Namada is currently in closed beta. ## Paper Wallet @@ -104,7 +105,7 @@ If you already have a key in your wallet, you can skip this step. Otherwise, [ge Then, send a transaction to initialize your new established account and save its address with the alias `my-new-acc`. The `my-key` public key will be written into the account's storage for authorizing future transactions. We also sign this transaction with `my-key`. ```shell -anoma client init-account \ +namada client init-account \ --alias my-new-acc \ --public-key my-key \ --source my-key @@ -116,11 +117,10 @@ This command uses the prebuilt [User Validity Predicate](https://github.com/anom ### Send a Payment - To submit a regular token transfer from your account to the `validator-1` address: ```shell -anoma client transfer \ +namada client transfer \ --source my-new-acc \ --target validator-1 \ --token NAM \ @@ -134,7 +134,7 @@ This command will attempt to find and use the key of the source address to sign To query token balances for a specific token and/or owner: ```shell -anoma client balance --token NAM --owner my-new-acc +namada client balance --token NAM --owner my-new-acc ``` ```admonish note @@ -143,9 +143,9 @@ For any client command that submits a transaction (`init-account`, `transfer`, ` ``` ### See every known addresses' balance + You can see the token's addresses known by the client when you query all tokens balances: ```shell -anoma client balance +namada client balance ``` - From 717a71a8cee9b6dd407f949ea7832a405c673f23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zemanovi=C4=8D?= Date: Wed, 17 Aug 2022 13:26:26 +0200 Subject: [PATCH 046/118] docs: add notes about the books --- documentation/docs/src/README.md | 4 ++++ documentation/specs/src/index.md | 7 ++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/documentation/docs/src/README.md b/documentation/docs/src/README.md index 3e1330b24c..29f18f2b50 100644 --- a/documentation/docs/src/README.md +++ b/documentation/docs/src/README.md @@ -10,3 +10,7 @@ To learn more about the protocol, we recommend the following resources: - [Introducing Namada: Shielded Transfers with Any Assets](https://medium.com/anomanetwork/introducing-namada-shielded-transfers-with-any-assets-dce2e579384c) - [Namada's specifications](https://specs.namada.net) + +This book is written using [mdBook](https://rust-lang.github.io/mdBook/), the source can be found in the [Namada repository](https://github.com/anoma/namada/tree/main/documentation/docs). + +[Contributions](https://github.com/anoma/namada/blob/main/CONTRIBUTING.md) to the contents and the structure of this book should be made via pull requests. diff --git a/documentation/specs/src/index.md b/documentation/specs/src/index.md index df8cd94182..e33811757b 100644 --- a/documentation/specs/src/index.md +++ b/documentation/specs/src/index.md @@ -15,6 +15,7 @@ is provided in order to facilitate safe and private user interaction with the pr ### How does Namada relate to Anoma? Namada is _two things_: + - The first major release _version_ of the Anoma protocol. - The first _fractal instance_ launched as part of the Anoma network. @@ -56,4 +57,8 @@ The Namada specification documents are organised into five sub-sections: - [Multi-asset shielded pool](./masp.md) - [Interoperability](./interoperability.md) - [Economics](./economics.md) -- [User interfaces](./user-interfaces.md) \ No newline at end of file +- [User interfaces](./user-interfaces.md) + +This book is written using [mdBook](https://rust-lang.github.io/mdBook/), the source can be found in the [Namada repository](https://github.com/anoma/namada/tree/main/documentation/specs). + +[Contributions](https://github.com/anoma/namada/blob/main/CONTRIBUTING.md) to the contents and the structure of this book should be made via pull requests. From a5deec83fd85ed44f690959cadc3a73919f06fc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zemanovi=C4=8D?= Date: Wed, 17 Aug 2022 13:31:40 +0200 Subject: [PATCH 047/118] docs: update book's config branch, edit-url and repo links --- documentation/dev/book.toml | 4 ++-- documentation/docs/book.toml | 4 ++-- documentation/specs/book.toml | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/documentation/dev/book.toml b/documentation/dev/book.toml index f1b171cd24..f9ac4cebb2 100644 --- a/documentation/dev/book.toml +++ b/documentation/dev/book.toml @@ -8,12 +8,12 @@ src = "src" title = "Anoma - DOCS" [output.html] -edit-url-template = "https://github.com/anoma/namada/edit/master/documentation/dev/{path}" +edit-url-template = "https://github.com/anoma/namada/edit/main/documentation/dev/{path}" git-repository-url = "https://github.com/anoma/namada" additional-css = ["assets/custom.css", "assets/mdbook-admonish.css"] additional-js = ["assets/mermaid.min.js", "assets/mermaid-init.js"] mathjax-support = true -git-branch = "master" +git-branch = "main" [output.html.search] expand = true diff --git a/documentation/docs/book.toml b/documentation/docs/book.toml index cef6122f68..11d7630a7b 100644 --- a/documentation/docs/book.toml +++ b/documentation/docs/book.toml @@ -7,8 +7,8 @@ src = "src" title = "Namada Documentation" [output.html] -edit-url-template = "https://github.com/anoma/namada/documentation/docs/edit/main/{path}" -git-repository-url = "https://github.com/anoma/namada/documentation/docs" +edit-url-template = "https://github.com/anoma/namada/edit/main/documentation/docs/{path}" +git-repository-url = "https://github.com/anoma/namada" additional-css = ["assets/custom.css", "assets/mdbook-admonish.css"] git-branch = "main" diff --git a/documentation/specs/book.toml b/documentation/specs/book.toml index 9e2663d5d3..7848d519db 100644 --- a/documentation/specs/book.toml +++ b/documentation/specs/book.toml @@ -7,8 +7,9 @@ src = "src" title = "Namada Specifications" [output.html] -edit-url-template = "https://github.com/anoma/namada/edit/master/documentation/spec/{path}" +edit-url-template = "https://github.com/anoma/namada/edit/main/documentation/specs/{path}" git-repository-url = "https://github.com/anoma/namada" +git-branch = "main" [output.html.search] expand = true From 2f1343cc65a3c2ff70ef091fcc56c0e32f1a26e9 Mon Sep 17 00:00:00 2001 From: brentstone Date: Thu, 23 Jun 2022 12:33:26 +0200 Subject: [PATCH 048/118] changes to Cargo.toml and Cargo.lock from adding latest version of zeroize crate --- Cargo.lock | 50 ++++++++++++++++----------- shared/Cargo.toml | 1 + wasm/checksums.json | 34 +++++++++--------- wasm/tx_template/Cargo.lock | 5 +-- wasm/vp_template/Cargo.lock | 5 +-- wasm/wasm_source/Cargo.lock | 5 +-- wasm_for_tests/wasm_source/Cargo.lock | 5 +-- 7 files changed, 60 insertions(+), 45 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 31d67389e0..b10595dcad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -34,7 +34,7 @@ checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" dependencies = [ "cfg-if 1.0.0", "cipher", - "cpufeatures", + "cpufeatures 0.2.2", "opaque-debug 0.3.0", ] @@ -910,13 +910,13 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chacha20" -version = "0.7.3" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f08493fa7707effc63254c66c6ea908675912493cd67952eda23c09fae2610b1" +checksum = "fee7ad89dc1128635074c268ee661f90c3f7e83d9fd12910608c36b47d6c3412" dependencies = [ "cfg-if 1.0.0", "cipher", - "cpufeatures", + "cpufeatures 0.1.5", "zeroize", ] @@ -928,17 +928,17 @@ checksum = "01b72a433d0cf2aef113ba70f62634c56fddb0f244e6377185c56a7cadbd8f91" dependencies = [ "cfg-if 1.0.0", "cipher", - "cpufeatures", + "cpufeatures 0.2.2", ] [[package]] name = "chacha20poly1305" -version = "0.8.2" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6547abe025f4027edacd9edaa357aded014eecec42a5070d9b885c3c334aba2" +checksum = "1580317203210c517b6d44794abfbe600698276db18127e37ad3e69bf5e848e5" dependencies = [ "aead", - "chacha20 0.7.3", + "chacha20 0.7.1", "cipher", "poly1305", "zeroize", @@ -1123,6 +1123,15 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" +[[package]] +name = "cpufeatures" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66c99696f6c9dd7f35d486b9d04d7e6e202aa3e8c40d553f2fdf5e7e0c6a71ef" +dependencies = [ + "libc", +] + [[package]] name = "cpufeatures" version = "0.2.2" @@ -1376,9 +1385,9 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "3.2.1" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f9d052967f590a76e62eb387bd0bbb1b000182c3cefe5364db6b7211651bc0" +checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" dependencies = [ "byteorder", "digest 0.9.0", @@ -3928,6 +3937,7 @@ dependencies = [ "wasmer-engine-universal", "wasmer-vm", "wasmparser 0.83.0", + "zeroize", ] [[package]] @@ -4752,7 +4762,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "048aeb476be11a4b6ca432ca569e375810de9294ae78f4774e78ea98a9246ede" dependencies = [ - "cpufeatures", + "cpufeatures 0.2.2", "opaque-debug 0.3.0", "universal-hash", ] @@ -4764,7 +4774,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1" dependencies = [ "cfg-if 1.0.0", - "cpufeatures", + "cpufeatures 0.2.2", "opaque-debug 0.3.0", "universal-hash", ] @@ -5922,7 +5932,7 @@ checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" dependencies = [ "block-buffer 0.9.0", "cfg-if 1.0.0", - "cpufeatures", + "cpufeatures 0.2.2", "digest 0.9.0", "opaque-debug 0.3.0", ] @@ -5934,7 +5944,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" dependencies = [ "cfg-if 1.0.0", - "cpufeatures", + "cpufeatures 0.2.2", "digest 0.10.3", ] @@ -5958,7 +5968,7 @@ checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" dependencies = [ "block-buffer 0.9.0", "cfg-if 1.0.0", - "cpufeatures", + "cpufeatures 0.2.2", "digest 0.9.0", "opaque-debug 0.3.0", ] @@ -5970,7 +5980,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" dependencies = [ "cfg-if 1.0.0", - "cpufeatures", + "cpufeatures 0.2.2", "digest 0.10.3", ] @@ -8236,9 +8246,9 @@ dependencies = [ [[package]] name = "x25519-dalek" -version = "1.2.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2392b6b94a576b4e2bf3c5b2757d63f10ada8020a2e4d08ac849ebcf6ea8e077" +checksum = "5a0c105152107e3b96f6a00a65e86ce82d9b125230e1c4302940eca58ff71f4f" dependencies = [ "curve25519-dalek", "rand_core 0.5.1", @@ -8279,9 +8289,9 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.3.0" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd" +checksum = "94693807d016b2f2d2e14420eb3bfcca689311ff775dcf113d74ea624b7cdf07" dependencies = [ "zeroize_derive", ] diff --git a/shared/Cargo.toml b/shared/Cargo.toml index d63acc035f..570bb4a8e3 100644 --- a/shared/Cargo.toml +++ b/shared/Cargo.toml @@ -116,6 +116,7 @@ wasmer-engine-dylib = {version = "=2.2.0", optional = true} wasmer-engine-universal = {version = "=2.2.0", optional = true} wasmer-vm = {version = "2.2.0", optional = true} wasmparser = "0.83.0" +zeroize = "1.5.5" [dev-dependencies] assert_matches = "1.5.0" diff --git a/wasm/checksums.json b/wasm/checksums.json index 1495d6f6f5..be2bac12bf 100644 --- a/wasm/checksums.json +++ b/wasm/checksums.json @@ -1,19 +1,19 @@ { - "tx_bond.wasm": "tx_bond.302172cc7d0a7e2278ce58299809875f354925364b25c9b64e92461995c51950.wasm", - "tx_from_intent.wasm": "tx_from_intent.19099ad11a5f59272bd5dbd8b7bc7093ae66ae7a2b25034300f1b34d3e37ffd1.wasm", - "tx_ibc.wasm": "tx_ibc.9aec1969a37705f9ae5d6e95d13126e0f37e78171ef37c2f0fdd0eb16ac49270.wasm", - "tx_init_account.wasm": "tx_init_account.7a45233a98978c67ff005bf8a1fb8f3f7689a75f98684c1735617776f98fabad.wasm", - "tx_init_nft.wasm": "tx_init_nft.b0dd29e0e982c3bd04c7a8c4dcd0184d9d827df6a4211794dd74fbdced1e7430.wasm", - "tx_init_proposal.wasm": "tx_init_proposal.45be75dc2c22048dce23ae346c895b2be19737a39844416436aac62914847388.wasm", - "tx_init_validator.wasm": "tx_init_validator.5a7c9a3a115883359246a4145af11f748ded043b5b36d1cb71e54fb3ef169183.wasm", - "tx_mint_nft.wasm": "tx_mint_nft.fd8932515db71638263193930f60c14cec54c11e72e6ab40d8201d0247db0c1a.wasm", - "tx_transfer.wasm": "tx_transfer.9e51e5b48ba3ddee699fed334e14fe9a81b7e299b0cfcbf10482b9f784c092c2.wasm", - "tx_unbond.wasm": "tx_unbond.020d22fa306850b0a4aade96f711087d03568ed45276fff60226a80de47cc455.wasm", - "tx_update_vp.wasm": "tx_update_vp.00d828bdf510d92d971ca59015945c8c00f285a802a655451cc5ee87c5ee99bc.wasm", - "tx_vote_proposal.wasm": "tx_vote_proposal.b8aa22d6d22c31fa6c1f4619a81eaa43aa40c8865b91f71449a5f3c65b84eacf.wasm", - "tx_withdraw.wasm": "tx_withdraw.b8538e5acfc2945e98b76cc17eb11a03c545021e8f70cf6e5b436219e749b559.wasm", - "vp_nft.wasm": "vp_nft.d272e0c50f17c020fe806e03278e83377ec45b81e88432316ce836ee24605f6e.wasm", - "vp_testnet_faucet.wasm": "vp_testnet_faucet.79c1da702d67f464453af0b145872bba28913b029508f1257b4a22f69123ec1e.wasm", - "vp_token.wasm": "vp_token.04482a8132e91ab726b4a9027f44a84c885c36e3d608e9c4e153d0cfe4f88449.wasm", - "vp_user.wasm": "vp_user.e390d55fc2e797fcc4c43bd40b93ea1c3d58544d5f086301a0dbc38bd93388ba.wasm" + "tx_bond.wasm": "tx_bond.4cf89dcee2f8bdbcd32dbaa775cfc3a555625ded42abc2e14f3ed74f588e48fc.wasm", + "tx_from_intent.wasm": "tx_from_intent.4686836f77003d358d503dc87d887eb8fc05d204803c7429a7c8797f1e8a980d.wasm", + "tx_ibc.wasm": "tx_ibc.f9a9eea5f43152e4681c253f051cc4f410e52e7a081af226c87e89940c474941.wasm", + "tx_init_account.wasm": "tx_init_account.401ea88ac321c52f1f4c5ae18c365dbc2c72bf0ae5cc4ca3c4dc0bcf493a39b8.wasm", + "tx_init_nft.wasm": "tx_init_nft.4c632cbea80c534e8da7785d61bd75c1866bbbb34813585789b01343036f6b2d.wasm", + "tx_init_proposal.wasm": "tx_init_proposal.1895eddc512ae33a3151bb4c9221dcbbaa28cade5877550e76f8a2a1b85eed71.wasm", + "tx_init_validator.wasm": "tx_init_validator.ffac85a6e5912e71e40dafdca2f86fdd0c0fb10b7c0269ef2730da4808b0f113.wasm", + "tx_mint_nft.wasm": "tx_mint_nft.4bedacdc1b6c3af4c3c28be51c6bd770abeeb3b5281b9dc85bc49242da119f45.wasm", + "tx_transfer.wasm": "tx_transfer.be41dd45e9e11189f9121a5ac82e3bd3b19e473d7ce7e3fda529fe12e073aa35.wasm", + "tx_unbond.wasm": "tx_unbond.1e2a5b321d52135b74189335e04f338c37189bcfc967032504860cae4e62762c.wasm", + "tx_update_vp.wasm": "tx_update_vp.d47bfe6ef55a86bce36093feeff74fe09ec7cffebf9696dd37658756a4eb793d.wasm", + "tx_vote_proposal.wasm": "tx_vote_proposal.05d61a0b198e2a1c02446e0764c8a1345d1471e20574a4a0b28062fd384e0011.wasm", + "tx_withdraw.wasm": "tx_withdraw.4af4f9a999b607f9941400af4e42c6988b1aef71c8f4764a4df2449551181b3d.wasm", + "vp_nft.wasm": "vp_nft.f6023b1d856727caafdffae5a75eeac46716ae4f75d653c7650226402e426957.wasm", + "vp_testnet_faucet.wasm": "vp_testnet_faucet.d7df80ef8bff74f6788163a2ad4cf36b556df6ef94d5fb18ccc5f8c608a13a48.wasm", + "vp_token.wasm": "vp_token.118aef31933858351cf77315069fc2f7c61e7db8891c7990e77f9ffd6ef90af0.wasm", + "vp_user.wasm": "vp_user.ecfadfe38747b67ae1fa2c590e634cca723a086d24e3dc46d7db66419441478a.wasm" } \ No newline at end of file diff --git a/wasm/tx_template/Cargo.lock b/wasm/tx_template/Cargo.lock index fcda82a6a5..063f40a223 100644 --- a/wasm/tx_template/Cargo.lock +++ b/wasm/tx_template/Cargo.lock @@ -1396,6 +1396,7 @@ dependencies = [ "wasmer-engine-universal", "wasmer-vm", "wasmparser 0.83.0", + "zeroize", ] [[package]] @@ -3274,9 +3275,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "zeroize" -version = "1.5.3" +version = "1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50344758e2f40e3a1fcfc8f6f91aa57b5f8ebd8d27919fe6451f15aaaf9ee608" +checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f" dependencies = [ "zeroize_derive", ] diff --git a/wasm/vp_template/Cargo.lock b/wasm/vp_template/Cargo.lock index 3c82e7293e..7dc2e8f86c 100644 --- a/wasm/vp_template/Cargo.lock +++ b/wasm/vp_template/Cargo.lock @@ -1396,6 +1396,7 @@ dependencies = [ "wasmer-engine-universal", "wasmer-vm", "wasmparser 0.83.0", + "zeroize", ] [[package]] @@ -3274,9 +3275,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "zeroize" -version = "1.5.3" +version = "1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50344758e2f40e3a1fcfc8f6f91aa57b5f8ebd8d27919fe6451f15aaaf9ee608" +checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f" dependencies = [ "zeroize_derive", ] diff --git a/wasm/wasm_source/Cargo.lock b/wasm/wasm_source/Cargo.lock index 6b59401588..5a10a7ae4d 100644 --- a/wasm/wasm_source/Cargo.lock +++ b/wasm/wasm_source/Cargo.lock @@ -1396,6 +1396,7 @@ dependencies = [ "wasmer-engine-universal", "wasmer-vm", "wasmparser 0.83.0", + "zeroize", ] [[package]] @@ -3289,9 +3290,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "zeroize" -version = "1.5.3" +version = "1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50344758e2f40e3a1fcfc8f6f91aa57b5f8ebd8d27919fe6451f15aaaf9ee608" +checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f" dependencies = [ "zeroize_derive", ] diff --git a/wasm_for_tests/wasm_source/Cargo.lock b/wasm_for_tests/wasm_source/Cargo.lock index 2507c11460..97af2f4415 100644 --- a/wasm_for_tests/wasm_source/Cargo.lock +++ b/wasm_for_tests/wasm_source/Cargo.lock @@ -1407,6 +1407,7 @@ dependencies = [ "wasmer-engine-universal", "wasmer-vm", "wasmparser 0.83.0", + "zeroize", ] [[package]] @@ -3301,9 +3302,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "zeroize" -version = "1.5.4" +version = "1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb5728b8afd3f280a869ce1d4c554ffaed35f45c231fc41bfbd0381bef50317" +checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f" dependencies = [ "zeroize_derive", ] From f9f067455e17f87f91bd0711f5b0fef74d14d3fe Mon Sep 17 00:00:00 2001 From: brentstone Date: Thu, 23 Jun 2022 12:38:14 +0200 Subject: [PATCH 049/118] wrap SigningKey in a Box pointer when placing into SecretKey struct, test that memory is actually zeroized after dropping SecretKey --- shared/src/types/key/ed25519.rs | 21 +++++++++++++++------ shared/src/types/key/mod.rs | 17 +++++++++++++++++ wasm/checksums.json | 30 +++++++++++++++--------------- 3 files changed, 47 insertions(+), 21 deletions(-) diff --git a/shared/src/types/key/ed25519.rs b/shared/src/types/key/ed25519.rs index 12e5093bd2..48db89005a 100644 --- a/shared/src/types/key/ed25519.rs +++ b/shared/src/types/key/ed25519.rs @@ -9,6 +9,7 @@ use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; #[cfg(feature = "rand")] use rand::{CryptoRng, RngCore}; use serde::{Deserialize, Serialize}; +use zeroize::Zeroize; use super::{ ParsePublicKeyError, ParseSecretKeyError, ParseSignatureError, RefTo, @@ -122,8 +123,8 @@ impl FromStr for PublicKey { } /// Ed25519 secret key -#[derive(Debug, Serialize, Deserialize)] -pub struct SecretKey(pub ed25519_consensus::SigningKey); +#[derive(Debug, Serialize, Deserialize, Zeroize)] +pub struct SecretKey(pub Box); impl super::SecretKey for SecretKey { type PublicKey = PublicKey; @@ -157,13 +158,15 @@ impl RefTo for SecretKey { impl Clone for SecretKey { fn clone(&self) -> SecretKey { - SecretKey(ed25519_consensus::SigningKey::from(self.0.to_bytes())) + SecretKey(Box::new(ed25519_consensus::SigningKey::from( + self.0.to_bytes(), + ))) } } impl BorshDeserialize for SecretKey { fn deserialize(buf: &mut &[u8]) -> std::io::Result { - Ok(SecretKey( + Ok(SecretKey(Box::new( ed25519_consensus::SigningKey::try_from( <[u8; SECRET_KEY_LENGTH] as BorshDeserialize>::deserialize( buf, @@ -173,7 +176,7 @@ impl BorshDeserialize for SecretKey { .map_err(|e| { std::io::Error::new(std::io::ErrorKind::InvalidInput, e) })?, - )) + ))) } } @@ -218,6 +221,12 @@ impl FromStr for SecretKey { } } +impl Drop for SecretKey { + fn drop(&mut self) { + self.0.zeroize(); + } +} + /// Ed25519 signature #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] pub struct Signature(pub ed25519_consensus::Signature); @@ -325,7 +334,7 @@ impl super::SigScheme for SigScheme { where R: CryptoRng + RngCore, { - SecretKey(ed25519_consensus::SigningKey::new(csprng)) + SecretKey(Box::new(ed25519_consensus::SigningKey::new(csprng))) } fn sign(keypair: &SecretKey, data: impl AsRef<[u8]>) -> Self::Signature { diff --git a/shared/src/types/key/mod.rs b/shared/src/types/key/mod.rs index a1343cd7e5..e7571bb050 100644 --- a/shared/src/types/key/mod.rs +++ b/shared/src/types/key/mod.rs @@ -415,6 +415,23 @@ macro_rules! sigscheme_test { println!("Public key: {}", public_key); println!("Secret key: {}", secret_key); } + + #[test] + fn zeroize_keypair() { + use rand::thread_rng; + + let sk = ed25519::SecretKey(Box::new( + ed25519_consensus::SigningKey::new(thread_rng()), + )); + let len = sk.0.as_bytes().len(); + let ptr = sk.0.as_bytes().as_ptr(); + + drop(sk); + + assert_eq!(&[0u8; 32], unsafe { + core::slice::from_raw_parts(ptr, len) + }); + } } }; } diff --git a/wasm/checksums.json b/wasm/checksums.json index be2bac12bf..2e55738ba5 100644 --- a/wasm/checksums.json +++ b/wasm/checksums.json @@ -1,19 +1,19 @@ { - "tx_bond.wasm": "tx_bond.4cf89dcee2f8bdbcd32dbaa775cfc3a555625ded42abc2e14f3ed74f588e48fc.wasm", - "tx_from_intent.wasm": "tx_from_intent.4686836f77003d358d503dc87d887eb8fc05d204803c7429a7c8797f1e8a980d.wasm", - "tx_ibc.wasm": "tx_ibc.f9a9eea5f43152e4681c253f051cc4f410e52e7a081af226c87e89940c474941.wasm", - "tx_init_account.wasm": "tx_init_account.401ea88ac321c52f1f4c5ae18c365dbc2c72bf0ae5cc4ca3c4dc0bcf493a39b8.wasm", - "tx_init_nft.wasm": "tx_init_nft.4c632cbea80c534e8da7785d61bd75c1866bbbb34813585789b01343036f6b2d.wasm", - "tx_init_proposal.wasm": "tx_init_proposal.1895eddc512ae33a3151bb4c9221dcbbaa28cade5877550e76f8a2a1b85eed71.wasm", - "tx_init_validator.wasm": "tx_init_validator.ffac85a6e5912e71e40dafdca2f86fdd0c0fb10b7c0269ef2730da4808b0f113.wasm", - "tx_mint_nft.wasm": "tx_mint_nft.4bedacdc1b6c3af4c3c28be51c6bd770abeeb3b5281b9dc85bc49242da119f45.wasm", - "tx_transfer.wasm": "tx_transfer.be41dd45e9e11189f9121a5ac82e3bd3b19e473d7ce7e3fda529fe12e073aa35.wasm", - "tx_unbond.wasm": "tx_unbond.1e2a5b321d52135b74189335e04f338c37189bcfc967032504860cae4e62762c.wasm", + "tx_bond.wasm": "tx_bond.e8fcf7413067810f82e1c0f54fdc9675a4c686b172db9c44c714310d3f19baf6.wasm", + "tx_from_intent.wasm": "tx_from_intent.cd5f7af4d3af9300df8dc16e891f39f85d6497a43a2cd74d30d1dc506649291e.wasm", + "tx_ibc.wasm": "tx_ibc.3805f69ceafd60b857a860d26e6fbe2973f309289147cf59c10e0bd65a30057e.wasm", + "tx_init_account.wasm": "tx_init_account.8abb68c5f40fa9ea39f03ddb9c387bc84a642bac4f40c7e9ceebb8418b3ccde7.wasm", + "tx_init_nft.wasm": "tx_init_nft.564390006d7b8f4f46d215704b05561a7279c92a6fe8f3ec61118a5486a3e092.wasm", + "tx_init_proposal.wasm": "tx_init_proposal.5fc912c847cb4d04743b4dea650418a4eae233f4abf91493791a92e3de5050aa.wasm", + "tx_init_validator.wasm": "tx_init_validator.92d11bc1cc27818864e13d122179a199043a274f7bba901b11c6474261eb97eb.wasm", + "tx_mint_nft.wasm": "tx_mint_nft.9f5b723dd4ed195b489b8456a6d83167829f0b2b8fb479be19b877a60b81c803.wasm", + "tx_transfer.wasm": "tx_transfer.032bfa997c8f2ee2cc5bf053f0128880a79a57ad3d8c3ecc6ff0c22e27f47ebd.wasm", + "tx_unbond.wasm": "tx_unbond.17444d665b8a7bebb624691eaab318c845c8ce18c557d0af440b7bfdb7efa806.wasm", "tx_update_vp.wasm": "tx_update_vp.d47bfe6ef55a86bce36093feeff74fe09ec7cffebf9696dd37658756a4eb793d.wasm", - "tx_vote_proposal.wasm": "tx_vote_proposal.05d61a0b198e2a1c02446e0764c8a1345d1471e20574a4a0b28062fd384e0011.wasm", - "tx_withdraw.wasm": "tx_withdraw.4af4f9a999b607f9941400af4e42c6988b1aef71c8f4764a4df2449551181b3d.wasm", - "vp_nft.wasm": "vp_nft.f6023b1d856727caafdffae5a75eeac46716ae4f75d653c7650226402e426957.wasm", - "vp_testnet_faucet.wasm": "vp_testnet_faucet.d7df80ef8bff74f6788163a2ad4cf36b556df6ef94d5fb18ccc5f8c608a13a48.wasm", + "tx_vote_proposal.wasm": "tx_vote_proposal.1bee09ffd3a1e577dc9b9d6d5f91c4a6f91a9b2ac9e3a3d8258c00cd12902304.wasm", + "tx_withdraw.wasm": "tx_withdraw.75dbdc78924d8072ffcefaed67715d9480dd9f702ac77cf18ee15d0e44a38ab0.wasm", + "vp_nft.wasm": "vp_nft.3711eac06bda0c39ab52618bc458df7e6b16ed096bb3930b93ade93c9b7cf23a.wasm", + "vp_testnet_faucet.wasm": "vp_testnet_faucet.400be39dcf0fedf099232bdecfa42c2dbe1f0aaede34fb99ec26da3b6623c09a.wasm", "vp_token.wasm": "vp_token.118aef31933858351cf77315069fc2f7c61e7db8891c7990e77f9ffd6ef90af0.wasm", - "vp_user.wasm": "vp_user.ecfadfe38747b67ae1fa2c590e634cca723a086d24e3dc46d7db66419441478a.wasm" + "vp_user.wasm": "vp_user.73136ffcd68e46e2f88d27ae9e48a0731b06d883dd3defcb41b604cc7968c638.wasm" } \ No newline at end of file From bc0e71ae9e3e0974cc199f964a9568a91ffa7a46 Mon Sep 17 00:00:00 2001 From: brentstone Date: Wed, 6 Jul 2022 00:41:27 +0200 Subject: [PATCH 050/118] move zeroize test out of macro (also in advance of incorporating secp256k1) --- shared/src/types/key/mod.rs | 39 +++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/shared/src/types/key/mod.rs b/shared/src/types/key/mod.rs index e7571bb050..9deccf75a9 100644 --- a/shared/src/types/key/mod.rs +++ b/shared/src/types/key/mod.rs @@ -415,26 +415,31 @@ macro_rules! sigscheme_test { println!("Public key: {}", public_key); println!("Secret key: {}", secret_key); } - - #[test] - fn zeroize_keypair() { - use rand::thread_rng; - - let sk = ed25519::SecretKey(Box::new( - ed25519_consensus::SigningKey::new(thread_rng()), - )); - let len = sk.0.as_bytes().len(); - let ptr = sk.0.as_bytes().as_ptr(); - - drop(sk); - - assert_eq!(&[0u8; 32], unsafe { - core::slice::from_raw_parts(ptr, len) - }); - } } }; } #[cfg(test)] sigscheme_test! {ed25519_test, ed25519::SigScheme} + +#[cfg(test)] +mod more_tests { + use super::*; + + #[test] + fn zeroize_keypair_ed25519() { + use rand::thread_rng; + + let sk = ed25519::SecretKey(Box::new( + ed25519_consensus::SigningKey::new(thread_rng()), + )); + let len = sk.0.as_bytes().len(); + let ptr = sk.0.as_bytes().as_ptr(); + + drop(sk); + + assert_eq!(&[0u8; 32], unsafe { + core::slice::from_raw_parts(ptr, len) + }); + } +} From 3948c98db41a5e3c38b7b25de870d06bfaab7cb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zemanovi=C4=8D?= Date: Fri, 5 Aug 2022 16:30:15 +0200 Subject: [PATCH 051/118] changelog: add #277 --- .changelog/unreleased/improvements/277-zeroize-secret-keys.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .changelog/unreleased/improvements/277-zeroize-secret-keys.md diff --git a/.changelog/unreleased/improvements/277-zeroize-secret-keys.md b/.changelog/unreleased/improvements/277-zeroize-secret-keys.md new file mode 100644 index 0000000000..27cb40bf55 --- /dev/null +++ b/.changelog/unreleased/improvements/277-zeroize-secret-keys.md @@ -0,0 +1,2 @@ +- Zeroize secret keys from memory + ([#277](https://github.com/anoma/namada/pull/277)) \ No newline at end of file From 69dae061cd416db7a84a5fd875721f3741789e89 Mon Sep 17 00:00:00 2001 From: brentstone Date: Wed, 15 Jun 2022 13:48:42 +0200 Subject: [PATCH 052/118] initial commit for supporting secp256k1 keys --- Cargo.lock | 77 +++- shared/Cargo.toml | 1 + shared/src/types/key/common.rs | 61 +++- shared/src/types/key/ed25519.rs | 6 +- shared/src/types/key/mod.rs | 39 +- shared/src/types/key/secp256k1.rs | 494 ++++++++++++++++++++++++++ wasm/checksums.json | 34 +- wasm/tx_template/Cargo.lock | 87 +++++ wasm/vp_template/Cargo.lock | 87 +++++ wasm/wasm_source/Cargo.lock | 87 +++++ wasm_for_tests/wasm_source/Cargo.lock | 87 +++++ 11 files changed, 1023 insertions(+), 37 deletions(-) create mode 100644 shared/src/types/key/secp256k1.rs diff --git a/Cargo.lock b/Cargo.lock index b10595dcad..3fd0bf98af 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2443,6 +2443,16 @@ dependencies = [ "digest 0.8.1", ] +[[package]] +name = "hmac" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" +dependencies = [ + "crypto-mac 0.8.0", + "digest 0.9.0", +] + [[package]] name = "hmac-drbg" version = "0.2.0" @@ -2451,7 +2461,18 @@ checksum = "c6e570451493f10f6581b48cdd530413b63ea9e780f544bfd3bdcaa0d89d1a7b" dependencies = [ "digest 0.8.1", "generic-array 0.12.4", - "hmac", + "hmac 0.7.1", +] + +[[package]] +name = "hmac-drbg" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" +dependencies = [ + "digest 0.9.0", + "generic-array 0.14.5", + "hmac 0.8.1", ] [[package]] @@ -3058,7 +3079,7 @@ dependencies = [ "futures 0.3.21", "futures-timer", "lazy_static 1.4.0", - "libsecp256k1", + "libsecp256k1 0.3.5", "log 0.4.17", "multihash", "multistream-select", @@ -3442,13 +3463,62 @@ dependencies = [ "arrayref", "crunchy", "digest 0.8.1", - "hmac-drbg", + "hmac-drbg 0.2.0", "rand 0.7.3", "sha2 0.8.2", "subtle 2.4.1", "typenum", ] +[[package]] +name = "libsecp256k1" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95b09eff1b35ed3b33b877ced3a691fc7a481919c7e29c53c906226fcf55e2a1" +dependencies = [ + "arrayref", + "base64 0.13.0", + "digest 0.9.0", + "hmac-drbg 0.3.0", + "lazy_static 1.4.0", + "libsecp256k1-core", + "libsecp256k1-gen-ecmult", + "libsecp256k1-gen-genmult", + "rand 0.8.5", + "serde 1.0.137", + "sha2 0.9.9", + "typenum", +] + +[[package]] +name = "libsecp256k1-core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451" +dependencies = [ + "crunchy", + "digest 0.9.0", + "subtle 2.4.1", +] + +[[package]] +name = "libsecp256k1-gen-ecmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3038c808c55c87e8a172643a7d87187fc6c4174468159cb3090659d55bcb4809" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "libsecp256k1-gen-genmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db8d6ba2cec9eacc40e6e8ccc98931840301f1006e95647ceb2dd5c3aa06f7c" +dependencies = [ + "libsecp256k1-core", +] + [[package]] name = "libssh2-sys" version = "0.2.23" @@ -3905,6 +3975,7 @@ dependencies = [ "ibc-proto 0.16.0 (git+https://github.com/heliaxdev/ibc-rs?rev=30b3495ac56c6c37c99bc69ef9f2e84c3309c6cc)", "ics23", "itertools 0.10.3", + "libsecp256k1 0.7.1", "loupe", "namada_proof_of_stake", "parity-wasm", diff --git a/shared/Cargo.toml b/shared/Cargo.toml index 570bb4a8e3..8110e1f89f 100644 --- a/shared/Cargo.toml +++ b/shared/Cargo.toml @@ -86,6 +86,7 @@ ibc-proto-abci = {package = "ibc-proto", git = "https://github.com/heliaxdev/ibc ics23 = "0.6.7" itertools = "0.10.0" loupe = {version = "0.1.3", optional = true} +libsecp256k1 = {version = "0.7.0", default-features = false, features = ["std", "hmac", "lazy-static-context"]} parity-wasm = {version = "0.42.2", optional = true} # A fork with state machine testing proptest = {git = "https://github.com/heliaxdev/proptest", branch = "tomas/sm", optional = true} diff --git a/shared/src/types/key/common.rs b/shared/src/types/key/common.rs index 27e7c29b89..1986799142 100644 --- a/shared/src/types/key/common.rs +++ b/shared/src/types/key/common.rs @@ -9,7 +9,7 @@ use rand::{CryptoRng, RngCore}; use serde::{Deserialize, Serialize}; use super::{ - ed25519, ParsePublicKeyError, ParseSecretKeyError, ParseSignatureError, + ed25519, secp256k1, ParsePublicKeyError, ParseSecretKeyError, ParseSignatureError, RefTo, SchemeType, SigScheme as SigSchemeTrait, VerifySigError, }; @@ -31,6 +31,8 @@ use super::{ pub enum PublicKey { /// Encapsulate Ed25519 public keys Ed25519(ed25519::PublicKey), + /// Encapsulate Secp256k1 public keys + Secp256k1(secp256k1::PublicKey), } impl super::PublicKey for PublicKey { @@ -49,6 +51,13 @@ impl super::PublicKey for PublicKey { ) .map_err(ParsePublicKeyError::InvalidEncoding)?, )) + } else if PK::TYPE == secp256k1::PublicKey::TYPE { + Ok(Self::Secp256k1( + secp256k1::PublicKey::try_from_slice( + pk.try_to_vec().unwrap().as_slice(), + ) + .map_err(ParsePublicKeyError::InvalidEncoding)?, + )) } else { Err(ParsePublicKeyError::MismatchedScheme) } @@ -77,6 +86,8 @@ impl FromStr for PublicKey { pub enum SecretKey { /// Encapsulate Ed25519 secret keys Ed25519(ed25519::SecretKey), + /// Encapsulate Secp256k1 secret keys + Secp256k1(secp256k1::SecretKey), } impl Serialize for SecretKey { @@ -88,13 +99,12 @@ impl Serialize for SecretKey { S: serde::Serializer, { // String encoded, because toml doesn't support enums - match self { - ed25519_sk @ SecretKey::Ed25519(_) => { - let keypair_string = - format!("{}{}", "ED25519_SK_PREFIX", ed25519_sk); - Serialize::serialize(&keypair_string, serializer) - } - } + let prefix = match self { + SecretKey::Ed25519(_) => "ED25519_SK_PREFIX", + SecretKey::Secp256k1(_) => "SECP256K1_SK_PREFIX", + }; + let keypair_string = format!("{}{}",prefix,self); + Serialize::serialize(&keypair_string,serializer) } } @@ -110,6 +120,8 @@ impl<'de> Deserialize<'de> for SecretKey { .map_err(D::Error::custom)?; if let Some(raw) = keypair_string.strip_prefix("ED25519_SK_PREFIX") { SecretKey::from_str(raw).map_err(D::Error::custom) + } else if let Some(raw) = keypair_string.strip_prefix("SECP256K1_SK_PREFIX") { + SecretKey::from_str(raw).map_err(D::Error::custom) } else { Err(D::Error::custom( "Could not deserialize SecretKey do to invalid prefix", @@ -136,7 +148,13 @@ impl super::SecretKey for SecretKey { ) .map_err(ParseSecretKeyError::InvalidEncoding)?, )) - } else { + } else if PK::TYPE == secp256k1::SecretKey::TYPE { + Ok(Self::Secp256k1( + secp256k1::SecretKey::try_from_slice( + pk.try_to_vec().unwrap().as_ref(), + ) + .map_err(ParseSecretKeyError::InvalidEncoding)?, + )) } else { Err(ParseSecretKeyError::MismatchedScheme) } } @@ -146,6 +164,7 @@ impl RefTo for SecretKey { fn ref_to(&self) -> PublicKey { match self { SecretKey::Ed25519(sk) => PublicKey::Ed25519(sk.ref_to()), + SecretKey::Secp256k1(sk) => PublicKey::Secp256k1(sk.ref_to()), } } } @@ -183,6 +202,8 @@ impl FromStr for SecretKey { pub enum Signature { /// Encapsulate Ed25519 signatures Ed25519(ed25519::Signature), + /// Encapsulate Secp256k1 signatures + Secp256k1(secp256k1::Signature), } impl super::Signature for Signature { @@ -201,6 +222,13 @@ impl super::Signature for Signature { ) .map_err(ParseSignatureError::InvalidEncoding)?, )) + } else if PK::TYPE == secp256k1::Signature::TYPE { + Ok(Self::Secp256k1( + secp256k1::Signature::try_from_slice( + pk.try_to_vec().unwrap().as_slice(), + ) + .map_err(ParseSignatureError::InvalidEncoding)?, + )) } else { Err(ParseSignatureError::MismatchedScheme) } @@ -248,6 +276,9 @@ impl super::SigScheme for SigScheme { SecretKey::Ed25519(kp) => { Signature::Ed25519(ed25519::SigScheme::sign(kp, data)) } + SecretKey::Secp256k1(kp) => { + Signature::Secp256k1(secp256k1::SigScheme::sign(kp, data)) + } } } @@ -259,7 +290,11 @@ impl super::SigScheme for SigScheme { match (pk, sig) { (PublicKey::Ed25519(pk), Signature::Ed25519(sig)) => { ed25519::SigScheme::verify_signature(pk, data, sig) - } // _ => Err(VerifySigError::MismatchedScheme), + } + (PublicKey::Secp256k1(pk), Signature::Secp256k1(sig)) => { + secp256k1::SigScheme::verify_signature(pk, data, sig) + } + _ => Err(VerifySigError::MismatchedScheme), } } @@ -271,7 +306,11 @@ impl super::SigScheme for SigScheme { match (pk, sig) { (PublicKey::Ed25519(pk), Signature::Ed25519(sig)) => { ed25519::SigScheme::verify_signature_raw(pk, data, sig) - } // _ => Err(VerifySigError::MismatchedScheme), + } + (PublicKey::Secp256k1(pk), Signature::Secp256k1(sig)) => { + secp256k1::SigScheme::verify_signature_raw(pk, data, sig) + } + _ => Err(VerifySigError::MismatchedScheme), } } } diff --git a/shared/src/types/key/ed25519.rs b/shared/src/types/key/ed25519.rs index 48db89005a..4f3f9f02d7 100644 --- a/shared/src/types/key/ed25519.rs +++ b/shared/src/types/key/ed25519.rs @@ -35,7 +35,7 @@ impl super::PublicKey for PublicKey { #[allow(clippy::bind_instead_of_map)] super::common::PublicKey::try_from_pk(pk).and_then(|x| match x { super::common::PublicKey::Ed25519(epk) => Ok(epk), - // _ => Err(ParsePublicKeyError::MismatchedScheme), + _ => Err(ParsePublicKeyError::MismatchedScheme), }) } else if PK::TYPE == Self::TYPE { Self::try_from_slice(pk.try_to_vec().unwrap().as_slice()) @@ -139,7 +139,7 @@ impl super::SecretKey for SecretKey { #[allow(clippy::bind_instead_of_map)] super::common::SecretKey::try_from_sk(pk).and_then(|x| match x { super::common::SecretKey::Ed25519(epk) => Ok(epk), - // _ => Err(ParseSecretKeyError::MismatchedScheme), + _ => Err(ParseSecretKeyError::MismatchedScheme), }) } else if PK::TYPE == Self::TYPE { Self::try_from_slice(pk.try_to_vec().unwrap().as_slice()) @@ -242,7 +242,7 @@ impl super::Signature for Signature { #[allow(clippy::bind_instead_of_map)] super::common::Signature::try_from_sig(pk).and_then(|x| match x { super::common::Signature::Ed25519(epk) => Ok(epk), - // _ => Err(ParseSignatureError::MismatchedScheme), + _ => Err(ParseSignatureError::MismatchedScheme), }) } else if PK::TYPE == Self::TYPE { Self::try_from_slice(pk.try_to_vec().unwrap().as_slice()) diff --git a/shared/src/types/key/mod.rs b/shared/src/types/key/mod.rs index 9deccf75a9..6a95d2eb2d 100644 --- a/shared/src/types/key/mod.rs +++ b/shared/src/types/key/mod.rs @@ -19,6 +19,7 @@ use crate::types::address; pub mod common; pub mod ed25519; +pub mod secp256k1; const PK_STORAGE_KEY: &str = "public_key"; const PROTOCOL_PK_STORAGE_KEY: &str = "protocol_public_key"; @@ -126,18 +127,33 @@ pub trait TryFromRef: Sized { } /// Type capturing signature scheme IDs -#[derive(PartialEq, Eq, Copy, Clone)] +#[derive(PartialEq, Eq, Copy, Clone, Debug)] pub enum SchemeType { /// Type identifier for Ed25519-consensus Ed25519Consensus, + /// Type identifier for Secp256k1-consensus + Secp256k1Consensus, /// Type identifier for Common Common, } +impl FromStr for SchemeType { + type Err = (); + + fn from_str(input: &str) -> Result { + match input.to_lowercase().as_str() { + "ed25519" => Ok(Self::Ed25519Consensus), + "secp256k1" => Ok(Self::Secp256k1Consensus), + "common" => Ok(Self::Common), + _ => Err(()), + } + } +} + /// Represents a signature pub trait Signature: - Hash + PartialOrd + Serialize + BorshSerialize + BorshDeserialize + Hash + PartialOrd + Serialize + BorshSerialize + BorshDeserialize + BorshSchema { /// The scheme type of this implementation const TYPE: SchemeType; @@ -164,6 +180,7 @@ pub trait Signature: pub trait PublicKey: BorshSerialize + BorshDeserialize + + BorshSchema + Ord + Clone + Display @@ -199,6 +216,7 @@ pub trait PublicKey: pub trait SecretKey: BorshSerialize + BorshDeserialize + + BorshSchema + Display + Debug + RefTo @@ -415,12 +433,27 @@ macro_rules! sigscheme_test { println!("Public key: {}", public_key); println!("Secret key: {}", secret_key); } + + /// Run `cargo test gen_keypair -- --nocapture` to generate a + /// new keypair. + #[test] + fn gen_sign_verify() { + use rand::prelude::ThreadRng; + use rand::thread_rng; + + let mut rng: ThreadRng = thread_rng(); + let sk = <$type>::generate(&mut rng); + let sig = <$type>::sign(&sk, b"hello"); + assert!(<$type>::verify_signature_raw(&sk.ref_to(), b"hello", &sig).is_ok()); + } } }; } #[cfg(test)] sigscheme_test! {ed25519_test, ed25519::SigScheme} +#[cfg(test)] +sigscheme_test! {secp256k1_test, secp256k1::SigScheme} #[cfg(test)] mod more_tests { @@ -442,4 +475,4 @@ mod more_tests { core::slice::from_raw_parts(ptr, len) }); } -} +} \ No newline at end of file diff --git a/shared/src/types/key/secp256k1.rs b/shared/src/types/key/secp256k1.rs new file mode 100644 index 0000000000..2b7e2995de --- /dev/null +++ b/shared/src/types/key/secp256k1.rs @@ -0,0 +1,494 @@ +//! secp256k1 keys and related functionality + +use std::fmt; +use std::fmt::{Debug, Display}; +use std::hash::{Hash, Hasher}; +use std::io::{ErrorKind, Write}; +use std::str::FromStr; +use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; +use serde::Serializer; + +//use libsecp256k1::util::SECRET_KEY_SIZE; +use sha2::{Digest, Sha256}; + +#[cfg(feature = "rand")] +use rand::{CryptoRng, RngCore}; +use serde::{Deserialize,Serialize}; +use serde::de::{Error, SeqAccess, Visitor}; +use serde::ser::SerializeTuple; + +use super::{ + ParsePublicKeyError, ParseSecretKeyError, ParseSignatureError, RefTo, + SchemeType, SigScheme as SigSchemeTrait, VerifySigError, +}; + + +/// secp256k1 public key +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +pub struct PublicKey(libsecp256k1::PublicKey); + +impl super::PublicKey for PublicKey { + const TYPE: SchemeType = SigScheme::TYPE; + + fn try_from_pk( + pk: &PK, + ) -> Result { + if PK::TYPE == super::common::PublicKey::TYPE { + // TODO remove once the wildcard match is used below + #[allow(clippy::bind_instead_of_map)] + super::common::PublicKey::try_from_pk(pk).and_then(|x| match x { + super::common::PublicKey::Secp256k1(epk) => Ok(epk), + _ => Err(ParsePublicKeyError::MismatchedScheme), + }) + } else if PK::TYPE == Self::TYPE { + Self::try_from_slice(pk.try_to_vec().unwrap().as_slice()) + .map_err(ParsePublicKeyError::InvalidEncoding) + } else { + Err(ParsePublicKeyError::MismatchedScheme) + } + } +} + +impl BorshDeserialize for PublicKey { + fn deserialize(buf: &mut &[u8]) -> std::io::Result { + // deserialize the bytes first + let pk = libsecp256k1::PublicKey::parse_compressed( + buf.get(0..libsecp256k1::util::COMPRESSED_PUBLIC_KEY_SIZE) + .ok_or_else(|| std::io::Error::from(ErrorKind::UnexpectedEof))? + .try_into() + .unwrap(), + ) + .map_err(|e| { + std::io::Error::new( + ErrorKind::InvalidInput, + format!("Error decoding secp256k1 public key: {}", e), + ) + })?; + *buf = &buf[libsecp256k1::util::COMPRESSED_PUBLIC_KEY_SIZE..]; + Ok(PublicKey(pk)) + } +} + +impl BorshSerialize for PublicKey { + fn serialize(&self, writer: &mut W) -> std::io::Result<()> { + writer.write_all(&self.0.serialize_compressed())?; + Ok(()) + } +} + +impl BorshSchema for PublicKey { + fn add_definitions_recursively( + definitions: &mut std::collections::HashMap< + borsh::schema::Declaration, + borsh::schema::Definition, + >, + ) { + // Encoded as `[u8; COMPRESSED_PUBLIC_KEY_SIZE]` + let elements = "u8".into(); + let length = libsecp256k1::util::COMPRESSED_PUBLIC_KEY_SIZE as u32; + let definition = borsh::schema::Definition::Array { elements, length }; + definitions.insert(Self::declaration(), definition); + } + + fn declaration() -> borsh::schema::Declaration { + "secp256k1::PublicKey".into() + } +} + +#[allow(clippy::derive_hash_xor_eq)] +impl Hash for PublicKey { + fn hash(&self, state: &mut H) { + self.0.serialize_compressed().hash(state); + } +} + +impl PartialOrd for PublicKey { + fn partial_cmp(&self, other: &Self) -> Option { + self.0.serialize_compressed().partial_cmp(&other.0.serialize_compressed()) + } +} + +impl Ord for PublicKey { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.0.serialize_compressed().cmp(&other.0.serialize_compressed()) + } +} + +impl Display for PublicKey { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", hex::encode(&self.0.serialize_compressed())) + } +} + +impl FromStr for PublicKey { + type Err = ParsePublicKeyError; + + fn from_str(s: &str) -> Result { + let vec = hex::decode(s).map_err(ParsePublicKeyError::InvalidHex)?; + BorshDeserialize::try_from_slice(&vec) + .map_err(ParsePublicKeyError::InvalidEncoding) + } +} + +impl From for PublicKey { + fn from(pk: libsecp256k1::PublicKey) -> Self { + Self(pk) + } +} + +/// Secp256k1 secret key +#[derive(Debug, Clone)] +pub struct SecretKey(libsecp256k1::SecretKey); + +impl super::SecretKey for SecretKey { + type PublicKey = PublicKey; + + const TYPE: SchemeType = SigScheme::TYPE; + + fn try_from_sk( + pk: &PK, + ) -> Result { + if PK::TYPE == super::common::SecretKey::TYPE { + // TODO remove once the wildcard match is used below + #[allow(clippy::bind_instead_of_map)] + super::common::SecretKey::try_from_sk(pk).and_then(|x| match x { + super::common::SecretKey::Secp256k1(epk) => Ok(epk), + _ => Err(ParseSecretKeyError::MismatchedScheme), + }) + } else if PK::TYPE == Self::TYPE { + Self::try_from_slice(pk.try_to_vec().unwrap().as_slice()) + .map_err(ParseSecretKeyError::InvalidEncoding) + } else { + Err(ParseSecretKeyError::MismatchedScheme) + } + } +} + +impl Serialize for SecretKey { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + // not sure if this is how I should be doing this! + // https://serde.rs/impl-serialize.html! + let arr = self.0.serialize(); + let mut seq = serializer.serialize_tuple(arr.len())?; + for elem in &arr[..] { + seq.serialize_element(elem)?; + } + seq.end() + } +} + +impl<'de> Deserialize<'de> for SecretKey { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de> + { + struct ByteArrayVisitor; + + impl<'de> Visitor<'de> for ByteArrayVisitor { + type Value = [u8; libsecp256k1::util::SECRET_KEY_SIZE]; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str(&format!("expecting an array of length {}", libsecp256k1::util::SECRET_KEY_SIZE)) + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + let mut arr = [0u8; libsecp256k1::util::SECRET_KEY_SIZE]; + #[allow(clippy::needless_range_loop)] + for i in 0..libsecp256k1::util::SECRET_KEY_SIZE { + arr[i] = seq.next_element()? + .ok_or_else(|| Error::invalid_length(i, &self))?; + } + Ok(arr) + } + } + + let arr_res = deserializer.deserialize_tuple(libsecp256k1::util::SECRET_KEY_SIZE, ByteArrayVisitor)?; + let key = libsecp256k1::SecretKey::parse_slice(&arr_res) + .map_err(D::Error::custom); + Ok(SecretKey(key.unwrap())) + + } +} + +impl BorshDeserialize for SecretKey { + fn deserialize(buf: &mut &[u8]) -> std::io::Result { + // deserialize the bytes first + Ok(SecretKey( + libsecp256k1::SecretKey::parse( + &(BorshDeserialize::deserialize(buf)?), + ) + .map_err(|e| { + std::io::Error::new( + ErrorKind::InvalidInput, + format!("Error decoding secp256k1 secret key: {}", e), + ) + })?, + )) + } +} + +impl BorshSerialize for SecretKey { + fn serialize(&self, writer: &mut W) -> std::io::Result<()> { + BorshSerialize::serialize(&self.0.serialize(), writer) + } +} + +impl BorshSchema for SecretKey { + fn add_definitions_recursively( + definitions: &mut std::collections::HashMap< + borsh::schema::Declaration, + borsh::schema::Definition, + >, + ) { + // Encoded as `[u8; SECRET_KEY_SIZE]` + let elements = "u8".into(); + let length = libsecp256k1::util::SECRET_KEY_SIZE as u32; + let definition = borsh::schema::Definition::Array { elements, length }; + definitions.insert(Self::declaration(), definition); + } + + fn declaration() -> borsh::schema::Declaration { + "secp256k1::SecretKey".into() + } +} + +impl Display for SecretKey { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", hex::encode(&self.0.serialize())) + } +} + +impl FromStr for SecretKey { + type Err = ParseSecretKeyError; + + fn from_str(s: &str) -> Result { + let vec = hex::decode(s).map_err(ParseSecretKeyError::InvalidHex)?; + BorshDeserialize::try_from_slice(&vec) + .map_err(ParseSecretKeyError::InvalidEncoding) + } +} + +impl RefTo for SecretKey { + fn ref_to(&self) -> PublicKey { + PublicKey(libsecp256k1::PublicKey::from_secret_key(&self.0)) + } +} + +/// Secp256k1 signature +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct Signature(libsecp256k1::Signature); + +impl super::Signature for Signature { + const TYPE: SchemeType = SigScheme::TYPE; + + fn try_from_sig( + pk: &PK, + ) -> Result { + if PK::TYPE == super::common::Signature::TYPE { + // TODO remove once the wildcard match is used below + #[allow(clippy::bind_instead_of_map)] + super::common::Signature::try_from_sig(pk).and_then(|x| match x { + super::common::Signature::Secp256k1(epk) => Ok(epk), + _ => Err(ParseSignatureError::MismatchedScheme), + }) + } else if PK::TYPE == Self::TYPE { + Self::try_from_slice(pk.try_to_vec().unwrap().as_slice()) + .map_err(ParseSignatureError::InvalidEncoding) + } else { + Err(ParseSignatureError::MismatchedScheme) + } + } +} + +impl Serialize for Signature { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let arr = self.0.serialize(); + let mut seq = serializer.serialize_tuple(arr.len())?; + for elem in &arr[..] { + seq.serialize_element(elem)?; + } + seq.end() + } +} + +impl<'de> Deserialize<'de> for Signature { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de> + { + struct ByteArrayVisitor; + + impl<'de> Visitor<'de> for ByteArrayVisitor { + type Value = [u8; libsecp256k1::util::SIGNATURE_SIZE]; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str(&format!("an array of length {}", libsecp256k1::util::SIGNATURE_SIZE)) + } + + fn visit_seq(self, mut seq: A) -> Result<[u8; 64], A::Error> + where + A: SeqAccess<'de>, + { + let mut arr = [0u8; libsecp256k1::util::SIGNATURE_SIZE]; + #[allow(clippy::needless_range_loop)] + for i in 0..libsecp256k1::util::SIGNATURE_SIZE { + arr[i] = seq.next_element()? + .ok_or_else(|| Error::invalid_length(i, &self))?; + } + Ok(arr) + } + } + + let arr_res = deserializer.deserialize_tuple(libsecp256k1::util::SIGNATURE_SIZE, ByteArrayVisitor)?; + let sig = libsecp256k1::Signature::parse_standard(&arr_res) + .map_err(D::Error::custom); + Ok(Signature(sig.unwrap())) + + } +} + +impl BorshDeserialize for Signature { + fn deserialize(buf: &mut &[u8]) -> std::io::Result { + // deserialize the bytes first + Ok(Signature( + libsecp256k1::Signature::parse_standard( + &(BorshDeserialize::deserialize(buf)?), + ) + .map_err(|e| { + std::io::Error::new( + ErrorKind::InvalidInput, + format!("Error decoding secp256k1 signature: {}", e), + ) + })?, + )) + } +} + +impl BorshSerialize for Signature { + fn serialize(&self, writer: &mut W) -> std::io::Result<()> { + BorshSerialize::serialize(&self.0.serialize(), writer) + } +} + +impl BorshSchema for Signature { + fn add_definitions_recursively( + definitions: &mut std::collections::HashMap< + borsh::schema::Declaration, + borsh::schema::Definition, + >, + ) { + // Encoded as `[u8; SIGNATURE_SIZE]` + let elements = "u8".into(); + let length = libsecp256k1::util::SIGNATURE_SIZE as u32; + let definition = borsh::schema::Definition::Array { elements, length }; + definitions.insert(Self::declaration(), definition); + } + + fn declaration() -> borsh::schema::Declaration { + "secp256k1::Signature".into() + } +} + +#[allow(clippy::derive_hash_xor_eq)] +impl Hash for Signature { + fn hash(&self, state: &mut H) { + self.0.serialize().hash(state); + } +} + +impl PartialOrd for Signature { + fn partial_cmp(&self, other: &Self) -> Option { + self.0.serialize().partial_cmp(&other.0.serialize()) + } +} + +/// An implementation of the Secp256k1 signature scheme +#[derive( + Debug, + Clone, + BorshSerialize, + BorshDeserialize, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Serialize, + Deserialize, + Default, +)] +pub struct SigScheme; + +impl super::SigScheme for SigScheme { + type PublicKey = PublicKey; + type SecretKey = SecretKey; + type Signature = Signature; + + const TYPE: SchemeType = SchemeType::Secp256k1Consensus; + + #[cfg(feature = "rand")] + fn generate(csprng: &mut R) -> SecretKey + where + R: CryptoRng + RngCore, + { + SecretKey(libsecp256k1::SecretKey::random(csprng)) + } + + /// Sign the data with a key + fn sign(keypair: &SecretKey, data: impl AsRef<[u8]>) -> Self::Signature { + let hash = Sha256::digest(data.as_ref()); + let message = libsecp256k1::Message::parse_slice(hash.as_ref()) + .expect("Message encoding should not fail"); + Signature(libsecp256k1::sign(&message, &keypair.0).0) + } + + fn verify_signature( + pk: &Self::PublicKey, + data: &T, + sig: &Self::Signature, + ) -> Result<(), VerifySigError> { + let bytes = &data + .try_to_vec() + .map_err(VerifySigError::DataEncodingError)?[..]; + let hash = Sha256::digest(bytes); + let message = &libsecp256k1::Message::parse_slice(hash.as_ref()) + .expect("Error parsing given data"); + let check = libsecp256k1::verify(message, &sig.0, &pk.0); + match check { + true => Ok(()), + false => Err(VerifySigError::SigVerifyError( + format!("Error verifying secp256k1 signature: {}",libsecp256k1::Error::InvalidSignature) + )), + } + + + + } + + fn verify_signature_raw( + pk: &Self::PublicKey, + data: &[u8], + sig: &Self::Signature, + ) -> Result<(), VerifySigError> { + let hash = Sha256::digest(data); + let message = &libsecp256k1::Message::parse_slice(hash.as_ref()) + .expect("Error parsing raw data"); + let check = libsecp256k1::verify(message,&sig.0, &pk.0); + match check { + true => Ok(()), + false => Err(VerifySigError::SigVerifyError( + format!("Error verifying secp256k1 signature: {}",libsecp256k1::Error::InvalidSignature) + )), + } + + } +} diff --git a/wasm/checksums.json b/wasm/checksums.json index 2e55738ba5..ffbac6d9b0 100644 --- a/wasm/checksums.json +++ b/wasm/checksums.json @@ -1,19 +1,19 @@ { - "tx_bond.wasm": "tx_bond.e8fcf7413067810f82e1c0f54fdc9675a4c686b172db9c44c714310d3f19baf6.wasm", - "tx_from_intent.wasm": "tx_from_intent.cd5f7af4d3af9300df8dc16e891f39f85d6497a43a2cd74d30d1dc506649291e.wasm", - "tx_ibc.wasm": "tx_ibc.3805f69ceafd60b857a860d26e6fbe2973f309289147cf59c10e0bd65a30057e.wasm", - "tx_init_account.wasm": "tx_init_account.8abb68c5f40fa9ea39f03ddb9c387bc84a642bac4f40c7e9ceebb8418b3ccde7.wasm", - "tx_init_nft.wasm": "tx_init_nft.564390006d7b8f4f46d215704b05561a7279c92a6fe8f3ec61118a5486a3e092.wasm", - "tx_init_proposal.wasm": "tx_init_proposal.5fc912c847cb4d04743b4dea650418a4eae233f4abf91493791a92e3de5050aa.wasm", - "tx_init_validator.wasm": "tx_init_validator.92d11bc1cc27818864e13d122179a199043a274f7bba901b11c6474261eb97eb.wasm", - "tx_mint_nft.wasm": "tx_mint_nft.9f5b723dd4ed195b489b8456a6d83167829f0b2b8fb479be19b877a60b81c803.wasm", - "tx_transfer.wasm": "tx_transfer.032bfa997c8f2ee2cc5bf053f0128880a79a57ad3d8c3ecc6ff0c22e27f47ebd.wasm", - "tx_unbond.wasm": "tx_unbond.17444d665b8a7bebb624691eaab318c845c8ce18c557d0af440b7bfdb7efa806.wasm", - "tx_update_vp.wasm": "tx_update_vp.d47bfe6ef55a86bce36093feeff74fe09ec7cffebf9696dd37658756a4eb793d.wasm", - "tx_vote_proposal.wasm": "tx_vote_proposal.1bee09ffd3a1e577dc9b9d6d5f91c4a6f91a9b2ac9e3a3d8258c00cd12902304.wasm", - "tx_withdraw.wasm": "tx_withdraw.75dbdc78924d8072ffcefaed67715d9480dd9f702ac77cf18ee15d0e44a38ab0.wasm", - "vp_nft.wasm": "vp_nft.3711eac06bda0c39ab52618bc458df7e6b16ed096bb3930b93ade93c9b7cf23a.wasm", - "vp_testnet_faucet.wasm": "vp_testnet_faucet.400be39dcf0fedf099232bdecfa42c2dbe1f0aaede34fb99ec26da3b6623c09a.wasm", - "vp_token.wasm": "vp_token.118aef31933858351cf77315069fc2f7c61e7db8891c7990e77f9ffd6ef90af0.wasm", - "vp_user.wasm": "vp_user.73136ffcd68e46e2f88d27ae9e48a0731b06d883dd3defcb41b604cc7968c638.wasm" + "tx_bond.wasm": "tx_bond.366f7448cfd065184c0ed35df2d6e6957bf92c10079f23e43630c1fec113d68b.wasm", + "tx_from_intent.wasm": "tx_from_intent.b33dd8f843660475405886899710ed70e91b39d1880a86a6acea6a9c8a6fd5aa.wasm", + "tx_ibc.wasm": "tx_ibc.404dd804e5725ea8d4fbfcd7cf3c0681a148a34d284a5fdae799ef5be2179861.wasm", + "tx_init_account.wasm": "tx_init_account.9b1b141a7ed7bd75af9f3ccc401b0a64c161aabf5f8b56ac645920f0fbdb72fb.wasm", + "tx_init_nft.wasm": "tx_init_nft.ede5a3f4e2ce8f2cfdaa664b6b9aca5a461f8317b3f2a4273a29dbde6a1cb8d0.wasm", + "tx_init_proposal.wasm": "tx_init_proposal.d0c03bfe805d90cf7a094e11e4d903fc71f09f871c0b3daedf71172210409fac.wasm", + "tx_init_validator.wasm": "tx_init_validator.5ac10736e2521aa00c06c4cd4165b3587ca95470d947793b9ee2134c1b80220d.wasm", + "tx_mint_nft.wasm": "tx_mint_nft.ec77b12d4e7dfbf998e0c5021d11308e4ace27daf390b6f4c7dcfc04a3d1ff31.wasm", + "tx_transfer.wasm": "tx_transfer.35546938bd04de4e8070addb43275e68e0d9bed7baa159a9804a96494a7cac71.wasm", + "tx_unbond.wasm": "tx_unbond.fbbc6b35d188b9fbeb0f1d0f98434ff00efa7a2ba1fd4d527aa17b920f7f64c5.wasm", + "tx_update_vp.wasm": "tx_update_vp.cdb6de03931bb5e2d62d1db0d59777c3bb7bfb14214992328d0df95d1851f45e.wasm", + "tx_vote_proposal.wasm": "tx_vote_proposal.257a819ca6bb8cba60c43d5341381c8175dc0b6b1de7ceb07e7e0a8ed11c862d.wasm", + "tx_withdraw.wasm": "tx_withdraw.d11e3e3a6b5f94184f023b579a9bfabc9d268b0c35c11049525dffdbcf6ad948.wasm", + "vp_nft.wasm": "vp_nft.a4eff2933f866250fd98dd65e91d45f08d4ebc49a36df63f0216181b07dc9d8d.wasm", + "vp_testnet_faucet.wasm": "vp_testnet_faucet.6f81a8be815dcab8f8dc726b4a2a01920a21901d02bc23daf097b4bfa35c5318.wasm", + "vp_token.wasm": "vp_token.a083be83b0dc78d953999e26dc6b8c10a0e9828c74d365f836c5668533f4e41c.wasm", + "vp_user.wasm": "vp_user.db97989f32edc6c780ae5fc9f5b4296640206b890f273b753fc0ffba317233fd.wasm" } \ No newline at end of file diff --git a/wasm/tx_template/Cargo.lock b/wasm/tx_template/Cargo.lock index 063f40a223..d085610948 100644 --- a/wasm/tx_template/Cargo.lock +++ b/wasm/tx_template/Cargo.lock @@ -531,6 +531,12 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + [[package]] name = "crypto-common" version = "0.1.3" @@ -541,6 +547,16 @@ dependencies = [ "typenum", ] +[[package]] +name = "crypto-mac" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" +dependencies = [ + "generic-array", + "subtle", +] + [[package]] name = "curve25519-dalek" version = "3.2.0" @@ -996,6 +1012,27 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hmac" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" +dependencies = [ + "crypto-mac", + "digest 0.9.0", +] + +[[package]] +name = "hmac-drbg" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" +dependencies = [ + "digest 0.9.0", + "generic-array", + "hmac", +] + [[package]] name = "http" version = "0.2.6" @@ -1223,6 +1260,55 @@ dependencies = [ "winapi", ] +[[package]] +name = "libsecp256k1" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95b09eff1b35ed3b33b877ced3a691fc7a481919c7e29c53c906226fcf55e2a1" +dependencies = [ + "arrayref", + "base64", + "digest 0.9.0", + "hmac-drbg", + "lazy_static", + "libsecp256k1-core", + "libsecp256k1-gen-ecmult", + "libsecp256k1-gen-genmult", + "rand", + "serde", + "sha2 0.9.9", + "typenum", +] + +[[package]] +name = "libsecp256k1-core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451" +dependencies = [ + "crunchy", + "digest 0.9.0", + "subtle", +] + +[[package]] +name = "libsecp256k1-gen-ecmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3038c808c55c87e8a172643a7d87187fc6c4174468159cb3090659d55bcb4809" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "libsecp256k1-gen-genmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db8d6ba2cec9eacc40e6e8ccc98931840301f1006e95647ceb2dd5c3aa06f7c" +dependencies = [ + "libsecp256k1-core", +] + [[package]] name = "log" version = "0.4.14" @@ -1369,6 +1455,7 @@ dependencies = [ "ibc-proto", "ics23", "itertools", + "libsecp256k1", "loupe", "namada_proof_of_stake", "parity-wasm", diff --git a/wasm/vp_template/Cargo.lock b/wasm/vp_template/Cargo.lock index 7dc2e8f86c..67aef12e0a 100644 --- a/wasm/vp_template/Cargo.lock +++ b/wasm/vp_template/Cargo.lock @@ -531,6 +531,12 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + [[package]] name = "crypto-common" version = "0.1.3" @@ -541,6 +547,16 @@ dependencies = [ "typenum", ] +[[package]] +name = "crypto-mac" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" +dependencies = [ + "generic-array", + "subtle", +] + [[package]] name = "curve25519-dalek" version = "3.2.0" @@ -996,6 +1012,27 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hmac" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" +dependencies = [ + "crypto-mac", + "digest 0.9.0", +] + +[[package]] +name = "hmac-drbg" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" +dependencies = [ + "digest 0.9.0", + "generic-array", + "hmac", +] + [[package]] name = "http" version = "0.2.6" @@ -1223,6 +1260,55 @@ dependencies = [ "winapi", ] +[[package]] +name = "libsecp256k1" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95b09eff1b35ed3b33b877ced3a691fc7a481919c7e29c53c906226fcf55e2a1" +dependencies = [ + "arrayref", + "base64", + "digest 0.9.0", + "hmac-drbg", + "lazy_static", + "libsecp256k1-core", + "libsecp256k1-gen-ecmult", + "libsecp256k1-gen-genmult", + "rand", + "serde", + "sha2 0.9.9", + "typenum", +] + +[[package]] +name = "libsecp256k1-core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451" +dependencies = [ + "crunchy", + "digest 0.9.0", + "subtle", +] + +[[package]] +name = "libsecp256k1-gen-ecmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3038c808c55c87e8a172643a7d87187fc6c4174468159cb3090659d55bcb4809" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "libsecp256k1-gen-genmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db8d6ba2cec9eacc40e6e8ccc98931840301f1006e95647ceb2dd5c3aa06f7c" +dependencies = [ + "libsecp256k1-core", +] + [[package]] name = "log" version = "0.4.14" @@ -1369,6 +1455,7 @@ dependencies = [ "ibc-proto", "ics23", "itertools", + "libsecp256k1", "loupe", "namada_proof_of_stake", "parity-wasm", diff --git a/wasm/wasm_source/Cargo.lock b/wasm/wasm_source/Cargo.lock index 5a10a7ae4d..f1816d434e 100644 --- a/wasm/wasm_source/Cargo.lock +++ b/wasm/wasm_source/Cargo.lock @@ -531,6 +531,12 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + [[package]] name = "crypto-common" version = "0.1.3" @@ -541,6 +547,16 @@ dependencies = [ "typenum", ] +[[package]] +name = "crypto-mac" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" +dependencies = [ + "generic-array", + "subtle", +] + [[package]] name = "curve25519-dalek" version = "3.2.0" @@ -996,6 +1012,27 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hmac" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" +dependencies = [ + "crypto-mac", + "digest 0.9.0", +] + +[[package]] +name = "hmac-drbg" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" +dependencies = [ + "digest 0.9.0", + "generic-array", + "hmac", +] + [[package]] name = "http" version = "0.2.6" @@ -1223,6 +1260,55 @@ dependencies = [ "winapi", ] +[[package]] +name = "libsecp256k1" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95b09eff1b35ed3b33b877ced3a691fc7a481919c7e29c53c906226fcf55e2a1" +dependencies = [ + "arrayref", + "base64", + "digest 0.9.0", + "hmac-drbg", + "lazy_static", + "libsecp256k1-core", + "libsecp256k1-gen-ecmult", + "libsecp256k1-gen-genmult", + "rand", + "serde", + "sha2 0.9.9", + "typenum", +] + +[[package]] +name = "libsecp256k1-core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451" +dependencies = [ + "crunchy", + "digest 0.9.0", + "subtle", +] + +[[package]] +name = "libsecp256k1-gen-ecmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3038c808c55c87e8a172643a7d87187fc6c4174468159cb3090659d55bcb4809" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "libsecp256k1-gen-genmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db8d6ba2cec9eacc40e6e8ccc98931840301f1006e95647ceb2dd5c3aa06f7c" +dependencies = [ + "libsecp256k1-core", +] + [[package]] name = "log" version = "0.4.14" @@ -1369,6 +1455,7 @@ dependencies = [ "ibc-proto", "ics23", "itertools", + "libsecp256k1", "loupe", "namada_proof_of_stake", "parity-wasm", diff --git a/wasm_for_tests/wasm_source/Cargo.lock b/wasm_for_tests/wasm_source/Cargo.lock index 97af2f4415..23d27344a6 100644 --- a/wasm_for_tests/wasm_source/Cargo.lock +++ b/wasm_for_tests/wasm_source/Cargo.lock @@ -532,6 +532,12 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + [[package]] name = "crypto-common" version = "0.1.3" @@ -542,6 +548,16 @@ dependencies = [ "typenum", ] +[[package]] +name = "crypto-mac" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" +dependencies = [ + "generic-array", + "subtle", +] + [[package]] name = "curve25519-dalek" version = "3.2.0" @@ -1006,6 +1022,27 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hmac" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" +dependencies = [ + "crypto-mac", + "digest 0.9.0", +] + +[[package]] +name = "hmac-drbg" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" +dependencies = [ + "digest 0.9.0", + "generic-array", + "hmac", +] + [[package]] name = "http" version = "0.2.6" @@ -1233,6 +1270,55 @@ dependencies = [ "winapi", ] +[[package]] +name = "libsecp256k1" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95b09eff1b35ed3b33b877ced3a691fc7a481919c7e29c53c906226fcf55e2a1" +dependencies = [ + "arrayref", + "base64", + "digest 0.9.0", + "hmac-drbg", + "lazy_static", + "libsecp256k1-core", + "libsecp256k1-gen-ecmult", + "libsecp256k1-gen-genmult", + "rand", + "serde", + "sha2 0.9.9", + "typenum", +] + +[[package]] +name = "libsecp256k1-core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451" +dependencies = [ + "crunchy", + "digest 0.9.0", + "subtle", +] + +[[package]] +name = "libsecp256k1-gen-ecmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3038c808c55c87e8a172643a7d87187fc6c4174468159cb3090659d55bcb4809" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "libsecp256k1-gen-genmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db8d6ba2cec9eacc40e6e8ccc98931840301f1006e95647ceb2dd5c3aa06f7c" +dependencies = [ + "libsecp256k1-core", +] + [[package]] name = "log" version = "0.4.16" @@ -1380,6 +1466,7 @@ dependencies = [ "ibc-proto", "ics23", "itertools", + "libsecp256k1", "loupe", "namada_proof_of_stake", "parity-wasm", From b0d7a54f2e29c05a326be3d4c8b03508020ea845 Mon Sep 17 00:00:00 2001 From: brentstone Date: Fri, 17 Jun 2022 18:11:56 +0200 Subject: [PATCH 053/118] command line options for specifying key scheme --- apps/src/lib/cli.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/apps/src/lib/cli.rs b/apps/src/lib/cli.rs index 95f7368668..e1330064f0 100644 --- a/apps/src/lib/cli.rs +++ b/apps/src/lib/cli.rs @@ -1463,6 +1463,7 @@ pub mod args { const REWARDS_CODE_PATH: ArgOpt = arg_opt("rewards-code-path"); const REWARDS_KEY: ArgOpt = arg_opt("rewards-key"); const RPC_SOCKET_ADDR: ArgOpt = arg_opt("rpc"); + const SCHEME: ArgDefault = arg_default("scheme", DefaultFn(|| SchemeType::Ed25519Consensus)); const SIGNER: ArgOpt = arg_opt("signer"); const SIGNING_KEY_OPT: ArgOpt = SIGNING_KEY.opt(); const SIGNING_KEY: Arg = arg("signing-key"); @@ -2727,6 +2728,8 @@ pub mod args { /// Wallet generate key and implicit address arguments #[derive(Clone, Debug)] pub struct KeyAndAddressGen { + /// Scheme type + pub scheme: SchemeType, /// Key alias pub alias: Option, /// Don't encrypt the keypair @@ -2735,16 +2738,23 @@ pub mod args { impl Args for KeyAndAddressGen { fn parse(matches: &ArgMatches) -> Self { + let scheme = SCHEME.parse(matches); let alias = ALIAS_OPT.parse(matches); let unsafe_dont_encrypt = UNSAFE_DONT_ENCRYPT.parse(matches); Self { + scheme, alias, unsafe_dont_encrypt, } } fn def(app: App) -> App { - app.arg(ALIAS_OPT.def().about( + app.arg(SCHEME.def().about( + "The type of key that should be generated. Argument must be \ + either ed25519 or secp256k1. If none provided, the default key scheme \ + is ed25519.", + )) + .arg(ALIAS_OPT.def().about( "The key and address alias. If none provided, the alias will \ be the public key hash.", )) @@ -3015,6 +3025,7 @@ pub mod args { pub alias: String, pub net_address: SocketAddr, pub unsafe_dont_encrypt: bool, + pub key_scheme: SchemeType, } impl Args for InitGenesisValidator { @@ -3022,10 +3033,12 @@ pub mod args { let alias = ALIAS.parse(matches); let net_address = NET_ADDRESS.parse(matches); let unsafe_dont_encrypt = UNSAFE_DONT_ENCRYPT.parse(matches); + let key_scheme = SCHEME.parse(matches); Self { alias, net_address, unsafe_dont_encrypt, + key_scheme, } } @@ -3040,6 +3053,10 @@ pub mod args { "UNSAFE: Do not encrypt the generated keypairs. Do not \ use this for keys used in a live network.", )) + .arg(SCHEME.def().about( + "The key scheme/type used for the validator keys. Currently \ + support ed25519 and secp256k1." + )) } } } From 9851a104d3e623bd83ab216e95016bc073760be2 Mon Sep 17 00:00:00 2001 From: brentstone Date: Fri, 17 Jun 2022 18:19:19 +0200 Subject: [PATCH 054/118] incorporate options into key generation functions --- apps/src/bin/anoma-wallet/cli.rs | 3 +- apps/src/lib/client/tx.rs | 18 ++++++-- apps/src/lib/client/utils.rs | 74 ++++++++++++++++++++---------- apps/src/lib/wallet/mod.rs | 4 +- apps/src/lib/wallet/pre_genesis.rs | 21 +++++---- apps/src/lib/wallet/store.rs | 21 ++++++--- 6 files changed, 97 insertions(+), 44 deletions(-) diff --git a/apps/src/bin/anoma-wallet/cli.rs b/apps/src/bin/anoma-wallet/cli.rs index 9807516a93..3889489956 100644 --- a/apps/src/bin/anoma-wallet/cli.rs +++ b/apps/src/bin/anoma-wallet/cli.rs @@ -45,12 +45,13 @@ pub fn main() -> Result<()> { fn key_and_address_gen( ctx: Context, args::KeyAndAddressGen { + scheme, alias, unsafe_dont_encrypt, }: args::KeyAndAddressGen, ) { let mut wallet = ctx.wallet; - let (alias, _key) = wallet.gen_key(alias, unsafe_dont_encrypt); + let (alias, _key) = wallet.gen_key(scheme, alias, unsafe_dont_encrypt); wallet.save().unwrap_or_else(|err| eprintln!("{}", err)); println!( "Successfully added a key and an address with alias: \"{}\"", diff --git a/apps/src/lib/client/tx.rs b/apps/src/lib/client/tx.rs index 5335f7d450..94a1874d77 100644 --- a/apps/src/lib/client/tx.rs +++ b/apps/src/lib/client/tx.rs @@ -193,7 +193,11 @@ pub async fn submit_init_validator( let account_key = ctx.get_opt_cached(&account_key).unwrap_or_else(|| { println!("Generating validator account key..."); ctx.wallet - .gen_key(Some(validator_key_alias.clone()), unsafe_dont_encrypt) + .gen_key( + SchemeType::Ed25519Consensus, + Some(validator_key_alias.clone()), + unsafe_dont_encrypt, + ) .1 .ref_to() }); @@ -202,7 +206,11 @@ pub async fn submit_init_validator( ctx.get_opt_cached(&consensus_key).unwrap_or_else(|| { println!("Generating consensus key..."); ctx.wallet - .gen_key(Some(consensus_key_alias.clone()), unsafe_dont_encrypt) + .gen_key( + SchemeType::Ed25519Consensus, + Some(consensus_key_alias.clone()), + unsafe_dont_encrypt, + ) .1 }); @@ -210,7 +218,11 @@ pub async fn submit_init_validator( ctx.get_opt_cached(&rewards_account_key).unwrap_or_else(|| { println!("Generating staking reward account key..."); ctx.wallet - .gen_key(Some(rewards_key_alias.clone()), unsafe_dont_encrypt) + .gen_key( + SchemeType::Ed25519Consensus, + Some(rewards_key_alias.clone()), + unsafe_dont_encrypt, + ) .1 .ref_to() }); diff --git a/apps/src/lib/client/utils.rs b/apps/src/lib/client/utils.rs index d16e80e8d3..21ba310c44 100644 --- a/apps/src/lib/client/utils.rs +++ b/apps/src/lib/client/utils.rs @@ -263,11 +263,13 @@ pub async fn join_network( if let Some((validator_alias, pre_genesis_wallet)) = validator_alias_and_pre_genesis_wallet { - let tendermint_node_key: ed25519::SecretKey = pre_genesis_wallet + let tendermint_node_key: common::SecretKey = pre_genesis_wallet .tendermint_node_key .try_to_sk() .unwrap_or_else(|_err| { - eprintln!("Tendermint node key must be ed25519"); + eprintln!( + "Tendermint node key must be common (need to change?)" + ); cli::safe_exit(1) }); @@ -339,7 +341,7 @@ pub async fn join_network( .. } = peer { - node_id != *peer_id + node_id.as_ref().unwrap() != peer_id } else { true } @@ -357,11 +359,14 @@ pub async fn join_network( const TENDERMINT_NODE_ID_LENGTH: usize = 20; /// Derive Tendermint node ID from public key -fn id_from_pk(pk: &ed25519::PublicKey) -> TendermintNodeId { - let digest = Sha256::digest(pk.try_to_vec().unwrap().as_slice()); +fn id_from_pk( + pk: &common::PublicKey, +) -> Result { + let pk_bytes = pk.try_to_vec(); + let digest = Sha256::digest(pk_bytes.unwrap().as_slice()); let mut bytes = [0u8; TENDERMINT_NODE_ID_LENGTH]; bytes.copy_from_slice(&digest[..TENDERMINT_NODE_ID_LENGTH]); - TendermintNodeId::new(bytes) + Ok(TendermintNodeId::new(bytes)) } /// Initialize a new test network from the given configuration. @@ -446,10 +451,10 @@ pub fn init_network( format!("validator {name} Tendermint node key"), &config.tendermint_node_key, ) - .map(|pk| ed25519::PublicKey::try_from_pk(&pk).unwrap()) + .map(|pk| common::PublicKey::try_from_pk(&pk).unwrap()) .unwrap_or_else(|| { // Generate a node key - let node_sk = ed25519::SigScheme::generate(&mut rng); + let node_sk = common::SigScheme::generate(&mut rng); let node_pk = write_tendermint_node_key(&tm_home_dir, node_sk); @@ -459,7 +464,7 @@ pub fn init_network( }); // Derive the node ID from the node key - let node_id: TendermintNodeId = id_from_pk(&node_pk); + let node_id: TendermintNodeId = id_from_pk(&node_pk).unwrap(); // Build the list of persistent peers from the validators' node IDs let peer = TendermintAddress::from_str(&format!( @@ -518,8 +523,11 @@ pub fn init_network( .unwrap_or_else(|| { let alias = format!("{}-consensus-key", name); println!("Generating validator {} consensus key...", name); - let (_alias, keypair) = - wallet.gen_key(Some(alias), unsafe_dont_encrypt); + let (_alias, keypair) = wallet.gen_key( + SchemeType::Common, + Some(alias), + unsafe_dont_encrypt, + ); // Write consensus key for Tendermint tendermint_node::write_validator_key( @@ -538,8 +546,11 @@ pub fn init_network( .unwrap_or_else(|| { let alias = format!("{}-account-key", name); println!("Generating validator {} account key...", name); - let (_alias, keypair) = - wallet.gen_key(Some(alias), unsafe_dont_encrypt); + let (_alias, keypair) = wallet.gen_key( + SchemeType::Common, + Some(alias), + unsafe_dont_encrypt, + ); keypair.ref_to() }); @@ -553,8 +564,11 @@ pub fn init_network( "Generating validator {} staking reward account key...", name ); - let (_alias, keypair) = - wallet.gen_key(Some(alias), unsafe_dont_encrypt); + let (_alias, keypair) = wallet.gen_key( + SchemeType::Common, + Some(alias), + unsafe_dont_encrypt, + ); keypair.ref_to() }); @@ -565,8 +579,11 @@ pub fn init_network( .unwrap_or_else(|| { let alias = format!("{}-protocol-key", name); println!("Generating validator {} protocol signing key...", name); - let (_alias, keypair) = - wallet.gen_key(Some(alias), unsafe_dont_encrypt); + let (_alias, keypair) = wallet.gen_key( + SchemeType::Common, + Some(alias), + unsafe_dont_encrypt, + ); keypair.ref_to() }); @@ -721,8 +738,11 @@ pub fn init_network( "Generating implicit account {} key and address ...", name ); - let (_alias, keypair) = - wallet.gen_key(Some(name.clone()), unsafe_dont_encrypt); + let (_alias, keypair) = wallet.gen_key( + SchemeType::Common, + Some(name.clone()), + unsafe_dont_encrypt, + ); let public_key = genesis_config::HexString(keypair.ref_to().to_string()); config.public_key = Some(public_key); @@ -1011,6 +1031,7 @@ fn init_established_account( if config.public_key.is_none() { println!("Generating established account {} key...", name.as_ref()); let (_alias, keypair) = wallet.gen_key( + SchemeType::Common, Some(format!("{}-key", name.as_ref())), unsafe_dont_encrypt, ); @@ -1032,12 +1053,14 @@ pub fn init_genesis_validator( alias, net_address, unsafe_dont_encrypt, + key_scheme, }: args::InitGenesisValidator, ) { let pre_genesis_dir = validator_pre_genesis_dir(&global_args.base_dir, &alias); println!("Generating validator keys..."); let pre_genesis = pre_genesis::ValidatorWallet::gen_and_store( + key_scheme, unsafe_dont_encrypt, &pre_genesis_dir, ) @@ -1142,16 +1165,21 @@ fn network_configs_url_prefix(chain_id: &ChainId) -> String { fn write_tendermint_node_key( tm_home_dir: &Path, - node_sk: ed25519::SecretKey, -) -> ed25519::PublicKey { - let node_pk: ed25519::PublicKey = node_sk.ref_to(); + node_sk: common::SecretKey, +) -> common::PublicKey { + let node_pk: common::PublicKey = node_sk.ref_to(); // Convert and write the keypair into Tendermint // node_key.json file let node_keypair = [node_sk.try_to_vec().unwrap(), node_pk.try_to_vec().unwrap()].concat(); + + let key_str = match node_sk { + common::SecretKey::Ed25519(_) => "Ed25519", + common::SecretKey::Secp256k1(_) => "Secp256k1", + }; let tm_node_keypair_json = json!({ "priv_key": { - "type": "tendermint/PrivKeyEd25519", + "type": format!("tendermint/PrivKey{}",key_str), "value": base64::encode(node_keypair), } }); diff --git a/apps/src/lib/wallet/mod.rs b/apps/src/lib/wallet/mod.rs index 5fec7dca98..7b0afd899d 100644 --- a/apps/src/lib/wallet/mod.rs +++ b/apps/src/lib/wallet/mod.rs @@ -101,11 +101,12 @@ impl Wallet { /// key. pub fn gen_key( &mut self, + scheme: SchemeType, alias: Option, unsafe_dont_encrypt: bool, ) -> (String, Rc) { let password = read_and_confirm_pwd(unsafe_dont_encrypt); - let (alias, key) = self.store.gen_key(alias, password); + let (alias, key) = self.store.gen_key(scheme, alias, password); // Cache the newly added key self.decrypted_key_cache.insert(alias.clone(), key.clone()); (alias.into(), key) @@ -134,6 +135,7 @@ impl Wallet { Some(Err(err)) => Err(err), other => Ok(Store::gen_validator_keys( other.map(|res| res.unwrap().as_ref().clone()), + SchemeType::Common )), } } diff --git a/apps/src/lib/wallet/pre_genesis.rs b/apps/src/lib/wallet/pre_genesis.rs index 6ecb396004..49fd2bbeaf 100644 --- a/apps/src/lib/wallet/pre_genesis.rs +++ b/apps/src/lib/wallet/pre_genesis.rs @@ -2,9 +2,9 @@ use std::fs; use std::path::{Path, PathBuf}; use std::rc::Rc; +use anoma::types::key::{common, SchemeType}; use ark_serialize::{Read, Write}; use file_lock::{FileLock, FileOptions}; -use namada::types::key::common; use serde::{Deserialize, Serialize}; use thiserror::Error; @@ -66,10 +66,11 @@ impl ValidatorWallet { /// Generate a new [`ValidatorWallet`] with required pre-genesis keys and /// store it as TOML at the given path. pub fn gen_and_store( + scheme: SchemeType, unsafe_dont_encrypt: bool, store_dir: &Path, ) -> std::io::Result { - let validator = Self::gen(unsafe_dont_encrypt); + let validator = Self::gen(scheme, unsafe_dont_encrypt); let data = validator.store.encode(); let wallet_path = validator_file_name(store_dir); // Make sure the dir exists @@ -140,14 +141,15 @@ impl ValidatorWallet { /// Generate a new [`Validator`] with required pre-genesis keys. Will prompt /// for password when `!unsafe_dont_encrypt`. - fn gen(unsafe_dont_encrypt: bool) -> Self { + fn gen(scheme: SchemeType, unsafe_dont_encrypt: bool) -> Self { let password = wallet::read_and_confirm_pwd(unsafe_dont_encrypt); - let (account_key, account_sk) = gen_key_to_store(&password); - let (consensus_key, consensus_sk) = gen_key_to_store(&password); - let (rewards_key, rewards_sk) = gen_key_to_store(&password); + let (account_key, account_sk) = gen_key_to_store(scheme, &password); + let (consensus_key, consensus_sk) = gen_key_to_store(scheme, &password); + let (rewards_key, rewards_sk) = gen_key_to_store(scheme, &password); let (tendermint_node_key, tendermint_node_sk) = - gen_key_to_store(&password); - let validator_keys = store::Store::gen_validator_keys(None); + gen_key_to_store(scheme, &password); + let validator_keys = + store::Store::gen_validator_keys(None, SchemeType::Common); let store = ValidatorStore { account_key, consensus_key, @@ -180,9 +182,10 @@ impl ValidatorStore { } fn gen_key_to_store( + scheme: SchemeType, password: &Option, ) -> (StoredKeypair, Rc) { - let sk = store::gen_sk(); + let sk = store::gen_sk(scheme); StoredKeypair::new(sk, password.clone()) } diff --git a/apps/src/lib/wallet/store.rs b/apps/src/lib/wallet/store.rs index 95454d3d2a..cabaa6eb49 100644 --- a/apps/src/lib/wallet/store.rs +++ b/apps/src/lib/wallet/store.rs @@ -259,10 +259,11 @@ impl Store { /// pointer to the key. pub fn gen_key( &mut self, + scheme: SchemeType, alias: Option, password: Option, ) -> (Alias, Rc) { - let sk = gen_sk(); + let sk = gen_sk(scheme); let pkh: PublicKeyHash = PublicKeyHash::from(&sk.ref_to()); let (keypair_to_store, raw_keypair) = StoredKeypair::new(sk, password); let address = Address::Implicit(ImplicitAddress(pkh.clone())); @@ -287,8 +288,9 @@ impl Store { /// Note that this removes the validator data. pub fn gen_validator_keys( protocol_keypair: Option, + scheme: SchemeType ) -> ValidatorKeys { - let protocol_keypair = protocol_keypair.unwrap_or_else(gen_sk); + let protocol_keypair = protocol_keypair.unwrap_or_else(|| gen_sk(scheme)); let dkg_keypair = ferveo_common::Keypair::::new( &mut StdRng::from_entropy(), ); @@ -500,12 +502,17 @@ pub fn wallet_file(store_dir: impl AsRef) -> PathBuf { } /// Generate a new secret key. -pub fn gen_sk() -> common::SecretKey { +pub fn gen_sk(scheme: SchemeType) -> common::SecretKey { use rand::rngs::OsRng; let mut csprng = OsRng {}; - ed25519::SigScheme::generate(&mut csprng) - .try_to_sk() - .unwrap() + match scheme { + SchemeType::Ed25519Consensus => + ed25519::SigScheme::generate(&mut csprng).try_to_sk().unwrap(), + SchemeType::Secp256k1Consensus => + secp256k1::SigScheme::generate(&mut csprng).try_to_sk().unwrap(), + SchemeType::Common => + common::SigScheme::generate(&mut csprng).try_to_sk().unwrap(), + } } #[cfg(all(test, feature = "dev"))] @@ -515,7 +522,7 @@ mod test_wallet { #[test] fn test_toml_roundtrip() { let mut store = Store::new(); - let validator_keys = Store::gen_validator_keys(None); + let validator_keys = Store::gen_validator_keys(None,SchemeType::Common); store.add_validator_data( Address::decode("atest1v4ehgw36x3prswzxggunzv6pxqmnvdj9xvcyzvpsggeyvs3cg9qnywf589qnwvfsg5erg3fkl09rg5").unwrap(), validator_keys From 98c4325e88a7d4ea0deac1702ea8e4900949ce26 Mon Sep 17 00:00:00 2001 From: brentstone Date: Mon, 27 Jun 2022 14:35:20 +0200 Subject: [PATCH 055/118] remove clippy::bind_instead_of_map now that we will use wildcard --- shared/src/types/key/ed25519.rs | 6 ------ shared/src/types/key/secp256k1.rs | 6 ------ 2 files changed, 12 deletions(-) diff --git a/shared/src/types/key/ed25519.rs b/shared/src/types/key/ed25519.rs index 4f3f9f02d7..d8f3765acd 100644 --- a/shared/src/types/key/ed25519.rs +++ b/shared/src/types/key/ed25519.rs @@ -31,8 +31,6 @@ impl super::PublicKey for PublicKey { pk: &PK, ) -> Result { if PK::TYPE == super::common::PublicKey::TYPE { - // TODO remove once the wildcard match is used below - #[allow(clippy::bind_instead_of_map)] super::common::PublicKey::try_from_pk(pk).and_then(|x| match x { super::common::PublicKey::Ed25519(epk) => Ok(epk), _ => Err(ParsePublicKeyError::MismatchedScheme), @@ -135,8 +133,6 @@ impl super::SecretKey for SecretKey { pk: &PK, ) -> Result { if PK::TYPE == super::common::SecretKey::TYPE { - // TODO remove once the wildcard match is used below - #[allow(clippy::bind_instead_of_map)] super::common::SecretKey::try_from_sk(pk).and_then(|x| match x { super::common::SecretKey::Ed25519(epk) => Ok(epk), _ => Err(ParseSecretKeyError::MismatchedScheme), @@ -238,8 +234,6 @@ impl super::Signature for Signature { pk: &PK, ) -> Result { if PK::TYPE == super::common::Signature::TYPE { - // TODO remove once the wildcard match is used below - #[allow(clippy::bind_instead_of_map)] super::common::Signature::try_from_sig(pk).and_then(|x| match x { super::common::Signature::Ed25519(epk) => Ok(epk), _ => Err(ParseSignatureError::MismatchedScheme), diff --git a/shared/src/types/key/secp256k1.rs b/shared/src/types/key/secp256k1.rs index 2b7e2995de..ae9ec991d7 100644 --- a/shared/src/types/key/secp256k1.rs +++ b/shared/src/types/key/secp256k1.rs @@ -34,8 +34,6 @@ impl super::PublicKey for PublicKey { pk: &PK, ) -> Result { if PK::TYPE == super::common::PublicKey::TYPE { - // TODO remove once the wildcard match is used below - #[allow(clippy::bind_instead_of_map)] super::common::PublicKey::try_from_pk(pk).and_then(|x| match x { super::common::PublicKey::Secp256k1(epk) => Ok(epk), _ => Err(ParsePublicKeyError::MismatchedScheme), @@ -149,8 +147,6 @@ impl super::SecretKey for SecretKey { pk: &PK, ) -> Result { if PK::TYPE == super::common::SecretKey::TYPE { - // TODO remove once the wildcard match is used below - #[allow(clippy::bind_instead_of_map)] super::common::SecretKey::try_from_sk(pk).and_then(|x| match x { super::common::SecretKey::Secp256k1(epk) => Ok(epk), _ => Err(ParseSecretKeyError::MismatchedScheme), @@ -291,8 +287,6 @@ impl super::Signature for Signature { pk: &PK, ) -> Result { if PK::TYPE == super::common::Signature::TYPE { - // TODO remove once the wildcard match is used below - #[allow(clippy::bind_instead_of_map)] super::common::Signature::try_from_sig(pk).and_then(|x| match x { super::common::Signature::Secp256k1(epk) => Ok(epk), _ => Err(ParseSignatureError::MismatchedScheme), From 5398e250481d1d1ef450383f46343a17e319f6b4 Mon Sep 17 00:00:00 2001 From: brentstone Date: Mon, 27 Jun 2022 14:36:30 +0200 Subject: [PATCH 056/118] make libsecp256k1 objects public when wrapped within our own Key and Sig objects --- shared/src/types/key/secp256k1.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/shared/src/types/key/secp256k1.rs b/shared/src/types/key/secp256k1.rs index ae9ec991d7..8dff25dcd1 100644 --- a/shared/src/types/key/secp256k1.rs +++ b/shared/src/types/key/secp256k1.rs @@ -25,7 +25,7 @@ use super::{ /// secp256k1 public key #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] -pub struct PublicKey(libsecp256k1::PublicKey); +pub struct PublicKey(pub libsecp256k1::PublicKey); impl super::PublicKey for PublicKey { const TYPE: SchemeType = SigScheme::TYPE; @@ -136,7 +136,7 @@ impl From for PublicKey { /// Secp256k1 secret key #[derive(Debug, Clone)] -pub struct SecretKey(libsecp256k1::SecretKey); +pub struct SecretKey(pub libsecp256k1::SecretKey); impl super::SecretKey for SecretKey { type PublicKey = PublicKey; @@ -278,7 +278,7 @@ impl RefTo for SecretKey { /// Secp256k1 signature #[derive(Clone, Debug, Eq, PartialEq)] -pub struct Signature(libsecp256k1::Signature); +pub struct Signature(pub libsecp256k1::Signature); impl super::Signature for Signature { const TYPE: SchemeType = SigScheme::TYPE; From c6dfb884b8a02d0cd0327ac509b2d1c192cbaefd Mon Sep 17 00:00:00 2001 From: brentstone Date: Mon, 27 Jun 2022 22:57:16 +0200 Subject: [PATCH 057/118] drop 'Consensus' from SchemeType enum variants --- apps/src/lib/cli.rs | 4 ++-- apps/src/lib/client/tx.rs | 6 +++--- apps/src/lib/wallet/store.rs | 4 ++-- shared/src/types/key/ed25519.rs | 2 +- shared/src/types/key/mod.rs | 12 ++++++------ shared/src/types/key/secp256k1.rs | 2 +- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/apps/src/lib/cli.rs b/apps/src/lib/cli.rs index e1330064f0..03ff487c14 100644 --- a/apps/src/lib/cli.rs +++ b/apps/src/lib/cli.rs @@ -1463,7 +1463,7 @@ pub mod args { const REWARDS_CODE_PATH: ArgOpt = arg_opt("rewards-code-path"); const REWARDS_KEY: ArgOpt = arg_opt("rewards-key"); const RPC_SOCKET_ADDR: ArgOpt = arg_opt("rpc"); - const SCHEME: ArgDefault = arg_default("scheme", DefaultFn(|| SchemeType::Ed25519Consensus)); + const SCHEME: ArgDefault = arg_default("scheme", DefaultFn(|| SchemeType::Ed25519)); const SIGNER: ArgOpt = arg_opt("signer"); const SIGNING_KEY_OPT: ArgOpt = SIGNING_KEY.opt(); const SIGNING_KEY: Arg = arg("signing-key"); @@ -3055,7 +3055,7 @@ pub mod args { )) .arg(SCHEME.def().about( "The key scheme/type used for the validator keys. Currently \ - support ed25519 and secp256k1." + supports ed25519 and secp256k1." )) } } diff --git a/apps/src/lib/client/tx.rs b/apps/src/lib/client/tx.rs index 94a1874d77..798ef62cd4 100644 --- a/apps/src/lib/client/tx.rs +++ b/apps/src/lib/client/tx.rs @@ -194,7 +194,7 @@ pub async fn submit_init_validator( println!("Generating validator account key..."); ctx.wallet .gen_key( - SchemeType::Ed25519Consensus, + SchemeType::Ed25519, Some(validator_key_alias.clone()), unsafe_dont_encrypt, ) @@ -207,7 +207,7 @@ pub async fn submit_init_validator( println!("Generating consensus key..."); ctx.wallet .gen_key( - SchemeType::Ed25519Consensus, + SchemeType::Ed25519, Some(consensus_key_alias.clone()), unsafe_dont_encrypt, ) @@ -219,7 +219,7 @@ pub async fn submit_init_validator( println!("Generating staking reward account key..."); ctx.wallet .gen_key( - SchemeType::Ed25519Consensus, + SchemeType::Ed25519, Some(rewards_key_alias.clone()), unsafe_dont_encrypt, ) diff --git a/apps/src/lib/wallet/store.rs b/apps/src/lib/wallet/store.rs index cabaa6eb49..63e4f0d4b6 100644 --- a/apps/src/lib/wallet/store.rs +++ b/apps/src/lib/wallet/store.rs @@ -506,9 +506,9 @@ pub fn gen_sk(scheme: SchemeType) -> common::SecretKey { use rand::rngs::OsRng; let mut csprng = OsRng {}; match scheme { - SchemeType::Ed25519Consensus => + SchemeType::Ed25519 => ed25519::SigScheme::generate(&mut csprng).try_to_sk().unwrap(), - SchemeType::Secp256k1Consensus => + SchemeType::Secp256k1 => secp256k1::SigScheme::generate(&mut csprng).try_to_sk().unwrap(), SchemeType::Common => common::SigScheme::generate(&mut csprng).try_to_sk().unwrap(), diff --git a/shared/src/types/key/ed25519.rs b/shared/src/types/key/ed25519.rs index d8f3765acd..dbcf9fe04c 100644 --- a/shared/src/types/key/ed25519.rs +++ b/shared/src/types/key/ed25519.rs @@ -321,7 +321,7 @@ impl super::SigScheme for SigScheme { type SecretKey = SecretKey; type Signature = Signature; - const TYPE: SchemeType = SchemeType::Ed25519Consensus; + const TYPE: SchemeType = SchemeType::Ed25519; #[cfg(feature = "rand")] fn generate(csprng: &mut R) -> SecretKey diff --git a/shared/src/types/key/mod.rs b/shared/src/types/key/mod.rs index 6a95d2eb2d..f90cc4aa2e 100644 --- a/shared/src/types/key/mod.rs +++ b/shared/src/types/key/mod.rs @@ -129,10 +129,10 @@ pub trait TryFromRef: Sized { /// Type capturing signature scheme IDs #[derive(PartialEq, Eq, Copy, Clone, Debug)] pub enum SchemeType { - /// Type identifier for Ed25519-consensus - Ed25519Consensus, - /// Type identifier for Secp256k1-consensus - Secp256k1Consensus, + /// Type identifier for Ed25519 scheme + Ed25519, + /// Type identifier for Secp256k1 scheme + Secp256k1, /// Type identifier for Common Common, } @@ -142,8 +142,8 @@ impl FromStr for SchemeType { fn from_str(input: &str) -> Result { match input.to_lowercase().as_str() { - "ed25519" => Ok(Self::Ed25519Consensus), - "secp256k1" => Ok(Self::Secp256k1Consensus), + "ed25519" => Ok(Self::Ed25519), + "secp256k1" => Ok(Self::Secp256k1), "common" => Ok(Self::Common), _ => Err(()), } diff --git a/shared/src/types/key/secp256k1.rs b/shared/src/types/key/secp256k1.rs index 8dff25dcd1..15dc6a838b 100644 --- a/shared/src/types/key/secp256k1.rs +++ b/shared/src/types/key/secp256k1.rs @@ -427,7 +427,7 @@ impl super::SigScheme for SigScheme { type SecretKey = SecretKey; type Signature = Signature; - const TYPE: SchemeType = SchemeType::Secp256k1Consensus; + const TYPE: SchemeType = SchemeType::Secp256k1; #[cfg(feature = "rand")] fn generate(csprng: &mut R) -> SecretKey From ee80a74daee1aea1ee1aed8d6b9be6c7526094d0 Mon Sep 17 00:00:00 2001 From: brentstone Date: Mon, 27 Jun 2022 23:49:27 +0200 Subject: [PATCH 058/118] remove Result layering for id_from_pk --- apps/src/lib/client/utils.rs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/apps/src/lib/client/utils.rs b/apps/src/lib/client/utils.rs index 21ba310c44..36bcdf480f 100644 --- a/apps/src/lib/client/utils.rs +++ b/apps/src/lib/client/utils.rs @@ -341,7 +341,7 @@ pub async fn join_network( .. } = peer { - node_id.as_ref().unwrap() != peer_id + node_id != *peer_id } else { true } @@ -359,14 +359,11 @@ pub async fn join_network( const TENDERMINT_NODE_ID_LENGTH: usize = 20; /// Derive Tendermint node ID from public key -fn id_from_pk( - pk: &common::PublicKey, -) -> Result { - let pk_bytes = pk.try_to_vec(); - let digest = Sha256::digest(pk_bytes.unwrap().as_slice()); +fn id_from_pk(pk: &common::PublicKey) -> TendermintNodeId { + let digest = Sha256::digest(pk.try_to_vec().unwrap().as_slice()); let mut bytes = [0u8; TENDERMINT_NODE_ID_LENGTH]; bytes.copy_from_slice(&digest[..TENDERMINT_NODE_ID_LENGTH]); - Ok(TendermintNodeId::new(bytes)) + TendermintNodeId::new(bytes) } /// Initialize a new test network from the given configuration. @@ -464,7 +461,7 @@ pub fn init_network( }); // Derive the node ID from the node key - let node_id: TendermintNodeId = id_from_pk(&node_pk).unwrap(); + let node_id: TendermintNodeId = id_from_pk(&node_pk); // Build the list of persistent peers from the validators' node IDs let peer = TendermintAddress::from_str(&format!( From e1b3d0b436e53f05713417b1a8ac523939f36d8b Mon Sep 17 00:00:00 2001 From: brentstone Date: Tue, 28 Jun 2022 18:45:34 +0200 Subject: [PATCH 059/118] clean up code implementing Serialize/Deserialize, comment on certain implementations --- shared/src/types/key/secp256k1.rs | 40 +++++++------------------------ 1 file changed, 8 insertions(+), 32 deletions(-) diff --git a/shared/src/types/key/secp256k1.rs b/shared/src/types/key/secp256k1.rs index 15dc6a838b..b83d98c720 100644 --- a/shared/src/types/key/secp256k1.rs +++ b/shared/src/types/key/secp256k1.rs @@ -165,14 +165,8 @@ impl Serialize for SecretKey { where S: Serializer, { - // not sure if this is how I should be doing this! - // https://serde.rs/impl-serialize.html! let arr = self.0.serialize(); - let mut seq = serializer.serialize_tuple(arr.len())?; - for elem in &arr[..] { - seq.serialize_element(elem)?; - } - seq.end() + serde::Serialize::serialize(&arr, serializer) } } @@ -181,34 +175,10 @@ impl<'de> Deserialize<'de> for SecretKey { where D: serde::Deserializer<'de> { - struct ByteArrayVisitor; - - impl<'de> Visitor<'de> for ByteArrayVisitor { - type Value = [u8; libsecp256k1::util::SECRET_KEY_SIZE]; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str(&format!("expecting an array of length {}", libsecp256k1::util::SECRET_KEY_SIZE)) - } - - fn visit_seq(self, mut seq: A) -> Result - where - A: SeqAccess<'de>, - { - let mut arr = [0u8; libsecp256k1::util::SECRET_KEY_SIZE]; - #[allow(clippy::needless_range_loop)] - for i in 0..libsecp256k1::util::SECRET_KEY_SIZE { - arr[i] = seq.next_element()? - .ok_or_else(|| Error::invalid_length(i, &self))?; - } - Ok(arr) - } - } - - let arr_res = deserializer.deserialize_tuple(libsecp256k1::util::SECRET_KEY_SIZE, ByteArrayVisitor)?; + let arr_res: [u8; libsecp256k1::util::SECRET_KEY_SIZE] = serde::Deserialize::deserialize(deserializer)?; let key = libsecp256k1::SecretKey::parse_slice(&arr_res) .map_err(D::Error::custom); Ok(SecretKey(key.unwrap())) - } } @@ -300,12 +270,18 @@ impl super::Signature for Signature { } } +// Would ideally like Serialize, Deserialize to be implemented in libsecp256k1, may try to do so and merge +// upstream in the future. + impl Serialize for Signature { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let arr = self.0.serialize(); + // TODO: implement the line below, currently cannot support [u8; 64] + // serde::Serialize::serialize(&arr, serializer) + let mut seq = serializer.serialize_tuple(arr.len())?; for elem in &arr[..] { seq.serialize_element(elem)?; From 870d6777c8265f30c46a576139d761fbb24d81e0 Mon Sep 17 00:00:00 2001 From: brentstone Date: Tue, 28 Jun 2022 22:44:23 +0200 Subject: [PATCH 060/118] change variable names in fns try_to_sk() and try_to_sig() to reduce confusion --- shared/src/types/key/common.rs | 32 ++++++++++++++++---------------- shared/src/types/key/mod.rs | 12 ++++++------ 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/shared/src/types/key/common.rs b/shared/src/types/key/common.rs index 1986799142..2543f0c056 100644 --- a/shared/src/types/key/common.rs +++ b/shared/src/types/key/common.rs @@ -135,23 +135,23 @@ impl super::SecretKey for SecretKey { const TYPE: SchemeType = SigScheme::TYPE; - fn try_from_sk( - pk: &PK, + fn try_from_sk( + sk: &SK, ) -> Result { - if PK::TYPE == Self::TYPE { - Self::try_from_slice(pk.try_to_vec().unwrap().as_ref()) + if SK::TYPE == Self::TYPE { + Self::try_from_slice(sk.try_to_vec().unwrap().as_ref()) .map_err(ParseSecretKeyError::InvalidEncoding) - } else if PK::TYPE == ed25519::SecretKey::TYPE { + } else if SK::TYPE == ed25519::SecretKey::TYPE { Ok(Self::Ed25519( ed25519::SecretKey::try_from_slice( - pk.try_to_vec().unwrap().as_ref(), + sk.try_to_vec().unwrap().as_ref(), ) .map_err(ParseSecretKeyError::InvalidEncoding)?, )) - } else if PK::TYPE == secp256k1::SecretKey::TYPE { + } else if SK::TYPE == secp256k1::SecretKey::TYPE { Ok(Self::Secp256k1( secp256k1::SecretKey::try_from_slice( - pk.try_to_vec().unwrap().as_ref(), + sk.try_to_vec().unwrap().as_ref(), ) .map_err(ParseSecretKeyError::InvalidEncoding)?, )) } else { @@ -209,23 +209,23 @@ pub enum Signature { impl super::Signature for Signature { const TYPE: SchemeType = SigScheme::TYPE; - fn try_from_sig( - pk: &PK, + fn try_from_sig( + sig: &SIG, ) -> Result { - if PK::TYPE == Self::TYPE { - Self::try_from_slice(pk.try_to_vec().unwrap().as_slice()) + if SIG::TYPE == Self::TYPE { + Self::try_from_slice(sig.try_to_vec().unwrap().as_slice()) .map_err(ParseSignatureError::InvalidEncoding) - } else if PK::TYPE == ed25519::Signature::TYPE { + } else if SIG::TYPE == ed25519::Signature::TYPE { Ok(Self::Ed25519( ed25519::Signature::try_from_slice( - pk.try_to_vec().unwrap().as_slice(), + sig.try_to_vec().unwrap().as_slice(), ) .map_err(ParseSignatureError::InvalidEncoding)?, )) - } else if PK::TYPE == secp256k1::Signature::TYPE { + } else if SIG::TYPE == secp256k1::Signature::TYPE { Ok(Self::Secp256k1( secp256k1::Signature::try_from_slice( - pk.try_to_vec().unwrap().as_slice(), + sig.try_to_vec().unwrap().as_slice(), ) .map_err(ParseSignatureError::InvalidEncoding)?, )) diff --git a/shared/src/types/key/mod.rs b/shared/src/types/key/mod.rs index f90cc4aa2e..9ce1b03838 100644 --- a/shared/src/types/key/mod.rs +++ b/shared/src/types/key/mod.rs @@ -158,11 +158,11 @@ pub trait Signature: /// The scheme type of this implementation const TYPE: SchemeType; /// Convert from one Signature type to another - fn try_from_sig( - pk: &PK, + fn try_from_sig( + sig: &SIG, ) -> Result { - if PK::TYPE == Self::TYPE { - let sig_arr = pk.try_to_vec().unwrap(); + if SIG::TYPE == Self::TYPE { + let sig_arr = sig.try_to_vec().unwrap(); let res = Self::try_from_slice(sig_arr.as_ref()); res.map_err(ParseSignatureError::InvalidEncoding) } else { @@ -170,8 +170,8 @@ pub trait Signature: } } /// Convert from self to another SecretKey type - fn try_to_sig(&self) -> Result { - PK::try_from_sig(self) + fn try_to_sig(&self) -> Result { + SIG::try_from_sig(self) } } From 604f0433d5e15b6add816675bfaa1f3aadfb1bf8 Mon Sep 17 00:00:00 2001 From: brentstone Date: Wed, 29 Jun 2022 12:57:36 +0200 Subject: [PATCH 061/118] convert from common to underlying key type in id_from_pk() when constructing the TendermintNodeId --- apps/src/lib/client/utils.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/apps/src/lib/client/utils.rs b/apps/src/lib/client/utils.rs index 36bcdf480f..b6e52c26df 100644 --- a/apps/src/lib/client/utils.rs +++ b/apps/src/lib/client/utils.rs @@ -360,9 +360,20 @@ const TENDERMINT_NODE_ID_LENGTH: usize = 20; /// Derive Tendermint node ID from public key fn id_from_pk(pk: &common::PublicKey) -> TendermintNodeId { - let digest = Sha256::digest(pk.try_to_vec().unwrap().as_slice()); let mut bytes = [0u8; TENDERMINT_NODE_ID_LENGTH]; - bytes.copy_from_slice(&digest[..TENDERMINT_NODE_ID_LENGTH]); + + match pk { + common::PublicKey::Ed25519(_) => { + let _pk: ed25519::PublicKey = pk.try_to_pk().unwrap(); + let digest = Sha256::digest(_pk.try_to_vec().unwrap().as_slice()); + bytes.copy_from_slice(&digest[..TENDERMINT_NODE_ID_LENGTH]); + }, + common::PublicKey::Secp256k1(_) => { + let _pk: secp256k1::PublicKey = pk.try_to_pk().unwrap(); + let digest = Sha256::digest(_pk.try_to_vec().unwrap().as_slice()); + bytes.copy_from_slice(&digest[..TENDERMINT_NODE_ID_LENGTH]); + }, + } TendermintNodeId::new(bytes) } From 428327fc1009bc1f8514fdc756f97bd82763e174 Mon Sep 17 00:00:00 2001 From: brentstone Date: Wed, 29 Jun 2022 14:38:57 +0200 Subject: [PATCH 062/118] improve write_tendermint_node_key() to produce the proper json given the underlying key scheme --- apps/src/lib/client/utils.rs | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/apps/src/lib/client/utils.rs b/apps/src/lib/client/utils.rs index b6e52c26df..7921412643 100644 --- a/apps/src/lib/client/utils.rs +++ b/apps/src/lib/client/utils.rs @@ -1176,15 +1176,20 @@ fn write_tendermint_node_key( node_sk: common::SecretKey, ) -> common::PublicKey { let node_pk: common::PublicKey = node_sk.ref_to(); - // Convert and write the keypair into Tendermint - // node_key.json file - let node_keypair = - [node_sk.try_to_vec().unwrap(), node_pk.try_to_vec().unwrap()].concat(); - - let key_str = match node_sk { - common::SecretKey::Ed25519(_) => "Ed25519", - common::SecretKey::Secp256k1(_) => "Secp256k1", + + // Convert and write the keypair into Tendermint node_key.json file. + // Tendermint requires concatenating the private-public keys for ed25519 + // but does not for secp256k1. + let (node_keypair, key_str) = match node_sk { + common::SecretKey::Ed25519(_) => { + ([node_sk.try_to_vec().unwrap(), node_pk.try_to_vec().unwrap()].concat(), + "Ed25519") + }, + common::SecretKey::Secp256k1(_) => { + (node_sk.try_to_vec().unwrap(), "Secp256k1") + }, }; + let tm_node_keypair_json = json!({ "priv_key": { "type": format!("tendermint/PrivKey{}",key_str), From d34bf60590b46a201582992f1042c5884d7d767f Mon Sep 17 00:00:00 2001 From: brentstone Date: Wed, 29 Jun 2022 22:07:21 +0200 Subject: [PATCH 063/118] allow CL specification of a specific key scheme for the TxInitValidator --- apps/src/lib/cli.rs | 7 +++++++ apps/src/lib/client/tx.rs | 7 ++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/apps/src/lib/cli.rs b/apps/src/lib/cli.rs index 03ff487c14..4513cb10f3 100644 --- a/apps/src/lib/cli.rs +++ b/apps/src/lib/cli.rs @@ -1696,6 +1696,7 @@ pub mod args { pub struct TxInitValidator { pub tx: Tx, pub source: WalletAddress, + pub scheme: SchemeType, pub account_key: Option, pub consensus_key: Option, pub rewards_account_key: Option, @@ -1709,6 +1710,7 @@ pub mod args { fn parse(matches: &ArgMatches) -> Self { let tx = Tx::parse(matches); let source = SOURCE.parse(matches); + let scheme = SCHEME.parse(matches); let account_key = VALIDATOR_ACCOUNT_KEY.parse(matches); let consensus_key = VALIDATOR_CONSENSUS_KEY.parse(matches); let rewards_account_key = REWARDS_KEY.parse(matches); @@ -1719,6 +1721,7 @@ pub mod args { Self { tx, source, + scheme, account_key, consensus_key, rewards_account_key, @@ -1734,6 +1737,10 @@ pub mod args { .arg(SOURCE.def().about( "The source account's address that signs the transaction.", )) + .arg(SCHEME.def().about( + "The key scheme/type used for the validator keys. Currently \ + supports ed25519 and secp256k1." + )) .arg(VALIDATOR_ACCOUNT_KEY.def().about( "A public key for the validator account. A new one will \ be generated if none given.", diff --git a/apps/src/lib/client/tx.rs b/apps/src/lib/client/tx.rs index 798ef62cd4..c6b2c9b254 100644 --- a/apps/src/lib/client/tx.rs +++ b/apps/src/lib/client/tx.rs @@ -172,6 +172,7 @@ pub async fn submit_init_validator( args::TxInitValidator { tx: tx_args, source, + scheme, account_key, consensus_key, rewards_account_key, @@ -194,7 +195,7 @@ pub async fn submit_init_validator( println!("Generating validator account key..."); ctx.wallet .gen_key( - SchemeType::Ed25519, + scheme, Some(validator_key_alias.clone()), unsafe_dont_encrypt, ) @@ -207,7 +208,7 @@ pub async fn submit_init_validator( println!("Generating consensus key..."); ctx.wallet .gen_key( - SchemeType::Ed25519, + scheme, Some(consensus_key_alias.clone()), unsafe_dont_encrypt, ) @@ -219,7 +220,7 @@ pub async fn submit_init_validator( println!("Generating staking reward account key..."); ctx.wallet .gen_key( - SchemeType::Ed25519, + scheme, Some(rewards_key_alias.clone()), unsafe_dont_encrypt, ) From dd58b30378794867ca93b5b15485a6dcffa3ea4f Mon Sep 17 00:00:00 2001 From: brentstone Date: Wed, 29 Jun 2022 22:08:14 +0200 Subject: [PATCH 064/118] clean and simplify code in id_from_pk() --- apps/src/lib/client/utils.rs | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/apps/src/lib/client/utils.rs b/apps/src/lib/client/utils.rs index 7921412643..4b4ea25430 100644 --- a/apps/src/lib/client/utils.rs +++ b/apps/src/lib/client/utils.rs @@ -361,19 +361,12 @@ const TENDERMINT_NODE_ID_LENGTH: usize = 20; /// Derive Tendermint node ID from public key fn id_from_pk(pk: &common::PublicKey) -> TendermintNodeId { let mut bytes = [0u8; TENDERMINT_NODE_ID_LENGTH]; - - match pk { - common::PublicKey::Ed25519(_) => { - let _pk: ed25519::PublicKey = pk.try_to_pk().unwrap(); - let digest = Sha256::digest(_pk.try_to_vec().unwrap().as_slice()); - bytes.copy_from_slice(&digest[..TENDERMINT_NODE_ID_LENGTH]); - }, - common::PublicKey::Secp256k1(_) => { - let _pk: secp256k1::PublicKey = pk.try_to_pk().unwrap(); - let digest = Sha256::digest(_pk.try_to_vec().unwrap().as_slice()); - bytes.copy_from_slice(&digest[..TENDERMINT_NODE_ID_LENGTH]); - }, - } + let pk_bytes = match pk { + common::PublicKey::Ed25519(_pk) => _pk.try_to_vec().unwrap(), + common::PublicKey::Secp256k1(_pk) => _pk.try_to_vec().unwrap(), + }; + let digest = Sha256::digest(pk_bytes.as_slice()); + bytes.copy_from_slice(&digest[..TENDERMINT_NODE_ID_LENGTH]); TendermintNodeId::new(bytes) } From 43c708c55fd2e7956973fb7042ed3c16a215dabc Mon Sep 17 00:00:00 2001 From: brentstone Date: Wed, 15 Jun 2022 13:48:42 +0200 Subject: [PATCH 065/118] initial commit for supporting secp256k1 keys --- shared/src/types/key/common.rs | 25 ++++++++++++++++++------- shared/src/types/key/mod.rs | 7 +++++-- shared/src/types/key/secp256k1.rs | 6 ------ 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/shared/src/types/key/common.rs b/shared/src/types/key/common.rs index 2543f0c056..e536a7171d 100644 --- a/shared/src/types/key/common.rs +++ b/shared/src/types/key/common.rs @@ -9,8 +9,9 @@ use rand::{CryptoRng, RngCore}; use serde::{Deserialize, Serialize}; use super::{ - ed25519, secp256k1, ParsePublicKeyError, ParseSecretKeyError, ParseSignatureError, - RefTo, SchemeType, SigScheme as SigSchemeTrait, VerifySigError, + ed25519, secp256k1, ParsePublicKeyError, ParseSecretKeyError, + ParseSignatureError, RefTo, SchemeType, SigScheme as SigSchemeTrait, + VerifySigError, }; /// Public key @@ -100,11 +101,11 @@ impl Serialize for SecretKey { { // String encoded, because toml doesn't support enums let prefix = match self { - SecretKey::Ed25519(_) => "ED25519_SK_PREFIX", + SecretKey::Ed25519(_) => "ED25519_SK_PREFIX", SecretKey::Secp256k1(_) => "SECP256K1_SK_PREFIX", }; - let keypair_string = format!("{}{}",prefix,self); - Serialize::serialize(&keypair_string,serializer) + let keypair_string = format!("{}{}", prefix, self); + Serialize::serialize(&keypair_string, serializer) } } @@ -120,7 +121,9 @@ impl<'de> Deserialize<'de> for SecretKey { .map_err(D::Error::custom)?; if let Some(raw) = keypair_string.strip_prefix("ED25519_SK_PREFIX") { SecretKey::from_str(raw).map_err(D::Error::custom) - } else if let Some(raw) = keypair_string.strip_prefix("SECP256K1_SK_PREFIX") { + } else if let Some(raw) = + keypair_string.strip_prefix("SECP256K1_SK_PREFIX") + { SecretKey::from_str(raw).map_err(D::Error::custom) } else { Err(D::Error::custom( @@ -154,7 +157,8 @@ impl super::SecretKey for SecretKey { sk.try_to_vec().unwrap().as_ref(), ) .map_err(ParseSecretKeyError::InvalidEncoding)?, - )) } else { + )) + } else { Err(ParseSecretKeyError::MismatchedScheme) } } @@ -229,6 +233,13 @@ impl super::Signature for Signature { ) .map_err(ParseSignatureError::InvalidEncoding)?, )) + } else if SIG::TYPE == secp256k1::Signature::TYPE { + Ok(Self::Secp256k1( + secp256k1::Signature::try_from_slice( + sig.try_to_vec().unwrap().as_slice(), + ) + .map_err(ParseSignatureError::InvalidEncoding)?, + )) } else { Err(ParseSignatureError::MismatchedScheme) } diff --git a/shared/src/types/key/mod.rs b/shared/src/types/key/mod.rs index 9ce1b03838..a1323a4bc6 100644 --- a/shared/src/types/key/mod.rs +++ b/shared/src/types/key/mod.rs @@ -444,7 +444,10 @@ macro_rules! sigscheme_test { let mut rng: ThreadRng = thread_rng(); let sk = <$type>::generate(&mut rng); let sig = <$type>::sign(&sk, b"hello"); - assert!(<$type>::verify_signature_raw(&sk.ref_to(), b"hello", &sig).is_ok()); + assert!( + <$type>::verify_signature_raw(&sk.ref_to(), b"hello", &sig) + .is_ok() + ); } } }; @@ -475,4 +478,4 @@ mod more_tests { core::slice::from_raw_parts(ptr, len) }); } -} \ No newline at end of file +} diff --git a/shared/src/types/key/secp256k1.rs b/shared/src/types/key/secp256k1.rs index b83d98c720..90fbc82376 100644 --- a/shared/src/types/key/secp256k1.rs +++ b/shared/src/types/key/secp256k1.rs @@ -270,18 +270,12 @@ impl super::Signature for Signature { } } -// Would ideally like Serialize, Deserialize to be implemented in libsecp256k1, may try to do so and merge -// upstream in the future. - impl Serialize for Signature { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let arr = self.0.serialize(); - // TODO: implement the line below, currently cannot support [u8; 64] - // serde::Serialize::serialize(&arr, serializer) - let mut seq = serializer.serialize_tuple(arr.len())?; for elem in &arr[..] { seq.serialize_element(elem)?; From 8c769d5829dadca5bafc378e07d39c9f885a70a2 Mon Sep 17 00:00:00 2001 From: brentstone Date: Fri, 17 Jun 2022 18:11:56 +0200 Subject: [PATCH 066/118] command line options for specifying key scheme --- apps/src/lib/cli.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/apps/src/lib/cli.rs b/apps/src/lib/cli.rs index 4513cb10f3..a629fdf1c9 100644 --- a/apps/src/lib/cli.rs +++ b/apps/src/lib/cli.rs @@ -1463,7 +1463,8 @@ pub mod args { const REWARDS_CODE_PATH: ArgOpt = arg_opt("rewards-code-path"); const REWARDS_KEY: ArgOpt = arg_opt("rewards-key"); const RPC_SOCKET_ADDR: ArgOpt = arg_opt("rpc"); - const SCHEME: ArgDefault = arg_default("scheme", DefaultFn(|| SchemeType::Ed25519)); + const SCHEME: ArgDefault = + arg_default("scheme", DefaultFn(|| SchemeType::Ed25519)); const SIGNER: ArgOpt = arg_opt("signer"); const SIGNING_KEY_OPT: ArgOpt = SIGNING_KEY.opt(); const SIGNING_KEY: Arg = arg("signing-key"); @@ -1738,8 +1739,8 @@ pub mod args { "The source account's address that signs the transaction.", )) .arg(SCHEME.def().about( - "The key scheme/type used for the validator keys. Currently \ - supports ed25519 and secp256k1." + "The key scheme/type used for the validator keys. \ + Currently supports ed25519 and secp256k1.", )) .arg(VALIDATOR_ACCOUNT_KEY.def().about( "A public key for the validator account. A new one will \ @@ -2758,8 +2759,8 @@ pub mod args { fn def(app: App) -> App { app.arg(SCHEME.def().about( "The type of key that should be generated. Argument must be \ - either ed25519 or secp256k1. If none provided, the default key scheme \ - is ed25519.", + either ed25519 or secp256k1. If none provided, the default \ + key scheme is ed25519.", )) .arg(ALIAS_OPT.def().about( "The key and address alias. If none provided, the alias will \ @@ -3061,8 +3062,8 @@ pub mod args { use this for keys used in a live network.", )) .arg(SCHEME.def().about( - "The key scheme/type used for the validator keys. Currently \ - supports ed25519 and secp256k1." + "The key scheme/type used for the validator keys. \ + Currently supports ed25519 and secp256k1.", )) } } From a13e5e586a38d5bb9203c0044ae44d80eff5c735 Mon Sep 17 00:00:00 2001 From: brentstone Date: Fri, 17 Jun 2022 18:19:19 +0200 Subject: [PATCH 067/118] incorporate options into key generation functions --- apps/src/lib/client/tx.rs | 6 +++--- apps/src/lib/client/utils.rs | 33 +++++++++++++++--------------- apps/src/lib/wallet/pre_genesis.rs | 5 ++--- apps/src/lib/wallet/store.rs | 27 ++++++++++++++++-------- 4 files changed, 39 insertions(+), 32 deletions(-) diff --git a/apps/src/lib/client/tx.rs b/apps/src/lib/client/tx.rs index c6b2c9b254..4d829fe61d 100644 --- a/apps/src/lib/client/tx.rs +++ b/apps/src/lib/client/tx.rs @@ -195,7 +195,7 @@ pub async fn submit_init_validator( println!("Generating validator account key..."); ctx.wallet .gen_key( - scheme, + SchemeType::Ed25519Consensus, Some(validator_key_alias.clone()), unsafe_dont_encrypt, ) @@ -208,7 +208,7 @@ pub async fn submit_init_validator( println!("Generating consensus key..."); ctx.wallet .gen_key( - scheme, + SchemeType::Ed25519Consensus, Some(consensus_key_alias.clone()), unsafe_dont_encrypt, ) @@ -220,7 +220,7 @@ pub async fn submit_init_validator( println!("Generating staking reward account key..."); ctx.wallet .gen_key( - scheme, + SchemeType::Ed25519Consensus, Some(rewards_key_alias.clone()), unsafe_dont_encrypt, ) diff --git a/apps/src/lib/client/utils.rs b/apps/src/lib/client/utils.rs index 4b4ea25430..d11f9d8632 100644 --- a/apps/src/lib/client/utils.rs +++ b/apps/src/lib/client/utils.rs @@ -341,7 +341,7 @@ pub async fn join_network( .. } = peer { - node_id != *peer_id + node_id.as_ref().unwrap() != peer_id } else { true } @@ -359,7 +359,11 @@ pub async fn join_network( const TENDERMINT_NODE_ID_LENGTH: usize = 20; /// Derive Tendermint node ID from public key -fn id_from_pk(pk: &common::PublicKey) -> TendermintNodeId { +fn id_from_pk( + pk: &common::PublicKey, +) -> Result { + let pk_bytes = pk.try_to_vec(); + let digest = Sha256::digest(pk_bytes.unwrap().as_slice()); let mut bytes = [0u8; TENDERMINT_NODE_ID_LENGTH]; let pk_bytes = match pk { common::PublicKey::Ed25519(_pk) => _pk.try_to_vec().unwrap(), @@ -367,7 +371,7 @@ fn id_from_pk(pk: &common::PublicKey) -> TendermintNodeId { }; let digest = Sha256::digest(pk_bytes.as_slice()); bytes.copy_from_slice(&digest[..TENDERMINT_NODE_ID_LENGTH]); - TendermintNodeId::new(bytes) + Ok(TendermintNodeId::new(bytes)) } /// Initialize a new test network from the given configuration. @@ -465,7 +469,7 @@ pub fn init_network( }); // Derive the node ID from the node key - let node_id: TendermintNodeId = id_from_pk(&node_pk); + let node_id: TendermintNodeId = id_from_pk(&node_pk).unwrap(); // Build the list of persistent peers from the validators' node IDs let peer = TendermintAddress::from_str(&format!( @@ -1169,20 +1173,15 @@ fn write_tendermint_node_key( node_sk: common::SecretKey, ) -> common::PublicKey { let node_pk: common::PublicKey = node_sk.ref_to(); - - // Convert and write the keypair into Tendermint node_key.json file. - // Tendermint requires concatenating the private-public keys for ed25519 - // but does not for secp256k1. - let (node_keypair, key_str) = match node_sk { - common::SecretKey::Ed25519(_) => { - ([node_sk.try_to_vec().unwrap(), node_pk.try_to_vec().unwrap()].concat(), - "Ed25519") - }, - common::SecretKey::Secp256k1(_) => { - (node_sk.try_to_vec().unwrap(), "Secp256k1") - }, + // Convert and write the keypair into Tendermint + // node_key.json file + let node_keypair = + [node_sk.try_to_vec().unwrap(), node_pk.try_to_vec().unwrap()].concat(); + + let key_str = match node_sk { + common::SecretKey::Ed25519(_) => "Ed25519", + common::SecretKey::Secp256k1(_) => "Secp256k1", }; - let tm_node_keypair_json = json!({ "priv_key": { "type": format!("tendermint/PrivKey{}",key_str), diff --git a/apps/src/lib/wallet/pre_genesis.rs b/apps/src/lib/wallet/pre_genesis.rs index 49fd2bbeaf..4a6b4a4679 100644 --- a/apps/src/lib/wallet/pre_genesis.rs +++ b/apps/src/lib/wallet/pre_genesis.rs @@ -2,9 +2,9 @@ use std::fs; use std::path::{Path, PathBuf}; use std::rc::Rc; -use anoma::types::key::{common, SchemeType}; use ark_serialize::{Read, Write}; use file_lock::{FileLock, FileOptions}; +use namada::types::key::{common, SchemeType}; use serde::{Deserialize, Serialize}; use thiserror::Error; @@ -148,8 +148,7 @@ impl ValidatorWallet { let (rewards_key, rewards_sk) = gen_key_to_store(scheme, &password); let (tendermint_node_key, tendermint_node_sk) = gen_key_to_store(scheme, &password); - let validator_keys = - store::Store::gen_validator_keys(None, SchemeType::Common); + let validator_keys = store::Store::gen_validator_keys(None, scheme); let store = ValidatorStore { account_key, consensus_key, diff --git a/apps/src/lib/wallet/store.rs b/apps/src/lib/wallet/store.rs index 63e4f0d4b6..70af381426 100644 --- a/apps/src/lib/wallet/store.rs +++ b/apps/src/lib/wallet/store.rs @@ -288,9 +288,10 @@ impl Store { /// Note that this removes the validator data. pub fn gen_validator_keys( protocol_keypair: Option, - scheme: SchemeType + scheme: SchemeType, ) -> ValidatorKeys { - let protocol_keypair = protocol_keypair.unwrap_or_else(|| gen_sk(scheme)); + let protocol_keypair = + protocol_keypair.unwrap_or_else(|| gen_sk(scheme)); let dkg_keypair = ferveo_common::Keypair::::new( &mut StdRng::from_entropy(), ); @@ -506,12 +507,19 @@ pub fn gen_sk(scheme: SchemeType) -> common::SecretKey { use rand::rngs::OsRng; let mut csprng = OsRng {}; match scheme { - SchemeType::Ed25519 => - ed25519::SigScheme::generate(&mut csprng).try_to_sk().unwrap(), - SchemeType::Secp256k1 => - secp256k1::SigScheme::generate(&mut csprng).try_to_sk().unwrap(), - SchemeType::Common => - common::SigScheme::generate(&mut csprng).try_to_sk().unwrap(), + SchemeType::Ed25519Consensus => { + ed25519::SigScheme::generate(&mut csprng) + .try_to_sk() + .unwrap() + } + SchemeType::Secp256k1Consensus => { + secp256k1::SigScheme::generate(&mut csprng) + .try_to_sk() + .unwrap() + } + SchemeType::Common => common::SigScheme::generate(&mut csprng) + .try_to_sk() + .unwrap(), } } @@ -522,7 +530,8 @@ mod test_wallet { #[test] fn test_toml_roundtrip() { let mut store = Store::new(); - let validator_keys = Store::gen_validator_keys(None,SchemeType::Common); + let validator_keys = + Store::gen_validator_keys(None, SchemeType::Common); store.add_validator_data( Address::decode("atest1v4ehgw36x3prswzxggunzv6pxqmnvdj9xvcyzvpsggeyvs3cg9qnywf589qnwvfsg5erg3fkl09rg5").unwrap(), validator_keys From e44a734312f5300c07755dac987da82cf1e0c1a4 Mon Sep 17 00:00:00 2001 From: brentstone Date: Mon, 27 Jun 2022 22:57:16 +0200 Subject: [PATCH 068/118] drop 'Consensus' from SchemeType enum variants --- apps/src/lib/cli.rs | 4 ++-- apps/src/lib/client/tx.rs | 6 +++--- apps/src/lib/wallet/store.rs | 16 ++++++---------- 3 files changed, 11 insertions(+), 15 deletions(-) diff --git a/apps/src/lib/cli.rs b/apps/src/lib/cli.rs index a629fdf1c9..8a013deef9 100644 --- a/apps/src/lib/cli.rs +++ b/apps/src/lib/cli.rs @@ -3062,8 +3062,8 @@ pub mod args { use this for keys used in a live network.", )) .arg(SCHEME.def().about( - "The key scheme/type used for the validator keys. \ - Currently supports ed25519 and secp256k1.", + "The key scheme/type used for the validator keys. Currently \ + supports ed25519 and secp256k1." )) } } diff --git a/apps/src/lib/client/tx.rs b/apps/src/lib/client/tx.rs index 4d829fe61d..cb5da89387 100644 --- a/apps/src/lib/client/tx.rs +++ b/apps/src/lib/client/tx.rs @@ -195,7 +195,7 @@ pub async fn submit_init_validator( println!("Generating validator account key..."); ctx.wallet .gen_key( - SchemeType::Ed25519Consensus, + SchemeType::Ed25519, Some(validator_key_alias.clone()), unsafe_dont_encrypt, ) @@ -208,7 +208,7 @@ pub async fn submit_init_validator( println!("Generating consensus key..."); ctx.wallet .gen_key( - SchemeType::Ed25519Consensus, + SchemeType::Ed25519, Some(consensus_key_alias.clone()), unsafe_dont_encrypt, ) @@ -220,7 +220,7 @@ pub async fn submit_init_validator( println!("Generating staking reward account key..."); ctx.wallet .gen_key( - SchemeType::Ed25519Consensus, + SchemeType::Ed25519, Some(rewards_key_alias.clone()), unsafe_dont_encrypt, ) diff --git a/apps/src/lib/wallet/store.rs b/apps/src/lib/wallet/store.rs index 70af381426..d60af1be96 100644 --- a/apps/src/lib/wallet/store.rs +++ b/apps/src/lib/wallet/store.rs @@ -507,16 +507,12 @@ pub fn gen_sk(scheme: SchemeType) -> common::SecretKey { use rand::rngs::OsRng; let mut csprng = OsRng {}; match scheme { - SchemeType::Ed25519Consensus => { - ed25519::SigScheme::generate(&mut csprng) - .try_to_sk() - .unwrap() - } - SchemeType::Secp256k1Consensus => { - secp256k1::SigScheme::generate(&mut csprng) - .try_to_sk() - .unwrap() - } + SchemeType::Ed25519 => ed25519::SigScheme::generate(&mut csprng) + .try_to_sk() + .unwrap(), + SchemeType::Secp256k1 => secp256k1::SigScheme::generate(&mut csprng) + .try_to_sk() + .unwrap(), SchemeType::Common => common::SigScheme::generate(&mut csprng) .try_to_sk() .unwrap(), From 6b080b03695d65c98a1e5c7fa7c7602f61fd6d67 Mon Sep 17 00:00:00 2001 From: brentstone Date: Mon, 27 Jun 2022 23:49:27 +0200 Subject: [PATCH 069/118] remove Result layering for id_from_pk --- apps/src/lib/client/utils.rs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/apps/src/lib/client/utils.rs b/apps/src/lib/client/utils.rs index d11f9d8632..391164d178 100644 --- a/apps/src/lib/client/utils.rs +++ b/apps/src/lib/client/utils.rs @@ -341,7 +341,7 @@ pub async fn join_network( .. } = peer { - node_id.as_ref().unwrap() != peer_id + node_id != *peer_id } else { true } @@ -359,11 +359,8 @@ pub async fn join_network( const TENDERMINT_NODE_ID_LENGTH: usize = 20; /// Derive Tendermint node ID from public key -fn id_from_pk( - pk: &common::PublicKey, -) -> Result { - let pk_bytes = pk.try_to_vec(); - let digest = Sha256::digest(pk_bytes.unwrap().as_slice()); +fn id_from_pk(pk: &common::PublicKey) -> TendermintNodeId { + let digest = Sha256::digest(pk.try_to_vec().unwrap().as_slice()); let mut bytes = [0u8; TENDERMINT_NODE_ID_LENGTH]; let pk_bytes = match pk { common::PublicKey::Ed25519(_pk) => _pk.try_to_vec().unwrap(), @@ -371,7 +368,7 @@ fn id_from_pk( }; let digest = Sha256::digest(pk_bytes.as_slice()); bytes.copy_from_slice(&digest[..TENDERMINT_NODE_ID_LENGTH]); - Ok(TendermintNodeId::new(bytes)) + TendermintNodeId::new(bytes) } /// Initialize a new test network from the given configuration. @@ -469,7 +466,7 @@ pub fn init_network( }); // Derive the node ID from the node key - let node_id: TendermintNodeId = id_from_pk(&node_pk).unwrap(); + let node_id: TendermintNodeId = id_from_pk(&node_pk); // Build the list of persistent peers from the validators' node IDs let peer = TendermintAddress::from_str(&format!( From 3d1586893f8593c451f3b79cd083091370df9a0a Mon Sep 17 00:00:00 2001 From: brentstone Date: Tue, 28 Jun 2022 18:45:34 +0200 Subject: [PATCH 070/118] clean up code implementing Serialize/Deserialize, comment on certain implementations --- shared/src/types/key/secp256k1.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/shared/src/types/key/secp256k1.rs b/shared/src/types/key/secp256k1.rs index 90fbc82376..b83d98c720 100644 --- a/shared/src/types/key/secp256k1.rs +++ b/shared/src/types/key/secp256k1.rs @@ -270,12 +270,18 @@ impl super::Signature for Signature { } } +// Would ideally like Serialize, Deserialize to be implemented in libsecp256k1, may try to do so and merge +// upstream in the future. + impl Serialize for Signature { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let arr = self.0.serialize(); + // TODO: implement the line below, currently cannot support [u8; 64] + // serde::Serialize::serialize(&arr, serializer) + let mut seq = serializer.serialize_tuple(arr.len())?; for elem in &arr[..] { seq.serialize_element(elem)?; From b645b4313b8520de12a6fad5579399097e6c95e6 Mon Sep 17 00:00:00 2001 From: brentstone Date: Tue, 28 Jun 2022 22:44:23 +0200 Subject: [PATCH 071/118] change variable names in fns try_to_sk() and try_to_sig() to reduce confusion --- shared/src/types/key/common.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/shared/src/types/key/common.rs b/shared/src/types/key/common.rs index e536a7171d..3cdec73bb9 100644 --- a/shared/src/types/key/common.rs +++ b/shared/src/types/key/common.rs @@ -233,13 +233,6 @@ impl super::Signature for Signature { ) .map_err(ParseSignatureError::InvalidEncoding)?, )) - } else if SIG::TYPE == secp256k1::Signature::TYPE { - Ok(Self::Secp256k1( - secp256k1::Signature::try_from_slice( - sig.try_to_vec().unwrap().as_slice(), - ) - .map_err(ParseSignatureError::InvalidEncoding)?, - )) } else { Err(ParseSignatureError::MismatchedScheme) } From db2e69c848b5ca687c3356053e0e765922ed44c5 Mon Sep 17 00:00:00 2001 From: brentstone Date: Wed, 29 Jun 2022 12:57:36 +0200 Subject: [PATCH 072/118] convert from common to underlying key type in id_from_pk() when constructing the TendermintNodeId --- apps/src/lib/client/utils.rs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/apps/src/lib/client/utils.rs b/apps/src/lib/client/utils.rs index 391164d178..4cda41e9bb 100644 --- a/apps/src/lib/client/utils.rs +++ b/apps/src/lib/client/utils.rs @@ -360,14 +360,20 @@ const TENDERMINT_NODE_ID_LENGTH: usize = 20; /// Derive Tendermint node ID from public key fn id_from_pk(pk: &common::PublicKey) -> TendermintNodeId { - let digest = Sha256::digest(pk.try_to_vec().unwrap().as_slice()); let mut bytes = [0u8; TENDERMINT_NODE_ID_LENGTH]; - let pk_bytes = match pk { - common::PublicKey::Ed25519(_pk) => _pk.try_to_vec().unwrap(), - common::PublicKey::Secp256k1(_pk) => _pk.try_to_vec().unwrap(), - }; - let digest = Sha256::digest(pk_bytes.as_slice()); - bytes.copy_from_slice(&digest[..TENDERMINT_NODE_ID_LENGTH]); + + match pk { + common::PublicKey::Ed25519(_) => { + let _pk: ed25519::PublicKey = pk.try_to_pk().unwrap(); + let digest = Sha256::digest(_pk.try_to_vec().unwrap().as_slice()); + bytes.copy_from_slice(&digest[..TENDERMINT_NODE_ID_LENGTH]); + } + common::PublicKey::Secp256k1(_) => { + let _pk: secp256k1::PublicKey = pk.try_to_pk().unwrap(); + let digest = Sha256::digest(_pk.try_to_vec().unwrap().as_slice()); + bytes.copy_from_slice(&digest[..TENDERMINT_NODE_ID_LENGTH]); + } + } TendermintNodeId::new(bytes) } From f0f5b2f625079826ee36aee4bc8cb3dffb1a9a0b Mon Sep 17 00:00:00 2001 From: brentstone Date: Wed, 29 Jun 2022 14:38:57 +0200 Subject: [PATCH 073/118] improve write_tendermint_node_key() to produce the proper json given the underlying key scheme --- apps/src/lib/client/utils.rs | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/apps/src/lib/client/utils.rs b/apps/src/lib/client/utils.rs index 4cda41e9bb..9c650f6db5 100644 --- a/apps/src/lib/client/utils.rs +++ b/apps/src/lib/client/utils.rs @@ -1176,15 +1176,20 @@ fn write_tendermint_node_key( node_sk: common::SecretKey, ) -> common::PublicKey { let node_pk: common::PublicKey = node_sk.ref_to(); - // Convert and write the keypair into Tendermint - // node_key.json file - let node_keypair = - [node_sk.try_to_vec().unwrap(), node_pk.try_to_vec().unwrap()].concat(); - - let key_str = match node_sk { - common::SecretKey::Ed25519(_) => "Ed25519", - common::SecretKey::Secp256k1(_) => "Secp256k1", + + // Convert and write the keypair into Tendermint node_key.json file. + // Tendermint requires concatenating the private-public keys for ed25519 + // but does not for secp256k1. + let (node_keypair, key_str) = match node_sk { + common::SecretKey::Ed25519(_) => { + ([node_sk.try_to_vec().unwrap(), node_pk.try_to_vec().unwrap()].concat(), + "Ed25519") + }, + common::SecretKey::Secp256k1(_) => { + (node_sk.try_to_vec().unwrap(), "Secp256k1") + }, }; + let tm_node_keypair_json = json!({ "priv_key": { "type": format!("tendermint/PrivKey{}",key_str), From e39e9b0d7f2a3b8a14e014b0a09b67e8b21b9519 Mon Sep 17 00:00:00 2001 From: brentstone Date: Wed, 29 Jun 2022 22:07:21 +0200 Subject: [PATCH 074/118] allow CL specification of a specific key scheme for the TxInitValidator --- apps/src/lib/cli.rs | 4 ++-- apps/src/lib/client/tx.rs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/src/lib/cli.rs b/apps/src/lib/cli.rs index 8a013deef9..a629fdf1c9 100644 --- a/apps/src/lib/cli.rs +++ b/apps/src/lib/cli.rs @@ -3062,8 +3062,8 @@ pub mod args { use this for keys used in a live network.", )) .arg(SCHEME.def().about( - "The key scheme/type used for the validator keys. Currently \ - supports ed25519 and secp256k1." + "The key scheme/type used for the validator keys. \ + Currently supports ed25519 and secp256k1.", )) } } diff --git a/apps/src/lib/client/tx.rs b/apps/src/lib/client/tx.rs index cb5da89387..c6b2c9b254 100644 --- a/apps/src/lib/client/tx.rs +++ b/apps/src/lib/client/tx.rs @@ -195,7 +195,7 @@ pub async fn submit_init_validator( println!("Generating validator account key..."); ctx.wallet .gen_key( - SchemeType::Ed25519, + scheme, Some(validator_key_alias.clone()), unsafe_dont_encrypt, ) @@ -208,7 +208,7 @@ pub async fn submit_init_validator( println!("Generating consensus key..."); ctx.wallet .gen_key( - SchemeType::Ed25519, + scheme, Some(consensus_key_alias.clone()), unsafe_dont_encrypt, ) @@ -220,7 +220,7 @@ pub async fn submit_init_validator( println!("Generating staking reward account key..."); ctx.wallet .gen_key( - SchemeType::Ed25519, + scheme, Some(rewards_key_alias.clone()), unsafe_dont_encrypt, ) From db6f61fa069e5d126b7f1f278de4fe5f5a2edbe0 Mon Sep 17 00:00:00 2001 From: brentstone Date: Wed, 29 Jun 2022 22:08:14 +0200 Subject: [PATCH 075/118] clean and simplify code in id_from_pk() --- apps/src/lib/client/utils.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/apps/src/lib/client/utils.rs b/apps/src/lib/client/utils.rs index 9c650f6db5..4d796943b9 100644 --- a/apps/src/lib/client/utils.rs +++ b/apps/src/lib/client/utils.rs @@ -1181,13 +1181,14 @@ fn write_tendermint_node_key( // Tendermint requires concatenating the private-public keys for ed25519 // but does not for secp256k1. let (node_keypair, key_str) = match node_sk { - common::SecretKey::Ed25519(_) => { - ([node_sk.try_to_vec().unwrap(), node_pk.try_to_vec().unwrap()].concat(), - "Ed25519") - }, + common::SecretKey::Ed25519(_) => ( + [node_sk.try_to_vec().unwrap(), node_pk.try_to_vec().unwrap()] + .concat(), + "Ed25519", + ), common::SecretKey::Secp256k1(_) => { (node_sk.try_to_vec().unwrap(), "Secp256k1") - }, + } }; let tm_node_keypair_json = json!({ From 1be249cf0944199b854ab10700ab63b1a5fcf54d Mon Sep 17 00:00:00 2001 From: brentstone Date: Mon, 4 Jul 2022 13:56:11 +0200 Subject: [PATCH 076/118] fix bug in supplying keypair to Tendermint --- apps/src/lib/client/utils.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/src/lib/client/utils.rs b/apps/src/lib/client/utils.rs index 4d796943b9..21de818fb2 100644 --- a/apps/src/lib/client/utils.rs +++ b/apps/src/lib/client/utils.rs @@ -1181,13 +1181,13 @@ fn write_tendermint_node_key( // Tendermint requires concatenating the private-public keys for ed25519 // but does not for secp256k1. let (node_keypair, key_str) = match node_sk { - common::SecretKey::Ed25519(_) => ( - [node_sk.try_to_vec().unwrap(), node_pk.try_to_vec().unwrap()] + common::SecretKey::Ed25519(sk) => ( + [sk.try_to_vec().unwrap(), sk.ref_to().try_to_vec().unwrap()] .concat(), "Ed25519", ), - common::SecretKey::Secp256k1(_) => { - (node_sk.try_to_vec().unwrap(), "Secp256k1") + common::SecretKey::Secp256k1(sk) => { + (sk.try_to_vec().unwrap(), "Secp256k1") } }; From f320caa7fa2fba416823b2ce82376afd9de18a25 Mon Sep 17 00:00:00 2001 From: brentstone Date: Mon, 4 Jul 2022 13:59:31 +0200 Subject: [PATCH 077/118] fix some comments --- shared/src/types/key/mod.rs | 5 ++--- shared/src/types/key/secp256k1.rs | 2 -- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/shared/src/types/key/mod.rs b/shared/src/types/key/mod.rs index a1323a4bc6..c88fe85ffa 100644 --- a/shared/src/types/key/mod.rs +++ b/shared/src/types/key/mod.rs @@ -205,7 +205,7 @@ pub trait PublicKey: Err(ParsePublicKeyError::MismatchedScheme) } } - /// Convert from self to another SecretKey type + /// Convert from self to another PublicKey type fn try_to_pk(&self) -> Result { PK::try_from_pk(self) } @@ -434,8 +434,7 @@ macro_rules! sigscheme_test { println!("Secret key: {}", secret_key); } - /// Run `cargo test gen_keypair -- --nocapture` to generate a - /// new keypair. + /// Sign a simple message and verify the signature. #[test] fn gen_sign_verify() { use rand::prelude::ThreadRng; diff --git a/shared/src/types/key/secp256k1.rs b/shared/src/types/key/secp256k1.rs index b83d98c720..dc7c16bade 100644 --- a/shared/src/types/key/secp256k1.rs +++ b/shared/src/types/key/secp256k1.rs @@ -7,8 +7,6 @@ use std::io::{ErrorKind, Write}; use std::str::FromStr; use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; use serde::Serializer; - -//use libsecp256k1::util::SECRET_KEY_SIZE; use sha2::{Digest, Sha256}; #[cfg(feature = "rand")] From 365c001e59509d75ded5b0dddca0e9f1070a2730 Mon Sep 17 00:00:00 2001 From: brentstone Date: Mon, 4 Jul 2022 14:00:30 +0200 Subject: [PATCH 078/118] e2e test_genesis_validators(): make each validator have different key scheme --- tests/src/e2e/ledger_tests.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/src/e2e/ledger_tests.rs b/tests/src/e2e/ledger_tests.rs index f150e6eac0..0e6fea4c92 100644 --- a/tests/src/e2e/ledger_tests.rs +++ b/tests/src/e2e/ledger_tests.rs @@ -1562,7 +1562,7 @@ fn test_genesis_validators() -> Result<()> { } }; - // 1. Setup 2 genesis validators + // 1. Setup 2 genesis validators, one with ed25519 keys (0) and one with secp256k1 keys (1) let validator_0_alias = "validator-0"; let validator_1_alias = "validator-1"; @@ -1574,6 +1574,7 @@ fn test_genesis_validators() -> Result<()> { "--unsafe-dont-encrypt", "--alias", validator_0_alias, + "--scheme ed25519", "--net-address", &format!("127.0.0.1:{}", get_first_port(0)), ], @@ -1610,6 +1611,7 @@ fn test_genesis_validators() -> Result<()> { "--unsafe-dont-encrypt", "--alias", validator_1_alias, + "--scheme secp256k1", "--net-address", &format!("127.0.0.1:{}", get_first_port(1)), ], From 97e8d3a6cc233b4ff13d36652273e57f3f2ab01f Mon Sep 17 00:00:00 2001 From: brentstone Date: Tue, 5 Jul 2022 15:08:19 +0200 Subject: [PATCH 079/118] fix unit test test_toml_roundtrip to supply good validator keys --- apps/src/lib/wallet/store.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/apps/src/lib/wallet/store.rs b/apps/src/lib/wallet/store.rs index d60af1be96..76a2053419 100644 --- a/apps/src/lib/wallet/store.rs +++ b/apps/src/lib/wallet/store.rs @@ -524,10 +524,23 @@ mod test_wallet { use super::*; #[test] - fn test_toml_roundtrip() { + fn test_toml_roundtrip_ed25519() { let mut store = Store::new(); let validator_keys = - Store::gen_validator_keys(None, SchemeType::Common); + Store::gen_validator_keys(None, SchemeType::Ed25519); + store.add_validator_data( + Address::decode("atest1v4ehgw36x3prswzxggunzv6pxqmnvdj9xvcyzvpsggeyvs3cg9qnywf589qnwvfsg5erg3fkl09rg5").unwrap(), + validator_keys + ); + let data = store.encode(); + let _ = Store::decode(data).expect("Test failed"); + } + + #[test] + fn test_toml_roundtrip_secp256k1() { + let mut store = Store::new(); + let validator_keys = + Store::gen_validator_keys(None, SchemeType::Secp256k1); store.add_validator_data( Address::decode("atest1v4ehgw36x3prswzxggunzv6pxqmnvdj9xvcyzvpsggeyvs3cg9qnywf589qnwvfsg5erg3fkl09rg5").unwrap(), validator_keys From 85133eff6c415fe94ebfeea104c9f8a786a1a74a Mon Sep 17 00:00:00 2001 From: brentstone Date: Tue, 5 Jul 2022 15:09:49 +0200 Subject: [PATCH 080/118] make fmt --- apps/src/lib/wallet/mod.rs | 2 +- shared/src/types/key/secp256k1.rs | 73 +++++++++++++++++-------------- tests/src/e2e/ledger_tests.rs | 3 +- 3 files changed, 43 insertions(+), 35 deletions(-) diff --git a/apps/src/lib/wallet/mod.rs b/apps/src/lib/wallet/mod.rs index 7b0afd899d..5bdf8e6261 100644 --- a/apps/src/lib/wallet/mod.rs +++ b/apps/src/lib/wallet/mod.rs @@ -135,7 +135,7 @@ impl Wallet { Some(Err(err)) => Err(err), other => Ok(Store::gen_validator_keys( other.map(|res| res.unwrap().as_ref().clone()), - SchemeType::Common + SchemeType::Common, )), } } diff --git a/shared/src/types/key/secp256k1.rs b/shared/src/types/key/secp256k1.rs index dc7c16bade..677fc3c4b3 100644 --- a/shared/src/types/key/secp256k1.rs +++ b/shared/src/types/key/secp256k1.rs @@ -5,22 +5,20 @@ use std::fmt::{Debug, Display}; use std::hash::{Hash, Hasher}; use std::io::{ErrorKind, Write}; use std::str::FromStr; -use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; -use serde::Serializer; -use sha2::{Digest, Sha256}; +use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; #[cfg(feature = "rand")] use rand::{CryptoRng, RngCore}; -use serde::{Deserialize,Serialize}; use serde::de::{Error, SeqAccess, Visitor}; use serde::ser::SerializeTuple; +use serde::{Deserialize, Serialize, Serializer}; +use sha2::{Digest, Sha256}; use super::{ ParsePublicKeyError, ParseSecretKeyError, ParseSignatureError, RefTo, SchemeType, SigScheme as SigSchemeTrait, VerifySigError, }; - /// secp256k1 public key #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] pub struct PublicKey(pub libsecp256k1::PublicKey); @@ -50,9 +48,9 @@ impl BorshDeserialize for PublicKey { // deserialize the bytes first let pk = libsecp256k1::PublicKey::parse_compressed( buf.get(0..libsecp256k1::util::COMPRESSED_PUBLIC_KEY_SIZE) - .ok_or_else(|| std::io::Error::from(ErrorKind::UnexpectedEof))? - .try_into() - .unwrap(), + .ok_or_else(|| std::io::Error::from(ErrorKind::UnexpectedEof))? + .try_into() + .unwrap(), ) .map_err(|e| { std::io::Error::new( @@ -100,13 +98,17 @@ impl Hash for PublicKey { impl PartialOrd for PublicKey { fn partial_cmp(&self, other: &Self) -> Option { - self.0.serialize_compressed().partial_cmp(&other.0.serialize_compressed()) + self.0 + .serialize_compressed() + .partial_cmp(&other.0.serialize_compressed()) } } impl Ord for PublicKey { fn cmp(&self, other: &Self) -> std::cmp::Ordering { - self.0.serialize_compressed().cmp(&other.0.serialize_compressed()) + self.0 + .serialize_compressed() + .cmp(&other.0.serialize_compressed()) } } @@ -159,7 +161,7 @@ impl super::SecretKey for SecretKey { } impl Serialize for SecretKey { - fn serialize(&self, serializer: S) -> Result + fn serialize(&self, serializer: S) -> Result where S: Serializer, { @@ -171,9 +173,10 @@ impl Serialize for SecretKey { impl<'de> Deserialize<'de> for SecretKey { fn deserialize(deserializer: D) -> Result where - D: serde::Deserializer<'de> + D: serde::Deserializer<'de>, { - let arr_res: [u8; libsecp256k1::util::SECRET_KEY_SIZE] = serde::Deserialize::deserialize(deserializer)?; + let arr_res: [u8; libsecp256k1::util::SECRET_KEY_SIZE] = + serde::Deserialize::deserialize(deserializer)?; let key = libsecp256k1::SecretKey::parse_slice(&arr_res) .map_err(D::Error::custom); Ok(SecretKey(key.unwrap())) @@ -268,11 +271,11 @@ impl super::Signature for Signature { } } -// Would ideally like Serialize, Deserialize to be implemented in libsecp256k1, may try to do so and merge -// upstream in the future. +// Would ideally like Serialize, Deserialize to be implemented in libsecp256k1, +// may try to do so and merge upstream in the future. impl Serialize for Signature { - fn serialize(&self, serializer: S) -> Result + fn serialize(&self, serializer: S) -> Result where S: Serializer, { @@ -290,8 +293,8 @@ impl Serialize for Signature { impl<'de> Deserialize<'de> for Signature { fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de> + where + D: serde::Deserializer<'de>, { struct ByteArrayVisitor; @@ -299,7 +302,10 @@ impl<'de> Deserialize<'de> for Signature { type Value = [u8; libsecp256k1::util::SIGNATURE_SIZE]; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str(&format!("an array of length {}", libsecp256k1::util::SIGNATURE_SIZE)) + formatter.write_str(&format!( + "an array of length {}", + libsecp256k1::util::SIGNATURE_SIZE + )) } fn visit_seq(self, mut seq: A) -> Result<[u8; 64], A::Error> @@ -309,18 +315,21 @@ impl<'de> Deserialize<'de> for Signature { let mut arr = [0u8; libsecp256k1::util::SIGNATURE_SIZE]; #[allow(clippy::needless_range_loop)] for i in 0..libsecp256k1::util::SIGNATURE_SIZE { - arr[i] = seq.next_element()? + arr[i] = seq + .next_element()? .ok_or_else(|| Error::invalid_length(i, &self))?; } Ok(arr) } } - let arr_res = deserializer.deserialize_tuple(libsecp256k1::util::SIGNATURE_SIZE, ByteArrayVisitor)?; + let arr_res = deserializer.deserialize_tuple( + libsecp256k1::util::SIGNATURE_SIZE, + ByteArrayVisitor, + )?; let sig = libsecp256k1::Signature::parse_standard(&arr_res) .map_err(D::Error::custom); Ok(Signature(sig.unwrap())) - } } @@ -433,13 +442,11 @@ impl super::SigScheme for SigScheme { let check = libsecp256k1::verify(message, &sig.0, &pk.0); match check { true => Ok(()), - false => Err(VerifySigError::SigVerifyError( - format!("Error verifying secp256k1 signature: {}",libsecp256k1::Error::InvalidSignature) - )), + false => Err(VerifySigError::SigVerifyError(format!( + "Error verifying secp256k1 signature: {}", + libsecp256k1::Error::InvalidSignature + ))), } - - - } fn verify_signature_raw( @@ -450,13 +457,13 @@ impl super::SigScheme for SigScheme { let hash = Sha256::digest(data); let message = &libsecp256k1::Message::parse_slice(hash.as_ref()) .expect("Error parsing raw data"); - let check = libsecp256k1::verify(message,&sig.0, &pk.0); + let check = libsecp256k1::verify(message, &sig.0, &pk.0); match check { true => Ok(()), - false => Err(VerifySigError::SigVerifyError( - format!("Error verifying secp256k1 signature: {}",libsecp256k1::Error::InvalidSignature) - )), + false => Err(VerifySigError::SigVerifyError(format!( + "Error verifying secp256k1 signature: {}", + libsecp256k1::Error::InvalidSignature + ))), } - } } diff --git a/tests/src/e2e/ledger_tests.rs b/tests/src/e2e/ledger_tests.rs index 0e6fea4c92..526b96261c 100644 --- a/tests/src/e2e/ledger_tests.rs +++ b/tests/src/e2e/ledger_tests.rs @@ -1562,7 +1562,8 @@ fn test_genesis_validators() -> Result<()> { } }; - // 1. Setup 2 genesis validators, one with ed25519 keys (0) and one with secp256k1 keys (1) + // 1. Setup 2 genesis validators, one with ed25519 keys (0) and one with + // secp256k1 keys (1) let validator_0_alias = "validator-0"; let validator_1_alias = "validator-1"; From 3b1fd96140fbe3b70b9aa04b3112d11fafce43a3 Mon Sep 17 00:00:00 2001 From: brentstone Date: Wed, 6 Jul 2022 17:33:01 +0200 Subject: [PATCH 081/118] fix bug where we were generating a key with common scheme --- apps/src/lib/client/utils.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/src/lib/client/utils.rs b/apps/src/lib/client/utils.rs index 21de818fb2..cc32eb70ae 100644 --- a/apps/src/lib/client/utils.rs +++ b/apps/src/lib/client/utils.rs @@ -459,10 +459,11 @@ pub fn init_network( format!("validator {name} Tendermint node key"), &config.tendermint_node_key, ) - .map(|pk| common::PublicKey::try_from_pk(&pk).unwrap()) .unwrap_or_else(|| { - // Generate a node key - let node_sk = common::SigScheme::generate(&mut rng); + // Generate a node key with ed25519 as default + let node_sk = common::SecretKey::Ed25519( + ed25519::SigScheme::generate(&mut rng), + ); let node_pk = write_tendermint_node_key(&tm_home_dir, node_sk); From 9eb60167ec0fe3fab9e511acd5b1dcaeed9e3cfe Mon Sep 17 00:00:00 2001 From: brentstone Date: Wed, 6 Jul 2022 23:45:44 +0200 Subject: [PATCH 082/118] fix bug to prevent generating keys with common SchemeType --- apps/src/lib/client/utils.rs | 12 ++++++------ apps/src/lib/wallet/mod.rs | 6 +++++- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/apps/src/lib/client/utils.rs b/apps/src/lib/client/utils.rs index cc32eb70ae..5b45426d5a 100644 --- a/apps/src/lib/client/utils.rs +++ b/apps/src/lib/client/utils.rs @@ -533,7 +533,7 @@ pub fn init_network( let alias = format!("{}-consensus-key", name); println!("Generating validator {} consensus key...", name); let (_alias, keypair) = wallet.gen_key( - SchemeType::Common, + SchemeType::Ed25519, Some(alias), unsafe_dont_encrypt, ); @@ -556,7 +556,7 @@ pub fn init_network( let alias = format!("{}-account-key", name); println!("Generating validator {} account key...", name); let (_alias, keypair) = wallet.gen_key( - SchemeType::Common, + SchemeType::Ed25519, Some(alias), unsafe_dont_encrypt, ); @@ -574,7 +574,7 @@ pub fn init_network( name ); let (_alias, keypair) = wallet.gen_key( - SchemeType::Common, + SchemeType::Ed25519, Some(alias), unsafe_dont_encrypt, ); @@ -589,7 +589,7 @@ pub fn init_network( let alias = format!("{}-protocol-key", name); println!("Generating validator {} protocol signing key...", name); let (_alias, keypair) = wallet.gen_key( - SchemeType::Common, + SchemeType::Ed25519, Some(alias), unsafe_dont_encrypt, ); @@ -748,7 +748,7 @@ pub fn init_network( name ); let (_alias, keypair) = wallet.gen_key( - SchemeType::Common, + SchemeType::Ed25519, Some(name.clone()), unsafe_dont_encrypt, ); @@ -1040,7 +1040,7 @@ fn init_established_account( if config.public_key.is_none() { println!("Generating established account {} key...", name.as_ref()); let (_alias, keypair) = wallet.gen_key( - SchemeType::Common, + SchemeType::Ed25519, Some(format!("{}-key", name.as_ref())), unsafe_dont_encrypt, ); diff --git a/apps/src/lib/wallet/mod.rs b/apps/src/lib/wallet/mod.rs index 5bdf8e6261..b5c68dd2c1 100644 --- a/apps/src/lib/wallet/mod.rs +++ b/apps/src/lib/wallet/mod.rs @@ -120,6 +120,10 @@ impl Wallet { &mut self, protocol_pk: Option, ) -> Result { + let scheme = match protocol_pk.as_ref().unwrap() { + common::PublicKey::Ed25519(_) => SchemeType::Ed25519, + common::PublicKey::Secp256k1(_) => SchemeType::Secp256k1, + }; let protocol_keypair = protocol_pk.map(|pk| { self.find_key_by_pkh(&PublicKeyHash::from(&pk)) .ok() @@ -135,7 +139,7 @@ impl Wallet { Some(Err(err)) => Err(err), other => Ok(Store::gen_validator_keys( other.map(|res| res.unwrap().as_ref().clone()), - SchemeType::Common, + scheme, )), } } From 96b68c9b0e37321a7af72992f90a8c7740c5d897 Mon Sep 17 00:00:00 2001 From: brentstone Date: Fri, 8 Jul 2022 11:01:57 +0200 Subject: [PATCH 083/118] make validator_key_to_json() compatible with ed25519 and secp256k1 keys --- apps/src/lib/node/ledger/tendermint_node.rs | 52 ++++++++++++++------- 1 file changed, 34 insertions(+), 18 deletions(-) diff --git a/apps/src/lib/node/ledger/tendermint_node.rs b/apps/src/lib/node/ledger/tendermint_node.rs index c38146cd35..8a52dd669a 100644 --- a/apps/src/lib/node/ledger/tendermint_node.rs +++ b/apps/src/lib/node/ledger/tendermint_node.rs @@ -248,27 +248,43 @@ pub fn reset(tendermint_dir: impl AsRef) -> Result<()> { /// Convert a common signing scheme validator key into JSON for /// Tendermint -fn validator_key_to_json( +fn validator_key_to_json( address: &Address, - sk: &SK, + sk: &common::SecretKey, ) -> std::result::Result { let address = address.raw_hash().unwrap(); - ed25519::SecretKey::try_from_sk(sk).map(|sk| { - let pk: ed25519::PublicKey = sk.ref_to(); - let ck_arr = - [sk.try_to_vec().unwrap(), pk.try_to_vec().unwrap()].concat(); - json!({ - "address": address, - "pub_key": { - "type": "tendermint/PubKeyEd25519", - "value": base64::encode(pk.try_to_vec().unwrap()), - }, - "priv_key": { - "type": "tendermint/PrivKeyEd25519", - "value": base64::encode(ck_arr), - } - }) - }) + + let (id_str, pk_arr, kp_arr) = match sk { + common::SecretKey::Ed25519(_) => { + let sk_ed: ed25519::SecretKey = sk.try_to_sk().unwrap(); + let keypair = [ + sk_ed.try_to_vec().unwrap(), + sk_ed.ref_to().try_to_vec().unwrap(), + ] + .concat(); + ("Ed25519", sk_ed.ref_to().try_to_vec().unwrap(), keypair) + } + common::SecretKey::Secp256k1(_) => { + let sk_sec: secp256k1::SecretKey = sk.try_to_sk().unwrap(); + ( + "Secp256k1", + sk_sec.ref_to().try_to_vec().unwrap(), + sk_sec.try_to_vec().unwrap(), + ) + } + }; + + Ok(json!({ + "address": address, + "pub_key": { + "type": format!("tendermint/PubKey{}",id_str), + "value": base64::encode(pk_arr), + }, + "priv_key": { + "type": format!("tendermint/PrivKey{}",id_str), + "value": base64::encode(kp_arr), + } + })) } /// Initialize validator private key for Tendermint From 9da15544333d3c1b3585f9ebe41aa853aff0d928 Mon Sep 17 00:00:00 2001 From: brentstone Date: Fri, 8 Jul 2022 11:14:48 +0200 Subject: [PATCH 084/118] fix bug in supplying args to test_genesis_validators() --- tests/src/e2e/ledger_tests.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/src/e2e/ledger_tests.rs b/tests/src/e2e/ledger_tests.rs index 526b96261c..f863aee905 100644 --- a/tests/src/e2e/ledger_tests.rs +++ b/tests/src/e2e/ledger_tests.rs @@ -1575,7 +1575,8 @@ fn test_genesis_validators() -> Result<()> { "--unsafe-dont-encrypt", "--alias", validator_0_alias, - "--scheme ed25519", + "--scheme", + "ed25519", "--net-address", &format!("127.0.0.1:{}", get_first_port(0)), ], @@ -1612,7 +1613,8 @@ fn test_genesis_validators() -> Result<()> { "--unsafe-dont-encrypt", "--alias", validator_1_alias, - "--scheme secp256k1", + "--scheme", + "secp256k1", "--net-address", &format!("127.0.0.1:{}", get_first_port(1)), ], From 38e627097f0ab9a3688b1981463f54d1ee357e9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zemanovi=C4=8D?= Date: Fri, 5 Aug 2022 18:16:29 +0200 Subject: [PATCH 085/118] add a test to zeroize secp256k1 --- shared/src/types/key/mod.rs | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/shared/src/types/key/mod.rs b/shared/src/types/key/mod.rs index c88fe85ffa..1e12667346 100644 --- a/shared/src/types/key/mod.rs +++ b/shared/src/types/key/mod.rs @@ -465,11 +465,26 @@ mod more_tests { fn zeroize_keypair_ed25519() { use rand::thread_rng; - let sk = ed25519::SecretKey(Box::new( - ed25519_consensus::SigningKey::new(thread_rng()), - )); - let len = sk.0.as_bytes().len(); - let ptr = sk.0.as_bytes().as_ptr(); + let sk = ed25519::SigScheme::generate(&mut thread_rng()); + let sk_bytes = sk.0.as_bytes(); + let len = sk_bytes.len(); + let ptr = sk_bytes.as_ptr(); + + drop(sk); + + assert_eq!(&[0u8; 32], unsafe { + core::slice::from_raw_parts(ptr, len) + }); + } + + #[test] + fn zeroize_keypair_seck256k1() { + use rand::thread_rng; + + let sk = secp256k1::SigScheme::generate(&mut thread_rng()); + let sk_bytes = sk.0.serialize(); + let len = sk_bytes.len(); + let ptr = sk_bytes.as_ptr(); drop(sk); From 505b57a6df5bdcaf064f4216595fdc52057bd8df Mon Sep 17 00:00:00 2001 From: brentstone Date: Wed, 10 Aug 2022 11:16:29 -0400 Subject: [PATCH 086/118] wrap libsecp256k1::SecretKey in a Box within SecretKey struct --- shared/src/types/key/secp256k1.rs | 10 +++++----- wasm/checksums.json | 30 +++++++++++++++--------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/shared/src/types/key/secp256k1.rs b/shared/src/types/key/secp256k1.rs index 677fc3c4b3..18d74dd5e8 100644 --- a/shared/src/types/key/secp256k1.rs +++ b/shared/src/types/key/secp256k1.rs @@ -136,7 +136,7 @@ impl From for PublicKey { /// Secp256k1 secret key #[derive(Debug, Clone)] -pub struct SecretKey(pub libsecp256k1::SecretKey); +pub struct SecretKey(pub Box); impl super::SecretKey for SecretKey { type PublicKey = PublicKey; @@ -179,14 +179,14 @@ impl<'de> Deserialize<'de> for SecretKey { serde::Deserialize::deserialize(deserializer)?; let key = libsecp256k1::SecretKey::parse_slice(&arr_res) .map_err(D::Error::custom); - Ok(SecretKey(key.unwrap())) + Ok(SecretKey(Box::new(key.unwrap()))) } } impl BorshDeserialize for SecretKey { fn deserialize(buf: &mut &[u8]) -> std::io::Result { // deserialize the bytes first - Ok(SecretKey( + Ok(SecretKey(Box::new( libsecp256k1::SecretKey::parse( &(BorshDeserialize::deserialize(buf)?), ) @@ -196,7 +196,7 @@ impl BorshDeserialize for SecretKey { format!("Error decoding secp256k1 secret key: {}", e), ) })?, - )) + ))) } } @@ -417,7 +417,7 @@ impl super::SigScheme for SigScheme { where R: CryptoRng + RngCore, { - SecretKey(libsecp256k1::SecretKey::random(csprng)) + SecretKey(Box::new(libsecp256k1::SecretKey::random(csprng))) } /// Sign the data with a key diff --git a/wasm/checksums.json b/wasm/checksums.json index ffbac6d9b0..e4809b538c 100644 --- a/wasm/checksums.json +++ b/wasm/checksums.json @@ -1,19 +1,19 @@ { - "tx_bond.wasm": "tx_bond.366f7448cfd065184c0ed35df2d6e6957bf92c10079f23e43630c1fec113d68b.wasm", - "tx_from_intent.wasm": "tx_from_intent.b33dd8f843660475405886899710ed70e91b39d1880a86a6acea6a9c8a6fd5aa.wasm", - "tx_ibc.wasm": "tx_ibc.404dd804e5725ea8d4fbfcd7cf3c0681a148a34d284a5fdae799ef5be2179861.wasm", - "tx_init_account.wasm": "tx_init_account.9b1b141a7ed7bd75af9f3ccc401b0a64c161aabf5f8b56ac645920f0fbdb72fb.wasm", - "tx_init_nft.wasm": "tx_init_nft.ede5a3f4e2ce8f2cfdaa664b6b9aca5a461f8317b3f2a4273a29dbde6a1cb8d0.wasm", - "tx_init_proposal.wasm": "tx_init_proposal.d0c03bfe805d90cf7a094e11e4d903fc71f09f871c0b3daedf71172210409fac.wasm", - "tx_init_validator.wasm": "tx_init_validator.5ac10736e2521aa00c06c4cd4165b3587ca95470d947793b9ee2134c1b80220d.wasm", - "tx_mint_nft.wasm": "tx_mint_nft.ec77b12d4e7dfbf998e0c5021d11308e4ace27daf390b6f4c7dcfc04a3d1ff31.wasm", - "tx_transfer.wasm": "tx_transfer.35546938bd04de4e8070addb43275e68e0d9bed7baa159a9804a96494a7cac71.wasm", - "tx_unbond.wasm": "tx_unbond.fbbc6b35d188b9fbeb0f1d0f98434ff00efa7a2ba1fd4d527aa17b920f7f64c5.wasm", + "tx_bond.wasm": "tx_bond.d426722e133c4d386d5378a457f420e969197d24b151cd7085bfe08ec1719ced.wasm", + "tx_from_intent.wasm": "tx_from_intent.b3f9ee85f9ecc8c1c78b73169a567ad59ecf876bb72c76e4f57dbcf3c9dd6e17.wasm", + "tx_ibc.wasm": "tx_ibc.09518b4c922ed1f70699513fe8ab1c8fdc42031622e508fc0bdecdefb66bb9f5.wasm", + "tx_init_account.wasm": "tx_init_account.bfc5617cab4e138436f7dc1fc107c5bad4d94f3f8df5fcb0d95126b9463cea59.wasm", + "tx_init_nft.wasm": "tx_init_nft.d507eb96fa178535b68a3c6080b808b49ca5936300eab0eec7c36d4d3bc148bf.wasm", + "tx_init_proposal.wasm": "tx_init_proposal.295ac0505c98209b7a672504902d5ce523d45a84827388da7c0d60e38079ae01.wasm", + "tx_init_validator.wasm": "tx_init_validator.6f163d3cee0820bf0c555ecd8ee09c081c7d498394a0409b8005d39495ddcaeb.wasm", + "tx_mint_nft.wasm": "tx_mint_nft.df3cb6c43463e94d9cf4b125bd00c1d3d5ccd579beaa32336c5b56ce7957ef05.wasm", + "tx_transfer.wasm": "tx_transfer.3709be4f149050a34bcc84e1d5ec3776be45dedb63b5b224306066ed3fa23d2f.wasm", + "tx_unbond.wasm": "tx_unbond.56086ae05b845037b9cc0bbcbb76c496a95a8041e0eaaef20a881eae6cf0116d.wasm", "tx_update_vp.wasm": "tx_update_vp.cdb6de03931bb5e2d62d1db0d59777c3bb7bfb14214992328d0df95d1851f45e.wasm", - "tx_vote_proposal.wasm": "tx_vote_proposal.257a819ca6bb8cba60c43d5341381c8175dc0b6b1de7ceb07e7e0a8ed11c862d.wasm", - "tx_withdraw.wasm": "tx_withdraw.d11e3e3a6b5f94184f023b579a9bfabc9d268b0c35c11049525dffdbcf6ad948.wasm", - "vp_nft.wasm": "vp_nft.a4eff2933f866250fd98dd65e91d45f08d4ebc49a36df63f0216181b07dc9d8d.wasm", - "vp_testnet_faucet.wasm": "vp_testnet_faucet.6f81a8be815dcab8f8dc726b4a2a01920a21901d02bc23daf097b4bfa35c5318.wasm", + "tx_vote_proposal.wasm": "tx_vote_proposal.06a2ae40b5d8683899debb58b5217647b1d19f1818a2c01a97e1045d72c7cc2a.wasm", + "tx_withdraw.wasm": "tx_withdraw.a2d57125485db6c5162b699333ad23db2586f92d88df91e10642a8911854773e.wasm", + "vp_nft.wasm": "vp_nft.bc74013b04a2944e153d82a7a4f934c35aff87c2cd8daca7a22bfdab970bfadb.wasm", + "vp_testnet_faucet.wasm": "vp_testnet_faucet.f0c4c073c468f35edb7b8cd31dab326e40b00bbb9b2ab9e27c4028526146d066.wasm", "vp_token.wasm": "vp_token.a083be83b0dc78d953999e26dc6b8c10a0e9828c74d365f836c5668533f4e41c.wasm", - "vp_user.wasm": "vp_user.db97989f32edc6c780ae5fc9f5b4296640206b890f273b753fc0ffba317233fd.wasm" + "vp_user.wasm": "vp_user.065595512916500834e721eb4599a109201a10d8304664f6c474ab8200c11744.wasm" } \ No newline at end of file From 3cf25ecd05030b01b8b1fa12730ecdd4a96f9d08 Mon Sep 17 00:00:00 2001 From: brentstone Date: Wed, 10 Aug 2022 11:17:12 -0400 Subject: [PATCH 087/118] new test for zeroizing secp256k1 keys --- shared/src/types/key/mod.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/shared/src/types/key/mod.rs b/shared/src/types/key/mod.rs index 1e12667346..a287e2f8e3 100644 --- a/shared/src/types/key/mod.rs +++ b/shared/src/types/key/mod.rs @@ -478,18 +478,21 @@ mod more_tests { } #[test] - fn zeroize_keypair_seck256k1() { + fn zeroize_keypair_secp256k1() { use rand::thread_rng; - let sk = secp256k1::SigScheme::generate(&mut thread_rng()); - let sk_bytes = sk.0.serialize(); - let len = sk_bytes.len(); - let ptr = sk_bytes.as_ptr(); + let mut sk = secp256k1::SigScheme::generate(&mut thread_rng()); + let sk_scalar = sk.0.to_scalar_ref(); + let len = sk_scalar.0.len(); + let ptr = sk_scalar.0.as_ref().as_ptr(); + + let original_data = sk_scalar.0.clone(); drop(sk); - assert_eq!(&[0u8; 32], unsafe { + assert_ne!(&original_data, unsafe { core::slice::from_raw_parts(ptr, len) }); + } } From 73978706290956b467dbaadcb91f1e7de67fb3a2 Mon Sep 17 00:00:00 2001 From: "Raymond E. Pasco" Date: Sat, 20 Aug 2022 11:32:56 -0400 Subject: [PATCH 088/118] release: update release.toml for namada repo We release from "main", and name the releases "Namada". --- release.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/release.toml b/release.toml index 288708c60a..e82ec3b4c3 100644 --- a/release.toml +++ b/release.toml @@ -1,10 +1,10 @@ -allow-branch = ["master", "maint-*"] +allow-branch = ["main", "maint-*"] consolidate-commits = true disable-push = true disable-publish = true disable-tag = true no-dev-version = true -pre-release-commit-message = "Anoma {{version}}" +pre-release-commit-message = "Namada {{version}}" shared-version = true sign-tag = true -tag-message = "Anoma {{version}}" +tag-message = "Namada {{version}}" From 02f0d90f0853e3ba69c3cfe3444365f91e26f1d3 Mon Sep 17 00:00:00 2001 From: brentstone Date: Wed, 10 Aug 2022 11:25:58 -0400 Subject: [PATCH 089/118] use heliaxdev/libsecp256k1 crate fork as dependency for now --- Cargo.lock | 17 ++++++----------- shared/Cargo.toml | 2 +- wasm/checksums.json | 34 +++++++++++++++++----------------- wasm/wasm_source/Cargo.lock | 15 +++++---------- 4 files changed, 29 insertions(+), 39 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3fd0bf98af..743376121e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3472,15 +3472,13 @@ dependencies = [ [[package]] name = "libsecp256k1" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95b09eff1b35ed3b33b877ced3a691fc7a481919c7e29c53c906226fcf55e2a1" +version = "0.7.0" +source = "git+https://github.com/brentstone/libsecp256k1?rev=bbb3bd44a49db361f21d9db80f9a087c194c0ae9#bbb3bd44a49db361f21d9db80f9a087c194c0ae9" dependencies = [ "arrayref", "base64 0.13.0", "digest 0.9.0", "hmac-drbg 0.3.0", - "lazy_static 1.4.0", "libsecp256k1-core", "libsecp256k1-gen-ecmult", "libsecp256k1-gen-genmult", @@ -3493,8 +3491,7 @@ dependencies = [ [[package]] name = "libsecp256k1-core" version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451" +source = "git+https://github.com/brentstone/libsecp256k1?rev=bbb3bd44a49db361f21d9db80f9a087c194c0ae9#bbb3bd44a49db361f21d9db80f9a087c194c0ae9" dependencies = [ "crunchy", "digest 0.9.0", @@ -3504,8 +3501,7 @@ dependencies = [ [[package]] name = "libsecp256k1-gen-ecmult" version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3038c808c55c87e8a172643a7d87187fc6c4174468159cb3090659d55bcb4809" +source = "git+https://github.com/brentstone/libsecp256k1?rev=bbb3bd44a49db361f21d9db80f9a087c194c0ae9#bbb3bd44a49db361f21d9db80f9a087c194c0ae9" dependencies = [ "libsecp256k1-core", ] @@ -3513,8 +3509,7 @@ dependencies = [ [[package]] name = "libsecp256k1-gen-genmult" version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3db8d6ba2cec9eacc40e6e8ccc98931840301f1006e95647ceb2dd5c3aa06f7c" +source = "git+https://github.com/brentstone/libsecp256k1?rev=bbb3bd44a49db361f21d9db80f9a087c194c0ae9#bbb3bd44a49db361f21d9db80f9a087c194c0ae9" dependencies = [ "libsecp256k1-core", ] @@ -3975,7 +3970,7 @@ dependencies = [ "ibc-proto 0.16.0 (git+https://github.com/heliaxdev/ibc-rs?rev=30b3495ac56c6c37c99bc69ef9f2e84c3309c6cc)", "ics23", "itertools 0.10.3", - "libsecp256k1 0.7.1", + "libsecp256k1 0.7.0", "loupe", "namada_proof_of_stake", "parity-wasm", diff --git a/shared/Cargo.toml b/shared/Cargo.toml index 8110e1f89f..98c7a07c22 100644 --- a/shared/Cargo.toml +++ b/shared/Cargo.toml @@ -86,7 +86,7 @@ ibc-proto-abci = {package = "ibc-proto", git = "https://github.com/heliaxdev/ibc ics23 = "0.6.7" itertools = "0.10.0" loupe = {version = "0.1.3", optional = true} -libsecp256k1 = {version = "0.7.0", default-features = false, features = ["std", "hmac", "lazy-static-context"]} +libsecp256k1 = {git = "https://github.com/heliaxdev/libsecp256k1", rev = "bbb3bd44a49db361f21d9db80f9a087c194c0ae9"} parity-wasm = {version = "0.42.2", optional = true} # A fork with state machine testing proptest = {git = "https://github.com/heliaxdev/proptest", branch = "tomas/sm", optional = true} diff --git a/wasm/checksums.json b/wasm/checksums.json index e4809b538c..11598f4944 100644 --- a/wasm/checksums.json +++ b/wasm/checksums.json @@ -1,19 +1,19 @@ { - "tx_bond.wasm": "tx_bond.d426722e133c4d386d5378a457f420e969197d24b151cd7085bfe08ec1719ced.wasm", - "tx_from_intent.wasm": "tx_from_intent.b3f9ee85f9ecc8c1c78b73169a567ad59ecf876bb72c76e4f57dbcf3c9dd6e17.wasm", - "tx_ibc.wasm": "tx_ibc.09518b4c922ed1f70699513fe8ab1c8fdc42031622e508fc0bdecdefb66bb9f5.wasm", - "tx_init_account.wasm": "tx_init_account.bfc5617cab4e138436f7dc1fc107c5bad4d94f3f8df5fcb0d95126b9463cea59.wasm", - "tx_init_nft.wasm": "tx_init_nft.d507eb96fa178535b68a3c6080b808b49ca5936300eab0eec7c36d4d3bc148bf.wasm", - "tx_init_proposal.wasm": "tx_init_proposal.295ac0505c98209b7a672504902d5ce523d45a84827388da7c0d60e38079ae01.wasm", - "tx_init_validator.wasm": "tx_init_validator.6f163d3cee0820bf0c555ecd8ee09c081c7d498394a0409b8005d39495ddcaeb.wasm", - "tx_mint_nft.wasm": "tx_mint_nft.df3cb6c43463e94d9cf4b125bd00c1d3d5ccd579beaa32336c5b56ce7957ef05.wasm", - "tx_transfer.wasm": "tx_transfer.3709be4f149050a34bcc84e1d5ec3776be45dedb63b5b224306066ed3fa23d2f.wasm", - "tx_unbond.wasm": "tx_unbond.56086ae05b845037b9cc0bbcbb76c496a95a8041e0eaaef20a881eae6cf0116d.wasm", - "tx_update_vp.wasm": "tx_update_vp.cdb6de03931bb5e2d62d1db0d59777c3bb7bfb14214992328d0df95d1851f45e.wasm", - "tx_vote_proposal.wasm": "tx_vote_proposal.06a2ae40b5d8683899debb58b5217647b1d19f1818a2c01a97e1045d72c7cc2a.wasm", - "tx_withdraw.wasm": "tx_withdraw.a2d57125485db6c5162b699333ad23db2586f92d88df91e10642a8911854773e.wasm", - "vp_nft.wasm": "vp_nft.bc74013b04a2944e153d82a7a4f934c35aff87c2cd8daca7a22bfdab970bfadb.wasm", - "vp_testnet_faucet.wasm": "vp_testnet_faucet.f0c4c073c468f35edb7b8cd31dab326e40b00bbb9b2ab9e27c4028526146d066.wasm", - "vp_token.wasm": "vp_token.a083be83b0dc78d953999e26dc6b8c10a0e9828c74d365f836c5668533f4e41c.wasm", - "vp_user.wasm": "vp_user.065595512916500834e721eb4599a109201a10d8304664f6c474ab8200c11744.wasm" + "tx_bond.wasm": "tx_bond.42504d29d81008869e2c13775254e493181fa334f557940be8ad614ea8aa439a.wasm", + "tx_from_intent.wasm": "tx_from_intent.56a079838bf3d06d7be0160864ff4b70ad5961a9baff7ca8d28cf31e59111395.wasm", + "tx_ibc.wasm": "tx_ibc.8b4f5ead4fa069d2786e988cbe2bcb63f095cdcd47c913614829ef795dcbfa30.wasm", + "tx_init_account.wasm": "tx_init_account.80fbd4271cbef05fb6d340617ecb1437fc375c62f1a28baf989945d03850d0e1.wasm", + "tx_init_nft.wasm": "tx_init_nft.389a37111a810e71d9eafa56ea22f73374a1277d16325105f42cdc86ae23feca.wasm", + "tx_init_proposal.wasm": "tx_init_proposal.f3276f42cad9aa79ebc1da6516b78a9af624644d43cdfcca2b86f6e618334257.wasm", + "tx_init_validator.wasm": "tx_init_validator.a71938fb2aac071b44b9949ab055d493e29b5791f4dde3293635a0faf05c64a9.wasm", + "tx_mint_nft.wasm": "tx_mint_nft.d8af9ed4d99f1d58642a0a0b2759109b8df1f3dcb583b19609bb0da96b41b74c.wasm", + "tx_transfer.wasm": "tx_transfer.b35df2da33c8828287c7de8163d0ecc8c59b4444cd1c9afcf246c569ae653a74.wasm", + "tx_unbond.wasm": "tx_unbond.49d120af6a0e7183dc88ca1dfad44825763dcc6cd7c32afef694d4e814e64f50.wasm", + "tx_update_vp.wasm": "tx_update_vp.025a9dec03f1e138a3e5bdcafeebe53b220a75340c6cdf7160663b870ee92bb8.wasm", + "tx_vote_proposal.wasm": "tx_vote_proposal.ea9332b02b39d852fe4e8949de56d96bb6fdde9fad69a7252f32bb3465f527ff.wasm", + "tx_withdraw.wasm": "tx_withdraw.199ea7cb708d12196cf4cf06598c58403d1b07056284d275c3022d47207323c1.wasm", + "vp_nft.wasm": "vp_nft.31eb61ed64a4eda03d3d872d6b3716e0fe4210b7d02275463adae3bbf6dfcaa1.wasm", + "vp_testnet_faucet.wasm": "vp_testnet_faucet.87a7e0e37af26847bc91e1559de3018ac97382f969c76f99ca86423f3a19f502.wasm", + "vp_token.wasm": "vp_token.7cb6763045cc60eb013db6adf75d254eeedeb01d0b1ecb4a1dfce5288096de6a.wasm", + "vp_user.wasm": "vp_user.a63e9a36b20abc4ef105b50e77302577f0850e60993cdcdc3ee6b2d9886ebebc.wasm" } \ No newline at end of file diff --git a/wasm/wasm_source/Cargo.lock b/wasm/wasm_source/Cargo.lock index f1816d434e..6c46fad54a 100644 --- a/wasm/wasm_source/Cargo.lock +++ b/wasm/wasm_source/Cargo.lock @@ -1262,15 +1262,13 @@ dependencies = [ [[package]] name = "libsecp256k1" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95b09eff1b35ed3b33b877ced3a691fc7a481919c7e29c53c906226fcf55e2a1" +version = "0.7.0" +source = "git+https://github.com/heliaxdev/libsecp256k1?rev=bbb3bd44a49db361f21d9db80f9a087c194c0ae9#bbb3bd44a49db361f21d9db80f9a087c194c0ae9" dependencies = [ "arrayref", "base64", "digest 0.9.0", "hmac-drbg", - "lazy_static", "libsecp256k1-core", "libsecp256k1-gen-ecmult", "libsecp256k1-gen-genmult", @@ -1283,8 +1281,7 @@ dependencies = [ [[package]] name = "libsecp256k1-core" version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451" +source = "git+https://github.com/heliaxdev/libsecp256k1?rev=bbb3bd44a49db361f21d9db80f9a087c194c0ae9#bbb3bd44a49db361f21d9db80f9a087c194c0ae9" dependencies = [ "crunchy", "digest 0.9.0", @@ -1294,8 +1291,7 @@ dependencies = [ [[package]] name = "libsecp256k1-gen-ecmult" version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3038c808c55c87e8a172643a7d87187fc6c4174468159cb3090659d55bcb4809" +source = "git+https://github.com/heliaxdev/libsecp256k1?rev=bbb3bd44a49db361f21d9db80f9a087c194c0ae9#bbb3bd44a49db361f21d9db80f9a087c194c0ae9" dependencies = [ "libsecp256k1-core", ] @@ -1303,8 +1299,7 @@ dependencies = [ [[package]] name = "libsecp256k1-gen-genmult" version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3db8d6ba2cec9eacc40e6e8ccc98931840301f1006e95647ceb2dd5c3aa06f7c" +source = "git+https://github.com/heliaxdev/libsecp256k1?rev=bbb3bd44a49db361f21d9db80f9a087c194c0ae9#bbb3bd44a49db361f21d9db80f9a087c194c0ae9" dependencies = [ "libsecp256k1-core", ] From 4fba1c1b4e1b8d588a66c7d6dced6df1e018dc40 Mon Sep 17 00:00:00 2001 From: brentstone Date: Wed, 10 Aug 2022 11:30:24 -0400 Subject: [PATCH 090/118] fmt && clippy --- shared/src/types/key/mod.rs | 3 +-- wasm/tx_template/Cargo.lock | 15 +++++---------- wasm/vp_template/Cargo.lock | 15 +++++---------- wasm_for_tests/wasm_source/Cargo.lock | 15 +++++---------- 4 files changed, 16 insertions(+), 32 deletions(-) diff --git a/shared/src/types/key/mod.rs b/shared/src/types/key/mod.rs index a287e2f8e3..d8ccbb5a64 100644 --- a/shared/src/types/key/mod.rs +++ b/shared/src/types/key/mod.rs @@ -486,13 +486,12 @@ mod more_tests { let len = sk_scalar.0.len(); let ptr = sk_scalar.0.as_ref().as_ptr(); - let original_data = sk_scalar.0.clone(); + let original_data = sk_scalar.0; drop(sk); assert_ne!(&original_data, unsafe { core::slice::from_raw_parts(ptr, len) }); - } } diff --git a/wasm/tx_template/Cargo.lock b/wasm/tx_template/Cargo.lock index d085610948..7f9706fc3c 100644 --- a/wasm/tx_template/Cargo.lock +++ b/wasm/tx_template/Cargo.lock @@ -1262,15 +1262,13 @@ dependencies = [ [[package]] name = "libsecp256k1" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95b09eff1b35ed3b33b877ced3a691fc7a481919c7e29c53c906226fcf55e2a1" +version = "0.7.0" +source = "git+https://github.com/brentstone/libsecp256k1?rev=bbb3bd44a49db361f21d9db80f9a087c194c0ae9#bbb3bd44a49db361f21d9db80f9a087c194c0ae9" dependencies = [ "arrayref", "base64", "digest 0.9.0", "hmac-drbg", - "lazy_static", "libsecp256k1-core", "libsecp256k1-gen-ecmult", "libsecp256k1-gen-genmult", @@ -1283,8 +1281,7 @@ dependencies = [ [[package]] name = "libsecp256k1-core" version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451" +source = "git+https://github.com/brentstone/libsecp256k1?rev=bbb3bd44a49db361f21d9db80f9a087c194c0ae9#bbb3bd44a49db361f21d9db80f9a087c194c0ae9" dependencies = [ "crunchy", "digest 0.9.0", @@ -1294,8 +1291,7 @@ dependencies = [ [[package]] name = "libsecp256k1-gen-ecmult" version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3038c808c55c87e8a172643a7d87187fc6c4174468159cb3090659d55bcb4809" +source = "git+https://github.com/brentstone/libsecp256k1?rev=bbb3bd44a49db361f21d9db80f9a087c194c0ae9#bbb3bd44a49db361f21d9db80f9a087c194c0ae9" dependencies = [ "libsecp256k1-core", ] @@ -1303,8 +1299,7 @@ dependencies = [ [[package]] name = "libsecp256k1-gen-genmult" version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3db8d6ba2cec9eacc40e6e8ccc98931840301f1006e95647ceb2dd5c3aa06f7c" +source = "git+https://github.com/brentstone/libsecp256k1?rev=bbb3bd44a49db361f21d9db80f9a087c194c0ae9#bbb3bd44a49db361f21d9db80f9a087c194c0ae9" dependencies = [ "libsecp256k1-core", ] diff --git a/wasm/vp_template/Cargo.lock b/wasm/vp_template/Cargo.lock index 67aef12e0a..8b3351e947 100644 --- a/wasm/vp_template/Cargo.lock +++ b/wasm/vp_template/Cargo.lock @@ -1262,15 +1262,13 @@ dependencies = [ [[package]] name = "libsecp256k1" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95b09eff1b35ed3b33b877ced3a691fc7a481919c7e29c53c906226fcf55e2a1" +version = "0.7.0" +source = "git+https://github.com/brentstone/libsecp256k1?rev=bbb3bd44a49db361f21d9db80f9a087c194c0ae9#bbb3bd44a49db361f21d9db80f9a087c194c0ae9" dependencies = [ "arrayref", "base64", "digest 0.9.0", "hmac-drbg", - "lazy_static", "libsecp256k1-core", "libsecp256k1-gen-ecmult", "libsecp256k1-gen-genmult", @@ -1283,8 +1281,7 @@ dependencies = [ [[package]] name = "libsecp256k1-core" version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451" +source = "git+https://github.com/brentstone/libsecp256k1?rev=bbb3bd44a49db361f21d9db80f9a087c194c0ae9#bbb3bd44a49db361f21d9db80f9a087c194c0ae9" dependencies = [ "crunchy", "digest 0.9.0", @@ -1294,8 +1291,7 @@ dependencies = [ [[package]] name = "libsecp256k1-gen-ecmult" version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3038c808c55c87e8a172643a7d87187fc6c4174468159cb3090659d55bcb4809" +source = "git+https://github.com/brentstone/libsecp256k1?rev=bbb3bd44a49db361f21d9db80f9a087c194c0ae9#bbb3bd44a49db361f21d9db80f9a087c194c0ae9" dependencies = [ "libsecp256k1-core", ] @@ -1303,8 +1299,7 @@ dependencies = [ [[package]] name = "libsecp256k1-gen-genmult" version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3db8d6ba2cec9eacc40e6e8ccc98931840301f1006e95647ceb2dd5c3aa06f7c" +source = "git+https://github.com/brentstone/libsecp256k1?rev=bbb3bd44a49db361f21d9db80f9a087c194c0ae9#bbb3bd44a49db361f21d9db80f9a087c194c0ae9" dependencies = [ "libsecp256k1-core", ] diff --git a/wasm_for_tests/wasm_source/Cargo.lock b/wasm_for_tests/wasm_source/Cargo.lock index 23d27344a6..0cfcd70cb9 100644 --- a/wasm_for_tests/wasm_source/Cargo.lock +++ b/wasm_for_tests/wasm_source/Cargo.lock @@ -1272,15 +1272,13 @@ dependencies = [ [[package]] name = "libsecp256k1" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95b09eff1b35ed3b33b877ced3a691fc7a481919c7e29c53c906226fcf55e2a1" +version = "0.7.0" +source = "git+https://github.com/brentstone/libsecp256k1?rev=bbb3bd44a49db361f21d9db80f9a087c194c0ae9#bbb3bd44a49db361f21d9db80f9a087c194c0ae9" dependencies = [ "arrayref", "base64", "digest 0.9.0", "hmac-drbg", - "lazy_static", "libsecp256k1-core", "libsecp256k1-gen-ecmult", "libsecp256k1-gen-genmult", @@ -1293,8 +1291,7 @@ dependencies = [ [[package]] name = "libsecp256k1-core" version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451" +source = "git+https://github.com/brentstone/libsecp256k1?rev=bbb3bd44a49db361f21d9db80f9a087c194c0ae9#bbb3bd44a49db361f21d9db80f9a087c194c0ae9" dependencies = [ "crunchy", "digest 0.9.0", @@ -1304,8 +1301,7 @@ dependencies = [ [[package]] name = "libsecp256k1-gen-ecmult" version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3038c808c55c87e8a172643a7d87187fc6c4174468159cb3090659d55bcb4809" +source = "git+https://github.com/brentstone/libsecp256k1?rev=bbb3bd44a49db361f21d9db80f9a087c194c0ae9#bbb3bd44a49db361f21d9db80f9a087c194c0ae9" dependencies = [ "libsecp256k1-core", ] @@ -1313,8 +1309,7 @@ dependencies = [ [[package]] name = "libsecp256k1-gen-genmult" version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3db8d6ba2cec9eacc40e6e8ccc98931840301f1006e95647ceb2dd5c3aa06f7c" +source = "git+https://github.com/brentstone/libsecp256k1?rev=bbb3bd44a49db361f21d9db80f9a087c194c0ae9#bbb3bd44a49db361f21d9db80f9a087c194c0ae9" dependencies = [ "libsecp256k1-core", ] From ba0aa4c0e2d396005574cbdbbbc504d870950210 Mon Sep 17 00:00:00 2001 From: brentstone Date: Thu, 11 Aug 2022 17:10:09 -0400 Subject: [PATCH 091/118] handle secp256k1 in key_to_tendermint() --- apps/src/lib/node/ledger/shell/mod.rs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/apps/src/lib/node/ledger/shell/mod.rs b/apps/src/lib/node/ledger/shell/mod.rs index f72dcf615a..0c416bee4f 100644 --- a/apps/src/lib/node/ledger/shell/mod.rs +++ b/apps/src/lib/node/ledger/shell/mod.rs @@ -79,11 +79,22 @@ use crate::node::ledger::{protocol, storage, tendermint_node}; use crate::wallet::ValidatorData; use crate::{config, wallet}; -fn key_to_tendermint( - pk: &PK, +fn key_to_tendermint ( + pk: &common::PublicKey, ) -> std::result::Result { - ed25519::PublicKey::try_from_pk(pk) - .map(|pk| public_key::Sum::Ed25519(pk.try_to_vec().unwrap())) + println!("\nKEY TO TENDERMINT\n"); + match pk { + common::PublicKey::Ed25519(_) => { + println!("\nEd25519\n"); + ed25519::PublicKey::try_from_pk(pk) + .map(|pk| public_key::Sum::Ed25519(pk.try_to_vec().unwrap())) + }, + common::PublicKey::Secp256k1(_) => { + println!("\nSecp256k1\n"); + secp256k1::PublicKey::try_from_pk(pk) + .map(|pk| public_key::Sum::Secp256k1(pk.try_to_vec().unwrap())) + }, + } } #[derive(Error, Debug)] From 04e6ba4675ed089daee1447275462d22122329b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zemanovi=C4=8D?= Date: Fri, 12 Aug 2022 10:27:29 +0200 Subject: [PATCH 092/118] deps: enable secp256k1 in tendermint-rs note that to make cargo deps, which complained about: ``` error: failed to select a version for `signature` ``` it was needed to run `cargo update -p signature` to: ``` Updating signature v1.5.0 -> v1.4.0 ``` --- Cargo.lock | 150 ++++++++++++++++++++++++- apps/Cargo.toml | 2 +- shared/Cargo.toml | 2 +- wasm/tx_template/Cargo.lock | 154 +++++++++++++++++++++++++- wasm/vp_template/Cargo.lock | 154 +++++++++++++++++++++++++- wasm/wasm_source/Cargo.lock | 154 +++++++++++++++++++++++++- wasm_for_tests/wasm_source/Cargo.lock | 154 +++++++++++++++++++++++++- 7 files changed, 750 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 743376121e..289f5e4e38 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -519,6 +519,12 @@ dependencies = [ "rustc-demangle", ] +[[package]] +name = "base16ct" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" + [[package]] name = "base64" version = "0.9.3" @@ -1101,6 +1107,12 @@ dependencies = [ "windows", ] +[[package]] +name = "const-oid" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3" + [[package]] name = "constant_time_eq" version = "0.1.5" @@ -1272,6 +1284,18 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +[[package]] +name = "crypto-bigint" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c6a1d5fa1de37e071642dfa44ec552ca5b299adb128fab16138e24b548fd21" +dependencies = [ + "generic-array 0.14.5", + "rand_core 0.6.3", + "subtle 2.4.1", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.1.3" @@ -1302,6 +1326,16 @@ dependencies = [ "subtle 2.4.1", ] +[[package]] +name = "crypto-mac" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" +dependencies = [ + "generic-array 0.14.5", + "subtle 2.4.1", +] + [[package]] name = "ct-codecs" version = "1.1.1" @@ -1484,6 +1518,15 @@ version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ee2393c4a91429dffb4bedf19f4d6abf27d8a732c8ce4980305d782e5426d57" +[[package]] +name = "der" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6919815d73839e7ad218de758883aae3a257ba6759ce7a9992501efbb53d705c" +dependencies = [ + "const-oid", +] + [[package]] name = "derivative" version = "2.2.0" @@ -1646,6 +1689,18 @@ dependencies = [ "memmap2", ] +[[package]] +name = "ecdsa" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0d69ae62e0ce582d56380743515fefaf1a8c70cec685d9677636d7e30ae9dc9" +dependencies = [ + "der", + "elliptic-curve", + "rfc6979", + "signature", +] + [[package]] name = "ed25519" version = "1.5.2" @@ -1693,6 +1748,24 @@ version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +[[package]] +name = "elliptic-curve" +version = "0.11.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25b477563c2bfed38a3b7a60964c49e058b2510ad3f12ba3483fd8f62c2306d6" +dependencies = [ + "base16ct", + "crypto-bigint", + "der", + "ff", + "generic-array 0.14.5", + "group", + "rand_core 0.6.3", + "sec1", + "subtle 2.4.1", + "zeroize", +] + [[package]] name = "embed-resource" version = "1.7.2" @@ -1887,6 +1960,16 @@ dependencies = [ "serde_bytes", ] +[[package]] +name = "ff" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "131655483be284720a17d74ff97592b8e76576dc25563148601df2d7c9080924" +dependencies = [ + "rand_core 0.6.3", + "subtle 2.4.1", +] + [[package]] name = "file-lock" version = "2.1.4" @@ -2277,6 +2360,17 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "group" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5ac374b108929de78460075f3dc439fa66df9d8fc77e8f12caa5165fcf0c89" +dependencies = [ + "ff", + "rand_core 0.6.3", + "subtle 2.4.1", +] + [[package]] name = "group-threshold-cryptography" version = "0.1.0" @@ -2453,6 +2547,16 @@ dependencies = [ "digest 0.9.0", ] +[[package]] +name = "hmac" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" +dependencies = [ + "crypto-mac 0.11.1", + "digest 0.9.0", +] + [[package]] name = "hmac-drbg" version = "0.2.0" @@ -2930,6 +3034,19 @@ dependencies = [ "serde_json", ] +[[package]] +name = "k256" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19c3a5e0a0b8450278feda242592512e09f61c72e018b8cd5c859482802daf2d" +dependencies = [ + "cfg-if 1.0.0", + "ecdsa", + "elliptic-curve", + "sec1", + "sha2 0.9.9", +] + [[package]] name = "keccak" version = "0.1.2" @@ -5504,6 +5621,17 @@ dependencies = [ "quick-error 1.2.3", ] +[[package]] +name = "rfc6979" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96ef608575f6392792f9ecf7890c00086591d29a83910939d430753f7c050525" +dependencies = [ + "crypto-bigint", + "hmac 0.11.0", + "zeroize", +] + [[package]] name = "ring" version = "0.16.20" @@ -5803,6 +5931,18 @@ version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" +[[package]] +name = "sec1" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08da66b8b0965a5555b6bd6639e68ccba85e1e2506f5fbb089e93f8a04e1a2d1" +dependencies = [ + "der", + "generic-array 0.14.5", + "subtle 2.4.1", + "zeroize", +] + [[package]] name = "security-framework" version = "2.3.1" @@ -6104,9 +6244,13 @@ dependencies = [ [[package]] name = "signature" -version = "1.5.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f054c6c1a6e95179d6f23ed974060dcefb2d9388bb7256900badad682c499de4" +checksum = "02658e48d89f2bec991f9a78e69cfa4c316f8d6a6c4ec12fae1aeb263d486788" +dependencies = [ + "digest 0.9.0", + "rand_core 0.6.3", +] [[package]] name = "simple-error" @@ -6448,10 +6592,12 @@ dependencies = [ "ed25519-dalek", "flex-error", "futures 0.3.21", + "k256", "num-traits 0.2.15", "once_cell", "prost 0.9.0", "prost-types 0.9.0", + "ripemd160", "serde 1.0.137", "serde_bytes", "serde_json", diff --git a/apps/Cargo.toml b/apps/Cargo.toml index 1464b22c8b..0285cb7e48 100644 --- a/apps/Cargo.toml +++ b/apps/Cargo.toml @@ -123,7 +123,7 @@ sparse-merkle-tree = {git = "https://github.com/heliaxdev/sparse-merkle-tree", b sysinfo = {version = "=0.21.1", default-features = false} tar = "0.4.37" # temporarily using fork work-around -tendermint = {git = "https://github.com/heliaxdev/tendermint-rs", rev = "95c52476bc37927218374f94ac8e2a19bd35bec9", optional = true} +tendermint = {git = "https://github.com/heliaxdev/tendermint-rs", rev = "95c52476bc37927218374f94ac8e2a19bd35bec9", festures = ["secp256k1"], optional = true} tendermint-config = {git = "https://github.com/heliaxdev/tendermint-rs", rev = "95c52476bc37927218374f94ac8e2a19bd35bec9", optional = true} tendermint-config-abci = {package = "tendermint-config", git = "https://github.com/heliaxdev/tendermint-rs", branch = "yuji/rebase_v0.23.5", optional = true} tendermint-proto = {git = "https://github.com/heliaxdev/tendermint-rs", rev = "95c52476bc37927218374f94ac8e2a19bd35bec9", optional = true} diff --git a/shared/Cargo.toml b/shared/Cargo.toml index 98c7a07c22..630148db3e 100644 --- a/shared/Cargo.toml +++ b/shared/Cargo.toml @@ -104,7 +104,7 @@ sha2 = "0.9.3" sparse-merkle-tree = {git = "https://github.com/heliaxdev/sparse-merkle-tree", branch = "yuji/prost-0.9", default-features = false, features = ["std", "borsh"]} tempfile = {version = "3.2.0", optional = true} # temporarily using fork work-around for https://github.com/informalsystems/tendermint-rs/issues/971 -tendermint = {git = "https://github.com/heliaxdev/tendermint-rs", rev = "95c52476bc37927218374f94ac8e2a19bd35bec9", optional = true} +tendermint = {git = "https://github.com/heliaxdev/tendermint-rs", rev = "95c52476bc37927218374f94ac8e2a19bd35bec9", features = ["secp256k1"], optional = true} tendermint-proto = {git = "https://github.com/heliaxdev/tendermint-rs", rev = "95c52476bc37927218374f94ac8e2a19bd35bec9", optional = true} tendermint-proto-abci = {package = "tendermint-proto", git = "https://github.com/heliaxdev/tendermint-rs", branch = "yuji/rebase_v0.23.5", optional = true} tendermint-stable = {package = "tendermint", git = "https://github.com/heliaxdev/tendermint-rs", branch = "yuji/rebase_v0.23.5", optional = true} diff --git a/wasm/tx_template/Cargo.lock b/wasm/tx_template/Cargo.lock index 7f9706fc3c..b3a15bee65 100644 --- a/wasm/tx_template/Cargo.lock +++ b/wasm/tx_template/Cargo.lock @@ -205,6 +205,12 @@ dependencies = [ "rustc-demangle", ] +[[package]] +name = "base16ct" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" + [[package]] name = "base64" version = "0.13.0" @@ -403,6 +409,12 @@ dependencies = [ "syn", ] +[[package]] +name = "const-oid" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3" + [[package]] name = "constant_time_eq" version = "0.1.5" @@ -537,6 +549,18 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +[[package]] +name = "crypto-bigint" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c6a1d5fa1de37e071642dfa44ec552ca5b299adb128fab16138e24b548fd21" +dependencies = [ + "generic-array", + "rand_core 0.6.3", + "subtle", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.1.3" @@ -557,6 +581,16 @@ dependencies = [ "subtle", ] +[[package]] +name = "crypto-mac" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" +dependencies = [ + "generic-array", + "subtle", +] + [[package]] name = "curve25519-dalek" version = "3.2.0" @@ -618,6 +652,15 @@ dependencies = [ "syn", ] +[[package]] +name = "der" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6919815d73839e7ad218de758883aae3a257ba6759ce7a9992501efbb53d705c" +dependencies = [ + "const-oid", +] + [[package]] name = "derivative" version = "2.2.0" @@ -686,6 +729,18 @@ dependencies = [ "memmap2", ] +[[package]] +name = "ecdsa" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0d69ae62e0ce582d56380743515fefaf1a8c70cec685d9677636d7e30ae9dc9" +dependencies = [ + "der", + "elliptic-curve", + "rfc6979", + "signature", +] + [[package]] name = "ed25519" version = "1.4.0" @@ -728,6 +783,24 @@ version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +[[package]] +name = "elliptic-curve" +version = "0.11.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25b477563c2bfed38a3b7a60964c49e058b2510ad3f12ba3483fd8f62c2306d6" +dependencies = [ + "base16ct", + "crypto-bigint", + "der", + "ff", + "generic-array", + "group", + "rand_core 0.6.3", + "sec1", + "subtle", + "zeroize", +] + [[package]] name = "enum-iterator" version = "0.7.0" @@ -807,6 +880,16 @@ dependencies = [ "serde_bytes", ] +[[package]] +name = "ff" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "131655483be284720a17d74ff97592b8e76576dc25563148601df2d7c9080924" +dependencies = [ + "rand_core 0.6.3", + "subtle", +] + [[package]] name = "fixedbitset" version = "0.4.1" @@ -940,6 +1023,17 @@ version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" +[[package]] +name = "group" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5ac374b108929de78460075f3dc439fa66df9d8fc77e8f12caa5165fcf0c89" +dependencies = [ + "ff", + "rand_core 0.6.3", + "subtle", +] + [[package]] name = "gumdrop" version = "0.8.0" @@ -1018,7 +1112,17 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" dependencies = [ - "crypto-mac", + "crypto-mac 0.8.0", + "digest 0.9.0", +] + +[[package]] +name = "hmac" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" +dependencies = [ + "crypto-mac 0.11.1", "digest 0.9.0", ] @@ -1030,7 +1134,7 @@ checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" dependencies = [ "digest 0.9.0", "generic-array", - "hmac", + "hmac 0.8.1", ] [[package]] @@ -1226,6 +1330,19 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "k256" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19c3a5e0a0b8450278feda242592512e09f61c72e018b8cd5c859482802daf2d" +dependencies = [ + "cfg-if 1.0.0", + "ecdsa", + "elliptic-curve", + "sec1", + "sha2 0.9.9", +] + [[package]] name = "keccak" version = "0.1.0" @@ -2050,6 +2167,17 @@ dependencies = [ "bytecheck", ] +[[package]] +name = "rfc6979" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96ef608575f6392792f9ecf7890c00086591d29a83910939d430753f7c050525" +dependencies = [ + "crypto-bigint", + "hmac 0.11.0", + "zeroize", +] + [[package]] name = "ripemd160" version = "0.9.1" @@ -2210,6 +2338,18 @@ version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" +[[package]] +name = "sec1" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08da66b8b0965a5555b6bd6639e68ccba85e1e2506f5fbb089e93f8a04e1a2d1" +dependencies = [ + "der", + "generic-array", + "subtle", + "zeroize", +] + [[package]] name = "semver" version = "0.11.0" @@ -2326,9 +2466,13 @@ dependencies = [ [[package]] name = "signature" -version = "1.5.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f054c6c1a6e95179d6f23ed974060dcefb2d9388bb7256900badad682c499de4" +checksum = "02658e48d89f2bec991f9a78e69cfa4c316f8d6a6c4ec12fae1aeb263d486788" +dependencies = [ + "digest 0.9.0", + "rand_core 0.6.3", +] [[package]] name = "simple-error" @@ -2462,10 +2606,12 @@ dependencies = [ "ed25519-dalek", "flex-error", "futures", + "k256", "num-traits", "once_cell", "prost", "prost-types", + "ripemd160", "serde", "serde_bytes", "serde_json", diff --git a/wasm/vp_template/Cargo.lock b/wasm/vp_template/Cargo.lock index 8b3351e947..799256683d 100644 --- a/wasm/vp_template/Cargo.lock +++ b/wasm/vp_template/Cargo.lock @@ -205,6 +205,12 @@ dependencies = [ "rustc-demangle", ] +[[package]] +name = "base16ct" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" + [[package]] name = "base64" version = "0.13.0" @@ -403,6 +409,12 @@ dependencies = [ "syn", ] +[[package]] +name = "const-oid" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3" + [[package]] name = "constant_time_eq" version = "0.1.5" @@ -537,6 +549,18 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +[[package]] +name = "crypto-bigint" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c6a1d5fa1de37e071642dfa44ec552ca5b299adb128fab16138e24b548fd21" +dependencies = [ + "generic-array", + "rand_core 0.6.3", + "subtle", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.1.3" @@ -557,6 +581,16 @@ dependencies = [ "subtle", ] +[[package]] +name = "crypto-mac" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" +dependencies = [ + "generic-array", + "subtle", +] + [[package]] name = "curve25519-dalek" version = "3.2.0" @@ -618,6 +652,15 @@ dependencies = [ "syn", ] +[[package]] +name = "der" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6919815d73839e7ad218de758883aae3a257ba6759ce7a9992501efbb53d705c" +dependencies = [ + "const-oid", +] + [[package]] name = "derivative" version = "2.2.0" @@ -686,6 +729,18 @@ dependencies = [ "memmap2", ] +[[package]] +name = "ecdsa" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0d69ae62e0ce582d56380743515fefaf1a8c70cec685d9677636d7e30ae9dc9" +dependencies = [ + "der", + "elliptic-curve", + "rfc6979", + "signature", +] + [[package]] name = "ed25519" version = "1.4.0" @@ -728,6 +783,24 @@ version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +[[package]] +name = "elliptic-curve" +version = "0.11.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25b477563c2bfed38a3b7a60964c49e058b2510ad3f12ba3483fd8f62c2306d6" +dependencies = [ + "base16ct", + "crypto-bigint", + "der", + "ff", + "generic-array", + "group", + "rand_core 0.6.3", + "sec1", + "subtle", + "zeroize", +] + [[package]] name = "enum-iterator" version = "0.7.0" @@ -807,6 +880,16 @@ dependencies = [ "serde_bytes", ] +[[package]] +name = "ff" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "131655483be284720a17d74ff97592b8e76576dc25563148601df2d7c9080924" +dependencies = [ + "rand_core 0.6.3", + "subtle", +] + [[package]] name = "fixedbitset" version = "0.4.1" @@ -940,6 +1023,17 @@ version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" +[[package]] +name = "group" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5ac374b108929de78460075f3dc439fa66df9d8fc77e8f12caa5165fcf0c89" +dependencies = [ + "ff", + "rand_core 0.6.3", + "subtle", +] + [[package]] name = "gumdrop" version = "0.8.0" @@ -1018,7 +1112,17 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" dependencies = [ - "crypto-mac", + "crypto-mac 0.8.0", + "digest 0.9.0", +] + +[[package]] +name = "hmac" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" +dependencies = [ + "crypto-mac 0.11.1", "digest 0.9.0", ] @@ -1030,7 +1134,7 @@ checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" dependencies = [ "digest 0.9.0", "generic-array", - "hmac", + "hmac 0.8.1", ] [[package]] @@ -1226,6 +1330,19 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "k256" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19c3a5e0a0b8450278feda242592512e09f61c72e018b8cd5c859482802daf2d" +dependencies = [ + "cfg-if 1.0.0", + "ecdsa", + "elliptic-curve", + "sec1", + "sha2 0.9.9", +] + [[package]] name = "keccak" version = "0.1.0" @@ -2050,6 +2167,17 @@ dependencies = [ "bytecheck", ] +[[package]] +name = "rfc6979" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96ef608575f6392792f9ecf7890c00086591d29a83910939d430753f7c050525" +dependencies = [ + "crypto-bigint", + "hmac 0.11.0", + "zeroize", +] + [[package]] name = "ripemd160" version = "0.9.1" @@ -2210,6 +2338,18 @@ version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" +[[package]] +name = "sec1" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08da66b8b0965a5555b6bd6639e68ccba85e1e2506f5fbb089e93f8a04e1a2d1" +dependencies = [ + "der", + "generic-array", + "subtle", + "zeroize", +] + [[package]] name = "semver" version = "0.11.0" @@ -2326,9 +2466,13 @@ dependencies = [ [[package]] name = "signature" -version = "1.5.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f054c6c1a6e95179d6f23ed974060dcefb2d9388bb7256900badad682c499de4" +checksum = "02658e48d89f2bec991f9a78e69cfa4c316f8d6a6c4ec12fae1aeb263d486788" +dependencies = [ + "digest 0.9.0", + "rand_core 0.6.3", +] [[package]] name = "simple-error" @@ -2462,10 +2606,12 @@ dependencies = [ "ed25519-dalek", "flex-error", "futures", + "k256", "num-traits", "once_cell", "prost", "prost-types", + "ripemd160", "serde", "serde_bytes", "serde_json", diff --git a/wasm/wasm_source/Cargo.lock b/wasm/wasm_source/Cargo.lock index 6c46fad54a..5124bdd0c0 100644 --- a/wasm/wasm_source/Cargo.lock +++ b/wasm/wasm_source/Cargo.lock @@ -205,6 +205,12 @@ dependencies = [ "rustc-demangle", ] +[[package]] +name = "base16ct" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" + [[package]] name = "base64" version = "0.13.0" @@ -403,6 +409,12 @@ dependencies = [ "syn", ] +[[package]] +name = "const-oid" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3" + [[package]] name = "constant_time_eq" version = "0.1.5" @@ -537,6 +549,18 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +[[package]] +name = "crypto-bigint" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c6a1d5fa1de37e071642dfa44ec552ca5b299adb128fab16138e24b548fd21" +dependencies = [ + "generic-array", + "rand_core 0.6.3", + "subtle", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.1.3" @@ -557,6 +581,16 @@ dependencies = [ "subtle", ] +[[package]] +name = "crypto-mac" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" +dependencies = [ + "generic-array", + "subtle", +] + [[package]] name = "curve25519-dalek" version = "3.2.0" @@ -618,6 +652,15 @@ dependencies = [ "syn", ] +[[package]] +name = "der" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6919815d73839e7ad218de758883aae3a257ba6759ce7a9992501efbb53d705c" +dependencies = [ + "const-oid", +] + [[package]] name = "derivative" version = "2.2.0" @@ -686,6 +729,18 @@ dependencies = [ "memmap2", ] +[[package]] +name = "ecdsa" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0d69ae62e0ce582d56380743515fefaf1a8c70cec685d9677636d7e30ae9dc9" +dependencies = [ + "der", + "elliptic-curve", + "rfc6979", + "signature", +] + [[package]] name = "ed25519" version = "1.4.0" @@ -728,6 +783,24 @@ version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +[[package]] +name = "elliptic-curve" +version = "0.11.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25b477563c2bfed38a3b7a60964c49e058b2510ad3f12ba3483fd8f62c2306d6" +dependencies = [ + "base16ct", + "crypto-bigint", + "der", + "ff", + "generic-array", + "group", + "rand_core 0.6.3", + "sec1", + "subtle", + "zeroize", +] + [[package]] name = "enum-iterator" version = "0.7.0" @@ -807,6 +880,16 @@ dependencies = [ "serde_bytes", ] +[[package]] +name = "ff" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "131655483be284720a17d74ff97592b8e76576dc25563148601df2d7c9080924" +dependencies = [ + "rand_core 0.6.3", + "subtle", +] + [[package]] name = "fixedbitset" version = "0.4.1" @@ -940,6 +1023,17 @@ version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" +[[package]] +name = "group" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5ac374b108929de78460075f3dc439fa66df9d8fc77e8f12caa5165fcf0c89" +dependencies = [ + "ff", + "rand_core 0.6.3", + "subtle", +] + [[package]] name = "gumdrop" version = "0.8.0" @@ -1018,7 +1112,17 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" dependencies = [ - "crypto-mac", + "crypto-mac 0.8.0", + "digest 0.9.0", +] + +[[package]] +name = "hmac" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" +dependencies = [ + "crypto-mac 0.11.1", "digest 0.9.0", ] @@ -1030,7 +1134,7 @@ checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" dependencies = [ "digest 0.9.0", "generic-array", - "hmac", + "hmac 0.8.1", ] [[package]] @@ -1226,6 +1330,19 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "k256" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19c3a5e0a0b8450278feda242592512e09f61c72e018b8cd5c859482802daf2d" +dependencies = [ + "cfg-if 1.0.0", + "ecdsa", + "elliptic-curve", + "sec1", + "sha2 0.9.9", +] + [[package]] name = "keccak" version = "0.1.0" @@ -2076,6 +2193,17 @@ dependencies = [ "bytecheck", ] +[[package]] +name = "rfc6979" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96ef608575f6392792f9ecf7890c00086591d29a83910939d430753f7c050525" +dependencies = [ + "crypto-bigint", + "hmac 0.11.0", + "zeroize", +] + [[package]] name = "ripemd160" version = "0.9.1" @@ -2236,6 +2364,18 @@ version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" +[[package]] +name = "sec1" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08da66b8b0965a5555b6bd6639e68ccba85e1e2506f5fbb089e93f8a04e1a2d1" +dependencies = [ + "der", + "generic-array", + "subtle", + "zeroize", +] + [[package]] name = "semver" version = "0.11.0" @@ -2352,9 +2492,13 @@ dependencies = [ [[package]] name = "signature" -version = "1.5.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f054c6c1a6e95179d6f23ed974060dcefb2d9388bb7256900badad682c499de4" +checksum = "02658e48d89f2bec991f9a78e69cfa4c316f8d6a6c4ec12fae1aeb263d486788" +dependencies = [ + "digest 0.9.0", + "rand_core 0.6.3", +] [[package]] name = "simple-error" @@ -2488,10 +2632,12 @@ dependencies = [ "ed25519-dalek", "flex-error", "futures", + "k256", "num-traits", "once_cell", "prost", "prost-types", + "ripemd160", "serde", "serde_bytes", "serde_json", diff --git a/wasm_for_tests/wasm_source/Cargo.lock b/wasm_for_tests/wasm_source/Cargo.lock index 0cfcd70cb9..4d0e7b7875 100644 --- a/wasm_for_tests/wasm_source/Cargo.lock +++ b/wasm_for_tests/wasm_source/Cargo.lock @@ -205,6 +205,12 @@ dependencies = [ "rustc-demangle", ] +[[package]] +name = "base16ct" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" + [[package]] name = "base64" version = "0.13.0" @@ -403,6 +409,12 @@ dependencies = [ "syn", ] +[[package]] +name = "const-oid" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3" + [[package]] name = "constant_time_eq" version = "0.1.5" @@ -538,6 +550,18 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +[[package]] +name = "crypto-bigint" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c6a1d5fa1de37e071642dfa44ec552ca5b299adb128fab16138e24b548fd21" +dependencies = [ + "generic-array", + "rand_core 0.6.3", + "subtle", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.1.3" @@ -558,6 +582,16 @@ dependencies = [ "subtle", ] +[[package]] +name = "crypto-mac" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" +dependencies = [ + "generic-array", + "subtle", +] + [[package]] name = "curve25519-dalek" version = "3.2.0" @@ -619,6 +653,15 @@ dependencies = [ "syn", ] +[[package]] +name = "der" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6919815d73839e7ad218de758883aae3a257ba6759ce7a9992501efbb53d705c" +dependencies = [ + "const-oid", +] + [[package]] name = "derivative" version = "2.2.0" @@ -687,6 +730,18 @@ dependencies = [ "memmap2", ] +[[package]] +name = "ecdsa" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0d69ae62e0ce582d56380743515fefaf1a8c70cec685d9677636d7e30ae9dc9" +dependencies = [ + "der", + "elliptic-curve", + "rfc6979", + "signature", +] + [[package]] name = "ed25519" version = "1.4.1" @@ -729,6 +784,24 @@ version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +[[package]] +name = "elliptic-curve" +version = "0.11.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25b477563c2bfed38a3b7a60964c49e058b2510ad3f12ba3483fd8f62c2306d6" +dependencies = [ + "base16ct", + "crypto-bigint", + "der", + "ff", + "generic-array", + "group", + "rand_core 0.6.3", + "sec1", + "subtle", + "zeroize", +] + [[package]] name = "enum-iterator" version = "0.7.0" @@ -808,6 +881,16 @@ dependencies = [ "serde_bytes", ] +[[package]] +name = "ff" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "131655483be284720a17d74ff97592b8e76576dc25563148601df2d7c9080924" +dependencies = [ + "rand_core 0.6.3", + "subtle", +] + [[package]] name = "fixedbitset" version = "0.4.1" @@ -941,6 +1024,17 @@ version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" +[[package]] +name = "group" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5ac374b108929de78460075f3dc439fa66df9d8fc77e8f12caa5165fcf0c89" +dependencies = [ + "ff", + "rand_core 0.6.3", + "subtle", +] + [[package]] name = "gumdrop" version = "0.8.1" @@ -1028,7 +1122,17 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" dependencies = [ - "crypto-mac", + "crypto-mac 0.8.0", + "digest 0.9.0", +] + +[[package]] +name = "hmac" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" +dependencies = [ + "crypto-mac 0.11.1", "digest 0.9.0", ] @@ -1040,7 +1144,7 @@ checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" dependencies = [ "digest 0.9.0", "generic-array", - "hmac", + "hmac 0.8.1", ] [[package]] @@ -1236,6 +1340,19 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "k256" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19c3a5e0a0b8450278feda242592512e09f61c72e018b8cd5c859482802daf2d" +dependencies = [ + "cfg-if 1.0.0", + "ecdsa", + "elliptic-curve", + "sec1", + "sha2 0.9.9", +] + [[package]] name = "keccak" version = "0.1.0" @@ -2082,6 +2199,17 @@ dependencies = [ "bytecheck", ] +[[package]] +name = "rfc6979" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96ef608575f6392792f9ecf7890c00086591d29a83910939d430753f7c050525" +dependencies = [ + "crypto-bigint", + "hmac 0.11.0", + "zeroize", +] + [[package]] name = "ripemd160" version = "0.9.1" @@ -2242,6 +2370,18 @@ version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" +[[package]] +name = "sec1" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08da66b8b0965a5555b6bd6639e68ccba85e1e2506f5fbb089e93f8a04e1a2d1" +dependencies = [ + "der", + "generic-array", + "subtle", + "zeroize", +] + [[package]] name = "semver" version = "0.11.0" @@ -2358,9 +2498,13 @@ dependencies = [ [[package]] name = "signature" -version = "1.5.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f054c6c1a6e95179d6f23ed974060dcefb2d9388bb7256900badad682c499de4" +checksum = "02658e48d89f2bec991f9a78e69cfa4c316f8d6a6c4ec12fae1aeb263d486788" +dependencies = [ + "digest 0.9.0", + "rand_core 0.6.3", +] [[package]] name = "simple-error" @@ -2494,10 +2638,12 @@ dependencies = [ "ed25519-dalek", "flex-error", "futures", + "k256", "num-traits", "once_cell", "prost", "prost-types", + "ripemd160", "serde", "serde_bytes", "serde_json", From 7f2e44331e4a4b3da1e86992f9bd66cb201b83ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zemanovi=C4=8D?= Date: Fri, 12 Aug 2022 12:27:39 +0200 Subject: [PATCH 093/118] make fmt --- apps/src/lib/node/ledger/shell/mod.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/src/lib/node/ledger/shell/mod.rs b/apps/src/lib/node/ledger/shell/mod.rs index 0c416bee4f..23375f9e99 100644 --- a/apps/src/lib/node/ledger/shell/mod.rs +++ b/apps/src/lib/node/ledger/shell/mod.rs @@ -79,7 +79,7 @@ use crate::node::ledger::{protocol, storage, tendermint_node}; use crate::wallet::ValidatorData; use crate::{config, wallet}; -fn key_to_tendermint ( +fn key_to_tendermint( pk: &common::PublicKey, ) -> std::result::Result { println!("\nKEY TO TENDERMINT\n"); @@ -87,13 +87,13 @@ fn key_to_tendermint ( common::PublicKey::Ed25519(_) => { println!("\nEd25519\n"); ed25519::PublicKey::try_from_pk(pk) - .map(|pk| public_key::Sum::Ed25519(pk.try_to_vec().unwrap())) - }, + .map(|pk| public_key::Sum::Ed25519(pk.try_to_vec().unwrap())) + } common::PublicKey::Secp256k1(_) => { println!("\nSecp256k1\n"); secp256k1::PublicKey::try_from_pk(pk) - .map(|pk| public_key::Sum::Secp256k1(pk.try_to_vec().unwrap())) - }, + .map(|pk| public_key::Sum::Secp256k1(pk.try_to_vec().unwrap())) + } } } From 779e5834b45fcb217174ef839b8cb6de229424aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zemanovi=C4=8D?= Date: Fri, 12 Aug 2022 12:27:47 +0200 Subject: [PATCH 094/118] update rustdoc on PKH --- shared/src/types/key/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/shared/src/types/key/mod.rs b/shared/src/types/key/mod.rs index d8ccbb5a64..666cc3fb5e 100644 --- a/shared/src/types/key/mod.rs +++ b/shared/src/types/key/mod.rs @@ -285,7 +285,8 @@ pub trait SigScheme: Eq + Ord + Debug + Serialize + Default { ) -> Result<(), VerifySigError>; } -/// Ed25519 public key hash +/// Public key hash derived from `common::Key` borsh encoded bytes (hex string +/// of the first 40 chars of sha256 hash) #[derive( Debug, Clone, From d86e093b38af28c52bdd7feb48a6967c0665eb0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zemanovi=C4=8D?= Date: Fri, 12 Aug 2022 13:13:53 +0200 Subject: [PATCH 095/118] must use ed25519 for validator consensus key and node ID --- apps/src/lib/client/tx.rs | 3 ++- apps/src/lib/wallet/pre_genesis.rs | 13 ++++++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/apps/src/lib/client/tx.rs b/apps/src/lib/client/tx.rs index c6b2c9b254..0e95567460 100644 --- a/apps/src/lib/client/tx.rs +++ b/apps/src/lib/client/tx.rs @@ -208,7 +208,8 @@ pub async fn submit_init_validator( println!("Generating consensus key..."); ctx.wallet .gen_key( - scheme, + // Note that TM only allows ed25519 for consensus key + SchemeType::Ed25519, Some(consensus_key_alias.clone()), unsafe_dont_encrypt, ) diff --git a/apps/src/lib/wallet/pre_genesis.rs b/apps/src/lib/wallet/pre_genesis.rs index 4a6b4a4679..72f719d1e4 100644 --- a/apps/src/lib/wallet/pre_genesis.rs +++ b/apps/src/lib/wallet/pre_genesis.rs @@ -144,10 +144,17 @@ impl ValidatorWallet { fn gen(scheme: SchemeType, unsafe_dont_encrypt: bool) -> Self { let password = wallet::read_and_confirm_pwd(unsafe_dont_encrypt); let (account_key, account_sk) = gen_key_to_store(scheme, &password); - let (consensus_key, consensus_sk) = gen_key_to_store(scheme, &password); + let (consensus_key, consensus_sk) = gen_key_to_store( + // Note that TM only allows ed25519 for consensus key + SchemeType::Ed25519, + &password, + ); let (rewards_key, rewards_sk) = gen_key_to_store(scheme, &password); - let (tendermint_node_key, tendermint_node_sk) = - gen_key_to_store(scheme, &password); + let (tendermint_node_key, tendermint_node_sk) = gen_key_to_store( + // Note that TM only allows ed25519 for node IDs + SchemeType::Ed25519, + &password, + ); let validator_keys = store::Store::gen_validator_keys(None, scheme); let store = ValidatorStore { account_key, From 08d1d51aa51468dc1afea668260ecb5690ee645f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zemanovi=C4=8D?= Date: Fri, 12 Aug 2022 14:04:43 +0200 Subject: [PATCH 096/118] pick scheme for generating validator keys --- apps/src/lib/client/tx.rs | 3 ++- apps/src/lib/client/utils.rs | 5 ++++- apps/src/lib/wallet/mod.rs | 5 +---- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/apps/src/lib/client/tx.rs b/apps/src/lib/client/tx.rs index 0e95567460..0b2d8efc0e 100644 --- a/apps/src/lib/client/tx.rs +++ b/apps/src/lib/client/tx.rs @@ -234,7 +234,8 @@ pub async fn submit_init_validator( println!("Generating protocol signing key..."); } // Generate the validator keys - let validator_keys = ctx.wallet.gen_validator_keys(protocol_key).unwrap(); + let validator_keys = + ctx.wallet.gen_validator_keys(protocol_key, scheme).unwrap(); let protocol_key = validator_keys.get_protocol_keypair().ref_to(); let dkg_key = validator_keys .dkg_keypair diff --git a/apps/src/lib/client/utils.rs b/apps/src/lib/client/utils.rs index 5b45426d5a..e762e4d9f3 100644 --- a/apps/src/lib/client/utils.rs +++ b/apps/src/lib/client/utils.rs @@ -613,7 +613,10 @@ pub fn init_network( ); let validator_keys = wallet - .gen_validator_keys(Some(protocol_pk.clone())) + .gen_validator_keys( + Some(protocol_pk.clone()), + SchemeType::Ed25519, + ) .expect("Generating new validator keys should not fail"); let pk = validator_keys.dkg_keypair.as_ref().unwrap().public(); wallet.add_validator_data(address.clone(), validator_keys); diff --git a/apps/src/lib/wallet/mod.rs b/apps/src/lib/wallet/mod.rs index b5c68dd2c1..b3048ef97d 100644 --- a/apps/src/lib/wallet/mod.rs +++ b/apps/src/lib/wallet/mod.rs @@ -119,11 +119,8 @@ impl Wallet { pub fn gen_validator_keys( &mut self, protocol_pk: Option, + scheme: SchemeType, ) -> Result { - let scheme = match protocol_pk.as_ref().unwrap() { - common::PublicKey::Ed25519(_) => SchemeType::Ed25519, - common::PublicKey::Secp256k1(_) => SchemeType::Secp256k1, - }; let protocol_keypair = protocol_pk.map(|pk| { self.find_key_by_pkh(&PublicKeyHash::from(&pk)) .ok() From 204dffdc362bd2204c32d38b43c84996329b2746 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zemanovi=C4=8D?= Date: Fri, 12 Aug 2022 15:25:17 +0200 Subject: [PATCH 097/118] shared: optional secp256k1 signing and verification to avoid wasm bloat --- apps/Cargo.toml | 2 +- shared/Cargo.toml | 7 ++- shared/src/types/key/secp256k1.rs | 90 ++++++++++++++++++--------- wasm/tx_template/Cargo.lock | 37 +---------- wasm/vp_template/Cargo.lock | 37 +---------- wasm/wasm_source/Cargo.lock | 37 +---------- wasm_for_tests/wasm_source/Cargo.lock | 37 +---------- 7 files changed, 77 insertions(+), 170 deletions(-) diff --git a/apps/Cargo.toml b/apps/Cargo.toml index 0285cb7e48..ae3279d834 100644 --- a/apps/Cargo.toml +++ b/apps/Cargo.toml @@ -64,7 +64,7 @@ ABCI-plus-plus = [ testing = ["dev"] [dependencies] -namada = {path = "../shared", default-features = false, features = ["wasm-runtime", "ferveo-tpke", "rand"]} +namada = {path = "../shared", default-features = false, features = ["wasm-runtime", "ferveo-tpke", "rand", "secp256k1-sign-verify"]} ark-serialize = "0.3.0" ark-std = "0.3.0" async-std = {version = "1.9.0", features = ["unstable"]} diff --git a/shared/Cargo.toml b/shared/Cargo.toml index 630148db3e..71093ede33 100644 --- a/shared/Cargo.toml +++ b/shared/Cargo.toml @@ -61,6 +61,11 @@ wasm-runtime = [ "wasmer-vm", "wasmer", ] +# secp256k1 key signing and verification, disabled in WASM build by default as +# it bloats the build a lot +secp256k1-sign-verify = [ + "libsecp256k1/hmac", +] [dependencies] namada_proof_of_stake = {path = "../proof_of_stake"} @@ -86,7 +91,7 @@ ibc-proto-abci = {package = "ibc-proto", git = "https://github.com/heliaxdev/ibc ics23 = "0.6.7" itertools = "0.10.0" loupe = {version = "0.1.3", optional = true} -libsecp256k1 = {git = "https://github.com/heliaxdev/libsecp256k1", rev = "bbb3bd44a49db361f21d9db80f9a087c194c0ae9"} +libsecp256k1 = {git = "https://github.com/heliaxdev/libsecp256k1", rev = "bbb3bd44a49db361f21d9db80f9a087c194c0ae9", default-features = false, features = ["std", "static-context"]} parity-wasm = {version = "0.42.2", optional = true} # A fork with state machine testing proptest = {git = "https://github.com/heliaxdev/proptest", branch = "tomas/sm", optional = true} diff --git a/shared/src/types/key/secp256k1.rs b/shared/src/types/key/secp256k1.rs index 18d74dd5e8..e6607eda84 100644 --- a/shared/src/types/key/secp256k1.rs +++ b/shared/src/types/key/secp256k1.rs @@ -12,7 +12,6 @@ use rand::{CryptoRng, RngCore}; use serde::de::{Error, SeqAccess, Visitor}; use serde::ser::SerializeTuple; use serde::{Deserialize, Serialize, Serializer}; -use sha2::{Digest, Sha256}; use super::{ ParsePublicKeyError, ParseSecretKeyError, ParseSignatureError, RefTo, @@ -422,10 +421,21 @@ impl super::SigScheme for SigScheme { /// Sign the data with a key fn sign(keypair: &SecretKey, data: impl AsRef<[u8]>) -> Self::Signature { - let hash = Sha256::digest(data.as_ref()); - let message = libsecp256k1::Message::parse_slice(hash.as_ref()) - .expect("Message encoding should not fail"); - Signature(libsecp256k1::sign(&message, &keypair.0).0) + #[cfg(not(features = "secp256k1-sign-verify"))] + { + // to avoid `unused-variables` warn + let _ = (keypair, data); + panic!("\"secp256k1-sign-verify\" feature must be enabled"); + } + + #[cfg(features = "secp256k1-sign-verify")] + { + use sha2::{Digest, Sha256}; + let hash = Sha256::digest(data.as_ref()); + let message = libsecp256k1::Message::parse_slice(hash.as_ref()) + .expect("Message encoding should not fail"); + Signature(libsecp256k1::sign(&message, &keypair.0).0) + } } fn verify_signature( @@ -433,19 +443,31 @@ impl super::SigScheme for SigScheme { data: &T, sig: &Self::Signature, ) -> Result<(), VerifySigError> { - let bytes = &data - .try_to_vec() - .map_err(VerifySigError::DataEncodingError)?[..]; - let hash = Sha256::digest(bytes); - let message = &libsecp256k1::Message::parse_slice(hash.as_ref()) - .expect("Error parsing given data"); - let check = libsecp256k1::verify(message, &sig.0, &pk.0); - match check { - true => Ok(()), - false => Err(VerifySigError::SigVerifyError(format!( - "Error verifying secp256k1 signature: {}", - libsecp256k1::Error::InvalidSignature - ))), + #[cfg(not(features = "secp256k1-sign-verify"))] + { + // to avoid `unused-variables` warn + let _ = (pk, data, sig); + panic!("\"secp256k1-sign-verify\" feature must be enabled"); + } + + #[cfg(features = "secp256k1-sign-verify")] + { + use sha2::{Digest, Sha256}; + let bytes = &data + .try_to_vec() + .map_err(VerifySigError::DataEncodingError)?[..]; + let hash = Sha256::digest(bytes); + let message = &libsecp256k1::Message::parse_slice(hash.as_ref()) + .expect("Error parsing given data"); + let is_valid = libsecp256k1::verify(message, &sig.0, &pk.0); + if is_valid { + Ok(()) + } else { + Err(VerifySigError::SigVerifyError(format!( + "Error verifying secp256k1 signature: {}", + libsecp256k1::Error::InvalidSignature + ))) + } } } @@ -454,16 +476,28 @@ impl super::SigScheme for SigScheme { data: &[u8], sig: &Self::Signature, ) -> Result<(), VerifySigError> { - let hash = Sha256::digest(data); - let message = &libsecp256k1::Message::parse_slice(hash.as_ref()) - .expect("Error parsing raw data"); - let check = libsecp256k1::verify(message, &sig.0, &pk.0); - match check { - true => Ok(()), - false => Err(VerifySigError::SigVerifyError(format!( - "Error verifying secp256k1 signature: {}", - libsecp256k1::Error::InvalidSignature - ))), + #[cfg(not(features = "secp256k1-sign-verify"))] + { + // to avoid `unused-variables` warn + let _ = (pk, data, sig); + panic!("\"secp256k1-sign-verify\" feature must be enabled"); + } + + #[cfg(features = "secp256k1-sign-verify")] + { + use sha2::{Digest, Sha256}; + let hash = Sha256::digest(data); + let message = &libsecp256k1::Message::parse_slice(hash.as_ref()) + .expect("Error parsing raw data"); + let is_valid = libsecp256k1::verify(message, &sig.0, &pk.0); + if is_valid { + Ok(()) + } else { + Err(VerifySigError::SigVerifyError(format!( + "Error verifying secp256k1 signature: {}", + libsecp256k1::Error::InvalidSignature + ))) + } } } } diff --git a/wasm/tx_template/Cargo.lock b/wasm/tx_template/Cargo.lock index b3a15bee65..314538d3b4 100644 --- a/wasm/tx_template/Cargo.lock +++ b/wasm/tx_template/Cargo.lock @@ -571,16 +571,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "crypto-mac" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" -dependencies = [ - "generic-array", - "subtle", -] - [[package]] name = "crypto-mac" version = "0.11.1" @@ -1106,37 +1096,16 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -[[package]] -name = "hmac" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" -dependencies = [ - "crypto-mac 0.8.0", - "digest 0.9.0", -] - [[package]] name = "hmac" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" dependencies = [ - "crypto-mac 0.11.1", + "crypto-mac", "digest 0.9.0", ] -[[package]] -name = "hmac-drbg" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" -dependencies = [ - "digest 0.9.0", - "generic-array", - "hmac 0.8.1", -] - [[package]] name = "http" version = "0.2.6" @@ -1385,14 +1354,12 @@ dependencies = [ "arrayref", "base64", "digest 0.9.0", - "hmac-drbg", "libsecp256k1-core", "libsecp256k1-gen-ecmult", "libsecp256k1-gen-genmult", "rand", "serde", "sha2 0.9.9", - "typenum", ] [[package]] @@ -2174,7 +2141,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96ef608575f6392792f9ecf7890c00086591d29a83910939d430753f7c050525" dependencies = [ "crypto-bigint", - "hmac 0.11.0", + "hmac", "zeroize", ] diff --git a/wasm/vp_template/Cargo.lock b/wasm/vp_template/Cargo.lock index 799256683d..3e58845387 100644 --- a/wasm/vp_template/Cargo.lock +++ b/wasm/vp_template/Cargo.lock @@ -571,16 +571,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "crypto-mac" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" -dependencies = [ - "generic-array", - "subtle", -] - [[package]] name = "crypto-mac" version = "0.11.1" @@ -1106,37 +1096,16 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -[[package]] -name = "hmac" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" -dependencies = [ - "crypto-mac 0.8.0", - "digest 0.9.0", -] - [[package]] name = "hmac" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" dependencies = [ - "crypto-mac 0.11.1", + "crypto-mac", "digest 0.9.0", ] -[[package]] -name = "hmac-drbg" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" -dependencies = [ - "digest 0.9.0", - "generic-array", - "hmac 0.8.1", -] - [[package]] name = "http" version = "0.2.6" @@ -1385,14 +1354,12 @@ dependencies = [ "arrayref", "base64", "digest 0.9.0", - "hmac-drbg", "libsecp256k1-core", "libsecp256k1-gen-ecmult", "libsecp256k1-gen-genmult", "rand", "serde", "sha2 0.9.9", - "typenum", ] [[package]] @@ -2174,7 +2141,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96ef608575f6392792f9ecf7890c00086591d29a83910939d430753f7c050525" dependencies = [ "crypto-bigint", - "hmac 0.11.0", + "hmac", "zeroize", ] diff --git a/wasm/wasm_source/Cargo.lock b/wasm/wasm_source/Cargo.lock index 5124bdd0c0..e3dce7ddee 100644 --- a/wasm/wasm_source/Cargo.lock +++ b/wasm/wasm_source/Cargo.lock @@ -571,16 +571,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "crypto-mac" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" -dependencies = [ - "generic-array", - "subtle", -] - [[package]] name = "crypto-mac" version = "0.11.1" @@ -1106,37 +1096,16 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -[[package]] -name = "hmac" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" -dependencies = [ - "crypto-mac 0.8.0", - "digest 0.9.0", -] - [[package]] name = "hmac" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" dependencies = [ - "crypto-mac 0.11.1", + "crypto-mac", "digest 0.9.0", ] -[[package]] -name = "hmac-drbg" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" -dependencies = [ - "digest 0.9.0", - "generic-array", - "hmac 0.8.1", -] - [[package]] name = "http" version = "0.2.6" @@ -1385,14 +1354,12 @@ dependencies = [ "arrayref", "base64", "digest 0.9.0", - "hmac-drbg", "libsecp256k1-core", "libsecp256k1-gen-ecmult", "libsecp256k1-gen-genmult", "rand", "serde", "sha2 0.9.9", - "typenum", ] [[package]] @@ -2200,7 +2167,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96ef608575f6392792f9ecf7890c00086591d29a83910939d430753f7c050525" dependencies = [ "crypto-bigint", - "hmac 0.11.0", + "hmac", "zeroize", ] diff --git a/wasm_for_tests/wasm_source/Cargo.lock b/wasm_for_tests/wasm_source/Cargo.lock index 4d0e7b7875..c386be2926 100644 --- a/wasm_for_tests/wasm_source/Cargo.lock +++ b/wasm_for_tests/wasm_source/Cargo.lock @@ -572,16 +572,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "crypto-mac" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" -dependencies = [ - "generic-array", - "subtle", -] - [[package]] name = "crypto-mac" version = "0.11.1" @@ -1116,35 +1106,14 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -[[package]] -name = "hmac" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" -dependencies = [ - "crypto-mac 0.8.0", - "digest 0.9.0", -] - [[package]] name = "hmac" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" dependencies = [ - "crypto-mac 0.11.1", - "digest 0.9.0", -] - -[[package]] -name = "hmac-drbg" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" -dependencies = [ + "crypto-mac", "digest 0.9.0", - "generic-array", - "hmac 0.8.1", ] [[package]] @@ -1395,14 +1364,12 @@ dependencies = [ "arrayref", "base64", "digest 0.9.0", - "hmac-drbg", "libsecp256k1-core", "libsecp256k1-gen-ecmult", "libsecp256k1-gen-genmult", "rand", "serde", "sha2 0.9.9", - "typenum", ] [[package]] @@ -2206,7 +2173,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96ef608575f6392792f9ecf7890c00086591d29a83910939d430753f7c050525" dependencies = [ "crypto-bigint", - "hmac 0.11.0", + "hmac", "zeroize", ] From 170b02276608a4056647768a5a0d3e17f520f054 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zemanovi=C4=8D?= Date: Fri, 12 Aug 2022 15:39:04 +0200 Subject: [PATCH 098/118] client: add check on validator consensus key --- apps/src/lib/client/tx.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/apps/src/lib/client/tx.rs b/apps/src/lib/client/tx.rs index 0b2d8efc0e..a04cb702a1 100644 --- a/apps/src/lib/client/tx.rs +++ b/apps/src/lib/client/tx.rs @@ -203,8 +203,16 @@ pub async fn submit_init_validator( .ref_to() }); - let consensus_key = - ctx.get_opt_cached(&consensus_key).unwrap_or_else(|| { + let consensus_key = ctx + .get_opt_cached(&consensus_key) + .map(|key| match *key { + common::SecretKey::Ed25519(_) => key, + common::SecretKey::Secp256k1(_) => { + eprintln!("Consensus key can only be ed25519"); + safe_exit(1) + } + }) + .unwrap_or_else(|| { println!("Generating consensus key..."); ctx.wallet .gen_key( From baa22d3ad5a15a4877ec685374665d5442c129f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zemanovi=C4=8D?= Date: Fri, 12 Aug 2022 16:16:08 +0200 Subject: [PATCH 099/118] test: allow to sign and verify secp256k1 --- shared/Cargo.toml | 1 + shared/src/types/key/secp256k1.rs | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/shared/Cargo.toml b/shared/Cargo.toml index 71093ede33..a98b2df716 100644 --- a/shared/Cargo.toml +++ b/shared/Cargo.toml @@ -127,6 +127,7 @@ zeroize = "1.5.5" [dev-dependencies] assert_matches = "1.5.0" byte-unit = "4.0.13" +libsecp256k1 = {git = "https://github.com/brentstone/libsecp256k1", rev = "bbb3bd44a49db361f21d9db80f9a087c194c0ae9"} pretty_assertions = "0.7.2" # A fork with state machine testing proptest = {git = "https://github.com/heliaxdev/proptest", branch = "tomas/sm"} diff --git a/shared/src/types/key/secp256k1.rs b/shared/src/types/key/secp256k1.rs index e6607eda84..99bcbb3f67 100644 --- a/shared/src/types/key/secp256k1.rs +++ b/shared/src/types/key/secp256k1.rs @@ -421,14 +421,14 @@ impl super::SigScheme for SigScheme { /// Sign the data with a key fn sign(keypair: &SecretKey, data: impl AsRef<[u8]>) -> Self::Signature { - #[cfg(not(features = "secp256k1-sign-verify"))] + #[cfg(not(any(test, features = "secp256k1-sign-verify")))] { // to avoid `unused-variables` warn let _ = (keypair, data); panic!("\"secp256k1-sign-verify\" feature must be enabled"); } - #[cfg(features = "secp256k1-sign-verify")] + #[cfg(any(test, features = "secp256k1-sign-verify"))] { use sha2::{Digest, Sha256}; let hash = Sha256::digest(data.as_ref()); @@ -443,14 +443,14 @@ impl super::SigScheme for SigScheme { data: &T, sig: &Self::Signature, ) -> Result<(), VerifySigError> { - #[cfg(not(features = "secp256k1-sign-verify"))] + #[cfg(not(any(test, features = "secp256k1-sign-verify")))] { // to avoid `unused-variables` warn let _ = (pk, data, sig); panic!("\"secp256k1-sign-verify\" feature must be enabled"); } - #[cfg(features = "secp256k1-sign-verify")] + #[cfg(any(test, features = "secp256k1-sign-verify"))] { use sha2::{Digest, Sha256}; let bytes = &data @@ -476,14 +476,14 @@ impl super::SigScheme for SigScheme { data: &[u8], sig: &Self::Signature, ) -> Result<(), VerifySigError> { - #[cfg(not(features = "secp256k1-sign-verify"))] + #[cfg(not(any(test, features = "secp256k1-sign-verify")))] { // to avoid `unused-variables` warn let _ = (pk, data, sig); panic!("\"secp256k1-sign-verify\" feature must be enabled"); } - #[cfg(features = "secp256k1-sign-verify")] + #[cfg(any(test, features = "secp256k1-sign-verify"))] { use sha2::{Digest, Sha256}; let hash = Sha256::digest(data); From 4e5ff6a35dd24e1007825ea4eefa201e27464b3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zemanovi=C4=8D?= Date: Fri, 19 Aug 2022 18:21:06 +0200 Subject: [PATCH 100/118] changelog: add #278 --- .changelog/unreleased/features/278-secp256k1-support.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 .changelog/unreleased/features/278-secp256k1-support.md diff --git a/.changelog/unreleased/features/278-secp256k1-support.md b/.changelog/unreleased/features/278-secp256k1-support.md new file mode 100644 index 0000000000..fb257152e4 --- /dev/null +++ b/.changelog/unreleased/features/278-secp256k1-support.md @@ -0,0 +1 @@ +- Added secp256k1 support ([#278](https://github.com/anoma/anoma/pull/278)) \ No newline at end of file From 9e2fc9489236f77b2c741f49e8ce1ba3e37390e4 Mon Sep 17 00:00:00 2001 From: "Raymond E. Pasco" Date: Sat, 20 Aug 2022 11:45:13 -0400 Subject: [PATCH 101/118] realign cargo/wasm integrity --- shared/Cargo.toml | 2 +- wasm/checksums.json | 34 ++++----- wasm/wasm_source/Cargo.lock | 146 ------------------------------------ 3 files changed, 18 insertions(+), 164 deletions(-) diff --git a/shared/Cargo.toml b/shared/Cargo.toml index a98b2df716..7f66083afd 100644 --- a/shared/Cargo.toml +++ b/shared/Cargo.toml @@ -127,7 +127,7 @@ zeroize = "1.5.5" [dev-dependencies] assert_matches = "1.5.0" byte-unit = "4.0.13" -libsecp256k1 = {git = "https://github.com/brentstone/libsecp256k1", rev = "bbb3bd44a49db361f21d9db80f9a087c194c0ae9"} +libsecp256k1 = {git = "https://github.com/heliaxdev/libsecp256k1", rev = "bbb3bd44a49db361f21d9db80f9a087c194c0ae9"} pretty_assertions = "0.7.2" # A fork with state machine testing proptest = {git = "https://github.com/heliaxdev/proptest", branch = "tomas/sm"} diff --git a/wasm/checksums.json b/wasm/checksums.json index 11598f4944..3c3e15e1ce 100644 --- a/wasm/checksums.json +++ b/wasm/checksums.json @@ -1,19 +1,19 @@ { - "tx_bond.wasm": "tx_bond.42504d29d81008869e2c13775254e493181fa334f557940be8ad614ea8aa439a.wasm", - "tx_from_intent.wasm": "tx_from_intent.56a079838bf3d06d7be0160864ff4b70ad5961a9baff7ca8d28cf31e59111395.wasm", - "tx_ibc.wasm": "tx_ibc.8b4f5ead4fa069d2786e988cbe2bcb63f095cdcd47c913614829ef795dcbfa30.wasm", - "tx_init_account.wasm": "tx_init_account.80fbd4271cbef05fb6d340617ecb1437fc375c62f1a28baf989945d03850d0e1.wasm", - "tx_init_nft.wasm": "tx_init_nft.389a37111a810e71d9eafa56ea22f73374a1277d16325105f42cdc86ae23feca.wasm", - "tx_init_proposal.wasm": "tx_init_proposal.f3276f42cad9aa79ebc1da6516b78a9af624644d43cdfcca2b86f6e618334257.wasm", - "tx_init_validator.wasm": "tx_init_validator.a71938fb2aac071b44b9949ab055d493e29b5791f4dde3293635a0faf05c64a9.wasm", - "tx_mint_nft.wasm": "tx_mint_nft.d8af9ed4d99f1d58642a0a0b2759109b8df1f3dcb583b19609bb0da96b41b74c.wasm", - "tx_transfer.wasm": "tx_transfer.b35df2da33c8828287c7de8163d0ecc8c59b4444cd1c9afcf246c569ae653a74.wasm", - "tx_unbond.wasm": "tx_unbond.49d120af6a0e7183dc88ca1dfad44825763dcc6cd7c32afef694d4e814e64f50.wasm", - "tx_update_vp.wasm": "tx_update_vp.025a9dec03f1e138a3e5bdcafeebe53b220a75340c6cdf7160663b870ee92bb8.wasm", - "tx_vote_proposal.wasm": "tx_vote_proposal.ea9332b02b39d852fe4e8949de56d96bb6fdde9fad69a7252f32bb3465f527ff.wasm", - "tx_withdraw.wasm": "tx_withdraw.199ea7cb708d12196cf4cf06598c58403d1b07056284d275c3022d47207323c1.wasm", - "vp_nft.wasm": "vp_nft.31eb61ed64a4eda03d3d872d6b3716e0fe4210b7d02275463adae3bbf6dfcaa1.wasm", - "vp_testnet_faucet.wasm": "vp_testnet_faucet.87a7e0e37af26847bc91e1559de3018ac97382f969c76f99ca86423f3a19f502.wasm", - "vp_token.wasm": "vp_token.7cb6763045cc60eb013db6adf75d254eeedeb01d0b1ecb4a1dfce5288096de6a.wasm", - "vp_user.wasm": "vp_user.a63e9a36b20abc4ef105b50e77302577f0850e60993cdcdc3ee6b2d9886ebebc.wasm" + "tx_bond.wasm": "tx_bond.d241baf08f2d1789c6474ef157f62dda0f84e35374f40fd5dd0435dd3ef81e8a.wasm", + "tx_from_intent.wasm": "tx_from_intent.18c25e16faa536a1c330ad758df136b77ce7f89f1511018f34d055b28b793984.wasm", + "tx_ibc.wasm": "tx_ibc.08f96b03da8743079c6f84440aadc9935ba658a2687537c9132f6c4be7701246.wasm", + "tx_init_account.wasm": "tx_init_account.d891589ceacda745195586bc1315909e3c87137c3f2ee2d443ef404dc9ff7b5c.wasm", + "tx_init_nft.wasm": "tx_init_nft.aa8609aebfc81352a8d620e9404b963c05faf5bf0cdf5576ea1598f7af881f37.wasm", + "tx_init_proposal.wasm": "tx_init_proposal.0071943d94f6678d8b895bd711e80eacf77c92abe4db126811d17458150a4fe7.wasm", + "tx_init_validator.wasm": "tx_init_validator.d02373337986b978ff0cdff231e8690bfdecf69fb1cb0226f5a84dfd5dd8b9de.wasm", + "tx_mint_nft.wasm": "tx_mint_nft.c80b133547686d6f18c0a4b7df34280cb96cd946f59d3ed23cbea6338f004cd9.wasm", + "tx_transfer.wasm": "tx_transfer.605c3ad2ffe4ce507d488b5c2149ece2c6ceb622a1001776ffb42ee4a7ffef80.wasm", + "tx_unbond.wasm": "tx_unbond.4196060452c1b38ac8cdc665aff7cf58bd9020ac2a7c87acb09335892751d1eb.wasm", + "tx_update_vp.wasm": "tx_update_vp.59ede2f57cfe144ce9a4326cb9a0facff7dd0a159ac57e89052907f5baebf04a.wasm", + "tx_vote_proposal.wasm": "tx_vote_proposal.ad2cdff34ae652a4b7397d048809245f22ab0f52ef24ba317ca05bc549acce59.wasm", + "tx_withdraw.wasm": "tx_withdraw.41da7be6a61ac96f8d2f4a687402b7127eac7c8bfa27ac68d24020284bba4400.wasm", + "vp_nft.wasm": "vp_nft.90501e80fce11e84a65c00bab65a59378b8798bad40fc3dfd40a00ff9dfa1ad4.wasm", + "vp_testnet_faucet.wasm": "vp_testnet_faucet.36645a3512d3734dd9a3a12bfedb977a9ab2dcb85dd24eec6f7d3aa03c08ffd2.wasm", + "vp_token.wasm": "vp_token.919222c01ee2e2c3e56a9e40419075a8b412b81088707880757d4b7826d7721c.wasm", + "vp_user.wasm": "vp_user.9d80aed506488e6b31282fd480b4fa8563409fa3f0317d401153a7edcc9ebbaa.wasm" } \ No newline at end of file diff --git a/wasm/wasm_source/Cargo.lock b/wasm/wasm_source/Cargo.lock index e3dce7ddee..17b80af9b6 100644 --- a/wasm/wasm_source/Cargo.lock +++ b/wasm/wasm_source/Cargo.lock @@ -205,12 +205,6 @@ dependencies = [ "rustc-demangle", ] -[[package]] -name = "base16ct" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" - [[package]] name = "base64" version = "0.13.0" @@ -409,12 +403,6 @@ dependencies = [ "syn", ] -[[package]] -name = "const-oid" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3" - [[package]] name = "constant_time_eq" version = "0.1.5" @@ -549,18 +537,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" -[[package]] -name = "crypto-bigint" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c6a1d5fa1de37e071642dfa44ec552ca5b299adb128fab16138e24b548fd21" -dependencies = [ - "generic-array", - "rand_core 0.6.3", - "subtle", - "zeroize", -] - [[package]] name = "crypto-common" version = "0.1.3" @@ -571,16 +547,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "crypto-mac" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" -dependencies = [ - "generic-array", - "subtle", -] - [[package]] name = "curve25519-dalek" version = "3.2.0" @@ -642,15 +608,6 @@ dependencies = [ "syn", ] -[[package]] -name = "der" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6919815d73839e7ad218de758883aae3a257ba6759ce7a9992501efbb53d705c" -dependencies = [ - "const-oid", -] - [[package]] name = "derivative" version = "2.2.0" @@ -719,18 +676,6 @@ dependencies = [ "memmap2", ] -[[package]] -name = "ecdsa" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0d69ae62e0ce582d56380743515fefaf1a8c70cec685d9677636d7e30ae9dc9" -dependencies = [ - "der", - "elliptic-curve", - "rfc6979", - "signature", -] - [[package]] name = "ed25519" version = "1.4.0" @@ -773,24 +718,6 @@ version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" -[[package]] -name = "elliptic-curve" -version = "0.11.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25b477563c2bfed38a3b7a60964c49e058b2510ad3f12ba3483fd8f62c2306d6" -dependencies = [ - "base16ct", - "crypto-bigint", - "der", - "ff", - "generic-array", - "group", - "rand_core 0.6.3", - "sec1", - "subtle", - "zeroize", -] - [[package]] name = "enum-iterator" version = "0.7.0" @@ -870,16 +797,6 @@ dependencies = [ "serde_bytes", ] -[[package]] -name = "ff" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "131655483be284720a17d74ff97592b8e76576dc25563148601df2d7c9080924" -dependencies = [ - "rand_core 0.6.3", - "subtle", -] - [[package]] name = "fixedbitset" version = "0.4.1" @@ -1013,17 +930,6 @@ version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" -[[package]] -name = "group" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5ac374b108929de78460075f3dc439fa66df9d8fc77e8f12caa5165fcf0c89" -dependencies = [ - "ff", - "rand_core 0.6.3", - "subtle", -] - [[package]] name = "gumdrop" version = "0.8.0" @@ -1096,16 +1002,6 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -[[package]] -name = "hmac" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" -dependencies = [ - "crypto-mac", - "digest 0.9.0", -] - [[package]] name = "http" version = "0.2.6" @@ -1299,19 +1195,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "k256" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19c3a5e0a0b8450278feda242592512e09f61c72e018b8cd5c859482802daf2d" -dependencies = [ - "cfg-if 1.0.0", - "ecdsa", - "elliptic-curve", - "sec1", - "sha2 0.9.9", -] - [[package]] name = "keccak" version = "0.1.0" @@ -2160,17 +2043,6 @@ dependencies = [ "bytecheck", ] -[[package]] -name = "rfc6979" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96ef608575f6392792f9ecf7890c00086591d29a83910939d430753f7c050525" -dependencies = [ - "crypto-bigint", - "hmac", - "zeroize", -] - [[package]] name = "ripemd160" version = "0.9.1" @@ -2331,18 +2203,6 @@ version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" -[[package]] -name = "sec1" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08da66b8b0965a5555b6bd6639e68ccba85e1e2506f5fbb089e93f8a04e1a2d1" -dependencies = [ - "der", - "generic-array", - "subtle", - "zeroize", -] - [[package]] name = "semver" version = "0.11.0" @@ -2462,10 +2322,6 @@ name = "signature" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02658e48d89f2bec991f9a78e69cfa4c316f8d6a6c4ec12fae1aeb263d486788" -dependencies = [ - "digest 0.9.0", - "rand_core 0.6.3", -] [[package]] name = "simple-error" @@ -2599,12 +2455,10 @@ dependencies = [ "ed25519-dalek", "flex-error", "futures", - "k256", "num-traits", "once_cell", "prost", "prost-types", - "ripemd160", "serde", "serde_bytes", "serde_json", From bda02c28de18b2d2dedf069ac7326620a57f44d1 Mon Sep 17 00:00:00 2001 From: brentstone Date: Sat, 20 Aug 2022 14:56:35 +0200 Subject: [PATCH 102/118] fix spelling of 'features' in Cargo.toml --- apps/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/Cargo.toml b/apps/Cargo.toml index ae3279d834..6ea61b0bfd 100644 --- a/apps/Cargo.toml +++ b/apps/Cargo.toml @@ -123,7 +123,7 @@ sparse-merkle-tree = {git = "https://github.com/heliaxdev/sparse-merkle-tree", b sysinfo = {version = "=0.21.1", default-features = false} tar = "0.4.37" # temporarily using fork work-around -tendermint = {git = "https://github.com/heliaxdev/tendermint-rs", rev = "95c52476bc37927218374f94ac8e2a19bd35bec9", festures = ["secp256k1"], optional = true} +tendermint = {git = "https://github.com/heliaxdev/tendermint-rs", rev = "95c52476bc37927218374f94ac8e2a19bd35bec9", features = ["secp256k1"], optional = true} tendermint-config = {git = "https://github.com/heliaxdev/tendermint-rs", rev = "95c52476bc37927218374f94ac8e2a19bd35bec9", optional = true} tendermint-config-abci = {package = "tendermint-config", git = "https://github.com/heliaxdev/tendermint-rs", branch = "yuji/rebase_v0.23.5", optional = true} tendermint-proto = {git = "https://github.com/heliaxdev/tendermint-rs", rev = "95c52476bc37927218374f94ac8e2a19bd35bec9", optional = true} From d1a06a26abcfc8c3c0fd8904c020a79fac1ac52d Mon Sep 17 00:00:00 2001 From: "Raymond E. Pasco" Date: Sat, 20 Aug 2022 12:16:52 -0400 Subject: [PATCH 103/118] Namada 0.7.1 --- .../{unreleased => v0.7.1}/ci/222-new-ci.md | 0 .../docs/1070-pos-spec-updates.md | 0 .../docs/1143-update-libraries-docs.md | 0 .../docs/322-openapi-spec.md | 0 .../features/278-secp256k1-support.md | 0 .../improvements/1202-expectrl-logging.md | 0 .../improvements/1239-hide-tm-log.md | 0 .../improvements/277-zeroize-secret-keys.md | 0 .../miscellaneous/1158-gitignore-anoma.md | 0 .changelog/v0.7.1/summary.md | 4 ++ .../testing/1142-expectrl-switch-from-fork.md | 0 .../testing/247-e2e-fix-cmd-assert.md | 0 CHANGELOG.md | 47 +++++++++++++++++++ Cargo.lock | 18 +++---- apps/Cargo.toml | 2 +- encoding_spec/Cargo.toml | 2 +- macros/Cargo.toml | 2 +- proof_of_stake/Cargo.toml | 2 +- shared/Cargo.toml | 2 +- tests/Cargo.toml | 2 +- tx_prelude/Cargo.toml | 2 +- vm_env/Cargo.toml | 2 +- vp_prelude/Cargo.toml | 2 +- wasm/checksums.json | 32 ++++++------- wasm/tx_template/Cargo.lock | 22 ++++----- wasm/tx_template/Cargo.toml | 2 +- wasm/vp_template/Cargo.lock | 22 ++++----- wasm/vp_template/Cargo.toml | 2 +- wasm/wasm_source/Cargo.lock | 16 +++---- wasm/wasm_source/Cargo.toml | 2 +- wasm_for_tests/wasm_source/Cargo.toml | 2 +- 31 files changed, 119 insertions(+), 68 deletions(-) rename .changelog/{unreleased => v0.7.1}/ci/222-new-ci.md (100%) rename .changelog/{unreleased => v0.7.1}/docs/1070-pos-spec-updates.md (100%) rename .changelog/{unreleased => v0.7.1}/docs/1143-update-libraries-docs.md (100%) rename .changelog/{unreleased => v0.7.1}/docs/322-openapi-spec.md (100%) rename .changelog/{unreleased => v0.7.1}/features/278-secp256k1-support.md (100%) rename .changelog/{unreleased => v0.7.1}/improvements/1202-expectrl-logging.md (100%) rename .changelog/{unreleased => v0.7.1}/improvements/1239-hide-tm-log.md (100%) rename .changelog/{unreleased => v0.7.1}/improvements/277-zeroize-secret-keys.md (100%) rename .changelog/{unreleased => v0.7.1}/miscellaneous/1158-gitignore-anoma.md (100%) create mode 100644 .changelog/v0.7.1/summary.md rename .changelog/{unreleased => v0.7.1}/testing/1142-expectrl-switch-from-fork.md (100%) rename .changelog/{unreleased => v0.7.1}/testing/247-e2e-fix-cmd-assert.md (100%) diff --git a/.changelog/unreleased/ci/222-new-ci.md b/.changelog/v0.7.1/ci/222-new-ci.md similarity index 100% rename from .changelog/unreleased/ci/222-new-ci.md rename to .changelog/v0.7.1/ci/222-new-ci.md diff --git a/.changelog/unreleased/docs/1070-pos-spec-updates.md b/.changelog/v0.7.1/docs/1070-pos-spec-updates.md similarity index 100% rename from .changelog/unreleased/docs/1070-pos-spec-updates.md rename to .changelog/v0.7.1/docs/1070-pos-spec-updates.md diff --git a/.changelog/unreleased/docs/1143-update-libraries-docs.md b/.changelog/v0.7.1/docs/1143-update-libraries-docs.md similarity index 100% rename from .changelog/unreleased/docs/1143-update-libraries-docs.md rename to .changelog/v0.7.1/docs/1143-update-libraries-docs.md diff --git a/.changelog/unreleased/docs/322-openapi-spec.md b/.changelog/v0.7.1/docs/322-openapi-spec.md similarity index 100% rename from .changelog/unreleased/docs/322-openapi-spec.md rename to .changelog/v0.7.1/docs/322-openapi-spec.md diff --git a/.changelog/unreleased/features/278-secp256k1-support.md b/.changelog/v0.7.1/features/278-secp256k1-support.md similarity index 100% rename from .changelog/unreleased/features/278-secp256k1-support.md rename to .changelog/v0.7.1/features/278-secp256k1-support.md diff --git a/.changelog/unreleased/improvements/1202-expectrl-logging.md b/.changelog/v0.7.1/improvements/1202-expectrl-logging.md similarity index 100% rename from .changelog/unreleased/improvements/1202-expectrl-logging.md rename to .changelog/v0.7.1/improvements/1202-expectrl-logging.md diff --git a/.changelog/unreleased/improvements/1239-hide-tm-log.md b/.changelog/v0.7.1/improvements/1239-hide-tm-log.md similarity index 100% rename from .changelog/unreleased/improvements/1239-hide-tm-log.md rename to .changelog/v0.7.1/improvements/1239-hide-tm-log.md diff --git a/.changelog/unreleased/improvements/277-zeroize-secret-keys.md b/.changelog/v0.7.1/improvements/277-zeroize-secret-keys.md similarity index 100% rename from .changelog/unreleased/improvements/277-zeroize-secret-keys.md rename to .changelog/v0.7.1/improvements/277-zeroize-secret-keys.md diff --git a/.changelog/unreleased/miscellaneous/1158-gitignore-anoma.md b/.changelog/v0.7.1/miscellaneous/1158-gitignore-anoma.md similarity index 100% rename from .changelog/unreleased/miscellaneous/1158-gitignore-anoma.md rename to .changelog/v0.7.1/miscellaneous/1158-gitignore-anoma.md diff --git a/.changelog/v0.7.1/summary.md b/.changelog/v0.7.1/summary.md new file mode 100644 index 0000000000..3dff03d9d8 --- /dev/null +++ b/.changelog/v0.7.1/summary.md @@ -0,0 +1,4 @@ +Namada 0.7.1 is a patch release of the Namada software, continuing the +version numbering sequence previously used in the Anoma repository. +There are few important user-facing changes, but this is the first +tagged release in the Namada repository. diff --git a/.changelog/unreleased/testing/1142-expectrl-switch-from-fork.md b/.changelog/v0.7.1/testing/1142-expectrl-switch-from-fork.md similarity index 100% rename from .changelog/unreleased/testing/1142-expectrl-switch-from-fork.md rename to .changelog/v0.7.1/testing/1142-expectrl-switch-from-fork.md diff --git a/.changelog/unreleased/testing/247-e2e-fix-cmd-assert.md b/.changelog/v0.7.1/testing/247-e2e-fix-cmd-assert.md similarity index 100% rename from .changelog/unreleased/testing/247-e2e-fix-cmd-assert.md rename to .changelog/v0.7.1/testing/247-e2e-fix-cmd-assert.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c56bba7fe..12656661af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,52 @@ # CHANGELOG +## v0.7.1 + +Namada 0.7.1 is a patch release of the Namada software, continuing the +version numbering sequence previously used in the Anoma repository. +There are few important user-facing changes, but this is the first +tagged release in the Namada repository. + +### CI + +- New CI using Github Actions + ([#222](https://github.com/anoma/namada/pull/222)) + +### DOCS + +- Added OpenAPI spec ([#322](https://github.com/anoma/namada/pull/322)) +- Applied various fixes and updates to the PoS system spec and integration spec + ([#1070](https://github.com/anoma/anoma/pull/1070)) +- Fixes libraries doc typos and correct comment on the clap crate + ([#1143](https://github.com/anoma/anoma/pull/1143)) + +### FEATURES + +- Added secp256k1 support ([#278](https://github.com/anoma/anoma/pull/278)) + +### IMPROVEMENTS + +- Zeroize secret keys from memory + ([#277](https://github.com/anoma/namada/pull/277)) +- Better logging for end-to-end tests, and logs are + stored to disk in the test's temporary working directory + ([#1202](https://github.com/anoma/anoma/pull/1202)) +- Hidden the stdout of Tendermint process by default. To include + it in the node's output, run with `ANOMA_TM_STDOUT=true` + ([#1239](https://github.com/anoma/anoma/pull/1239)) + +### MISCELLANEOUS + +- Make some .gitignore patterns relative to repo root + ([#1158](https://github.com/anoma/anoma/pull/1158)) + +### TESTING + +- E2E: Consume unread output before checking exit status. + ([#247](https://github.com/anoma/namada/pull/247)) +- Switch back from a fork to a newly released version of expectrl + ([#1142](https://github.com/anoma/anoma/pull/1142)) + ## v0.6.1 Anoma 0.6.1 is a patch release updating the Rust toolchain and various diff --git a/Cargo.lock b/Cargo.lock index 4d073ec1ac..eafd05b2ff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4023,7 +4023,7 @@ dependencies = [ [[package]] name = "namada" -version = "0.7.0" +version = "0.7.1" dependencies = [ "ark-bls12-381", "ark-ec", @@ -4080,7 +4080,7 @@ dependencies = [ [[package]] name = "namada_apps" -version = "0.7.0" +version = "0.7.1" dependencies = [ "ark-serialize", "ark-std", @@ -4165,7 +4165,7 @@ dependencies = [ [[package]] name = "namada_encoding_spec" -version = "0.7.0" +version = "0.7.1" dependencies = [ "borsh", "itertools 0.10.3", @@ -4176,7 +4176,7 @@ dependencies = [ [[package]] name = "namada_macros" -version = "0.7.0" +version = "0.7.1" dependencies = [ "quote", "syn", @@ -4184,7 +4184,7 @@ dependencies = [ [[package]] name = "namada_proof_of_stake" -version = "0.7.0" +version = "0.7.1" dependencies = [ "borsh", "proptest", @@ -4193,7 +4193,7 @@ dependencies = [ [[package]] name = "namada_tests" -version = "0.7.0" +version = "0.7.1" dependencies = [ "assert_cmd", "borsh", @@ -4227,7 +4227,7 @@ dependencies = [ [[package]] name = "namada_tx_prelude" -version = "0.7.0" +version = "0.7.1" dependencies = [ "namada_vm_env", "sha2 0.10.2", @@ -4235,7 +4235,7 @@ dependencies = [ [[package]] name = "namada_vm_env" -version = "0.7.0" +version = "0.7.1" dependencies = [ "borsh", "hex", @@ -4245,7 +4245,7 @@ dependencies = [ [[package]] name = "namada_vp_prelude" -version = "0.7.0" +version = "0.7.1" dependencies = [ "namada_vm_env", "sha2 0.10.2", diff --git a/apps/Cargo.toml b/apps/Cargo.toml index 9f9b65ffd5..65d7d84eed 100644 --- a/apps/Cargo.toml +++ b/apps/Cargo.toml @@ -6,7 +6,7 @@ license = "GPL-3.0" name = "namada_apps" readme = "../README.md" resolver = "2" -version = "0.7.0" +version = "0.7.1" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/encoding_spec/Cargo.toml b/encoding_spec/Cargo.toml index d875bfc1a7..428db752b7 100644 --- a/encoding_spec/Cargo.toml +++ b/encoding_spec/Cargo.toml @@ -6,7 +6,7 @@ license = "GPL-3.0" name = "namada_encoding_spec" readme = "../README.md" resolver = "2" -version = "0.7.0" +version = "0.7.1" [features] default = [] diff --git a/macros/Cargo.toml b/macros/Cargo.toml index d63497d87c..19cb20fd9d 100644 --- a/macros/Cargo.toml +++ b/macros/Cargo.toml @@ -4,7 +4,7 @@ edition = "2021" license = "GPL-3.0" name = "namada_macros" resolver = "2" -version = "0.7.0" +version = "0.7.1" [lib] proc-macro = true diff --git a/proof_of_stake/Cargo.toml b/proof_of_stake/Cargo.toml index 449df509d0..dbc3de0061 100644 --- a/proof_of_stake/Cargo.toml +++ b/proof_of_stake/Cargo.toml @@ -6,7 +6,7 @@ license = "GPL-3.0" name = "namada_proof_of_stake" readme = "../README.md" resolver = "2" -version = "0.7.0" +version = "0.7.1" [features] default = [] diff --git a/shared/Cargo.toml b/shared/Cargo.toml index d0ec9f87a9..53ab95f15c 100644 --- a/shared/Cargo.toml +++ b/shared/Cargo.toml @@ -4,7 +4,7 @@ edition = "2021" license = "GPL-3.0" name = "namada" resolver = "2" -version = "0.7.0" +version = "0.7.1" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/tests/Cargo.toml b/tests/Cargo.toml index ed453ad450..4ae17e8fff 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" license = "GPL-3.0" name = "namada_tests" resolver = "2" -version = "0.7.0" +version = "0.7.1" [features] default = ["wasm-runtime"] diff --git a/tx_prelude/Cargo.toml b/tx_prelude/Cargo.toml index a35324da05..76419f417a 100644 --- a/tx_prelude/Cargo.toml +++ b/tx_prelude/Cargo.toml @@ -4,7 +4,7 @@ edition = "2021" license = "GPL-3.0" name = "namada_tx_prelude" resolver = "2" -version = "0.7.0" +version = "0.7.1" [features] default = [] diff --git a/vm_env/Cargo.toml b/vm_env/Cargo.toml index f11d57d1b0..cebcd4c0ca 100644 --- a/vm_env/Cargo.toml +++ b/vm_env/Cargo.toml @@ -4,7 +4,7 @@ edition = "2021" license = "GPL-3.0" name = "namada_vm_env" resolver = "2" -version = "0.7.0" +version = "0.7.1" [features] default = [] diff --git a/vp_prelude/Cargo.toml b/vp_prelude/Cargo.toml index f59c5ed032..d915826e49 100644 --- a/vp_prelude/Cargo.toml +++ b/vp_prelude/Cargo.toml @@ -4,7 +4,7 @@ edition = "2021" license = "GPL-3.0" name = "namada_vp_prelude" resolver = "2" -version = "0.7.0" +version = "0.7.1" [features] default = [] diff --git a/wasm/checksums.json b/wasm/checksums.json index b08f88838c..898f6e9763 100644 --- a/wasm/checksums.json +++ b/wasm/checksums.json @@ -1,19 +1,19 @@ { - "tx_bond.wasm": "tx_bond.7cdd51f8b994d5116e6de12535afcb29df22519f4d3da7d507fe0367a2942a34.wasm", - "tx_from_intent.wasm": "tx_from_intent.6cdb481f546875239af11816d5cc1311306c8d5a325f1ad44921ec5eb2c5ab94.wasm", - "tx_ibc.wasm": "tx_ibc.4ae21c942a1c047949fb756b4f941149ad2d2f87af15afab78edd813a2e828ae.wasm", - "tx_init_account.wasm": "tx_init_account.a4a0bed00c70568a16a78cf8a802fcdc0ae29a062acec713ac39902d43ce6de8.wasm", - "tx_init_nft.wasm": "tx_init_nft.ea7f747f7f8532d53093bd4b54df1a45ab448b3b5202df390932a1e72e22ecbc.wasm", - "tx_init_proposal.wasm": "tx_init_proposal.34e1b8e27bfc0badbc13234520f8382d7caf697d35aa5a67faf62b3e8876523f.wasm", - "tx_init_validator.wasm": "tx_init_validator.123d7245003176581bf52f49da926113ff61774c937c390e2ed82583c79658fd.wasm", - "tx_mint_nft.wasm": "tx_mint_nft.8e9b3c5fdf814e2aea1858e30a14a9d226584b6ba3b32d7b6d535c790ebde93b.wasm", - "tx_transfer.wasm": "tx_transfer.3dcde1395e25c0399de2c6cb46cf8e2146a97c063a821ea555ddd086b7786419.wasm", - "tx_unbond.wasm": "tx_unbond.4a08ccb3c82d7bdbd6ca0d6b15ffe2086017e8779dfd15fd55d5cec241af02f7.wasm", + "tx_bond.wasm": "tx_bond.16097490afa7378c79e6216751b20796cde3a9026c34255c3f1e5ec5a4c9482e.wasm", + "tx_from_intent.wasm": "tx_from_intent.f8d1937b17a3abaf7ea595526c870b3d57ddef8e0c1bc96f8e0a448864b186c7.wasm", + "tx_ibc.wasm": "tx_ibc.378b10551c0b22c2c892d24e2676ee5160d654e2e53a50e7925e0f2c6321497b.wasm", + "tx_init_account.wasm": "tx_init_account.adab66c2b4d635e9c42133936aafb143363f91dddff2a60f94df504ffec951a6.wasm", + "tx_init_nft.wasm": "tx_init_nft.d1065ebd80ba6ea97f29bc2268becf9ba3ba2952641992464f3e9e868df17447.wasm", + "tx_init_proposal.wasm": "tx_init_proposal.184131576a579f9ece96460d1eb20e5970fcd149b0527c8e56b711e5c535aa5f.wasm", + "tx_init_validator.wasm": "tx_init_validator.2990747d24d467b56e19724c5d13df826a3aab83f7e1bf26558dbdf44e260f8a.wasm", + "tx_mint_nft.wasm": "tx_mint_nft.33db14dea4a03ff7508ca44f3ae956d83c0abceb3dae5be844668e54ac22b273.wasm", + "tx_transfer.wasm": "tx_transfer.a601d62296f56f6b4dabb0a2ad082478d195e667c7469f363bdfd5fe41349bd8.wasm", + "tx_unbond.wasm": "tx_unbond.014cbf5b0aa3ac592c0a6940dd502ec8569a3af4d12782e3a5931c15dc13042f.wasm", "tx_update_vp.wasm": "tx_update_vp.83d4caeb5a9ca3009cd899810493a6b87b4c07fa9ed36f297db99dc881fb9a1c.wasm", - "tx_vote_proposal.wasm": "tx_vote_proposal.cffcfd2414084def136f09d84a0a904898758a93925e09694fc688f6d1c2c4ee.wasm", - "tx_withdraw.wasm": "tx_withdraw.4dc442c9369e1831105eece71f73446b44f5712702ddf338756002669cd3166b.wasm", - "vp_nft.wasm": "vp_nft.4e865442cf80b77b71301a7b34ae95dad54947a39b24b7e80ff7bb9f5d3830b9.wasm", - "vp_testnet_faucet.wasm": "vp_testnet_faucet.e4d276346dcf0d920f91a4e1f67a3a941e055b6ea290bbdf0256fdac6212891f.wasm", - "vp_token.wasm": "vp_token.0612d2f42697fdd431bb503f3746e7092f8851c0600b377ad07e311c4d22fbca.wasm", - "vp_user.wasm": "vp_user.1d97195ab464b9dac70815a436ab8f7990b50b52bd6ff5042949d5dd14ac9a62.wasm" + "tx_vote_proposal.wasm": "tx_vote_proposal.bcb5280be9dfeed0a7650ba5e4a3cebc2c19b76780fd74dcb345be3da766b64a.wasm", + "tx_withdraw.wasm": "tx_withdraw.8fc0a3439ee9ae66047c520519877bc1f540e0cb02abfa31afa8cce8cd069b6f.wasm", + "vp_nft.wasm": "vp_nft.2c820c728d241b82bf0ed3c552ee9e7c046bceaa4f7b6f12d3236a1a3d7c1589.wasm", + "vp_testnet_faucet.wasm": "vp_testnet_faucet.6e762f3fda8aa7a252e2b29a4a312db91ded062d6c18b8b489883733c89dc227.wasm", + "vp_token.wasm": "vp_token.c45cc3848f12fc47713702dc206d1312ad740a6bbee7f141556714f6f89d4985.wasm", + "vp_user.wasm": "vp_user.d6cd2f4b5bc26f96df6aa300fddf4d25e1656920d59896209bd54ae8d407ecde.wasm" } \ No newline at end of file diff --git a/wasm/tx_template/Cargo.lock b/wasm/tx_template/Cargo.lock index d41c7c2f4f..4e85d68f2c 100644 --- a/wasm/tx_template/Cargo.lock +++ b/wasm/tx_template/Cargo.lock @@ -1347,7 +1347,7 @@ dependencies = [ [[package]] name = "libsecp256k1" version = "0.7.0" -source = "git+https://github.com/brentstone/libsecp256k1?rev=bbb3bd44a49db361f21d9db80f9a087c194c0ae9#bbb3bd44a49db361f21d9db80f9a087c194c0ae9" +source = "git+https://github.com/heliaxdev/libsecp256k1?rev=bbb3bd44a49db361f21d9db80f9a087c194c0ae9#bbb3bd44a49db361f21d9db80f9a087c194c0ae9" dependencies = [ "arrayref", "base64", @@ -1363,7 +1363,7 @@ dependencies = [ [[package]] name = "libsecp256k1-core" version = "0.3.0" -source = "git+https://github.com/brentstone/libsecp256k1?rev=bbb3bd44a49db361f21d9db80f9a087c194c0ae9#bbb3bd44a49db361f21d9db80f9a087c194c0ae9" +source = "git+https://github.com/heliaxdev/libsecp256k1?rev=bbb3bd44a49db361f21d9db80f9a087c194c0ae9#bbb3bd44a49db361f21d9db80f9a087c194c0ae9" dependencies = [ "crunchy", "digest 0.9.0", @@ -1373,7 +1373,7 @@ dependencies = [ [[package]] name = "libsecp256k1-gen-ecmult" version = "0.3.0" -source = "git+https://github.com/brentstone/libsecp256k1?rev=bbb3bd44a49db361f21d9db80f9a087c194c0ae9#bbb3bd44a49db361f21d9db80f9a087c194c0ae9" +source = "git+https://github.com/heliaxdev/libsecp256k1?rev=bbb3bd44a49db361f21d9db80f9a087c194c0ae9#bbb3bd44a49db361f21d9db80f9a087c194c0ae9" dependencies = [ "libsecp256k1-core", ] @@ -1381,7 +1381,7 @@ dependencies = [ [[package]] name = "libsecp256k1-gen-genmult" version = "0.3.0" -source = "git+https://github.com/brentstone/libsecp256k1?rev=bbb3bd44a49db361f21d9db80f9a087c194c0ae9#bbb3bd44a49db361f21d9db80f9a087c194c0ae9" +source = "git+https://github.com/heliaxdev/libsecp256k1?rev=bbb3bd44a49db361f21d9db80f9a087c194c0ae9#bbb3bd44a49db361f21d9db80f9a087c194c0ae9" dependencies = [ "libsecp256k1-core", ] @@ -1516,7 +1516,7 @@ checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" [[package]] name = "namada" -version = "0.7.0" +version = "0.7.1" dependencies = [ "ark-bls12-381", "ark-serialize", @@ -1565,7 +1565,7 @@ dependencies = [ [[package]] name = "namada_macros" -version = "0.7.0" +version = "0.7.1" dependencies = [ "quote", "syn", @@ -1573,7 +1573,7 @@ dependencies = [ [[package]] name = "namada_proof_of_stake" -version = "0.7.0" +version = "0.7.1" dependencies = [ "borsh", "proptest", @@ -1582,7 +1582,7 @@ dependencies = [ [[package]] name = "namada_tests" -version = "0.7.0" +version = "0.7.1" dependencies = [ "chrono", "concat-idents", @@ -1600,7 +1600,7 @@ dependencies = [ [[package]] name = "namada_tx_prelude" -version = "0.7.0" +version = "0.7.1" dependencies = [ "namada_vm_env", "sha2 0.10.2", @@ -1608,7 +1608,7 @@ dependencies = [ [[package]] name = "namada_vm_env" -version = "0.7.0" +version = "0.7.1" dependencies = [ "borsh", "hex", @@ -2982,7 +2982,7 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" [[package]] name = "tx_template" -version = "0.6.1" +version = "0.7.1" dependencies = [ "borsh", "getrandom", diff --git a/wasm/tx_template/Cargo.toml b/wasm/tx_template/Cargo.toml index 469104ce65..25f95edea7 100644 --- a/wasm/tx_template/Cargo.toml +++ b/wasm/tx_template/Cargo.toml @@ -4,7 +4,7 @@ edition = "2021" license = "GPL-3.0" name = "tx_template" resolver = "2" -version = "0.6.1" +version = "0.7.1" [lib] crate-type = ["cdylib"] diff --git a/wasm/vp_template/Cargo.lock b/wasm/vp_template/Cargo.lock index 7fafa8a32c..25070a9319 100644 --- a/wasm/vp_template/Cargo.lock +++ b/wasm/vp_template/Cargo.lock @@ -1347,7 +1347,7 @@ dependencies = [ [[package]] name = "libsecp256k1" version = "0.7.0" -source = "git+https://github.com/brentstone/libsecp256k1?rev=bbb3bd44a49db361f21d9db80f9a087c194c0ae9#bbb3bd44a49db361f21d9db80f9a087c194c0ae9" +source = "git+https://github.com/heliaxdev/libsecp256k1?rev=bbb3bd44a49db361f21d9db80f9a087c194c0ae9#bbb3bd44a49db361f21d9db80f9a087c194c0ae9" dependencies = [ "arrayref", "base64", @@ -1363,7 +1363,7 @@ dependencies = [ [[package]] name = "libsecp256k1-core" version = "0.3.0" -source = "git+https://github.com/brentstone/libsecp256k1?rev=bbb3bd44a49db361f21d9db80f9a087c194c0ae9#bbb3bd44a49db361f21d9db80f9a087c194c0ae9" +source = "git+https://github.com/heliaxdev/libsecp256k1?rev=bbb3bd44a49db361f21d9db80f9a087c194c0ae9#bbb3bd44a49db361f21d9db80f9a087c194c0ae9" dependencies = [ "crunchy", "digest 0.9.0", @@ -1373,7 +1373,7 @@ dependencies = [ [[package]] name = "libsecp256k1-gen-ecmult" version = "0.3.0" -source = "git+https://github.com/brentstone/libsecp256k1?rev=bbb3bd44a49db361f21d9db80f9a087c194c0ae9#bbb3bd44a49db361f21d9db80f9a087c194c0ae9" +source = "git+https://github.com/heliaxdev/libsecp256k1?rev=bbb3bd44a49db361f21d9db80f9a087c194c0ae9#bbb3bd44a49db361f21d9db80f9a087c194c0ae9" dependencies = [ "libsecp256k1-core", ] @@ -1381,7 +1381,7 @@ dependencies = [ [[package]] name = "libsecp256k1-gen-genmult" version = "0.3.0" -source = "git+https://github.com/brentstone/libsecp256k1?rev=bbb3bd44a49db361f21d9db80f9a087c194c0ae9#bbb3bd44a49db361f21d9db80f9a087c194c0ae9" +source = "git+https://github.com/heliaxdev/libsecp256k1?rev=bbb3bd44a49db361f21d9db80f9a087c194c0ae9#bbb3bd44a49db361f21d9db80f9a087c194c0ae9" dependencies = [ "libsecp256k1-core", ] @@ -1516,7 +1516,7 @@ checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" [[package]] name = "namada" -version = "0.7.0" +version = "0.7.1" dependencies = [ "ark-bls12-381", "ark-serialize", @@ -1565,7 +1565,7 @@ dependencies = [ [[package]] name = "namada_macros" -version = "0.7.0" +version = "0.7.1" dependencies = [ "quote", "syn", @@ -1573,7 +1573,7 @@ dependencies = [ [[package]] name = "namada_proof_of_stake" -version = "0.7.0" +version = "0.7.1" dependencies = [ "borsh", "proptest", @@ -1582,7 +1582,7 @@ dependencies = [ [[package]] name = "namada_tests" -version = "0.7.0" +version = "0.7.1" dependencies = [ "chrono", "concat-idents", @@ -1600,7 +1600,7 @@ dependencies = [ [[package]] name = "namada_vm_env" -version = "0.7.0" +version = "0.7.1" dependencies = [ "borsh", "hex", @@ -1610,7 +1610,7 @@ dependencies = [ [[package]] name = "namada_vp_prelude" -version = "0.7.0" +version = "0.7.1" dependencies = [ "namada_vm_env", "sha2 0.10.2", @@ -3057,7 +3057,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "vp_template" -version = "0.6.1" +version = "0.7.1" dependencies = [ "borsh", "getrandom", diff --git a/wasm/vp_template/Cargo.toml b/wasm/vp_template/Cargo.toml index 125b50d07a..6819729320 100644 --- a/wasm/vp_template/Cargo.toml +++ b/wasm/vp_template/Cargo.toml @@ -4,7 +4,7 @@ edition = "2021" license = "GPL-3.0" name = "vp_template" resolver = "2" -version = "0.6.1" +version = "0.7.1" [lib] crate-type = ["cdylib"] diff --git a/wasm/wasm_source/Cargo.lock b/wasm/wasm_source/Cargo.lock index e420c8d5df..269535735e 100644 --- a/wasm/wasm_source/Cargo.lock +++ b/wasm/wasm_source/Cargo.lock @@ -1516,7 +1516,7 @@ checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" [[package]] name = "namada" -version = "0.7.0" +version = "0.7.1" dependencies = [ "ark-bls12-381", "ark-serialize", @@ -1565,7 +1565,7 @@ dependencies = [ [[package]] name = "namada_macros" -version = "0.7.0" +version = "0.7.1" dependencies = [ "quote", "syn", @@ -1573,7 +1573,7 @@ dependencies = [ [[package]] name = "namada_proof_of_stake" -version = "0.7.0" +version = "0.7.1" dependencies = [ "borsh", "proptest", @@ -1582,7 +1582,7 @@ dependencies = [ [[package]] name = "namada_tests" -version = "0.7.0" +version = "0.7.1" dependencies = [ "chrono", "concat-idents", @@ -1600,7 +1600,7 @@ dependencies = [ [[package]] name = "namada_tx_prelude" -version = "0.7.0" +version = "0.7.1" dependencies = [ "namada_vm_env", "sha2 0.10.2", @@ -1608,7 +1608,7 @@ dependencies = [ [[package]] name = "namada_vm_env" -version = "0.7.0" +version = "0.7.1" dependencies = [ "borsh", "hex", @@ -1618,7 +1618,7 @@ dependencies = [ [[package]] name = "namada_vp_prelude" -version = "0.7.0" +version = "0.7.1" dependencies = [ "namada_vm_env", "sha2 0.10.2", @@ -1626,7 +1626,7 @@ dependencies = [ [[package]] name = "namada_wasm" -version = "0.7.0" +version = "0.7.1" dependencies = [ "borsh", "getrandom", diff --git a/wasm/wasm_source/Cargo.toml b/wasm/wasm_source/Cargo.toml index ee2234928a..4e9c0f1cae 100644 --- a/wasm/wasm_source/Cargo.toml +++ b/wasm/wasm_source/Cargo.toml @@ -4,7 +4,7 @@ edition = "2021" license = "GPL-3.0" name = "namada_wasm" resolver = "2" -version = "0.7.0" +version = "0.7.1" [lib] crate-type = ["cdylib"] diff --git a/wasm_for_tests/wasm_source/Cargo.toml b/wasm_for_tests/wasm_source/Cargo.toml index cdd56aaf89..d4df7a2e5c 100644 --- a/wasm_for_tests/wasm_source/Cargo.toml +++ b/wasm_for_tests/wasm_source/Cargo.toml @@ -4,7 +4,7 @@ edition = "2021" license = "GPL-3.0" name = "namada_wasm_for_tests" resolver = "2" -version = "0.7.0" +version = "0.7.1" [lib] crate-type = ["cdylib"] From 33608337f95a0e342162153a0de9ee90b8215d63 Mon Sep 17 00:00:00 2001 From: Gianmarco Fraccaroli <> Date: Sun, 21 Aug 2022 09:09:50 +0200 Subject: [PATCH 104/118] [fix] use fetch-depth: 0 on tag pipeline --- .github/workflows/release.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 70e2c3492f..b926d268d7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -33,6 +33,8 @@ jobs: steps: - name: Checkout repo uses: actions/checkout@v3 + with: + fetch-depth: 0 - name: Configure AWS Credentials uses: aws-actions/configure-aws-credentials@v1 with: From a9b2cc6244182d44266c459600f07ce31bc60925 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zemanovi=C4=8D?= Date: Tue, 30 Aug 2022 15:32:18 +0200 Subject: [PATCH 105/118] docs/dev: update encoding spec generation --- documentation/dev/src/specs/encoding.md | 2 +- encoding_spec/README.md | 2 +- encoding_spec/src/main.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/documentation/dev/src/specs/encoding.md b/documentation/dev/src/specs/encoding.md index 40e4b79b3c..53ff3ad5bd 100644 --- a/documentation/dev/src/specs/encoding.md +++ b/documentation/dev/src/specs/encoding.md @@ -16,7 +16,7 @@ The encoding schemas below are described in terms of [Borsh specification](https Note that "nil" corresponds to unit (`()`) which is encoded as empty bytes (nothing is being written). - + {{#include encoding/generated-borsh-spec.md}} diff --git a/encoding_spec/README.md b/encoding_spec/README.md index 25123f6b44..92e53cc6d2 100644 --- a/encoding_spec/README.md +++ b/encoding_spec/README.md @@ -2,4 +2,4 @@ This bin crate is used to derive encoding specifications from pre-selected public types via their `BorshSchema` implementations. The `BorshSchema` provides recursive definitions of all the used types and these are also included in the generated specification. -When executed, this crate will generate `docs/src/specs/encoding/generated-borsh-spec.md` (see `OUTPUT_PATH` in the source). This page is itself included in the `docs/src/specs/encoding.md` page. +When executed, this crate will generate `documentation/dev/src/specs/encoding/generated-borsh-spec.md` (see `OUTPUT_PATH` in the source). This page is itself included in the `documentation/dev/src/specs/encoding.md` page. diff --git a/encoding_spec/src/main.rs b/encoding_spec/src/main.rs index 8877ff3e77..db65f24667 100644 --- a/encoding_spec/src/main.rs +++ b/encoding_spec/src/main.rs @@ -32,7 +32,7 @@ use namada::types::{token, transaction}; /// This generator will write output into this `docs` file. const OUTPUT_PATH: &str = - "documentation/docs/src/specs/encoding/generated-borsh-spec.md"; + "documentation/dev/src/specs/encoding/generated-borsh-spec.md"; lazy_static! { /// Borsh types may be used by declarations. These are displayed differently in the [`md_fmt_type`]. From cf78ec2f660cced629195c001a8b745c79a7550f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zemanovi=C4=8D?= Date: Tue, 30 Aug 2022 15:44:07 +0200 Subject: [PATCH 106/118] encoding_spec: rm ":" from fragment links in e.g. `ed25519::PublicKey` --- encoding_spec/src/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/encoding_spec/src/main.rs b/encoding_spec/src/main.rs index db65f24667..5579178210 100644 --- a/encoding_spec/src/main.rs +++ b/encoding_spec/src/main.rs @@ -394,6 +394,7 @@ fn escape_fragment_anchor(string: impl AsRef) -> String { .replace('<', "") .replace(',', "") .replace(' ', "-") + .replace(':', "") .to_ascii_lowercase() } From 6ae081a26a77757707df2a690e7b94819566fd1b Mon Sep 17 00:00:00 2001 From: FatemeShirazi Date: Wed, 31 Aug 2022 10:57:53 +0200 Subject: [PATCH 107/118] I removed the limitation. Deleted "The total value transferred cannot exceed 2/3 of the total stake." It should any way be 1/3+1, but we agreed to take it now here since we will have protection in UI for this attack. --- documentation/specs/src/economics/proof-of-stake.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/specs/src/economics/proof-of-stake.md b/documentation/specs/src/economics/proof-of-stake.md index 7160872da5..808f02e585 100644 --- a/documentation/specs/src/economics/proof-of-stake.md +++ b/documentation/specs/src/economics/proof-of-stake.md @@ -29,4 +29,4 @@ with the intent of carrying out attacks. Many PoS blockcains rely on the 1/3 Byz In blockchain systems we do not rely on altruistic behavior but rather economic security. We expect the validators to execute the protocol correctly. They get rewarded for doing so and punished otherwise. Each validator has some self-stake and some stake that is delegated to it by other token holders. The validator and delegators share the reward and risk of slashing impact with each other. -The total stake behind consensus should be taken into account when value is transferred via a transaction. The total value transferred cannot exceed 2/3 of the total stake. For example, if we have 1 billion tokens, we aim that 300 Million of these tokens is backing validators. This means that users should not transfer more than 200 million of this token within a block. \ No newline at end of file +The total stake behind consensus should be taken into account when value is transferred via a transaction. For example, if we have 1 billion tokens, we aim that 300 Million of these tokens is backing validators. This means that users should not transfer more than 200 million of this token within a block. From d991bd32111a25443ff90205b9d2d19fe5dad1b1 Mon Sep 17 00:00:00 2001 From: FatemeShirazi Date: Wed, 31 Aug 2022 10:57:53 +0200 Subject: [PATCH 108/118] I removed the limitation. Deleted "The total value transferred cannot exceed 2/3 of the total stake." It should any way be 1/3+1, but we agreed to take it now here since we will have protection in UI for this attack. --- documentation/specs/src/economics/proof-of-stake.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/specs/src/economics/proof-of-stake.md b/documentation/specs/src/economics/proof-of-stake.md index 7160872da5..808f02e585 100644 --- a/documentation/specs/src/economics/proof-of-stake.md +++ b/documentation/specs/src/economics/proof-of-stake.md @@ -29,4 +29,4 @@ with the intent of carrying out attacks. Many PoS blockcains rely on the 1/3 Byz In blockchain systems we do not rely on altruistic behavior but rather economic security. We expect the validators to execute the protocol correctly. They get rewarded for doing so and punished otherwise. Each validator has some self-stake and some stake that is delegated to it by other token holders. The validator and delegators share the reward and risk of slashing impact with each other. -The total stake behind consensus should be taken into account when value is transferred via a transaction. The total value transferred cannot exceed 2/3 of the total stake. For example, if we have 1 billion tokens, we aim that 300 Million of these tokens is backing validators. This means that users should not transfer more than 200 million of this token within a block. \ No newline at end of file +The total stake behind consensus should be taken into account when value is transferred via a transaction. For example, if we have 1 billion tokens, we aim that 300 Million of these tokens is backing validators. This means that users should not transfer more than 200 million of this token within a block. From d19e7ecf0dce2952b31c15bd8a63011c0b71e811 Mon Sep 17 00:00:00 2001 From: Gianmarco Fraccaroli <> Date: Wed, 31 Aug 2022 17:31:45 +0200 Subject: [PATCH 109/118] [ci] added dev documentation build, added rust doc build --- .github/workflows/docs.yml | 75 +++++++++++++++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index c24084a771..3f5e5e5159 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -47,6 +47,12 @@ jobs: command: cd documentation/docs && mdbook build cache_subkey: docs cache_version: v1 + - name: Build development docs + folder: documentation/dev + bucket: namada-dev-static-website + command: cargo run --bin namada_encoding_spec && cd documentation/dev && mdbook build + cache_subkey: dev + cache_version: v1 env: CARGO_INCREMENTAL: 0 @@ -64,7 +70,6 @@ jobs: # See comment in build-and-test.yml with: ref: ${{ github.event.pull_request.head.sha }} - - name: Configure AWS Credentials uses: aws-actions/configure-aws-credentials@v1 with: @@ -121,3 +126,71 @@ jobs: - name: Stop sccache server if: always() run: sccache --stop-server || true + + rust-docs: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest] + + env: + CARGO_INCREMENTAL: 0 + RUSTC_WRAPPER: sccache + SCCACHE_CACHE_SIZE: 100G + SCCACHE_BUCKET: namada-sccache-master + + steps: + - name: Checkout repo + uses: actions/checkout@v3 + if: ${{ github.event_name != 'pull_request_target' }} + - name: Checkout PR + uses: actions/checkout@v3 + if: ${{ github.event_name == 'pull_request_target' }} + # See comment in build-and-test.yml + with: + ref: ${{ github.event.pull_request.head.sha }} + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + role-to-assume: arn:aws:iam::375643557360:role/anoma-github-action-ci-master + aws-region: eu-west-1 + - name: Install sccache (ubuntu-latest) + if: matrix.os == 'ubuntu-latest' + env: + LINK: https://github.com/mozilla/sccache/releases/download + SCCACHE_VERSION: v0.3.0 + run: | + SCCACHE_FILE=sccache-$SCCACHE_VERSION-x86_64-unknown-linux-musl + mkdir -p $HOME/.local/bin + curl -L "$LINK/$SCCACHE_VERSION/$SCCACHE_FILE.tar.gz" | tar xz + mv -f $SCCACHE_FILE/sccache $HOME/.local/bin/sccache + chmod +x $HOME/.local/bin/sccache + echo "$HOME/.local/bin" >> $GITHUB_PATH + - name: Install sccache (macos-latest) + if: matrix.os == 'macos-latest' + run: | + brew update + brew install sccache + - name: Setup rust toolchain + uses: oxidecomputer/actions-rs_toolchain@ad3f86084a8a5acf2c09cb691421b31cf8af7a36 + with: + profile: default + override: true + - name: Setup rust nightly + uses: oxidecomputer/actions-rs_toolchain@ad3f86084a8a5acf2c09cb691421b31cf8af7a36 + with: + toolchain: ${{ matrix.nightly_version }} + profile: default + - name: Show rust toolchain info + run: rustup show + - name: Start sccache server + run: sccache --start-server + - name: Build rust-docs + run: make build-doc + - name: Print sccache stats + if: always() + run: sccache --show-stats + - name: Stop sccache server + if: always() + run: sccache --stop-server || true From bd1115e10582160f1d0c01abd2f42686c83d7c4b Mon Sep 17 00:00:00 2001 From: Gianmarco Fraccaroli <> Date: Wed, 31 Aug 2022 17:11:41 +0200 Subject: [PATCH 110/118] [ci] improve automation tool, add pls spawn devnet command --- .github/workflows/automation.yml | 43 +++++++++-- .github/workflows/build-and-test.yml | 1 - .github/workflows/docker.yml | 5 ++ .github/workflows/scripts/publish-wasm.py | 75 ------------------- .github/workflows/scripts/update-wasm.py | 90 ----------------------- 5 files changed, 40 insertions(+), 174 deletions(-) delete mode 100644 .github/workflows/scripts/publish-wasm.py delete mode 100644 .github/workflows/scripts/update-wasm.py diff --git a/.github/workflows/automation.yml b/.github/workflows/automation.yml index 1dc63f782a..7c5e77ea6a 100644 --- a/.github/workflows/automation.yml +++ b/.github/workflows/automation.yml @@ -7,9 +7,11 @@ on: permissions: id-token: write contents: write + pull-requests: write env: GIT_LFS_SKIP_SMUDGE: 1 + CHAIN_BUCKET: anoma-iac-files-master jobs: tasks: @@ -19,7 +21,16 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest] - command: [publish-wasm.py, update-wasm.py] + make: + - name: Update wasm + comment: pls update wasm + command: update-wasm.py + - name: Publish wasm + comment: pls publish wasm + command: publish-wasm.py + - name: Spawn devnet + comment: pls spawn devnet + command: spawn-devnet.py steps: - name: Configure AWS Credentials @@ -27,19 +38,35 @@ jobs: with: role-to-assume: arn:aws:iam::375643557360:role/anoma-github-action-ci-master aws-region: eu-west-1 + - uses: khan/pull-request-comment-trigger@v1.1.0 + id: check + with: + trigger: ${{ matrix.make.comment }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - uses: xt0rted/pull-request-comment-branch@v1 + if: steps.check.outputs.triggered == 'true' id: comment-branch - uses: actions/checkout@v3 - if: success() + if: steps.check.outputs.triggered == 'true' with: ref: ${{ steps.comment-branch.outputs.head_ref }} - - name: Run task + - name: Run task ${{ matrix.make.name }} + if: steps.check.outputs.triggered == 'true' + run: | + git config --global user.name 'github-actions[bot]' + git config --global user.email 'github-actions[bot]@users.noreply.github.com' + pip3 install ghapi boto3 toml >/dev/null 2>&1 + aws s3 cp s3://$CHAIN_BUCKET/scripts/${{ matrix.make.command }} .github/workflows/scripts/ + python3 .github/workflows/scripts/${{ matrix.make.command }} env: GITHUB_CONTEXT: ${{ toJson(github) }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_READ_ORG_TOKEN: ${{ secrets.GT_READ_ORG }} - run: | - git config --global user.name 'github-actions[bot]' - git config --global user.email 'github-actions[bot]@users.noreply.github.com' - pip3 install ghapi >/dev/null 2>&1 - python3 .github/workflows/scripts/${{ matrix.command }} + GITHUB_DISPATCH_TOKEN: ${{ secrets.GT_DISPATCH }} + BINARIES_COMMIT_SHA: ${{ steps.comment-branch.outputs.head_sha }} + - name: Comment not found + if: steps.check.outputs.triggered != 'true' + run: echo "Comment $COMMENT not found" + env: + COMMENT: ${{ matrix.make.comment }} \ No newline at end of file diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 020cc343cb..2e31ff2b4d 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -51,7 +51,6 @@ jobs: # to disallow that. with: ref: ${{ github.event.pull_request.head.sha }} - - name: Duplicate checksums file run: cp wasm/checksums.json wasm/original-checksums.json - name: Build WASM diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 7d288d544b..f524479810 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -10,6 +10,11 @@ on: env: GIT_LFS_SKIP_SMUDGE: 1 +permissions: + id-token: write + contents: write + packages: write + jobs: docker: runs-on: ${{ matrix.os }} diff --git a/.github/workflows/scripts/publish-wasm.py b/.github/workflows/scripts/publish-wasm.py deleted file mode 100644 index dcad5e1d34..0000000000 --- a/.github/workflows/scripts/publish-wasm.py +++ /dev/null @@ -1,75 +0,0 @@ -from ghapi.all import GhApi -from os import environ -from json import loads, load -from tempfile import gettempdir -import subprocess - - -def download_artifact(link: str, path: str, token: str): - return subprocess.run(["curl", "-H", "Accept: application/vnd.github+json".format(token), "-H", "Authorization: token {}".format(token), link, "-L", "-o", "{}/wasm.zip".format(path)], capture_output=True) - - -def unzip(path: str): - return subprocess.run(["unzip", "-o", "{}/wasm.zip".format(path), "-d", path], capture_output=True) - - -def publish_wasm(path: str, file_name: str, bucket: str): - return subprocess.run(["aws", "s3", "cp", "{}/{}".format(path, file_name), "s3://{}".format(bucket), "--acl", "public-read"], capture_output=True) - - -def log(data: str): - print(data) - - -PR_COMMENT = 'pls publish wasm' -TOKEN = environ["GITHUB_TOKEN"] -READ_ORG_TOKEN = environ['GITHUB_READ_ORG_TOKEN'] -REPOSITORY_NAME = environ['GITHUB_REPOSITORY_OWNER'] -TMP_DIRECTORY = gettempdir() -ARTIFACT_PER_PAGE = 75 -WASM_BUCKET = 'namada-wasm-master' - -read_org_api = GhApi(token=READ_ORG_TOKEN) -api = GhApi(owner=REPOSITORY_NAME, repo="namada", token=TOKEN) - -user_membership = read_org_api.teams.get_membership_for_user_in_org( - 'heliaxdev', 'company', 'fraccaman') -if user_membership['state'] != 'active': - exit(0) - -comment_event = loads(environ['GITHUB_CONTEXT']) -pr_comment = comment_event['event']['comment']['body'] -pr_number = comment_event['event']['issue']['number'] - -if pr_comment != PR_COMMENT: - exit(0) - -pr_info = api.pulls.get(pr_number) -head_sha = pr_info['head']['sha'] - -artifacts = api.actions.list_artifacts_for_repo(per_page=ARTIFACT_PER_PAGE) - -for artifact in artifacts['artifacts']: - if 'wasm' in artifact['name'] and artifact['workflow_run']['head_sha'] == head_sha and not artifact['expired']: - artifact_download_url = artifact['archive_download_url'] - - log("Downloading artifacts...") - curl_command_outcome = download_artifact( - artifact_download_url, TMP_DIRECTORY, TOKEN) - if curl_command_outcome.returncode != 0: - exit(1) - - log("Unzipping wasm.zip...") - unzip_command_outcome = unzip(TMP_DIRECTORY) - if unzip_command_outcome.returncode != 0: - exit(1) - - checksums = load(open("{}/checksums.json".format(TMP_DIRECTORY))) - for wasm in checksums.values(): - log("Uploading {}...".format(wasm)) - publish_wasm_command_outcome = publish_wasm( - TMP_DIRECTORY, wasm, WASM_BUCKET) - if publish_wasm_command_outcome.returncode != 0: - print("Error uploading {}!".format(wasm)) - - log("Done!") diff --git a/.github/workflows/scripts/update-wasm.py b/.github/workflows/scripts/update-wasm.py deleted file mode 100644 index 3527c6e754..0000000000 --- a/.github/workflows/scripts/update-wasm.py +++ /dev/null @@ -1,90 +0,0 @@ -from ghapi.all import GhApi -from os import environ -from json import loads -from tempfile import gettempdir -import subprocess - - -def log(data: str): - print(data) - - -def download_artifact(link: str, path: str, token: str): - return subprocess.run(["curl", "-H", "Accept: application/vnd.github+json".format(token), "-H", "Authorization: token {}".format(token), link, "-L", "-o", "{}/wasm.zip".format(path)], capture_output=True) - - -def unzip(path: str): - return subprocess.run(["unzip", "-o", "{}/wasm.zip".format(path), "-d", path], capture_output=True) - - -def replace_checksums(path: str): - return subprocess.run(["mv", "{}/checksums.json".format(path), "wasm/"], capture_output=True) - - -def commit_and_push(): - outcome = subprocess.run(["git", "status", "--porcelain"], capture_output=True) - if not len(outcome.stdout): - return outcome - outcome = subprocess.run( - ["git", "add", "wasm/checksums.json"], capture_output=True) - if outcome.returncode != 0: - return outcome - outcome = subprocess.run( - ["git", "commit", "-m", "[ci skip] wasm checksums update"], capture_output=True) - if outcome.returncode != 0: - return outcome - return subprocess.run(["git", "push"], capture_output=True) - - -PR_COMMENT = 'pls update wasm' -TOKEN = environ["GITHUB_TOKEN"] -READ_ORG_TOKEN = environ['GITHUB_READ_ORG_TOKEN'] -REPOSITORY_NAME = environ['GITHUB_REPOSITORY_OWNER'] -TMP_DIRECTORY = gettempdir() -ARTIFACT_PER_PAGE = 75 - -read_org_api = GhApi(token=READ_ORG_TOKEN) -api = GhApi(owner=REPOSITORY_NAME, repo="namada", token=TOKEN) - -user_membership = read_org_api.teams.get_membership_for_user_in_org( - 'heliaxdev', 'company', 'fraccaman') -if user_membership['state'] != 'active': - exit(0) - -comment_event = loads(environ['GITHUB_CONTEXT']) -pr_comment = comment_event['event']['comment']['body'] -pr_number = comment_event['event']['issue']['number'] - -if pr_comment != PR_COMMENT: - exit(0) - -pr_info = api.pulls.get(pr_number) -head_sha = pr_info['head']['sha'] - -artifacts = api.actions.list_artifacts_for_repo(per_page=ARTIFACT_PER_PAGE) - -for artifact in artifacts['artifacts']: - if 'wasm' in artifact['name'] and artifact['workflow_run']['head_sha'] == head_sha and not artifact['expired']: - artifact_download_url = artifact['archive_download_url'] - - log("Downloading artifacts...") - curl_command_outcome = download_artifact( - artifact_download_url, TMP_DIRECTORY, TOKEN) - if curl_command_outcome.returncode != 0: - exit(1) - - unzip_command_outcome = unzip(TMP_DIRECTORY) - if unzip_command_outcome.returncode != 0: - exit(1) - - log("Replacing checksums.json...") - replace_command_outcome = replace_checksums(TMP_DIRECTORY) - if replace_command_outcome.returncode != 0: - exit(1) - - log("Pushing new checksums.json...") - commit_and_push_command_outcome = commit_and_push() - if commit_and_push_command_outcome.returncode != 0: - exit(1) - - log("Done!") From e9627ec4422cee529b877449afb14c4716380da1 Mon Sep 17 00:00:00 2001 From: Gianmarco Fraccaroli <> Date: Wed, 3 Aug 2022 16:28:20 +0200 Subject: [PATCH 111/118] [ci] download masp paramters --- .github/workflows/build-and-test.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 020cc343cb..62561f2c4c 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -215,6 +215,12 @@ jobs: chmod +x target/release/namadan chmod +x target/release/namadac chmod +x /usr/local/bin/tendermint + - name: Download masp parameters + run: | + mkdir /home/runner/work/masp + curl -o /home/runner/work/masp/masp-spend.params -sLO https://github.com/anoma/masp/blob/ef0ef75e81696ff4428db775c654fbec1b39c21f/masp-spend.params?raw=true + curl -o /home/runner/work/masp/masp-output.params -sLO https://github.com/anoma/masp/blob/ef0ef75e81696ff4428db775c654fbec1b39c21f/masp-output.params?raw=true + curl -o /home/runner/work/masp/masp-convert.params -sLO https://github.com/anoma/masp/blob/ef0ef75e81696ff4428db775c654fbec1b39c21f/masp-convert.params?raw=true - name: Run e2e test run: make test-e2e${{ matrix.make.suffix }} env: @@ -223,6 +229,7 @@ jobs: ANOMA_E2E_KEEP_TEMP: "true" ENV_VAR_TM_STDOUT: "false" ANOMA_LOG_COLOR: "false" + ANOMA_MASP_PARAMS_DIR: "/home/runner/work/masp" ANOMA_LOG: "info" - name: Upload e2e logs if: success() || failure() From bf80836fa0727920c87f22a95ad1666243cfef50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zemanovi=C4=8D?= Date: Thu, 4 Aug 2022 12:19:25 +0200 Subject: [PATCH 112/118] ci: double the build-and-test timeout --- .github/workflows/build-and-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 62561f2c4c..5a62a5671f 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -102,7 +102,7 @@ jobs: anoma: runs-on: ${{ matrix.os }} - timeout-minutes: 40 + timeout-minutes: 80 strategy: fail-fast: false matrix: From 30f47aab055bae2f2ee4073fbf4577e58c92e387 Mon Sep 17 00:00:00 2001 From: Gianmarco Fraccaroli <> Date: Thu, 1 Sep 2022 14:06:17 +0200 Subject: [PATCH 113/118] [ci] remove drone --- .drone.yml | 1102 ---------------------------------------------------- 1 file changed, 1102 deletions(-) delete mode 100644 .drone.yml diff --git a/.drone.yml b/.drone.yml deleted file mode 100644 index 0fed4e8790..0000000000 --- a/.drone.yml +++ /dev/null @@ -1,1102 +0,0 @@ ---- -name: anoma-ci-wasm-pr -kind: pipeline -node: - project: anoma -steps: -- name: clone - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/git:latest - pull: never - commands: - - git clone $DRONE_GIT_HTTP_URL --depth 1 --quiet --branch ${DRONE_SOURCE_BRANCH:-master} - --single-branch . -- name: download-scripts - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/git:latest - pull: never - commands: - - aws s3 cp s3://$S3_BUCKET_SCRIPTS/anoma.zip scripts/ci/anoma.zip - - cd scripts/ci && unzip anoma.zip - environment: - S3_BUCKET_SCRIPTS: drone-ci-scripts - AWS_ACCESS_KEY_ID: - from_secret: aws_access_key_id - AWS_SECRET_ACCESS_KEY: - from_secret: aws_secret_access_key - depends_on: - - clone -- name: restore-cache - image: meltwater/drone-cache:latest - pull: never - settings: - archive_format: gzip - backend: s3 - bucket: heliax-drone-cache-v2 - cache_key: 1-54-0/wasm/{{ checksum "wasm/wasm_source/Cargo.lock" }} - mount: - - wasm/wasm_source/target - region: eu-west-1 - restore: true - environment: - AWS_ACCESS_KEY_ID: - from_secret: aws_access_key_id - AWS_SECRET_ACCESS_KEY: - from_secret: aws_secret_access_key - depends_on: - - download-scripts -- name: build-wasm - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/wasm:latest - pull: never - commands: - - cp wasm/checksums.json wasm/original-checksums.json - - make build-wasm-scripts - depends_on: - - restore-cache -- name: update-wasm - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/git:latest - pull: never - commands: - - sh scripts/ci/update-wasm.sh - environment: - AWS_ACCESS_KEY_ID: - from_secret: aws_access_key_id - AWS_SECRET_ACCESS_KEY: - from_secret: aws_secret_access_key - GITHUB_TOKEN: - from_secret: github_token - depends_on: - - build-wasm -- name: test-wasm - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/wasm:latest - pull: never - commands: - - make test-wasm - depends_on: - - update-wasm -- name: check-wasm - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/wasm:latest - pull: never - commands: - - cmp -- wasm/checksums.json wasm/original-checksums.json - depends_on: - - update-wasm -- name: clean-cache - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/wasm:latest - pull: never - commands: - - rm -f ./wasm/wasm_source/target/.rustc_info.json - - rm -rf ./wasm/wasm_source/target/debug - - find ./wasm/wasm_source/target/release -maxdepth 1 -type f -delete - - find ./wasm/wasm_source/target/wasm32-unknown-unknown -maxdepth 1 -type f -delete - depends_on: - - test-wasm - - check-wasm - when: - status: - - success - - failure -- name: rebuild-cache - image: meltwater/drone-cache:latest - pull: never - settings: - archive_format: gzip - backend: s3 - bucket: heliax-drone-cache-v2 - cache_key: 1-54-0/wasm/{{ checksum "wasm/wasm_source/Cargo.lock" }} - mount: - - wasm/wasm_source/target - override: false - region: eu-west-1 - rebuild: true - environment: - AWS_ACCESS_KEY_ID: - from_secret: aws_access_key_id - AWS_SECRET_ACCESS_KEY: - from_secret: aws_secret_access_key - BACKEND_OPERATION_TIMEOUT: 8m - depends_on: - - clean-cache - when: - status: - - success - - failure -trigger: - event: - - pull_request -type: docker -workspace: - path: /usr/local/rust/wasm -environment: - GIT_LFS_SKIP_SMUDGE: '1' -clone: - disable: true ---- -name: anoma-ci-wasm-master -kind: pipeline -node: - project: anoma -steps: -- name: clone - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/git:latest - pull: never - commands: - - git clone $DRONE_GIT_HTTP_URL --depth 1 --quiet --branch ${DRONE_SOURCE_BRANCH:-master} - --single-branch . -- name: download-scripts - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/git:latest - pull: never - commands: - - aws s3 cp s3://$S3_BUCKET_SCRIPTS/anoma.zip scripts/ci/anoma.zip - - cd scripts/ci && unzip anoma.zip - environment: - S3_BUCKET_SCRIPTS: drone-ci-scripts - AWS_ACCESS_KEY_ID: - from_secret: aws_access_key_id - AWS_SECRET_ACCESS_KEY: - from_secret: aws_secret_access_key - depends_on: - - clone -- name: restore-cache - image: meltwater/drone-cache:latest - pull: never - settings: - archive_format: gzip - backend: s3 - bucket: heliax-drone-cache-v2 - cache_key: 1-54-0/wasm/{{ checksum "wasm/wasm_source/Cargo.lock" }} - mount: - - wasm/wasm_source/target - region: eu-west-1 - restore: true - environment: - AWS_ACCESS_KEY_ID: - from_secret: aws_access_key_id - AWS_SECRET_ACCESS_KEY: - from_secret: aws_secret_access_key - depends_on: - - download-scripts -- name: build-wasm - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/wasm:latest - pull: never - commands: - - cp wasm/checksums.json wasm/original-checksums.json - - make build-wasm-scripts - depends_on: - - restore-cache -- name: update-wasm - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/git:latest - pull: never - commands: - - sh scripts/ci/update-wasm.sh - environment: - AWS_ACCESS_KEY_ID: - from_secret: aws_access_key_id - AWS_SECRET_ACCESS_KEY: - from_secret: aws_secret_access_key - GITHUB_TOKEN: - from_secret: github_token - depends_on: - - build-wasm -- name: test-wasm - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/wasm:latest - pull: never - commands: - - make test-wasm - depends_on: - - update-wasm -- name: check-wasm - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/wasm:latest - pull: never - commands: - - cmp -- wasm/checksums.json wasm/original-checksums.json - depends_on: - - update-wasm -- name: upload-wasm - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/git:latest - pull: never - commands: - - aws s3 sync wasm s3://heliax-anoma-wasm-v1 --acl public-read --exclude "*" --include - "*.wasm" --exclude "*/*" - environment: - AWS_ACCESS_KEY_ID: - from_secret: aws_access_key_id - AWS_SECRET_ACCESS_KEY: - from_secret: aws_secret_access_key - depends_on: - - test-wasm - - check-wasm -- name: clean-cache - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/wasm:latest - pull: never - commands: - - rm -f ./wasm/wasm_source/target/.rustc_info.json - - rm -rf ./wasm/wasm_source/target/debug - - find ./wasm/wasm_source/target/release -maxdepth 1 -type f -delete - - find ./wasm/wasm_source/target/wasm32-unknown-unknown -maxdepth 1 -type f -delete - depends_on: - - test-wasm - - check-wasm - - upload-wasm - when: - status: - - success - - failure -- name: rebuild-cache - image: meltwater/drone-cache:latest - pull: never - settings: - archive_format: gzip - backend: s3 - bucket: heliax-drone-cache-v2 - cache_key: 1-54-0/wasm/{{ checksum "wasm/wasm_source/Cargo.lock" }} - mount: - - wasm/wasm_source/target - override: false - region: eu-west-1 - rebuild: true - environment: - AWS_ACCESS_KEY_ID: - from_secret: aws_access_key_id - AWS_SECRET_ACCESS_KEY: - from_secret: aws_secret_access_key - BACKEND_OPERATION_TIMEOUT: 8m - depends_on: - - clean-cache - when: - status: - - success - - failure -trigger: - event: - - push - branch: - - master -type: docker -workspace: - path: /usr/local/rust/wasm -environment: - GIT_LFS_SKIP_SMUDGE: '1' -clone: - disable: true ---- -name: anoma-ci-build-pr -kind: pipeline -node: - project: anoma -steps: -- name: clone - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/git:latest - pull: never - commands: - - git clone $DRONE_GIT_HTTP_URL --depth 1 --quiet --branch ${DRONE_SOURCE_BRANCH:-master} - --single-branch . -- name: download-scripts - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/git:latest - pull: never - commands: - - aws s3 cp s3://$S3_BUCKET_SCRIPTS/anoma.zip scripts/ci/anoma.zip - - cd scripts/ci && unzip anoma.zip - environment: - S3_BUCKET_SCRIPTS: drone-ci-scripts - AWS_ACCESS_KEY_ID: - from_secret: aws_access_key_id - AWS_SECRET_ACCESS_KEY: - from_secret: aws_secret_access_key - depends_on: - - clone -- name: build - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/anoma:latest - pull: never - commands: - - sccache --start-server - - make build - environment: - AWS_ACCESS_KEY_ID: - from_secret: aws_access_key_id - AWS_SECRET_ACCESS_KEY: - from_secret: aws_secret_access_key - SCCACHE_BUCKET: heliax-drone-cache-v2 - SCCACHE_S3_KEY_PREFIX: sccache-build - depends_on: - - download-scripts -- name: build-test - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/anoma:latest - pull: never - commands: - - sccache --start-server - - make build-test - environment: - AWS_ACCESS_KEY_ID: - from_secret: aws_access_key_id - AWS_SECRET_ACCESS_KEY: - from_secret: aws_secret_access_key - SCCACHE_BUCKET: heliax-drone-cache-v2 - SCCACHE_S3_KEY_PREFIX: sccache-build-test - depends_on: - - build -- name: download-wasm - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/git:latest - pull: never - commands: - - sh scripts/ci/download-wasm.sh - depends_on: - - build-test -- name: test-unit - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/anoma:latest - pull: never - commands: - - sccache --start-server - - make test-unit - environment: - AWS_ACCESS_KEY_ID: - from_secret: aws_access_key_id - AWS_SECRET_ACCESS_KEY: - from_secret: aws_secret_access_key - SCCACHE_BUCKET: heliax-drone-cache-v2 - SCCACHE_S3_KEY_PREFIX: sccache-test-unit - depends_on: - - download-wasm -- name: test-e2e - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/anoma:latest - pull: never - commands: - - sccache --start-server - - make test-e2e - environment: - AWS_ACCESS_KEY_ID: - from_secret: aws_access_key_id - AWS_SECRET_ACCESS_KEY: - from_secret: aws_secret_access_key - SCCACHE_BUCKET: heliax-drone-cache-v2 - SCCACHE_S3_KEY_PREFIX: sccache-test-e2e - depends_on: - - download-wasm -trigger: - event: - - pull_request -type: docker -workspace: - path: /usr/local/rust/anoma -environment: - CARGO_INCREMENTAL: '0' - GIT_LFS_SKIP_SMUDGE: '1' -clone: - disable: true ---- -name: anoma-ci-build-abci-pr -kind: pipeline -node: - project: anoma -steps: -- name: clone - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/git:latest - pull: never - commands: - - git clone $DRONE_GIT_HTTP_URL --depth 1 --quiet --branch ${DRONE_SOURCE_BRANCH:-master} - --single-branch . -- name: download-scripts - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/git:latest - pull: never - commands: - - aws s3 cp s3://$S3_BUCKET_SCRIPTS/anoma.zip scripts/ci/anoma.zip - - cd scripts/ci && unzip anoma.zip - environment: - S3_BUCKET_SCRIPTS: drone-ci-scripts - AWS_ACCESS_KEY_ID: - from_secret: aws_access_key_id - AWS_SECRET_ACCESS_KEY: - from_secret: aws_secret_access_key - depends_on: - - clone -- name: build - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/anoma:latest - pull: never - commands: - - sccache --start-server - - make build-abci-plus-plus - environment: - AWS_ACCESS_KEY_ID: - from_secret: aws_access_key_id - AWS_SECRET_ACCESS_KEY: - from_secret: aws_secret_access_key - SCCACHE_BUCKET: heliax-drone-cache-v2 - SCCACHE_S3_KEY_PREFIX: sccache-build-abci - depends_on: - - download-scripts -- name: build-test - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/anoma:latest - pull: never - commands: - - sccache --start-server - - make build-test-abci-plus-plus - environment: - AWS_ACCESS_KEY_ID: - from_secret: aws_access_key_id - AWS_SECRET_ACCESS_KEY: - from_secret: aws_secret_access_key - SCCACHE_BUCKET: heliax-drone-cache-v2 - SCCACHE_S3_KEY_PREFIX: sccache-build-test-abci - depends_on: - - build -- name: download-wasm - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/git:latest - pull: never - commands: - - sh scripts/ci/download-wasm.sh - depends_on: - - build-test -- name: test-unit - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/anoma:latest - pull: never - commands: - - sccache --start-server - - make test-unit-abci-plus-plus - environment: - AWS_ACCESS_KEY_ID: - from_secret: aws_access_key_id - AWS_SECRET_ACCESS_KEY: - from_secret: aws_secret_access_key - SCCACHE_BUCKET: heliax-drone-cache-v2 - SCCACHE_S3_KEY_PREFIX: sccache-test-unit-abci - depends_on: - - download-wasm -- name: test-e2e - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/anoma:latest - pull: never - commands: - - sccache --start-server - - make test-e2e-abci-plus-plus - environment: - AWS_ACCESS_KEY_ID: - from_secret: aws_access_key_id - AWS_SECRET_ACCESS_KEY: - from_secret: aws_secret_access_key - SCCACHE_BUCKET: heliax-drone-cache-v2 - SCCACHE_S3_KEY_PREFIX: sccache-test-e2e-abci - TENDERMINT: /usr/local/bin/tendermint++ - depends_on: - - download-wasm -trigger: - event: - - pull_request -type: docker -workspace: - path: /usr/local/rust/abci -environment: - CARGO_INCREMENTAL: '0' - GIT_LFS_SKIP_SMUDGE: '1' -clone: - disable: true ---- -name: anoma-ci-checks-pr -kind: pipeline -node: - project: anoma -steps: -- name: clone - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/git:latest - pull: never - commands: - - git clone $DRONE_GIT_HTTP_URL --depth 1 --quiet --branch ${DRONE_SOURCE_BRANCH:-master} - --single-branch . -- name: download-scripts - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/git:latest - pull: never - commands: - - aws s3 cp s3://$S3_BUCKET_SCRIPTS/anoma.zip scripts/ci/anoma.zip - - cd scripts/ci && unzip anoma.zip - environment: - S3_BUCKET_SCRIPTS: drone-ci-scripts - AWS_ACCESS_KEY_ID: - from_secret: aws_access_key_id - AWS_SECRET_ACCESS_KEY: - from_secret: aws_secret_access_key - depends_on: - - clone -- name: clippy - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/anoma:latest - pull: never - commands: - - sccache --start-server - - make clippy - environment: - AWS_ACCESS_KEY_ID: - from_secret: aws_access_key_id - AWS_SECRET_ACCESS_KEY: - from_secret: aws_secret_access_key - SCCACHE_BUCKET: heliax-drone-cache-v2 - SCCACHE_S3_KEY_PREFIX: sccache-clippy - depends_on: - - download-scripts -- name: format - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/anoma:latest - pull: never - commands: - - sccache --start-server - - make fmt-check - environment: - AWS_ACCESS_KEY_ID: - from_secret: aws_access_key_id - AWS_SECRET_ACCESS_KEY: - from_secret: aws_secret_access_key - SCCACHE_BUCKET: heliax-drone-cache-v2 - SCCACHE_S3_KEY_PREFIX: sccache-format - depends_on: - - clippy -trigger: - event: - - push - - pull_request - branch: - - develop - - master -type: docker -workspace: - path: /usr/local/rust/anoma -environment: - CARGO_INCREMENTAL: '0' - GIT_LFS_SKIP_SMUDGE: '1' -clone: - disable: true ---- -name: anoma-ci-checks-abci-pr -kind: pipeline -node: - project: anoma -steps: -- name: clone - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/git:latest - pull: never - commands: - - git clone $DRONE_GIT_HTTP_URL --depth 1 --quiet --branch ${DRONE_SOURCE_BRANCH:-master} - --single-branch . -- name: download-scripts - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/git:latest - pull: never - commands: - - aws s3 cp s3://$S3_BUCKET_SCRIPTS/anoma.zip scripts/ci/anoma.zip - - cd scripts/ci && unzip anoma.zip - environment: - S3_BUCKET_SCRIPTS: drone-ci-scripts - AWS_ACCESS_KEY_ID: - from_secret: aws_access_key_id - AWS_SECRET_ACCESS_KEY: - from_secret: aws_secret_access_key - depends_on: - - clone -- name: clippy - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/anoma:latest - pull: never - commands: - - sccache --start-server - - make clippy-abci-plus-plus - environment: - AWS_ACCESS_KEY_ID: - from_secret: aws_access_key_id - AWS_SECRET_ACCESS_KEY: - from_secret: aws_secret_access_key - SCCACHE_BUCKET: heliax-drone-cache-v2 - SCCACHE_S3_KEY_PREFIX: sccache-clippy-abci - depends_on: - - download-scripts -trigger: - event: - - push - - pull_request - branch: - - develop - - master -type: docker -workspace: - path: /usr/local/rust/abci -environment: - CARGO_INCREMENTAL: '0' - GIT_LFS_SKIP_SMUDGE: '1' -clone: - disable: true ---- -name: anoma-ci-misc-pr -kind: pipeline -node: - project: anoma -steps: -- name: clone - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/git:latest - pull: never - commands: - - git clone $DRONE_GIT_HTTP_URL --depth 1 --quiet --branch ${DRONE_SOURCE_BRANCH:-master} - --single-branch . -- name: download-scripts - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/git:latest - pull: never - commands: - - aws s3 cp s3://$S3_BUCKET_SCRIPTS/anoma.zip scripts/ci/anoma.zip - - cd scripts/ci && unzip anoma.zip - environment: - S3_BUCKET_SCRIPTS: drone-ci-scripts - AWS_ACCESS_KEY_ID: - from_secret: aws_access_key_id - AWS_SECRET_ACCESS_KEY: - from_secret: aws_secret_access_key - depends_on: - - clone -- name: build-docs - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/anoma:latest - pull: never - commands: - - sccache --start-server - - sh scripts/ci/build-and-publish-docs.sh - environment: - GITHUB_TOKEN: - from_secret: github_token - AWS_ACCESS_KEY_ID: - from_secret: aws_access_key_id - AWS_SECRET_ACCESS_KEY: - from_secret: aws_secret_access_key - SCCACHE_BUCKET: heliax-drone-cache-v2 - SCCACHE_S3_KEY_PREFIX: sccache-docs - depends_on: - - download-scripts -trigger: - event: - - pull_request -type: docker -workspace: - path: /usr/local/rust/anoma -environment: - CARGO_INCREMENTAL: '0' - GIT_LFS_SKIP_SMUDGE: '1' -clone: - disable: true ---- -name: anoma-ci-cron -kind: pipeline -node: - project: anoma -steps: -- name: clone - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/git:latest - pull: never - commands: - - git clone $DRONE_GIT_HTTP_URL --depth 1 --quiet --branch ${DRONE_SOURCE_BRANCH:-master} - --single-branch . -- name: download-scripts - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/git:latest - pull: never - commands: - - aws s3 cp s3://$S3_BUCKET_SCRIPTS/anoma.zip scripts/ci/anoma.zip - - cd scripts/ci && unzip anoma.zip - environment: - S3_BUCKET_SCRIPTS: drone-ci-scripts - AWS_ACCESS_KEY_ID: - from_secret: aws_access_key_id - AWS_SECRET_ACCESS_KEY: - from_secret: aws_secret_access_key - depends_on: - - clone -- name: audit - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/anoma:latest - pull: never - commands: - - cd scripts/ci && sh audit.sh - environment: - AWS_ACCESS_KEY_ID: - from_secret: aws_access_key_id - AWS_SECRET_ACCESS_KEY: - from_secret: aws_secret_access_key - depends_on: - - download-scripts -- name: udeps - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/anoma:latest - pull: never - commands: - - cd scripts/ci && sh udeps.sh - environment: - AWS_ACCESS_KEY_ID: - from_secret: aws_access_key_id - AWS_SECRET_ACCESS_KEY: - from_secret: aws_secret_access_key - SCCACHE_BUCKET: heliax-drone-cache-v2 - SCCACHE_S3_KEY_PREFIX: sccache-udeps - depends_on: - - download-scripts -trigger: - event: - - cron - cron: - - audit -type: docker -workspace: - path: /usr/local/rust/anoma -environment: - CARGO_INCREMENTAL: '0' - GIT_LFS_SKIP_SMUDGE: '1' -clone: - disable: true ---- -name: anoma-ci-build-abci-master -kind: pipeline -node: - project: anoma -steps: -- name: clone - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/git:latest - pull: never - commands: - - git clone $DRONE_GIT_HTTP_URL --depth 1 --quiet --branch ${DRONE_SOURCE_BRANCH:-master} - --single-branch . -- name: download-scripts - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/git:latest - pull: never - commands: - - aws s3 cp s3://$S3_BUCKET_SCRIPTS/anoma.zip scripts/ci/anoma.zip - - cd scripts/ci && unzip anoma.zip - environment: - S3_BUCKET_SCRIPTS: drone-ci-scripts - AWS_ACCESS_KEY_ID: - from_secret: aws_access_key_id - AWS_SECRET_ACCESS_KEY: - from_secret: aws_secret_access_key - depends_on: - - clone -- name: build - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/anoma:latest - pull: never - commands: - - sccache --start-server - - make build-abci-plus-plus - environment: - AWS_ACCESS_KEY_ID: - from_secret: aws_access_key_id - AWS_SECRET_ACCESS_KEY: - from_secret: aws_secret_access_key - SCCACHE_BUCKET: heliax-drone-cache-v2 - SCCACHE_S3_KEY_PREFIX: sccache-build-abci - depends_on: - - download-scripts -- name: build-test - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/anoma:latest - pull: never - commands: - - sccache --start-server - - make build-test-abci-plus-plus - environment: - AWS_ACCESS_KEY_ID: - from_secret: aws_access_key_id - AWS_SECRET_ACCESS_KEY: - from_secret: aws_secret_access_key - SCCACHE_BUCKET: heliax-drone-cache-v2 - SCCACHE_S3_KEY_PREFIX: sccache-build-test-abci - depends_on: - - build -- name: download-wasm - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/git:latest - pull: never - commands: - - sh scripts/ci/download-wasm.sh - depends_on: - - build-test -- name: test-unit - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/anoma:latest - pull: never - commands: - - sccache --start-server - - make test-unit-abci-plus-plus - environment: - AWS_ACCESS_KEY_ID: - from_secret: aws_access_key_id - AWS_SECRET_ACCESS_KEY: - from_secret: aws_secret_access_key - SCCACHE_BUCKET: heliax-drone-cache-v2 - SCCACHE_S3_KEY_PREFIX: sccache-test-unit-abci - depends_on: - - download-wasm -- name: test-e2e - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/anoma:latest - pull: never - commands: - - sccache --start-server - - make test-e2e-abci-plus-plus - environment: - AWS_ACCESS_KEY_ID: - from_secret: aws_access_key_id - AWS_SECRET_ACCESS_KEY: - from_secret: aws_secret_access_key - SCCACHE_BUCKET: heliax-drone-cache-v2 - SCCACHE_S3_KEY_PREFIX: sccache-test-e2e-abci - TENDERMINT: /usr/local/bin/tendermint++ - depends_on: - - download-wasm -trigger: - event: - - push - branch: - - master -type: docker -workspace: - path: /usr/local/rust/abci -environment: - CARGO_INCREMENTAL: '0' - GIT_LFS_SKIP_SMUDGE: '1' -clone: - disable: true ---- -name: anoma-ci-docs-master -kind: pipeline -node: - project: anoma -steps: -- name: clone - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/git:latest - pull: never - commands: - - git clone $DRONE_GIT_HTTP_URL --depth 1 --quiet --branch ${DRONE_SOURCE_BRANCH:-master} - --single-branch . -- name: download-scripts - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/git:latest - pull: never - commands: - - aws s3 cp s3://$S3_BUCKET_SCRIPTS/anoma.zip scripts/ci/anoma.zip - - cd scripts/ci && unzip anoma.zip - environment: - S3_BUCKET_SCRIPTS: drone-ci-scripts - AWS_ACCESS_KEY_ID: - from_secret: aws_access_key_id - AWS_SECRET_ACCESS_KEY: - from_secret: aws_secret_access_key - depends_on: - - clone -- name: build-docs - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/anoma:latest - pull: never - commands: - - sccache --start-server - - sh scripts/ci/build-and-publish-docs.sh - environment: - GITHUB_TOKEN: - from_secret: github_token - AWS_ACCESS_KEY_ID: - from_secret: aws_access_key_id - AWS_SECRET_ACCESS_KEY: - from_secret: aws_secret_access_key - SCCACHE_BUCKET: heliax-drone-cache-v2 - SCCACHE_S3_KEY_PREFIX: sccache-docs - depends_on: - - download-scripts -trigger: - event: - - push - branch: - - master -type: docker -workspace: - path: /usr/local/rust/anoma -environment: - CARGO_INCREMENTAL: '0' - GIT_LFS_SKIP_SMUDGE: '1' -clone: - disable: true ---- -name: anoma-ci-build-master -kind: pipeline -node: - project: anoma -steps: -- name: clone - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/git:latest - pull: never - commands: - - git clone $DRONE_GIT_HTTP_URL --depth 1 --quiet --branch ${DRONE_SOURCE_BRANCH:-master} - --single-branch . -- name: download-scripts - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/git:latest - pull: never - commands: - - aws s3 cp s3://$S3_BUCKET_SCRIPTS/anoma.zip scripts/ci/anoma.zip - - cd scripts/ci && unzip anoma.zip - environment: - S3_BUCKET_SCRIPTS: drone-ci-scripts - AWS_ACCESS_KEY_ID: - from_secret: aws_access_key_id - AWS_SECRET_ACCESS_KEY: - from_secret: aws_secret_access_key - depends_on: - - clone -- name: build - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/anoma:latest - pull: never - commands: - - sccache --start-server - - make build - environment: - AWS_ACCESS_KEY_ID: - from_secret: aws_access_key_id - AWS_SECRET_ACCESS_KEY: - from_secret: aws_secret_access_key - SCCACHE_BUCKET: heliax-drone-cache-v2 - SCCACHE_S3_KEY_PREFIX: sccache-build - depends_on: - - download-scripts -- name: build-test - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/anoma:latest - pull: never - commands: - - sccache --start-server - - make build-test - environment: - AWS_ACCESS_KEY_ID: - from_secret: aws_access_key_id - AWS_SECRET_ACCESS_KEY: - from_secret: aws_secret_access_key - SCCACHE_BUCKET: heliax-drone-cache-v2 - SCCACHE_S3_KEY_PREFIX: sccache-build-test - depends_on: - - build -- name: download-wasm - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/git:latest - pull: never - commands: - - sh scripts/ci/download-wasm.sh - depends_on: - - build-test -- name: test-unit - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/anoma:latest - pull: never - commands: - - sccache --start-server - - make test-unit - environment: - AWS_ACCESS_KEY_ID: - from_secret: aws_access_key_id - AWS_SECRET_ACCESS_KEY: - from_secret: aws_secret_access_key - SCCACHE_BUCKET: heliax-drone-cache-v2 - SCCACHE_S3_KEY_PREFIX: sccache-test-unit - depends_on: - - download-wasm -- name: test-e2e - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/anoma:latest - pull: never - commands: - - sccache --start-server - - make test-e2e - environment: - AWS_ACCESS_KEY_ID: - from_secret: aws_access_key_id - AWS_SECRET_ACCESS_KEY: - from_secret: aws_secret_access_key - SCCACHE_BUCKET: heliax-drone-cache-v2 - SCCACHE_S3_KEY_PREFIX: sccache-test-e2e - depends_on: - - download-wasm -trigger: - event: - - push - branch: - - master -type: docker -workspace: - path: /usr/local/rust/anoma -environment: - CARGO_INCREMENTAL: '0' - GIT_LFS_SKIP_SMUDGE: '1' -clone: - disable: true ---- -name: anoma-ci-release -kind: pipeline -node: - project: anoma -steps: -- name: clone - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/git:latest - pull: never - commands: - - git clone $DRONE_GIT_HTTP_URL --depth 1 --quiet --branch ${DRONE_SOURCE_BRANCH:-master} - --single-branch . -- name: download-scripts - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/git:latest - pull: never - commands: - - aws s3 cp s3://$S3_BUCKET_SCRIPTS/anoma.zip scripts/ci/anoma.zip - - cd scripts/ci && unzip anoma.zip - environment: - S3_BUCKET_SCRIPTS: drone-ci-scripts - AWS_ACCESS_KEY_ID: - from_secret: aws_access_key_id - AWS_SECRET_ACCESS_KEY: - from_secret: aws_secret_access_key - depends_on: - - clone -- name: build-docs - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/anoma:latest - pull: never - commands: - - sccache --start-server - - sh scripts/ci/build-and-publish-docs.sh - environment: - GITHUB_TOKEN: - from_secret: github_token - AWS_ACCESS_KEY_ID: - from_secret: aws_access_key_id - AWS_SECRET_ACCESS_KEY: - from_secret: aws_secret_access_key - SCCACHE_BUCKET: heliax-drone-cache-v2 - SCCACHE_S3_KEY_PREFIX: sccache-docs - depends_on: - - download-scripts -- name: build-package - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/anoma:latest - pull: never - commands: - - sccache --start-server - - make package - environment: - AWS_ACCESS_KEY_ID: - from_secret: aws_access_key_id - AWS_SECRET_ACCESS_KEY: - from_secret: aws_secret_access_key - SCCACHE_BUCKET: heliax-drone-cache-v2 - SCCACHE_S3_KEY_PREFIX: sccache-build-release - depends_on: - - build-docs -- name: upload-wasm - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/git:latest - pull: never - commands: - - sh scripts/ci/upload-wasm.sh - environment: - AWS_ACCESS_KEY_ID: - from_secret: aws_access_key_id - AWS_SECRET_ACCESS_KEY: - from_secret: aws_secret_access_key - GITHUB_TOKEN: - from_secret: github_token - depends_on: - - build-docs -- name: create-release - image: 965844283396.dkr.ecr.eu-west-1.amazonaws.com/git:latest - pull: never - commands: - - sh scripts/ci/release.sh - environment: - GITHUB_TOKEN: - from_secret: github_token - depends_on: - - build-package - - upload-wasm -trigger: - event: - - tag -type: docker -workspace: - path: /usr/local/rust/anoma -environment: - CARGO_INCREMENTAL: '0' - GIT_LFS_SKIP_SMUDGE: '1' -clone: - disable: true ---- -kind: signature -hmac: 4c6a2d9c84b634a7417a897f5af3ac91c0f06230198e824160603b8931457c7c - -... From 8e4f4510a797c71d74965abf5d04d172e3599f78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zemanovi=C4=8D?= Date: Tue, 6 Sep 2022 16:32:29 +0200 Subject: [PATCH 114/118] make build-doc: only build rustdoc in this command --- Makefile | 2 -- 1 file changed, 2 deletions(-) diff --git a/Makefile b/Makefile index 3474f6c8e6..6bcb62c75f 100644 --- a/Makefile +++ b/Makefile @@ -129,8 +129,6 @@ clean: build-doc: $(cargo) doc --no-deps - $(cargo) run --bin namada_encoding_spec - make -C docs build doc: # build and opens the docs in browser From 81e9713176ff30da637fc51ac43ad0bad3677fcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zemanovi=C4=8D?= Date: Tue, 6 Sep 2022 15:44:31 +0200 Subject: [PATCH 115/118] rustdoc: fix outdated links --- apps/src/lib/node/ledger/shell/mod.rs | 4 ++-- apps/src/lib/node/ledger/shell/prepare_proposal.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/src/lib/node/ledger/shell/mod.rs b/apps/src/lib/node/ledger/shell/mod.rs index eb47160f9c..1f9759a2a2 100644 --- a/apps/src/lib/node/ledger/shell/mod.rs +++ b/apps/src/lib/node/ledger/shell/mod.rs @@ -1,8 +1,8 @@ //! The ledger shell connects the ABCI++ interface with the Anoma ledger app. //! //! Any changes applied before [`Shell::finalize_block`] might have to be -//! reverted, so any changes applied in the methods `Shell::prepare_proposal` -//! (ABCI++), [`Shell::process_and_decode_proposal`] must be also reverted +//! reverted, so any changes applied in the methods [`Shell::prepare_proposal`] +//! and [`Shell::process_proposal`] must be also reverted //! (unless we can simply overwrite them in the next block). //! More info in . mod finalize_block; diff --git a/apps/src/lib/node/ledger/shell/prepare_proposal.rs b/apps/src/lib/node/ledger/shell/prepare_proposal.rs index 7c15180d2c..57df2f2647 100644 --- a/apps/src/lib/node/ledger/shell/prepare_proposal.rs +++ b/apps/src/lib/node/ledger/shell/prepare_proposal.rs @@ -1,4 +1,4 @@ -//! Implementation of the [`PrepareProposal`] ABCI++ method for the Shell +//! Implementation of the [`RequestPrepareProposal`] ABCI++ method for the Shell use tendermint_proto::abci::TxRecord; From d7c4a339347e9f15933219398e1d2e8bca4d00ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zemanovi=C4=8D?= Date: Wed, 7 Sep 2022 09:55:07 +0200 Subject: [PATCH 116/118] changelog: add #442 --- .changelog/unreleased/bug-fixes/419-fix-rustdoc.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 .changelog/unreleased/bug-fixes/419-fix-rustdoc.md diff --git a/.changelog/unreleased/bug-fixes/419-fix-rustdoc.md b/.changelog/unreleased/bug-fixes/419-fix-rustdoc.md new file mode 100644 index 0000000000..09b6c343c2 --- /dev/null +++ b/.changelog/unreleased/bug-fixes/419-fix-rustdoc.md @@ -0,0 +1 @@ +- Fix the rustdoc build. ([#419](https://github.com/anoma/namada/issues/419)) \ No newline at end of file From 22ab0d33a73647409e515bab18f9f25b03d08d18 Mon Sep 17 00:00:00 2001 From: bengtlofgren <51077282+bengtlofgren@users.noreply.github.com> Date: Mon, 19 Sep 2022 09:26:47 +0100 Subject: [PATCH 117/118] Update getting-started.md The link to testnets was broken. I fixed it --- documentation/docs/src/user-guide/getting-started.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/docs/src/user-guide/getting-started.md b/documentation/docs/src/user-guide/getting-started.md index 6f2ce00e30..d9bd79d83f 100644 --- a/documentation/docs/src/user-guide/getting-started.md +++ b/documentation/docs/src/user-guide/getting-started.md @@ -23,7 +23,7 @@ After you installed Namada, you will need to join a live network (e.g. testnet) namada client utils join-network --chain-id= ``` -To join a testnet, head over to the [testnets](../testnets) section for details on how to do this. +To join a testnet, head over to the [testnets](../testnets/index.html) section for details on how to do this. ## Start your node From fda71af313e6f9efa1d4c9ca9b4566e31780ba94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zemanovi=C4=8D?= Date: Mon, 19 Sep 2022 10:51:55 +0200 Subject: [PATCH 118/118] Revert "Update getting-started.md" This reverts commit 22ab0d33a73647409e515bab18f9f25b03d08d18. --- documentation/docs/src/user-guide/getting-started.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/docs/src/user-guide/getting-started.md b/documentation/docs/src/user-guide/getting-started.md index d9bd79d83f..6f2ce00e30 100644 --- a/documentation/docs/src/user-guide/getting-started.md +++ b/documentation/docs/src/user-guide/getting-started.md @@ -23,7 +23,7 @@ After you installed Namada, you will need to join a live network (e.g. testnet) namada client utils join-network --chain-id= ``` -To join a testnet, head over to the [testnets](../testnets/index.html) section for details on how to do this. +To join a testnet, head over to the [testnets](../testnets) section for details on how to do this. ## Start your node