From 0280da8babe5882c93208c1e8cadf2523bc1efc4 Mon Sep 17 00:00:00 2001 From: mario4tier <4542410+mario4tier@users.noreply.github.com> Date: Fri, 16 Feb 2024 03:14:39 +0000 Subject: [PATCH] =?UTF-8?q?Deploying=20to=20gh-pages=20from=20@=20ChainMov?= =?UTF-8?q?ers/dtp@faa5b646ce0b90307794ca4f1687269ba97a0100=20=F0=9F=9A=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 404.html | 6 ++--- ....html-BL0QzlcP.js => 404.html-2OslWyTj.js} | 2 +- ...-CzB0Dlbt.js => api_rust.html-B1fR_PmW.js} | 2 +- ...-jR6an_Pz.js => api_rust.html-DgeZ6cWi.js} | 2 +- ...oGQ.js => api_typescript.html-CDBTYfuZ.js} | 2 +- ...Zzf.js => api_typescript.html-CShx0BZb.js} | 2 +- assets/{app-CKXWWpf0.js => app-BnFZaCe1.js} | 4 ++-- assets/design.html-84EaReMx.js | 14 ++++++++++++ assets/design.html-BDTT4CCh.js | 14 ++++++++++++ assets/design.html-BrbpjE_m.js | 11 --------- assets/design.html-CubwsOM8.js | 11 --------- ...l-C8UZnhJf.js => editors.html-CNXsfcsu.js} | 2 +- ....html-wlteNg54.js => faq.html-CV8sl42E.js} | 2 +- ...9U11CgD.js => full_setup.html-Cez3e24z.js} | 2 +- ...7HikED.js => future_work.html-B07VTehy.js} | 2 +- ...NaLhGO.js => future_work.html-Cj0rm1Vd.js} | 2 +- assets/images/design_inner_pipe_2.png | Bin 0 -> 64111 bytes ...tml-3uUFhvd2.js => index.html-B8jhZ03x.js} | 2 +- ...tml-BodtrdFm.js => index.html-BVUfEJTo.js} | 2 +- ...tml-D-JN27_M.js => index.html-BWOMH9gB.js} | 2 +- ...tml-CBpta1zV.js => index.html-CBcd5KzL.js} | 2 +- ...tml-D031wELU.js => index.html-CEa4pTjw.js} | 2 +- ...tml-BGgB7rPy.js => index.html-CnguV0tX.js} | 2 +- ...l-B3JszHVu.js => install.html-BAMq21Zx.js} | 2 +- ...tml-Bxgg0fO6.js => intro.html-BxGuE4wy.js} | 2 +- ...-BS4zMMEQ.js => npm_only.html-BApcLSxE.js} | 2 +- assets/ref_broadcast-BFGBhm9s.js | 1 + assets/ref_broadcast-wOf-j1_D.js | 1 - ...xw1oe.js => rpc_firewall.html-D9Yd1Ah_.js} | 2 +- ...PrZKz.js => runtime_only.html-CuZ2LIXr.js} | 2 +- ...l-DkAQ2N11.js => scripts.html-BZkBrHbZ.js} | 2 +- ...l-Bu-kSnJq.js => scripts.html-Dj-m4wYR.js} | 2 +- ...CtlHbOSD.js => web3_rust.html-DrfE3oTr.js} | 2 +- community/editors.html | 6 ++--- community/index.html | 6 ++--- docs/api_rust.html | 6 ++--- docs/api_typescript.html | 6 ++--- docs/design.html | 21 ++++++++++-------- docs/future_work.html | 6 ++--- docs/index.html | 6 ++--- docs/scripts.html | 6 ++--- examples/index.html | 6 ++--- examples/rpc_firewall.html | 6 ++--- examples/web3_rust.html | 6 ++--- faq.html | 6 ++--- how-to/full_setup.html | 6 ++--- how-to/index.html | 6 ++--- how-to/install.html | 6 ++--- how-to/npm_only.html | 6 ++--- how-to/runtime_only.html | 6 ++--- index.html | 6 ++--- intro.html | 6 ++--- ref/api_rust.html | 6 ++--- ref/api_typescript.html | 6 ++--- ref/design.html | 19 +++++++++------- ref/future_work.html | 6 ++--- ref/index.html | 6 ++--- ref/scripts.html | 6 ++--- sitemap.xml | 2 +- 59 files changed, 151 insertions(+), 139 deletions(-) rename assets/{404.html-BL0QzlcP.js => 404.html-2OslWyTj.js} (94%) rename assets/{api_rust.html-CzB0Dlbt.js => api_rust.html-B1fR_PmW.js} (96%) rename assets/{api_rust.html-jR6an_Pz.js => api_rust.html-DgeZ6cWi.js} (95%) rename assets/{api_typescript.html-BMmh0oGQ.js => api_typescript.html-CDBTYfuZ.js} (96%) rename assets/{api_typescript.html-BqGWlZzf.js => api_typescript.html-CShx0BZb.js} (95%) rename assets/{app-CKXWWpf0.js => app-BnFZaCe1.js} (98%) create mode 100644 assets/design.html-84EaReMx.js create mode 100644 assets/design.html-BDTT4CCh.js delete mode 100644 assets/design.html-BrbpjE_m.js delete mode 100644 assets/design.html-CubwsOM8.js rename assets/{editors.html-C8UZnhJf.js => editors.html-CNXsfcsu.js} (97%) rename assets/{faq.html-wlteNg54.js => faq.html-CV8sl42E.js} (99%) rename assets/{full_setup.html-D9U11CgD.js => full_setup.html-Cez3e24z.js} (97%) rename assets/{future_work.html-Dp7HikED.js => future_work.html-B07VTehy.js} (99%) rename assets/{future_work.html-CaNaLhGO.js => future_work.html-Cj0rm1Vd.js} (99%) create mode 100644 assets/images/design_inner_pipe_2.png rename assets/{index.html-3uUFhvd2.js => index.html-B8jhZ03x.js} (93%) rename assets/{index.html-BodtrdFm.js => index.html-BVUfEJTo.js} (98%) rename assets/{index.html-D-JN27_M.js => index.html-BWOMH9gB.js} (99%) rename assets/{index.html-CBpta1zV.js => index.html-CBcd5KzL.js} (98%) rename assets/{index.html-D031wELU.js => index.html-CEa4pTjw.js} (98%) rename assets/{index.html-BGgB7rPy.js => index.html-CnguV0tX.js} (98%) rename assets/{install.html-B3JszHVu.js => install.html-BAMq21Zx.js} (97%) rename assets/{intro.html-Bxgg0fO6.js => intro.html-BxGuE4wy.js} (97%) rename assets/{npm_only.html-BS4zMMEQ.js => npm_only.html-BApcLSxE.js} (96%) create mode 100644 assets/ref_broadcast-BFGBhm9s.js delete mode 100644 assets/ref_broadcast-wOf-j1_D.js rename assets/{rpc_firewall.html-DXKxw1oe.js => rpc_firewall.html-D9Yd1Ah_.js} (98%) rename assets/{runtime_only.html-BWVPrZKz.js => runtime_only.html-CuZ2LIXr.js} (96%) rename assets/{scripts.html-DkAQ2N11.js => scripts.html-BZkBrHbZ.js} (95%) rename assets/{scripts.html-Bu-kSnJq.js => scripts.html-Dj-m4wYR.js} (96%) rename assets/{web3_rust.html-CtlHbOSD.js => web3_rust.html-DrfE3oTr.js} (97%) diff --git a/404.html b/404.html index cd6cbf1..ed9ba70 100644 --- a/404.html +++ b/404.html @@ -30,11 +30,11 @@ Decentralized Transport Protocol - - + +
Skip to main content

404

Page not found

How did we get here?

- + diff --git a/assets/404.html-BL0QzlcP.js b/assets/404.html-2OslWyTj.js similarity index 94% rename from assets/404.html-BL0QzlcP.js rename to assets/404.html-2OslWyTj.js index 2538f20..46bab6b 100644 --- a/assets/404.html-BL0QzlcP.js +++ b/assets/404.html-2OslWyTj.js @@ -1 +1 @@ -import{_ as t}from"./plugin-vue_export-helper-DlAUqK2U.js";import{o as e,c as o,a as n}from"./app-CKXWWpf0.js";const r={},a=n("p",null,"404 Not Found",-1),c=[a];function p(s,i){return e(),o("div",null,c)}const m=t(r,[["render",p],["__file","404.html.vue"]]),_=JSON.parse('{"path":"/404.html","title":"","lang":"en-US","frontmatter":{"layout":"NotFound","description":"404 Not Found ","head":[["meta",{"property":"og:url","content":"https://dtp.dev/404.html"}],["meta",{"property":"og:site_name","content":"Decentralized Transport Protocol"}],["meta",{"property":"og:description","content":"404 Not Found "}],["meta",{"property":"og:type","content":"website"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"article:author","content":"dtp.dev"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"WebPage\\",\\"name\\":\\"\\",\\"description\\":\\"404 Not Found \\"}"]]},"headers":[],"git":{},"readingTime":{"minutes":0.01,"words":3},"filePathRelative":null,"autoDesc":true}');export{m as comp,_ as data}; +import{_ as t}from"./plugin-vue_export-helper-DlAUqK2U.js";import{o as e,c as o,a as n}from"./app-BnFZaCe1.js";const r={},a=n("p",null,"404 Not Found",-1),c=[a];function p(s,i){return e(),o("div",null,c)}const m=t(r,[["render",p],["__file","404.html.vue"]]),_=JSON.parse('{"path":"/404.html","title":"","lang":"en-US","frontmatter":{"layout":"NotFound","description":"404 Not Found ","head":[["meta",{"property":"og:url","content":"https://dtp.dev/404.html"}],["meta",{"property":"og:site_name","content":"Decentralized Transport Protocol"}],["meta",{"property":"og:description","content":"404 Not Found "}],["meta",{"property":"og:type","content":"website"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"article:author","content":"dtp.dev"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"WebPage\\",\\"name\\":\\"\\",\\"description\\":\\"404 Not Found \\"}"]]},"headers":[],"git":{},"readingTime":{"minutes":0.01,"words":3},"filePathRelative":null,"autoDesc":true}');export{m as comp,_ as data}; diff --git a/assets/api_rust.html-CzB0Dlbt.js b/assets/api_rust.html-B1fR_PmW.js similarity index 96% rename from assets/api_rust.html-CzB0Dlbt.js rename to assets/api_rust.html-B1fR_PmW.js index b856fa2..6d9a457 100644 --- a/assets/api_rust.html-CzB0Dlbt.js +++ b/assets/api_rust.html-B1fR_PmW.js @@ -1 +1 @@ -import{_ as e}from"./plugin-vue_export-helper-DlAUqK2U.js";import{o,c as r,a as t}from"./app-CKXWWpf0.js";const a={},i=t("div",{class:"hint-container warning"},[t("p",{class:"hint-container-title"},"Not yet written")],-1),n=[i];function c(p,s){return o(),r("div",null,n)}const l=e(a,[["render",c],["__file","api_rust.html.vue"]]),_=JSON.parse('{"path":"/docs/api_rust.html","title":"","lang":"en-US","frontmatter":{"editLink":true,"description":" Not yet written ","head":[["meta",{"property":"og:url","content":"https://dtp.dev/docs/api_rust.html"}],["meta",{"property":"og:site_name","content":"Decentralized Transport Protocol"}],["meta",{"property":"og:description","content":" Not yet written "}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2024-02-14T03:11:10.000Z"}],["meta",{"property":"article:author","content":"dtp.dev"}],["meta",{"property":"article:modified_time","content":"2024-02-14T03:11:10.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2024-02-14T03:11:10.000Z\\",\\"author\\":[{\\"@type\\":\\"Person\\",\\"name\\":\\"dtp.dev\\",\\"url\\":\\"https://dtp.dev\\"}]}"]]},"headers":[],"git":{"createdTime":1707880270000,"updatedTime":1707880270000,"contributors":[{"name":"mario4tier","email":"mario4tier@users.noreply.github.com","commits":1}]},"readingTime":{"minutes":0.02,"words":6},"filePathRelative":"docs/api_rust.md","localizedDate":"February 14, 2024","autoDesc":true}');export{l as comp,_ as data}; +import{_ as e}from"./plugin-vue_export-helper-DlAUqK2U.js";import{o,c as r,a as t}from"./app-BnFZaCe1.js";const a={},i=t("div",{class:"hint-container warning"},[t("p",{class:"hint-container-title"},"Not yet written")],-1),n=[i];function c(p,s){return o(),r("div",null,n)}const l=e(a,[["render",c],["__file","api_rust.html.vue"]]),_=JSON.parse('{"path":"/docs/api_rust.html","title":"","lang":"en-US","frontmatter":{"editLink":true,"description":" Not yet written ","head":[["meta",{"property":"og:url","content":"https://dtp.dev/docs/api_rust.html"}],["meta",{"property":"og:site_name","content":"Decentralized Transport Protocol"}],["meta",{"property":"og:description","content":" Not yet written "}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2024-02-14T03:11:10.000Z"}],["meta",{"property":"article:author","content":"dtp.dev"}],["meta",{"property":"article:modified_time","content":"2024-02-14T03:11:10.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2024-02-14T03:11:10.000Z\\",\\"author\\":[{\\"@type\\":\\"Person\\",\\"name\\":\\"dtp.dev\\",\\"url\\":\\"https://dtp.dev\\"}]}"]]},"headers":[],"git":{"createdTime":1707880270000,"updatedTime":1707880270000,"contributors":[{"name":"mario4tier","email":"mario4tier@users.noreply.github.com","commits":1}]},"readingTime":{"minutes":0.02,"words":6},"filePathRelative":"docs/api_rust.md","localizedDate":"February 14, 2024","autoDesc":true}');export{l as comp,_ as data}; diff --git a/assets/api_rust.html-jR6an_Pz.js b/assets/api_rust.html-DgeZ6cWi.js similarity index 95% rename from assets/api_rust.html-jR6an_Pz.js rename to assets/api_rust.html-DgeZ6cWi.js index d2b32d9..8182804 100644 --- a/assets/api_rust.html-jR6an_Pz.js +++ b/assets/api_rust.html-DgeZ6cWi.js @@ -1 +1 @@ -import{_ as e}from"./plugin-vue_export-helper-DlAUqK2U.js";import{o as r,c as o,a as t}from"./app-CKXWWpf0.js";const n={},a=t("div",{class:"hint-container warning"},[t("p",{class:"hint-container-title"},"Not yet written")],-1),i=[a];function p(c,s){return r(),o("div",null,i)}const m=e(n,[["render",p],["__file","api_rust.html.vue"]]),u=JSON.parse('{"path":"/ref/api_rust.html","title":"","lang":"en-US","frontmatter":{"editLink":true,"description":" Not yet written ","head":[["meta",{"property":"og:url","content":"https://dtp.dev/ref/api_rust.html"}],["meta",{"property":"og:site_name","content":"Decentralized Transport Protocol"}],["meta",{"property":"og:description","content":" Not yet written "}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"article:author","content":"dtp.dev"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"\\",\\"image\\":[\\"\\"],\\"dateModified\\":null,\\"author\\":[{\\"@type\\":\\"Person\\",\\"name\\":\\"dtp.dev\\",\\"url\\":\\"https://dtp.dev\\"}]}"]]},"headers":[],"git":{"createdTime":null,"updatedTime":null,"contributors":[]},"readingTime":{"minutes":0.02,"words":6},"filePathRelative":"ref/api_rust.md","autoDesc":true}');export{m as comp,u as data}; +import{_ as e}from"./plugin-vue_export-helper-DlAUqK2U.js";import{o as r,c as o,a as t}from"./app-BnFZaCe1.js";const n={},a=t("div",{class:"hint-container warning"},[t("p",{class:"hint-container-title"},"Not yet written")],-1),i=[a];function p(c,s){return r(),o("div",null,i)}const m=e(n,[["render",p],["__file","api_rust.html.vue"]]),u=JSON.parse('{"path":"/ref/api_rust.html","title":"","lang":"en-US","frontmatter":{"editLink":true,"description":" Not yet written ","head":[["meta",{"property":"og:url","content":"https://dtp.dev/ref/api_rust.html"}],["meta",{"property":"og:site_name","content":"Decentralized Transport Protocol"}],["meta",{"property":"og:description","content":" Not yet written "}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"article:author","content":"dtp.dev"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"\\",\\"image\\":[\\"\\"],\\"dateModified\\":null,\\"author\\":[{\\"@type\\":\\"Person\\",\\"name\\":\\"dtp.dev\\",\\"url\\":\\"https://dtp.dev\\"}]}"]]},"headers":[],"git":{"createdTime":null,"updatedTime":null,"contributors":[]},"readingTime":{"minutes":0.02,"words":6},"filePathRelative":"ref/api_rust.md","autoDesc":true}');export{m as comp,u as data}; diff --git a/assets/api_typescript.html-BMmh0oGQ.js b/assets/api_typescript.html-CDBTYfuZ.js similarity index 96% rename from assets/api_typescript.html-BMmh0oGQ.js rename to assets/api_typescript.html-CDBTYfuZ.js index 57657ae..2a2ce7e 100644 --- a/assets/api_typescript.html-BMmh0oGQ.js +++ b/assets/api_typescript.html-CDBTYfuZ.js @@ -1 +1 @@ -import{_ as e}from"./plugin-vue_export-helper-DlAUqK2U.js";import{o,c as r,a as t}from"./app-CKXWWpf0.js";const i={},a=t("div",{class:"hint-container warning"},[t("p",{class:"hint-container-title"},"Not yet written")],-1),n=[a];function p(c,s){return o(),r("div",null,n)}const l=e(i,[["render",p],["__file","api_typescript.html.vue"]]),_=JSON.parse('{"path":"/docs/api_typescript.html","title":"","lang":"en-US","frontmatter":{"editLink":true,"description":" Not yet written ","head":[["meta",{"property":"og:url","content":"https://dtp.dev/docs/api_typescript.html"}],["meta",{"property":"og:site_name","content":"Decentralized Transport Protocol"}],["meta",{"property":"og:description","content":" Not yet written "}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2024-02-14T03:11:10.000Z"}],["meta",{"property":"article:author","content":"dtp.dev"}],["meta",{"property":"article:modified_time","content":"2024-02-14T03:11:10.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2024-02-14T03:11:10.000Z\\",\\"author\\":[{\\"@type\\":\\"Person\\",\\"name\\":\\"dtp.dev\\",\\"url\\":\\"https://dtp.dev\\"}]}"]]},"headers":[],"git":{"createdTime":1707880270000,"updatedTime":1707880270000,"contributors":[{"name":"mario4tier","email":"mario4tier@users.noreply.github.com","commits":1}]},"readingTime":{"minutes":0.02,"words":6},"filePathRelative":"docs/api_typescript.md","localizedDate":"February 14, 2024","autoDesc":true}');export{l as comp,_ as data}; +import{_ as e}from"./plugin-vue_export-helper-DlAUqK2U.js";import{o,c as r,a as t}from"./app-BnFZaCe1.js";const i={},a=t("div",{class:"hint-container warning"},[t("p",{class:"hint-container-title"},"Not yet written")],-1),n=[a];function p(c,s){return o(),r("div",null,n)}const l=e(i,[["render",p],["__file","api_typescript.html.vue"]]),_=JSON.parse('{"path":"/docs/api_typescript.html","title":"","lang":"en-US","frontmatter":{"editLink":true,"description":" Not yet written ","head":[["meta",{"property":"og:url","content":"https://dtp.dev/docs/api_typescript.html"}],["meta",{"property":"og:site_name","content":"Decentralized Transport Protocol"}],["meta",{"property":"og:description","content":" Not yet written "}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2024-02-14T03:11:10.000Z"}],["meta",{"property":"article:author","content":"dtp.dev"}],["meta",{"property":"article:modified_time","content":"2024-02-14T03:11:10.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2024-02-14T03:11:10.000Z\\",\\"author\\":[{\\"@type\\":\\"Person\\",\\"name\\":\\"dtp.dev\\",\\"url\\":\\"https://dtp.dev\\"}]}"]]},"headers":[],"git":{"createdTime":1707880270000,"updatedTime":1707880270000,"contributors":[{"name":"mario4tier","email":"mario4tier@users.noreply.github.com","commits":1}]},"readingTime":{"minutes":0.02,"words":6},"filePathRelative":"docs/api_typescript.md","localizedDate":"February 14, 2024","autoDesc":true}');export{l as comp,_ as data}; diff --git a/assets/api_typescript.html-BqGWlZzf.js b/assets/api_typescript.html-CShx0BZb.js similarity index 95% rename from assets/api_typescript.html-BqGWlZzf.js rename to assets/api_typescript.html-CShx0BZb.js index dcbf104..e9dd533 100644 --- a/assets/api_typescript.html-BqGWlZzf.js +++ b/assets/api_typescript.html-CShx0BZb.js @@ -1 +1 @@ -import{_ as e}from"./plugin-vue_export-helper-DlAUqK2U.js";import{o as r,c as o,a as t}from"./app-CKXWWpf0.js";const n={},a=t("div",{class:"hint-container warning"},[t("p",{class:"hint-container-title"},"Not yet written")],-1),i=[a];function p(c,s){return r(),o("div",null,i)}const m=e(n,[["render",p],["__file","api_typescript.html.vue"]]),_=JSON.parse('{"path":"/ref/api_typescript.html","title":"","lang":"en-US","frontmatter":{"editLink":true,"description":" Not yet written ","head":[["meta",{"property":"og:url","content":"https://dtp.dev/ref/api_typescript.html"}],["meta",{"property":"og:site_name","content":"Decentralized Transport Protocol"}],["meta",{"property":"og:description","content":" Not yet written "}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"article:author","content":"dtp.dev"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"\\",\\"image\\":[\\"\\"],\\"dateModified\\":null,\\"author\\":[{\\"@type\\":\\"Person\\",\\"name\\":\\"dtp.dev\\",\\"url\\":\\"https://dtp.dev\\"}]}"]]},"headers":[],"git":{"createdTime":null,"updatedTime":null,"contributors":[]},"readingTime":{"minutes":0.02,"words":6},"filePathRelative":"ref/api_typescript.md","autoDesc":true}');export{m as comp,_ as data}; +import{_ as e}from"./plugin-vue_export-helper-DlAUqK2U.js";import{o as r,c as o,a as t}from"./app-BnFZaCe1.js";const n={},a=t("div",{class:"hint-container warning"},[t("p",{class:"hint-container-title"},"Not yet written")],-1),i=[a];function p(c,s){return r(),o("div",null,i)}const m=e(n,[["render",p],["__file","api_typescript.html.vue"]]),_=JSON.parse('{"path":"/ref/api_typescript.html","title":"","lang":"en-US","frontmatter":{"editLink":true,"description":" Not yet written ","head":[["meta",{"property":"og:url","content":"https://dtp.dev/ref/api_typescript.html"}],["meta",{"property":"og:site_name","content":"Decentralized Transport Protocol"}],["meta",{"property":"og:description","content":" Not yet written "}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"article:author","content":"dtp.dev"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"\\",\\"image\\":[\\"\\"],\\"dateModified\\":null,\\"author\\":[{\\"@type\\":\\"Person\\",\\"name\\":\\"dtp.dev\\",\\"url\\":\\"https://dtp.dev\\"}]}"]]},"headers":[],"git":{"createdTime":null,"updatedTime":null,"contributors":[]},"readingTime":{"minutes":0.02,"words":6},"filePathRelative":"ref/api_typescript.md","autoDesc":true}');export{m as comp,_ as data}; diff --git a/assets/app-CKXWWpf0.js b/assets/app-BnFZaCe1.js similarity index 98% rename from assets/app-CKXWWpf0.js rename to assets/app-BnFZaCe1.js index 2f29452..320f73d 100644 --- a/assets/app-CKXWWpf0.js +++ b/assets/app-BnFZaCe1.js @@ -14,7 +14,7 @@ * @vue/runtime-dom v3.4.19 * (c) 2018-present Yuxi (Evan) You and Vue contributors * @license MIT -**/const Of="http://www.w3.org/2000/svg",Mf="http://www.w3.org/1998/Math/MathML",Lt=typeof document<"u"?document:null,tl=Lt&&Lt.createElement("template"),$f={insert:(e,t,n)=>{t.insertBefore(e,n||null)},remove:e=>{const t=e.parentNode;t&&t.removeChild(e)},createElement:(e,t,n,r)=>{const o=t==="svg"?Lt.createElementNS(Of,e):t==="mathml"?Lt.createElementNS(Mf,e):Lt.createElement(e,n?{is:n}:void 0);return e==="select"&&r&&r.multiple!=null&&o.setAttribute("multiple",r.multiple),o},createText:e=>Lt.createTextNode(e),createComment:e=>Lt.createComment(e),setText:(e,t)=>{e.nodeValue=t},setElementText:(e,t)=>{e.textContent=t},parentNode:e=>e.parentNode,nextSibling:e=>e.nextSibling,querySelector:e=>Lt.querySelector(e),setScopeId(e,t){e.setAttribute(t,"")},insertStaticContent(e,t,n,r,o,s){const l=n?n.previousSibling:t.lastChild;if(o&&(o===s||o.nextSibling))for(;t.insertBefore(o.cloneNode(!0),n),!(o===s||!(o=o.nextSibling)););else{tl.innerHTML=r==="svg"?`${e}`:r==="mathml"?`${e}`:e;const a=tl.content;if(r==="svg"||r==="mathml"){const c=a.firstChild;for(;c.firstChild;)a.appendChild(c.firstChild);a.removeChild(c)}t.insertBefore(a,n)}return[l?l.nextSibling:t.firstChild,n?n.previousSibling:t.lastChild]}},xt="transition",An="animation",vn=Symbol("_vtc"),$t=(e,{slots:t})=>f(Bu,Ya(e),t);$t.displayName="Transition";const Ka={name:String,type:String,css:{type:Boolean,default:!0},duration:[String,Number,Object],enterFromClass:String,enterActiveClass:String,enterToClass:String,appearFromClass:String,appearActiveClass:String,appearToClass:String,leaveFromClass:String,leaveActiveClass:String,leaveToClass:String},Nf=$t.props=we({},Aa,Ka),Bt=(e,t=[])=>{X(e)?e.forEach(n=>n(...t)):e&&e(...t)},nl=e=>e?X(e)?e.some(t=>t.length>1):e.length>1:!1;function Ya(e){const t={};for(const H in e)H in Ka||(t[H]=e[H]);if(e.css===!1)return t;const{name:n="v",type:r,duration:o,enterFromClass:s=`${n}-enter-from`,enterActiveClass:l=`${n}-enter-active`,enterToClass:a=`${n}-enter-to`,appearFromClass:c=s,appearActiveClass:i=l,appearToClass:u=a,leaveFromClass:d=`${n}-leave-from`,leaveActiveClass:p=`${n}-leave-active`,leaveToClass:m=`${n}-leave-to`}=e,g=Df(o),E=g&&g[0],w=g&&g[1],{onBeforeEnter:b,onEnter:S,onEnterCancelled:y,onLeave:x,onLeaveCancelled:$,onBeforeAppear:C=b,onAppear:M=S,onAppearCancelled:P=y}=t,D=(H,J,be)=>{St(H,J?u:a),St(H,J?i:l),be&&be()},F=(H,J)=>{H._isLeaving=!1,St(H,d),St(H,m),St(H,p),J&&J()},Z=H=>(J,be)=>{const ye=H?M:S,G=()=>D(J,H,be);Bt(ye,[J,G]),rl(()=>{St(J,H?c:s),ht(J,H?u:a),nl(ye)||ol(J,r,E,G)})};return we(t,{onBeforeEnter(H){Bt(b,[H]),ht(H,s),ht(H,l)},onBeforeAppear(H){Bt(C,[H]),ht(H,c),ht(H,i)},onEnter:Z(!1),onAppear:Z(!0),onLeave(H,J){H._isLeaving=!0;const be=()=>F(H,J);ht(H,d),Qa(),ht(H,p),rl(()=>{H._isLeaving&&(St(H,d),ht(H,m),nl(x)||ol(H,r,w,be))}),Bt(x,[H,be])},onEnterCancelled(H){D(H,!1),Bt(y,[H])},onAppearCancelled(H){D(H,!0),Bt(P,[H])},onLeaveCancelled(H){F(H),Bt($,[H])}})}function Df(e){if(e==null)return null;if(me(e))return[io(e.enter),io(e.leave)];{const t=io(e);return[t,t]}}function io(e){return Hc(e)}function ht(e,t){t.split(/\s+/).forEach(n=>n&&e.classList.add(n)),(e[vn]||(e[vn]=new Set)).add(t)}function St(e,t){t.split(/\s+/).forEach(r=>r&&e.classList.remove(r));const n=e[vn];n&&(n.delete(t),n.size||(e[vn]=void 0))}function rl(e){requestAnimationFrame(()=>{requestAnimationFrame(e)})}let Ff=0;function ol(e,t,n,r){const o=e._endId=++Ff,s=()=>{o===e._endId&&r()};if(n)return setTimeout(s,n);const{type:l,timeout:a,propCount:c}=Ja(e,t);if(!l)return r();const i=l+"end";let u=0;const d=()=>{e.removeEventListener(i,p),s()},p=m=>{m.target===e&&++u>=c&&d()};setTimeout(()=>{u(n[g]||"").split(", "),o=r(`${xt}Delay`),s=r(`${xt}Duration`),l=sl(o,s),a=r(`${An}Delay`),c=r(`${An}Duration`),i=sl(a,c);let u=null,d=0,p=0;t===xt?l>0&&(u=xt,d=l,p=s.length):t===An?i>0&&(u=An,d=i,p=c.length):(d=Math.max(l,i),u=d>0?l>i?xt:An:null,p=u?u===xt?s.length:c.length:0);const m=u===xt&&/\b(transform|all)(,|$)/.test(r(`${xt}Property`).toString());return{type:u,timeout:d,propCount:p,hasTransform:m}}function sl(e,t){for(;e.lengthll(n)+ll(e[r])))}function ll(e){return e==="auto"?0:Number(e.slice(0,-1).replace(",","."))*1e3}function Qa(){return document.body.offsetHeight}function Hf(e,t,n){const r=e[vn];r&&(t=(t?[t,...r]:[...r]).join(" ")),t==null?e.removeAttribute("class"):n?e.setAttribute("class",t):e.className=t}const al=Symbol("_vod"),Bf=Symbol(""),jf=/(^|;)\s*display\s*:/;function Vf(e,t,n){const r=e.style,o=Ae(n),s=r.display;let l=!1;if(n&&!o){if(t&&!Ae(t))for(const a in t)n[a]==null&&$o(r,a,"");for(const a in n)a==="display"&&(l=!0),$o(r,a,n[a])}else if(o){if(t!==n){const a=r[Bf];a&&(n+=";"+a),r.cssText=n,l=jf.test(n)}}else t&&e.removeAttribute("style");al in e&&(e[al]=l?r.display:"",r.display=s)}const il=/\s*!important$/;function $o(e,t,n){if(X(n))n.forEach(r=>$o(e,t,r));else if(n==null&&(n=""),t.startsWith("--"))e.setProperty(t,n);else{const r=zf(e,t);il.test(n)?e.setProperty(_n(r),n.replace(il,""),"important"):e[r]=n}}const cl=["Webkit","Moz","ms"],co={};function zf(e,t){const n=co[t];if(n)return n;let r=ze(t);if(r!=="filter"&&r in e)return co[t]=r;r=wn(r);for(let o=0;ouo||(Jf.then(()=>uo=0),uo=Date.now());function Xf(e,t){const n=r=>{if(!r._vts)r._vts=Date.now();else if(r._vts<=n.attached)return;Xe(Zf(r,n.value),t,5,[r])};return n.value=e,n.attached=Qf(),n}function Zf(e,t){if(X(t)){const n=e.stopImmediatePropagation;return e.stopImmediatePropagation=()=>{n.call(e),e._stopped=!0},t.map(r=>o=>!o._stopped&&r&&r(o))}else return t}const pl=e=>e.charCodeAt(0)===111&&e.charCodeAt(1)===110&&e.charCodeAt(2)>96&&e.charCodeAt(2)<123,ed=(e,t,n,r,o,s,l,a,c)=>{const i=o==="svg";t==="class"?Hf(e,r,i):t==="style"?Vf(e,n,r):Xn(t)?Go(t)||Kf(e,t,n,r,l):(t[0]==="."?(t=t.slice(1),!0):t[0]==="^"?(t=t.slice(1),!1):td(e,t,r,i))?Uf(e,t,r,s,l,a,c):(t==="true-value"?e._trueValue=r:t==="false-value"&&(e._falseValue=r),Wf(e,t,r,i))};function td(e,t,n,r){if(r)return!!(t==="innerHTML"||t==="textContent"||t in e&&pl(t)&&ee(n));if(t==="spellcheck"||t==="draggable"||t==="translate"||t==="form"||t==="list"&&e.tagName==="INPUT"||t==="type"&&e.tagName==="TEXTAREA")return!1;if(t==="width"||t==="height"){const o=e.tagName;if(o==="IMG"||o==="VIDEO"||o==="CANVAS"||o==="SOURCE")return!1}return pl(t)&&Ae(n)?!1:t in e}const Xa=new WeakMap,Za=new WeakMap,Nr=Symbol("_moveCb"),hl=Symbol("_enterCb"),ei={name:"TransitionGroup",props:we({},Nf,{tag:String,moveClass:String}),setup(e,{slots:t}){const n=Cn(),r=ka();let o,s;return Pa(()=>{if(!o.length)return;const l=e.moveClass||`${e.name||"v"}-move`;if(!ad(o[0].el,n.vnode.el,l))return;o.forEach(od),o.forEach(sd);const a=o.filter(ld);Qa(),a.forEach(c=>{const i=c.el,u=i.style;ht(i,l),u.transform=u.webkitTransform=u.transitionDuration="";const d=i[Nr]=p=>{p&&p.target!==i||(!p||/transform$/.test(p.propertyName))&&(i.removeEventListener("transitionend",d),i[Nr]=null,St(i,l))};i.addEventListener("transitionend",d)})}),()=>{const l=oe(e),a=Ya(l);let c=l.tag||Ge;o=s,s=t.default?is(t.default()):[];for(let i=0;idelete e.mode;ei.props;const rd=ei;function od(e){const t=e.el;t[Nr]&&t[Nr](),t[hl]&&t[hl]()}function sd(e){Za.set(e,e.el.getBoundingClientRect())}function ld(e){const t=Xa.get(e),n=Za.get(e),r=t.left-n.left,o=t.top-n.top;if(r||o){const s=e.el.style;return s.transform=s.webkitTransform=`translate(${r}px,${o}px)`,s.transitionDuration="0s",e}}function ad(e,t,n){const r=e.cloneNode(),o=e[vn];o&&o.forEach(a=>{a.split(/\s+/).forEach(c=>c&&r.classList.remove(c))}),n.split(/\s+/).forEach(a=>a&&r.classList.add(a)),r.style.display="none";const s=t.nodeType===1?t:t.parentNode;s.appendChild(r);const{hasTransform:l}=Ja(r);return s.removeChild(r),l}const id=we({patchProp:ed},$f);let fo,vl=!1;function cd(){return fo=vl?fo:hf(id),vl=!0,fo}const ud=(...e)=>{const t=cd().createApp(...e),{mount:n}=t;return t.mount=r=>{const o=dd(r);if(o)return n(o,!0,fd(o))},t};function fd(e){if(e instanceof SVGElement)return"svg";if(typeof MathMLElement=="function"&&e instanceof MathMLElement)return"mathml"}function dd(e){return Ae(e)?document.querySelector(e):e}var pd=["link","meta","script","style","noscript","template"],hd=["title","base"],vd=([e,t,n])=>hd.includes(e)?e:pd.includes(e)?e==="meta"&&t.name?`${e}.${t.name}`:e==="template"&&t.id?`${e}.${t.id}`:JSON.stringify([e,Object.entries(t).map(([r,o])=>typeof o=="boolean"?o?[r,""]:null:[r,o]).filter(r=>r!=null).sort(([r],[o])=>r.localeCompare(o)),n]):null,md=e=>{const t=new Set,n=[];return e.forEach(r=>{const o=vd(r);o&&!t.has(o)&&(t.add(o),n.push(r))}),n},gd=e=>e[0]==="/"?e:`/${e}`,ti=e=>e[e.length-1]==="/"||e.endsWith(".html")?e:`${e}/`,Xt=e=>/^(https?:)?\/\//.test(e),bd=/.md((\?|#).*)?$/,mn=(e,t="/")=>!!(Xt(e)||e.startsWith("/")&&!e.startsWith(t)&&!bd.test(e)),ni=e=>/^[a-z][a-z0-9+.-]*:/.test(e),Gr=e=>Object.prototype.toString.call(e)==="[object Object]",yd=e=>{const[t,...n]=e.split(/(\?|#)/);if(!t||t.endsWith("/"))return e;let r=t.replace(/(^|\/)README.md$/i,"$1index.html");return r.endsWith(".md")?r=r.substring(0,r.length-3)+".html":r.endsWith(".html")||(r=r+".html"),r.endsWith("/index.html")&&(r=r.substring(0,r.length-10)),r+n.join("")},ps=e=>e[e.length-1]==="/"?e.slice(0,-1):e,ri=e=>e[0]==="/"?e.slice(1):e,_d=(e,t)=>{const n=Object.keys(e).sort((r,o)=>{const s=o.split("/").length-r.split("/").length;return s!==0?s:o.length-r.length});for(const r of n)if(t.startsWith(r))return r;return"/"},xe=e=>typeof e=="string";const wd="modulepreload",Ed=function(e){return"/"+e},ml={},fe=function(t,n,r){let o=Promise.resolve();if(n&&n.length>0){const s=document.getElementsByTagName("link");o=Promise.all(n.map(l=>{if(l=Ed(l),l in ml)return;ml[l]=!0;const a=l.endsWith(".css"),c=a?'[rel="stylesheet"]':"";if(!!r)for(let d=s.length-1;d>=0;d--){const p=s[d];if(p.href===l&&(!a||p.rel==="stylesheet"))return}else if(document.querySelector(`link[href="${l}"]${c}`))return;const u=document.createElement("link");if(u.rel=a?"stylesheet":wd,a||(u.as="script",u.crossOrigin=""),u.href=l,document.head.appendChild(u),a)return new Promise((d,p)=>{u.addEventListener("load",d),u.addEventListener("error",()=>p(new Error(`Unable to preload CSS for ${l}`)))})}))}return o.then(()=>t()).catch(s=>{const l=new Event("vite:preloadError",{cancelable:!0});if(l.payload=s,window.dispatchEvent(l),!l.defaultPrevented)throw s})},Cd=JSON.parse("{}"),xd=Object.fromEntries([["/",{loader:()=>fe(()=>import("./index.html-BGgB7rPy.js"),__vite__mapDeps([0,1])),meta:{y:"h",t:"Home",i:"home"}}],["/faq.html",{loader:()=>fe(()=>import("./faq.html-wlteNg54.js"),__vite__mapDeps([2,1])),meta:{y:"a",t:"FAQ"}}],["/intro.html",{loader:()=>fe(()=>import("./intro.html-Bxgg0fO6.js"),__vite__mapDeps([3,1])),meta:{y:"a",t:"What is DTP?"}}],["/community/",{loader:()=>fe(()=>import("./index.html-BodtrdFm.js"),__vite__mapDeps([4,1])),meta:{y:"a",t:"Community"}}],["/community/editors.html",{loader:()=>fe(()=>import("./editors.html-C8UZnhJf.js"),__vite__mapDeps([5,1])),meta:{y:"a",t:"How to propose fix/change to the website?",O:2}}],["/docs/",{loader:()=>fe(()=>import("./index.html-D031wELU.js"),__vite__mapDeps([6,1])),meta:{y:"a",t:"Basic Concept"}}],["/docs/api_rust.html",{loader:()=>fe(()=>import("./api_rust.html-CzB0Dlbt.js"),__vite__mapDeps([7,1])),meta:{y:"a",t:""}}],["/docs/api_typescript.html",{loader:()=>fe(()=>import("./api_typescript.html-BMmh0oGQ.js"),__vite__mapDeps([8,1])),meta:{y:"a",t:""}}],["/docs/design.html",{loader:()=>fe(()=>import("./design.html-CubwsOM8.js"),__vite__mapDeps([9,10,1])),meta:{y:"a",t:"Design"}}],["/docs/future_work.html",{loader:()=>fe(()=>import("./future_work.html-CaNaLhGO.js"),__vite__mapDeps([11,12,1])),meta:{y:"a",t:"Future Work"}}],["/docs/scripts.html",{loader:()=>fe(()=>import("./scripts.html-Bu-kSnJq.js"),__vite__mapDeps([13,1])),meta:{y:"a",t:""}}],["/examples/",{loader:()=>fe(()=>import("./index.html-D-JN27_M.js"),__vite__mapDeps([14,1])),meta:{y:"a",t:"Use Cases"}}],["/examples/rpc_firewall.html",{loader:()=>fe(()=>import("./rpc_firewall.html-DXKxw1oe.js"),__vite__mapDeps([15,1])),meta:{y:"a",t:"JSON-RPC Firewall"}}],["/examples/web3_rust.html",{loader:()=>fe(()=>import("./web3_rust.html-CtlHbOSD.js"),__vite__mapDeps([16,1])),meta:{y:"a",t:"Web3 Frontend / Rust Server"}}],["/how-to/full_setup.html",{loader:()=>fe(()=>import("./full_setup.html-D9U11CgD.js"),__vite__mapDeps([17,1])),meta:{y:"a",t:"Full Development Setup"}}],["/how-to/install.html",{loader:()=>fe(()=>import("./install.html-B3JszHVu.js"),__vite__mapDeps([18,1])),meta:{y:"a",t:"Installation"}}],["/how-to/npm_only.html",{loader:()=>fe(()=>import("./npm_only.html-BS4zMMEQ.js"),__vite__mapDeps([19,1])),meta:{y:"a",t:""}}],["/how-to/runtime_only.html",{loader:()=>fe(()=>import("./runtime_only.html-BWVPrZKz.js"),__vite__mapDeps([20,1])),meta:{y:"a",t:""}}],["/ref/",{loader:()=>fe(()=>import("./index.html-CBpta1zV.js"),__vite__mapDeps([21,1])),meta:{y:"a",t:"Basic Concept"}}],["/ref/api_rust.html",{loader:()=>fe(()=>import("./api_rust.html-jR6an_Pz.js"),__vite__mapDeps([22,1])),meta:{y:"a",t:""}}],["/ref/api_typescript.html",{loader:()=>fe(()=>import("./api_typescript.html-BqGWlZzf.js"),__vite__mapDeps([23,1])),meta:{y:"a",t:""}}],["/ref/design.html",{loader:()=>fe(()=>import("./design.html-BrbpjE_m.js"),__vite__mapDeps([24,10,1])),meta:{y:"a",t:"Design"}}],["/ref/future_work.html",{loader:()=>fe(()=>import("./future_work.html-Dp7HikED.js"),__vite__mapDeps([25,12,1])),meta:{y:"a",t:"Future Work"}}],["/ref/scripts.html",{loader:()=>fe(()=>import("./scripts.html-DkAQ2N11.js"),__vite__mapDeps([26,1])),meta:{y:"a",t:""}}],["/404.html",{loader:()=>fe(()=>import("./404.html-BL0QzlcP.js"),__vite__mapDeps([27,1])),meta:{y:"p",t:""}}],["/how-to/",{loader:()=>fe(()=>import("./index.html-3uUFhvd2.js"),__vite__mapDeps([28,1])),meta:{y:"p",t:"How to"}}]]);/*! +**/const Of="http://www.w3.org/2000/svg",Mf="http://www.w3.org/1998/Math/MathML",Lt=typeof document<"u"?document:null,tl=Lt&&Lt.createElement("template"),$f={insert:(e,t,n)=>{t.insertBefore(e,n||null)},remove:e=>{const t=e.parentNode;t&&t.removeChild(e)},createElement:(e,t,n,r)=>{const o=t==="svg"?Lt.createElementNS(Of,e):t==="mathml"?Lt.createElementNS(Mf,e):Lt.createElement(e,n?{is:n}:void 0);return e==="select"&&r&&r.multiple!=null&&o.setAttribute("multiple",r.multiple),o},createText:e=>Lt.createTextNode(e),createComment:e=>Lt.createComment(e),setText:(e,t)=>{e.nodeValue=t},setElementText:(e,t)=>{e.textContent=t},parentNode:e=>e.parentNode,nextSibling:e=>e.nextSibling,querySelector:e=>Lt.querySelector(e),setScopeId(e,t){e.setAttribute(t,"")},insertStaticContent(e,t,n,r,o,s){const l=n?n.previousSibling:t.lastChild;if(o&&(o===s||o.nextSibling))for(;t.insertBefore(o.cloneNode(!0),n),!(o===s||!(o=o.nextSibling)););else{tl.innerHTML=r==="svg"?`${e}`:r==="mathml"?`${e}`:e;const a=tl.content;if(r==="svg"||r==="mathml"){const c=a.firstChild;for(;c.firstChild;)a.appendChild(c.firstChild);a.removeChild(c)}t.insertBefore(a,n)}return[l?l.nextSibling:t.firstChild,n?n.previousSibling:t.lastChild]}},xt="transition",An="animation",vn=Symbol("_vtc"),$t=(e,{slots:t})=>f(Bu,Ya(e),t);$t.displayName="Transition";const Ka={name:String,type:String,css:{type:Boolean,default:!0},duration:[String,Number,Object],enterFromClass:String,enterActiveClass:String,enterToClass:String,appearFromClass:String,appearActiveClass:String,appearToClass:String,leaveFromClass:String,leaveActiveClass:String,leaveToClass:String},Nf=$t.props=we({},Aa,Ka),Bt=(e,t=[])=>{X(e)?e.forEach(n=>n(...t)):e&&e(...t)},nl=e=>e?X(e)?e.some(t=>t.length>1):e.length>1:!1;function Ya(e){const t={};for(const H in e)H in Ka||(t[H]=e[H]);if(e.css===!1)return t;const{name:n="v",type:r,duration:o,enterFromClass:s=`${n}-enter-from`,enterActiveClass:l=`${n}-enter-active`,enterToClass:a=`${n}-enter-to`,appearFromClass:c=s,appearActiveClass:i=l,appearToClass:u=a,leaveFromClass:d=`${n}-leave-from`,leaveActiveClass:p=`${n}-leave-active`,leaveToClass:m=`${n}-leave-to`}=e,g=Df(o),E=g&&g[0],w=g&&g[1],{onBeforeEnter:b,onEnter:S,onEnterCancelled:y,onLeave:x,onLeaveCancelled:$,onBeforeAppear:C=b,onAppear:M=S,onAppearCancelled:P=y}=t,D=(H,J,be)=>{St(H,J?u:a),St(H,J?i:l),be&&be()},F=(H,J)=>{H._isLeaving=!1,St(H,d),St(H,m),St(H,p),J&&J()},Z=H=>(J,be)=>{const ye=H?M:S,G=()=>D(J,H,be);Bt(ye,[J,G]),rl(()=>{St(J,H?c:s),ht(J,H?u:a),nl(ye)||ol(J,r,E,G)})};return we(t,{onBeforeEnter(H){Bt(b,[H]),ht(H,s),ht(H,l)},onBeforeAppear(H){Bt(C,[H]),ht(H,c),ht(H,i)},onEnter:Z(!1),onAppear:Z(!0),onLeave(H,J){H._isLeaving=!0;const be=()=>F(H,J);ht(H,d),Qa(),ht(H,p),rl(()=>{H._isLeaving&&(St(H,d),ht(H,m),nl(x)||ol(H,r,w,be))}),Bt(x,[H,be])},onEnterCancelled(H){D(H,!1),Bt(y,[H])},onAppearCancelled(H){D(H,!0),Bt(P,[H])},onLeaveCancelled(H){F(H),Bt($,[H])}})}function Df(e){if(e==null)return null;if(me(e))return[io(e.enter),io(e.leave)];{const t=io(e);return[t,t]}}function io(e){return Hc(e)}function ht(e,t){t.split(/\s+/).forEach(n=>n&&e.classList.add(n)),(e[vn]||(e[vn]=new Set)).add(t)}function St(e,t){t.split(/\s+/).forEach(r=>r&&e.classList.remove(r));const n=e[vn];n&&(n.delete(t),n.size||(e[vn]=void 0))}function rl(e){requestAnimationFrame(()=>{requestAnimationFrame(e)})}let Ff=0;function ol(e,t,n,r){const o=e._endId=++Ff,s=()=>{o===e._endId&&r()};if(n)return setTimeout(s,n);const{type:l,timeout:a,propCount:c}=Ja(e,t);if(!l)return r();const i=l+"end";let u=0;const d=()=>{e.removeEventListener(i,p),s()},p=m=>{m.target===e&&++u>=c&&d()};setTimeout(()=>{u(n[g]||"").split(", "),o=r(`${xt}Delay`),s=r(`${xt}Duration`),l=sl(o,s),a=r(`${An}Delay`),c=r(`${An}Duration`),i=sl(a,c);let u=null,d=0,p=0;t===xt?l>0&&(u=xt,d=l,p=s.length):t===An?i>0&&(u=An,d=i,p=c.length):(d=Math.max(l,i),u=d>0?l>i?xt:An:null,p=u?u===xt?s.length:c.length:0);const m=u===xt&&/\b(transform|all)(,|$)/.test(r(`${xt}Property`).toString());return{type:u,timeout:d,propCount:p,hasTransform:m}}function sl(e,t){for(;e.lengthll(n)+ll(e[r])))}function ll(e){return e==="auto"?0:Number(e.slice(0,-1).replace(",","."))*1e3}function Qa(){return document.body.offsetHeight}function Hf(e,t,n){const r=e[vn];r&&(t=(t?[t,...r]:[...r]).join(" ")),t==null?e.removeAttribute("class"):n?e.setAttribute("class",t):e.className=t}const al=Symbol("_vod"),Bf=Symbol(""),jf=/(^|;)\s*display\s*:/;function Vf(e,t,n){const r=e.style,o=Ae(n),s=r.display;let l=!1;if(n&&!o){if(t&&!Ae(t))for(const a in t)n[a]==null&&$o(r,a,"");for(const a in n)a==="display"&&(l=!0),$o(r,a,n[a])}else if(o){if(t!==n){const a=r[Bf];a&&(n+=";"+a),r.cssText=n,l=jf.test(n)}}else t&&e.removeAttribute("style");al in e&&(e[al]=l?r.display:"",r.display=s)}const il=/\s*!important$/;function $o(e,t,n){if(X(n))n.forEach(r=>$o(e,t,r));else if(n==null&&(n=""),t.startsWith("--"))e.setProperty(t,n);else{const r=zf(e,t);il.test(n)?e.setProperty(_n(r),n.replace(il,""),"important"):e[r]=n}}const cl=["Webkit","Moz","ms"],co={};function zf(e,t){const n=co[t];if(n)return n;let r=ze(t);if(r!=="filter"&&r in e)return co[t]=r;r=wn(r);for(let o=0;ouo||(Jf.then(()=>uo=0),uo=Date.now());function Xf(e,t){const n=r=>{if(!r._vts)r._vts=Date.now();else if(r._vts<=n.attached)return;Xe(Zf(r,n.value),t,5,[r])};return n.value=e,n.attached=Qf(),n}function Zf(e,t){if(X(t)){const n=e.stopImmediatePropagation;return e.stopImmediatePropagation=()=>{n.call(e),e._stopped=!0},t.map(r=>o=>!o._stopped&&r&&r(o))}else return t}const pl=e=>e.charCodeAt(0)===111&&e.charCodeAt(1)===110&&e.charCodeAt(2)>96&&e.charCodeAt(2)<123,ed=(e,t,n,r,o,s,l,a,c)=>{const i=o==="svg";t==="class"?Hf(e,r,i):t==="style"?Vf(e,n,r):Xn(t)?Go(t)||Kf(e,t,n,r,l):(t[0]==="."?(t=t.slice(1),!0):t[0]==="^"?(t=t.slice(1),!1):td(e,t,r,i))?Uf(e,t,r,s,l,a,c):(t==="true-value"?e._trueValue=r:t==="false-value"&&(e._falseValue=r),Wf(e,t,r,i))};function td(e,t,n,r){if(r)return!!(t==="innerHTML"||t==="textContent"||t in e&&pl(t)&&ee(n));if(t==="spellcheck"||t==="draggable"||t==="translate"||t==="form"||t==="list"&&e.tagName==="INPUT"||t==="type"&&e.tagName==="TEXTAREA")return!1;if(t==="width"||t==="height"){const o=e.tagName;if(o==="IMG"||o==="VIDEO"||o==="CANVAS"||o==="SOURCE")return!1}return pl(t)&&Ae(n)?!1:t in e}const Xa=new WeakMap,Za=new WeakMap,Nr=Symbol("_moveCb"),hl=Symbol("_enterCb"),ei={name:"TransitionGroup",props:we({},Nf,{tag:String,moveClass:String}),setup(e,{slots:t}){const n=Cn(),r=ka();let o,s;return Pa(()=>{if(!o.length)return;const l=e.moveClass||`${e.name||"v"}-move`;if(!ad(o[0].el,n.vnode.el,l))return;o.forEach(od),o.forEach(sd);const a=o.filter(ld);Qa(),a.forEach(c=>{const i=c.el,u=i.style;ht(i,l),u.transform=u.webkitTransform=u.transitionDuration="";const d=i[Nr]=p=>{p&&p.target!==i||(!p||/transform$/.test(p.propertyName))&&(i.removeEventListener("transitionend",d),i[Nr]=null,St(i,l))};i.addEventListener("transitionend",d)})}),()=>{const l=oe(e),a=Ya(l);let c=l.tag||Ge;o=s,s=t.default?is(t.default()):[];for(let i=0;idelete e.mode;ei.props;const rd=ei;function od(e){const t=e.el;t[Nr]&&t[Nr](),t[hl]&&t[hl]()}function sd(e){Za.set(e,e.el.getBoundingClientRect())}function ld(e){const t=Xa.get(e),n=Za.get(e),r=t.left-n.left,o=t.top-n.top;if(r||o){const s=e.el.style;return s.transform=s.webkitTransform=`translate(${r}px,${o}px)`,s.transitionDuration="0s",e}}function ad(e,t,n){const r=e.cloneNode(),o=e[vn];o&&o.forEach(a=>{a.split(/\s+/).forEach(c=>c&&r.classList.remove(c))}),n.split(/\s+/).forEach(a=>a&&r.classList.add(a)),r.style.display="none";const s=t.nodeType===1?t:t.parentNode;s.appendChild(r);const{hasTransform:l}=Ja(r);return s.removeChild(r),l}const id=we({patchProp:ed},$f);let fo,vl=!1;function cd(){return fo=vl?fo:hf(id),vl=!0,fo}const ud=(...e)=>{const t=cd().createApp(...e),{mount:n}=t;return t.mount=r=>{const o=dd(r);if(o)return n(o,!0,fd(o))},t};function fd(e){if(e instanceof SVGElement)return"svg";if(typeof MathMLElement=="function"&&e instanceof MathMLElement)return"mathml"}function dd(e){return Ae(e)?document.querySelector(e):e}var pd=["link","meta","script","style","noscript","template"],hd=["title","base"],vd=([e,t,n])=>hd.includes(e)?e:pd.includes(e)?e==="meta"&&t.name?`${e}.${t.name}`:e==="template"&&t.id?`${e}.${t.id}`:JSON.stringify([e,Object.entries(t).map(([r,o])=>typeof o=="boolean"?o?[r,""]:null:[r,o]).filter(r=>r!=null).sort(([r],[o])=>r.localeCompare(o)),n]):null,md=e=>{const t=new Set,n=[];return e.forEach(r=>{const o=vd(r);o&&!t.has(o)&&(t.add(o),n.push(r))}),n},gd=e=>e[0]==="/"?e:`/${e}`,ti=e=>e[e.length-1]==="/"||e.endsWith(".html")?e:`${e}/`,Xt=e=>/^(https?:)?\/\//.test(e),bd=/.md((\?|#).*)?$/,mn=(e,t="/")=>!!(Xt(e)||e.startsWith("/")&&!e.startsWith(t)&&!bd.test(e)),ni=e=>/^[a-z][a-z0-9+.-]*:/.test(e),Gr=e=>Object.prototype.toString.call(e)==="[object Object]",yd=e=>{const[t,...n]=e.split(/(\?|#)/);if(!t||t.endsWith("/"))return e;let r=t.replace(/(^|\/)README.md$/i,"$1index.html");return r.endsWith(".md")?r=r.substring(0,r.length-3)+".html":r.endsWith(".html")||(r=r+".html"),r.endsWith("/index.html")&&(r=r.substring(0,r.length-10)),r+n.join("")},ps=e=>e[e.length-1]==="/"?e.slice(0,-1):e,ri=e=>e[0]==="/"?e.slice(1):e,_d=(e,t)=>{const n=Object.keys(e).sort((r,o)=>{const s=o.split("/").length-r.split("/").length;return s!==0?s:o.length-r.length});for(const r of n)if(t.startsWith(r))return r;return"/"},xe=e=>typeof e=="string";const wd="modulepreload",Ed=function(e){return"/"+e},ml={},fe=function(t,n,r){let o=Promise.resolve();if(n&&n.length>0){const s=document.getElementsByTagName("link");o=Promise.all(n.map(l=>{if(l=Ed(l),l in ml)return;ml[l]=!0;const a=l.endsWith(".css"),c=a?'[rel="stylesheet"]':"";if(!!r)for(let d=s.length-1;d>=0;d--){const p=s[d];if(p.href===l&&(!a||p.rel==="stylesheet"))return}else if(document.querySelector(`link[href="${l}"]${c}`))return;const u=document.createElement("link");if(u.rel=a?"stylesheet":wd,a||(u.as="script",u.crossOrigin=""),u.href=l,document.head.appendChild(u),a)return new Promise((d,p)=>{u.addEventListener("load",d),u.addEventListener("error",()=>p(new Error(`Unable to preload CSS for ${l}`)))})}))}return o.then(()=>t()).catch(s=>{const l=new Event("vite:preloadError",{cancelable:!0});if(l.payload=s,window.dispatchEvent(l),!l.defaultPrevented)throw s})},Cd=JSON.parse("{}"),xd=Object.fromEntries([["/",{loader:()=>fe(()=>import("./index.html-CnguV0tX.js"),__vite__mapDeps([0,1])),meta:{y:"h",t:"Home",i:"home"}}],["/faq.html",{loader:()=>fe(()=>import("./faq.html-CV8sl42E.js"),__vite__mapDeps([2,1])),meta:{y:"a",t:"FAQ"}}],["/intro.html",{loader:()=>fe(()=>import("./intro.html-BxGuE4wy.js"),__vite__mapDeps([3,1])),meta:{y:"a",t:"What is DTP?"}}],["/community/",{loader:()=>fe(()=>import("./index.html-BVUfEJTo.js"),__vite__mapDeps([4,1])),meta:{y:"a",t:"Community"}}],["/community/editors.html",{loader:()=>fe(()=>import("./editors.html-CNXsfcsu.js"),__vite__mapDeps([5,1])),meta:{y:"a",t:"How to propose fix/change to the website?",O:2}}],["/examples/",{loader:()=>fe(()=>import("./index.html-BWOMH9gB.js"),__vite__mapDeps([6,1])),meta:{y:"a",t:"Use Cases"}}],["/examples/rpc_firewall.html",{loader:()=>fe(()=>import("./rpc_firewall.html-D9Yd1Ah_.js"),__vite__mapDeps([7,1])),meta:{y:"a",t:"JSON-RPC Firewall"}}],["/examples/web3_rust.html",{loader:()=>fe(()=>import("./web3_rust.html-DrfE3oTr.js"),__vite__mapDeps([8,1])),meta:{y:"a",t:"Web3 Frontend / Rust Server"}}],["/docs/",{loader:()=>fe(()=>import("./index.html-CEa4pTjw.js"),__vite__mapDeps([9,1])),meta:{y:"a",t:"Basic Concept"}}],["/docs/api_rust.html",{loader:()=>fe(()=>import("./api_rust.html-B1fR_PmW.js"),__vite__mapDeps([10,1])),meta:{y:"a",t:""}}],["/docs/api_typescript.html",{loader:()=>fe(()=>import("./api_typescript.html-CDBTYfuZ.js"),__vite__mapDeps([11,1])),meta:{y:"a",t:""}}],["/docs/design.html",{loader:()=>fe(()=>import("./design.html-84EaReMx.js"),__vite__mapDeps([12,13,1])),meta:{y:"a",t:"Design"}}],["/docs/future_work.html",{loader:()=>fe(()=>import("./future_work.html-Cj0rm1Vd.js"),__vite__mapDeps([14,15,1])),meta:{y:"a",t:"Future Work"}}],["/docs/scripts.html",{loader:()=>fe(()=>import("./scripts.html-Dj-m4wYR.js"),__vite__mapDeps([16,1])),meta:{y:"a",t:""}}],["/how-to/full_setup.html",{loader:()=>fe(()=>import("./full_setup.html-Cez3e24z.js"),__vite__mapDeps([17,1])),meta:{y:"a",t:"Full Development Setup"}}],["/how-to/install.html",{loader:()=>fe(()=>import("./install.html-BAMq21Zx.js"),__vite__mapDeps([18,1])),meta:{y:"a",t:"Installation"}}],["/how-to/npm_only.html",{loader:()=>fe(()=>import("./npm_only.html-BApcLSxE.js"),__vite__mapDeps([19,1])),meta:{y:"a",t:""}}],["/how-to/runtime_only.html",{loader:()=>fe(()=>import("./runtime_only.html-CuZ2LIXr.js"),__vite__mapDeps([20,1])),meta:{y:"a",t:""}}],["/ref/",{loader:()=>fe(()=>import("./index.html-CBcd5KzL.js"),__vite__mapDeps([21,1])),meta:{y:"a",t:"Basic Concept"}}],["/ref/api_rust.html",{loader:()=>fe(()=>import("./api_rust.html-DgeZ6cWi.js"),__vite__mapDeps([22,1])),meta:{y:"a",t:""}}],["/ref/api_typescript.html",{loader:()=>fe(()=>import("./api_typescript.html-CShx0BZb.js"),__vite__mapDeps([23,1])),meta:{y:"a",t:""}}],["/ref/design.html",{loader:()=>fe(()=>import("./design.html-BDTT4CCh.js"),__vite__mapDeps([24,13,1])),meta:{y:"a",t:"Design"}}],["/ref/future_work.html",{loader:()=>fe(()=>import("./future_work.html-B07VTehy.js"),__vite__mapDeps([25,15,1])),meta:{y:"a",t:"Future Work"}}],["/ref/scripts.html",{loader:()=>fe(()=>import("./scripts.html-BZkBrHbZ.js"),__vite__mapDeps([26,1])),meta:{y:"a",t:""}}],["/404.html",{loader:()=>fe(()=>import("./404.html-2OslWyTj.js"),__vite__mapDeps([27,1])),meta:{y:"p",t:""}}],["/how-to/",{loader:()=>fe(()=>import("./index.html-B8jhZ03x.js"),__vite__mapDeps([28,1])),meta:{y:"p",t:"How to"}}]]);/*! * vue-router v4.2.5 * (c) 2023 Eduardo San Martin Morote * @license MIT @@ -24,7 +24,7 @@ */const se={settings:{minimum:.08,easing:"ease",speed:200,trickle:!0,trickleRate:.02,trickleSpeed:800,barSelector:'[role="bar"]',parent:"body",template:'
'},status:null,set:e=>{const t=se.isStarted();e=yo(e,se.settings.minimum,1),se.status=e===1?null:e;const n=se.render(!t),r=n.querySelector(se.settings.barSelector),o=se.settings.speed,s=se.settings.easing;return n.offsetWidth,jh(l=>{xr(r,{transform:"translate3d("+Vl(e)+"%,0,0)",transition:"all "+o+"ms "+s}),e===1?(xr(n,{transition:"none",opacity:"1"}),n.offsetWidth,setTimeout(function(){xr(n,{transition:"all "+o+"ms linear",opacity:"0"}),setTimeout(function(){se.remove(),l()},o)},o)):setTimeout(()=>l(),o)}),se},isStarted:()=>typeof se.status=="number",start:()=>{se.status||se.set(0);const e=()=>{setTimeout(()=>{se.status&&(se.trickle(),e())},se.settings.trickleSpeed)};return se.settings.trickle&&e(),se},done:e=>!e&&!se.status?se:se.inc(.3+.5*Math.random()).set(1),inc:e=>{let t=se.status;return t?(typeof e!="number"&&(e=(1-t)*yo(Math.random()*t,.1,.95)),t=yo(t+e,0,.994),se.set(t)):se.start()},trickle:()=>se.inc(Math.random()*se.settings.trickleRate),render:e=>{if(se.isRendered())return document.getElementById("nprogress");zl(document.documentElement,"nprogress-busy");const t=document.createElement("div");t.id="nprogress",t.innerHTML=se.settings.template;const n=t.querySelector(se.settings.barSelector),r=e?"-100":Vl(se.status||0),o=document.querySelector(se.settings.parent);return xr(n,{transition:"all 0 linear",transform:"translate3d("+r+"%,0,0)"}),o!==document.body&&zl(o,"nprogress-custom-parent"),o==null||o.appendChild(t),t},remove:()=>{Wl(document.documentElement,"nprogress-busy"),Wl(document.querySelector(se.settings.parent),"nprogress-custom-parent");const e=document.getElementById("nprogress");e&&Vh(e)},isRendered:()=>!!document.getElementById("nprogress")},yo=(e,t,n)=>en?n:e,Vl=e=>(-1+e)*100,jh=function(){const e=[];function t(){const n=e.shift();n&&n(t)}return function(n){e.push(n),e.length===1&&t()}}(),xr=function(){const e=["Webkit","O","Moz","ms"],t={};function n(l){return l.replace(/^-ms-/,"ms-").replace(/-([\da-z])/gi,function(a,c){return c.toUpperCase()})}function r(l){const a=document.body.style;if(l in a)return l;let c=e.length;const i=l.charAt(0).toUpperCase()+l.slice(1);let u;for(;c--;)if(u=e[c]+i,u in a)return u;return l}function o(l){return l=n(l),t[l]??(t[l]=r(l))}function s(l,a,c){a=o(a),l.style[a]=c}return function(l,a){for(const c in a){const i=a[c];i!==void 0&&Object.prototype.hasOwnProperty.call(a,c)&&s(l,c,i)}}}(),zi=(e,t)=>(typeof e=="string"?e:xs(e)).indexOf(" "+t+" ")>=0,zl=(e,t)=>{const n=xs(e),r=n+t;zi(n,t)||(e.className=r.substring(1))},Wl=(e,t)=>{const n=xs(e);if(!zi(e,t))return;const r=n.replace(" "+t+" "," ");e.className=r.substring(1,r.length-1)},xs=e=>(" "+(e.className||"")+" ").replace(/\s+/gi," "),Vh=e=>{e&&e.parentNode&&e.parentNode.removeChild(e)},zh=()=>{_e(()=>{const e=Dt(),t=new Set;t.add(e.currentRoute.value.path),e.beforeEach(n=>{t.has(n.path)||se.start()}),e.afterEach(n=>{t.add(n.path),se.done()})})},Wh=lt({setup(){zh()}}),Uh=JSON.parse(`{"encrypt":{},"author":{"name":"dtp.dev","url":"https://dtp.dev"},"logo":"/logo.png","repo":"chainmovers/dtp","contributors":false,"editLink":false,"pageInfo":false,"breadcrumb":false,"toc":false,"docsDir":"docs/src","locales":{"/":{"lang":"en-US","navbarLocales":{"langName":"English","selectLangAriaLabel":"Select language"},"metaLocales":{"author":"Author","date":"Writing Date","origin":"Original","views":"Page views","category":"Category","tag":"Tag","readingTime":"Reading Time","words":"Words","toc":"On This Page","prev":"Prev","next":"Next","lastUpdated":"Last update","contributors":"Contributors","editLink":"Edit this page on GitHub","print":"Print"},"outlookLocales":{"themeColor":"Theme Color","darkmode":"Theme Mode","fullscreen":"Full Screen"},"routeLocales":{"skipToContent":"Skip to main content","notFoundTitle":"Page not found","notFoundMsg":["There’s nothing here.","How did we get here?","That’s a Four-Oh-Four.","Looks like we've got some broken links."],"back":"Go back","home":"Take me home","openInNewWindow":"Open in new window"},"navbar":[{"icon":"home","text":"","link":"/"},{"text":"Getting Started","link":"/intro.md"},{"text":"Use Cases","link":"/examples/"},{"text":"Docs","link":"/docs/"},{"text":"Community","link":"/community/"}],"sidebar":{"/":["",{"text":"Getting Started","link":"intro.md","children":[{"text":"What is DTP?","link":"intro.md"},{"text":"Installation","link":"how-to/install.md"},{"text":"FAQ","link":"faq.md"}]},{"text":"Use Cases","link":"examples/README.md","children":[{"text":"Examples/Ideas","link":"examples/README.md"},{"text":"JSON-RPC Firewall","link":"examples/rpc_firewall.md"},{"text":"Rust Backend","link":"examples/web3_rust.md"}]},{"text":"Docs","link":"docs/README.md","children":[{"text":"Basic Concepts","link":"docs/README.md"},{"text":"API","collapsible":true,"prefix":"docs/","children":[{"text":"Rust","link":"api_rust.md"},{"text":"Typescript","link":"api_typescript.md"},{"text":"'dtp' Command Line","link":"scripts.md"}]},{"text":"Design","link":"docs/design.md"},{"text":"Future Work","link":"docs/future_work.md"}]},{"text":"Community","link":"community/","children":[{"text":"Forums / Contacts","link":"community/"},{"text":"Become an Editor","link":"community/editors.md"}]}]},"footer":"DTP on Github         DTP on Discord","copyright":"Apache 2.0 Open-Source License","displayFooter":true}}}`),qh=te(Uh),Wi=()=>qh,Ui=Symbol(""),Gh=()=>{const e=Le(Ui);if(!e)throw new Error("useThemeLocaleData() is called without provider.");return e},Kh=(e,t)=>{const{locales:n,...r}=e;return{...r,...n==null?void 0:n[t]}},Yh=lt({enhance({app:e}){const t=Wi(),n=e._context.provides[ms],r=k(()=>Kh(t.value,n.routeLocale.value));e.provide(Ui,r),Object.defineProperties(e.config.globalProperties,{$theme:{get(){return t.value}},$themeLocale:{get(){return r.value}}})}}),Jh=/\b(?:Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini)/i,Qh=()=>typeof window<"u"&&window.navigator&&"userAgent"in window.navigator&&Jh.test(navigator.userAgent),_o=new Map,Xh=({delay:e=500,duration:t=2e3,locales:n,selector:r,showInMobile:o})=>{const{copy:s}=ih({legacy:!0}),l=sr(n),a=ge(),c=d=>{if(!d.hasAttribute("copy-code-registered")){const p=document.createElement("button");p.type="button",p.classList.add("vp-copy-code-button"),p.innerHTML='
',p.setAttribute("aria-label",l.value.copy),p.setAttribute("data-copied",l.value.copied),d.parentElement&&d.parentElement.insertBefore(p,d),d.setAttribute("copy-code-registered","")}},i=()=>{Qt().then(()=>setTimeout(()=>{r.forEach(d=>{document.querySelectorAll(d).forEach(c)})},e))},u=(d,p,m)=>{let{innerText:g=""}=p;/language-(shellscript|shell|bash|sh|zsh)/.test(d.classList.toString())&&(g=g.replace(/^ *(\$|>) /gm,"")),s(g).then(()=>{m.classList.add("copied"),clearTimeout(_o.get(m));const E=setTimeout(()=>{m.classList.remove("copied"),m.blur(),_o.delete(m)},t);_o.set(m,E)})};_e(()=>{const d=!Qh()||o;d&&i(),Ie("click",p=>{const m=p.target;if(m.matches('div[class*="language-"] > button.copy')){const g=m.parentElement,E=m.nextElementSibling;E&&u(g,E,m)}else if(m.matches('div[class*="language-"] div.vp-copy-icon')){const g=m.parentElement,E=g.parentElement,w=g.nextElementSibling;w&&u(E,w,g)}}),ie(()=>a.value.path,()=>{d&&i()})})};var Zh={"/":{copy:"Copy code",copied:"Copied"}},ev=['.theme-hope-content div[class*="language-"] pre'];const tv=500,nv=2e3,rv=Zh,ov=ev,sv=!1,lv=lt({setup:()=>{Xh({selector:ov,locales:rv,duration:nv,delay:tv,showInMobile:sv})}}),Sr=Es("VUEPRESS_CODE_TAB_STORE",{});var av=q({name:"CodeTabs",props:{active:{type:Number,default:0},data:{type:Array,required:!0},id:{type:String,required:!0},tabId:{type:String,default:""}},slots:Object,setup(e,{slots:t}){const n=te(e.active),r=Fe([]),o=()=>{e.tabId&&(Sr.value[e.tabId]=e.data[n.value].id)},s=(i=n.value)=>{n.value=i{n.value=i>0?i-1:r.value.length-1,r.value[n.value].focus()},a=(i,u)=>{i.key===" "||i.key==="Enter"?(i.preventDefault(),n.value=u):i.key==="ArrowRight"?(i.preventDefault(),s()):i.key==="ArrowLeft"&&(i.preventDefault(),l()),e.tabId&&(Sr.value[e.tabId]=e.data[n.value].id)},c=()=>{if(e.tabId){const i=e.data.findIndex(({id:u})=>Sr.value[e.tabId]===u);if(i!==-1)return i}return e.active};return _e(()=>{n.value=c(),ie(()=>Sr.value[e.tabId],(i,u)=>{if(e.tabId&&i!==u){const d=e.data.findIndex(({id:p})=>p===i);d!==-1&&(n.value=d)}})}),()=>e.data.length?f("div",{class:"vp-code-tabs"},[f("div",{class:"vp-code-tabs-nav",role:"tablist"},e.data.map(({id:i},u)=>{const d=u===n.value;return f("button",{type:"button",ref:p=>{p&&(r.value[u]=p)},class:["vp-code-tab-nav",{active:d}],role:"tab","aria-controls":`codetab-${e.id}-${u}`,"aria-selected":d,onClick:()=>{n.value=u,o()},onKeydown:p=>a(p,u)},t[`title${u}`]({value:i,isActive:d}))})),e.data.map(({id:i},u)=>{const d=u===n.value;return f("div",{class:["vp-code-tab",{active:d}],id:`codetab-${e.id}-${u}`,role:"tabpanel","aria-expanded":d},[f("div",{class:"vp-code-tab-title"},t[`title${u}`]({value:i,isActive:d})),t[`tab${u}`]({value:i,isActive:d})])})]):null}});const qi=({active:e=!1},{slots:t})=>{var n;return f("div",{class:["code-group-item",{active:e}],"aria-selected":e},(n=t.default)==null?void 0:n.call(t))};qi.displayName="CodeGroupItem";const iv=q({name:"CodeGroup",slots:Object,setup(e,{slots:t}){const n=te(-1),r=Fe([]),o=(a=n.value)=>{n.value=a{n.value=a>0?a-1:r.value.length-1,r.value[n.value].focus()},l=(a,c)=>{a.key===" "||a.key==="Enter"?(a.preventDefault(),n.value=c):a.key==="ArrowRight"?(a.preventDefault(),o(c)):a.key==="ArrowLeft"&&(a.preventDefault(),s(c))};return()=>{var c;const a=(((c=t.default)==null?void 0:c.call(t))||[]).filter(i=>i.type.name==="CodeGroupItem").map(i=>(i.props===null&&(i.props={}),i));return a.length===0?null:(n.value<0||n.value>a.length-1?(n.value=a.findIndex(i=>"active"in i.props),n.value===-1&&(n.value=0)):a.forEach((i,u)=>{i.props.active=u===n.value}),f("div",{class:"code-group"},[f("div",{class:"code-group-nav"},a.map((i,u)=>{const d=u===n.value;return f("button",{type:"button",ref:p=>{p&&(r.value[u]=p)},class:["code-group-nav-tab",{active:d}],"aria-pressed":d,"aria-expanded":d,onClick:()=>{n.value=u},onKeydown:p=>l(p,u)},i.props.title)})),a]))}}}),cv=()=>{Ie("beforeprint",()=>{document.querySelectorAll("details").forEach(e=>{e.open=!0})})},wo=Es("VUEPRESS_TAB_STORE",{});var uv=q({name:"Tabs",props:{active:{type:Number,default:0},data:{type:Array,required:!0},id:{type:String,required:!0},tabId:{type:String,default:""}},slots:Object,setup(e,{slots:t}){const n=te(e.active),r=Fe([]),o=()=>{e.tabId&&(wo.value[e.tabId]=e.data[n.value].id)},s=(i=n.value)=>{n.value=i{n.value=i>0?i-1:r.value.length-1,r.value[n.value].focus()},a=(i,u)=>{i.key===" "||i.key==="Enter"?(i.preventDefault(),n.value=u):i.key==="ArrowRight"?(i.preventDefault(),s()):i.key==="ArrowLeft"&&(i.preventDefault(),l()),o()},c=()=>{if(e.tabId){const i=e.data.findIndex(({id:u})=>wo.value[e.tabId]===u);if(i!==-1)return i}return e.active};return _e(()=>{n.value=c(),ie(()=>wo.value[e.tabId],(i,u)=>{if(e.tabId&&i!==u){const d=e.data.findIndex(({id:p})=>p===i);d!==-1&&(n.value=d)}})}),()=>e.data.length?f("div",{class:"vp-tabs"},[f("div",{class:"vp-tabs-nav",role:"tablist"},e.data.map(({id:i},u)=>{const d=u===n.value;return f("button",{type:"button",ref:p=>{p&&(r.value[u]=p)},class:["vp-tab-nav",{active:d}],role:"tab","aria-controls":`tab-${e.id}-${u}`,"aria-selected":d,onClick:()=>{n.value=u,o()},onKeydown:p=>a(p,u)},t[`title${u}`]({value:i,isActive:d}))})),e.data.map(({id:i},u)=>{const d=u===n.value;return f("div",{class:["vp-tab",{active:d}],id:`tab-${e.id}-${u}`,role:"tabpanel","aria-expanded":d},[f("div",{class:"vp-tab-title"},t[`title${u}`]({value:i,isActive:d})),t[`tab${u}`]({value:i,isActive:d})])})]):null}});const fv=lt({enhance:({app:e})=>{e.component("CodeTabs",av),ot("CodeGroup",e)||e.component("CodeGroup",iv),ot("CodeGroupItem",e)||e.component("CodeGroupItem",qi),e.component("Tabs",uv)},setup:()=>{cv()}});let dv={};const Gi=Symbol(""),pv=()=>Le(Gi),hv=e=>{e.provide(Gi,dv)},vv='
',mv=e=>xe(e)?Array.from(document.querySelectorAll(e)):e.map(t=>Array.from(document.querySelectorAll(t))).flat(),Ki=e=>new Promise((t,n)=>{e.complete?t({type:"image",element:e,src:e.src,width:e.naturalWidth,height:e.naturalHeight,alt:e.alt,msrc:e.src}):(e.onload=()=>t(Ki(e)),e.onerror=r=>n(r))}),gv=e=>{const{isSupported:t,toggle:n}=Cs();e.on("uiRegister",()=>{t.value&&e.ui.registerElement({name:"fullscreen",order:7,isButton:!0,html:'',onClick:()=>{n()}}),e.ui.registerElement({name:"download",order:8,isButton:!0,tagName:"a",html:{isCustomSVG:!0,inner:'',outlineID:"pswp__icn-download"},onInit:(r,o)=>{r.setAttribute("download",""),r.setAttribute("target","_blank"),r.setAttribute("rel","noopener"),o.on("change",()=>{r.setAttribute("href",o.currSlide.data.src)})}}),e.ui.registerElement({name:"bulletsIndicator",className:"photo-swipe-bullets-indicator",appendTo:"wrapper",onInit:(r,o)=>{const s=[];let l=-1;for(let a=0;a{o.goTo(s.indexOf(i.target))},s.push(c),r.appendChild(c)}o.on("change",()=>{l>=0&&s[l].classList.remove("active"),s[o.currIndex].classList.add("active"),l=o.currIndex})}})})},bv=(e,t,n=!0)=>fe(()=>import("./photoswipe.esm-SzV8tJDW.js"),__vite__mapDeps([])).then(({default:r})=>{let o=null;const s=e.map(l=>({html:vv,element:l,msrc:l.src}));return e.forEach((l,a)=>{const c=()=>{o==null||o.destroy(),o=new r({preloaderDelay:0,showHideAnimationType:"zoom",...t,dataSource:s,index:a,...n?{closeOnVerticalDrag:!0,wheelToZoom:!1}:{}}),gv(o),o.addFilter("thumbEl",()=>l),o.addFilter("placeholderSrc",()=>l.src),o.init()};l.getAttribute("photo-swipe")||(l.style.cursor="zoom-in",l.addEventListener("click",()=>{c()}),l.addEventListener("keypress",({key:i})=>{i==="Enter"&&c()}),l.setAttribute("photo-swipe","")),Ki(l).then(i=>{s.splice(a,1,i),o==null||o.refreshSlideContent(a)})}),n?Ie("wheel",()=>{o==null||o.close()}):()=>{}}),yv=({selector:e,locales:t,delay:n=500,scrollToClose:r=!0})=>{const o=pv(),s=sr(t),l=ge();let a=null;const c=()=>new Promise(i=>setTimeout(i,n)).then(()=>Qt()).then(async()=>{a=await bv(mv(e),{...o,...s.value},r)});_e(()=>{c(),ie(()=>l.value.path,()=>{a==null||a(),c()})}),En(()=>{a==null||a()})};var _v={"/":{closeTitle:"Close",downloadTitle:"Download Image",fullscreenTitle:"Switch to full screen",zoomTitle:"Zoom in/out",arrowPrevTitle:"Prev (Arrow Left)",arrowNextTitle:"Next (Arrow Right)"}};const wv=".theme-hope-content :not(a) > img:not([no-view])",Ev=_v,Cv=800,xv=!0,Sv=lt({enhance:({app:e})=>{hv(e)},setup:()=>{yv({selector:wv,delay:Cv,locales:Ev,scrollToClose:xv})}}),Yi=()=>{const e=ge();return k(()=>e.value.readingTime??null)},Tv=(e,t)=>{const{minutes:n,words:r}=e,{less1Minute:o,word:s,time:l}=t;return{time:n<1?o:l.replace("$time",Math.round(n).toString()),words:s.replace("$word",r.toString())}};var Ul={"/":{word:"About $word words",less1Minute:"Less than 1 minute",time:"About $time min"}};const ql={words:"",time:""},Bo=typeof Ul>"u"?null:Ul,kv=()=>Bo?sr(Bo):k(()=>null),Av=()=>{if(typeof Bo>"u")return k(()=>ql);const e=Yi(),t=kv();return k(()=>e.value&&t.value?Tv(e.value,t.value):ql)},Tn=()=>Wi(),de=()=>Gh(),cr=()=>{const e=Tn();return k(()=>!!e.value.pure)},Eo=()=>null,Lv="719px",Rv="1440px",Pv="false",Ss={mobileBreakPoint:Lv,pcBreakPoint:Rv,enableThemeColor:Pv},Ts={},Ji=e=>{const{icon:t="",color:n,size:r}=e,o=n||r?{}:null;return n&&(o.color=n),r&&(o.height=Number.isNaN(Number(r))?r:`${r}px`),Xt(t)?f("img",{class:"icon",src:t,alt:"","no-view":"",style:o}):ys(t)?f("img",{class:"icon",src:Ne(t),alt:"","aria-hidden":"","no-view":"",style:o}):f(rt("FontIcon"),e)};Ji.displayName="HopeIcon";var De=Ji;const Iv=()=>{const e=Dt(),t=_t();return n=>{if(n)if(ys(n))t.path!==n&&e.push(n);else if(ni(n))window&&window.open(n);else{const r=t.path.slice(0,t.path.lastIndexOf("/"));e.push(`${r}/${encodeURI(n)}`)}}},Qi=()=>{const e=de(),t=Se();return k(()=>{const{author:n}=t.value;return n?$l(n):n===!1?[]:$l(e.value.author,!1)})},Ov=()=>{const e=Se();return k(()=>Up(e.value.category).map(t=>({name:t,path:""})))},Mv=()=>{const e=Se();return k(()=>qp(e.value.tag).map(t=>({name:t,path:""})))},$v=()=>{const e=Se(),t=ge();return k(()=>{const n=jp(e.value.date);if(n)return n;const{createdTime:r}=t.value.git||{};return r?new Date(r):null})},Nv=()=>{const e=de(),t=ge(),n=Se(),r=Qi(),o=Ov(),s=Mv(),l=$v(),a=Yi(),c=Av(),i=k(()=>({author:r.value,category:o.value,date:l.value,localizedDate:t.value.localizedDate,tag:s.value,isOriginal:n.value.isOriginal||!1,readingTime:a.value,readingTimeLocale:c.value,pageview:"pageview"in n.value?n.value.pageview:!0})),u=k(()=>"pageInfo"in n.value?n.value.pageInfo:"pageInfo"in e.value?e.value.pageInfo:null);return{info:i,items:u}},{mobileBreakPoint:Dv,pcBreakPoint:Fv}=Ss,Gl=e=>e.endsWith("px")?Number(e.slice(0,-2)):null,Zr=()=>{const e=te(!1),t=te(!1),n=()=>{e.value=window.innerWidth<=(Gl(Dv)??719),t.value=window.innerWidth>=(Gl(Fv)??1440)};return _e(()=>{n(),Ie("resize",n,!1),Ie("orientationchange",n,!1)}),{isMobile:e,isPC:t}},Xi=Symbol(""),ur=()=>{const e=Le(Xi);if(!e)throw new Error("useDarkmode() is called without provider.");return e},Hv=e=>{const t=Tn(),n=hh(),r=k(()=>t.value.darkmode||"switch"),o=Es("vuepress-theme-hope-scheme","auto"),s=k(()=>{const a=r.value;return a==="disable"?!1:a==="enable"?!0:a==="auto"?n.value:a==="toggle"?o.value==="dark":o.value==="dark"||o.value==="auto"&&n.value}),l=k(()=>{const a=r.value;return a==="switch"||a==="toggle"});e.provide(Xi,{canToggle:l,config:r,isDarkmode:s,status:o}),Object.defineProperties(e.config.globalProperties,{$isDarkmode:{get:()=>s.value}})},Bv=()=>{const{config:e,isDarkmode:t,status:n}=ur();Sa(()=>{e.value==="disable"?n.value="light":e.value==="enable"?n.value="dark":e.value==="toggle"&&n.value==="auto"&&(n.value="light")}),_e(()=>{ie(t,r=>document.documentElement.setAttribute("data-theme",r?"dark":"light"),{immediate:!0})})};var Ve=q({name:"AutoLink",inheritAttrs:!1,props:{config:{type:Object,required:!0},exact:Boolean,noExternalLinkIcon:Boolean},emits:["focusout"],slots:Object,setup(e,{attrs:t,emit:n,slots:r}){const o=_t(),s=vi(),l=Vr(e,"config"),a=k(()=>Xt(l.value.link)),c=k(()=>!a.value&&ni(l.value.link)),i=k(()=>l.value.target||(a.value?"_blank":void 0)),u=k(()=>i.value==="_blank"),d=k(()=>!a.value&&!c.value&&!u.value),p=k(()=>l.value.rel||(u.value?"noopener noreferrer":null)),m=k(()=>l.value.ariaLabel||l.value.text),g=k(()=>{if(e.exact)return!1;const w=lr(s.value.locales);return w.length?w.every(b=>b!==l.value.link):l.value.link!=="/"}),E=k(()=>d.value?l.value.activeMatch?new RegExp(l.value.activeMatch,"u").test(o.path):g.value?Jn(o.path,l.value.link):o.path===l.value.link:!1);return()=>{const{before:w,after:b,default:S}=r,{text:y,icon:x,link:$}=l.value;return d.value?f(je,{to:$,"aria-label":m.value,...t,class:["nav-link",{active:E.value},t.class],onFocusout:()=>n("focusout")},()=>S?S():[w?w():f(De,{icon:x}),y,b==null?void 0:b()]):f("a",{href:$,rel:p.value,target:i.value,"aria-label":m.value,...t,class:["nav-link",t.class],onFocusout:()=>n("focusout")},S?S():[w?w():f(De,{icon:x}),y,e.noExternalLinkIcon?null:f(Vi),b==null?void 0:b()])}}});const yn=(e,t,n=!1)=>"activeMatch"in t?new RegExp(t.activeMatch,"u").test(e.path):ki(e,t.link)?!0:t.children&&!n?t.children.some(r=>yn(e,r)):!1,Zi=(e,t)=>t.type==="group"?t.children.some(n=>n.type==="group"?Zi(e,n):n.type==="page"&&yn(e,n,!0))||"prefix"in t&&ki(e,t.prefix):!1,ec=(e,t)=>xe(e.link)?f(Ve,{...t,config:e}):f("p",t,[f(De,{icon:e.icon}),e.text]),tc=e=>{const t=_t();return e?f("ul",{class:"vp-sidebar-sub-headers"},e.map(n=>f("li",{class:"vp-sidebar-sub-header"},[ec(n,{class:["vp-sidebar-link","vp-heading",{active:yn(t,n,!0)}]}),tc(n.children)]))):null};var mt=(e=>(e.type="y",e.title="t",e.shortTitle="s",e.icon="i",e.author="a",e.date="d",e.localizedDate="l",e.category="c",e.tag="g",e.isEncrypted="n",e.isOriginal="o",e.readingTime="r",e.excerpt="e",e.sticky="u",e.cover="v",e.index="I",e.order="O",e))(mt||{}),jv=(e=>(e.article="a",e.home="h",e.slide="s",e.page="p",e))(jv||{});const Wt=(e="",t="")=>ys(t)?t:`${ti(e)}${t}`,fn=(e,t=!1)=>{const{meta:n,path:r}=Jr(e);return n?{text:!t&&n[mt.shortTitle]?n[mt.shortTitle]:n[mt.title]||r,link:r,...n[mt.icon]?{icon:n[mt.icon]}:{}}:{text:r,link:r}},eo=(e,t,n)=>n>0?t.map(r=>({type:"heading",text:r.title,link:`${e.path}#${r.slug}`,children:eo(e,r.children,n-1)})):[],jo=({config:e,page:t,headerDepth:n,prefix:r=""})=>{const o=(s,l=r)=>{var c;const a=xe(s)?fn(Wt(l,s)):s.link?{...s,...mn(s.link)?{}:{link:fn(Wt(l,s.link)).link}}:s;if("children"in a){const i=Wt(l,a.prefix),u=a.children==="structure"?Ts[i]:a.children;return{type:"group",...a,prefix:i,children:u.map(d=>o(d,i))}}return{type:"page",...a,children:a.link===t.path?eo(t,((c=t.headers[0])==null?void 0:c.level)===1?t.headers[0].children:t.headers,n):[]}};return e.map(s=>o(s))},Vv=({config:e,page:t,headerDepth:n})=>{const r=lr(e).sort((o,s)=>s.length-o.length);for(const o of r)if(Jn(decodeURI(t.path),o)){const s=e[o];return s?jo({config:s==="structure"?Ts[o]:s==="heading"?eo(t,t.headers,n):s,page:t,headerDepth:n,prefix:o}):[]}return console.warn(`${t.path} is missing sidebar config.`),[]},zv=({config:e,routeLocale:t,page:n,headerDepth:r})=>e==="heading"?eo(n,n.headers,r):e==="structure"?jo({config:Ts[t],page:n,headerDepth:r,prefix:t}):Ho(e)?jo({config:e,page:n,headerDepth:r}):Gr(e)?Vv({config:e,page:n,headerDepth:r}):[],nc=Symbol(""),Wv=()=>{const e=Se(),t=de(),n=ge(),r=xn(),o=k(()=>e.value.home?!1:e.value.sidebar??t.value.sidebar??"structure"),s=k(()=>e.value.headerDepth??t.value.headerDepth??2),l=_s(()=>[o.value,s.value,n.value.path,null],()=>zv({config:o.value,routeLocale:r.value,page:n.value,headerDepth:s.value}));un(nc,l)},ks=()=>{const e=Le(nc);if(!e)throw new Error("useSidebarItems() is called without provider.");return e};var Uv=q({name:"PageFooter",setup(){const e=Tn(),t=de(),n=Se(),r=Qi(),o=k(()=>{const{copyright:i,footer:u}=n.value;return u!==!1&&!!(i||u||t.value.displayFooter)}),s=k(()=>{const{footer:i}=n.value;return i===!1?!1:xe(i)?i:t.value.footer||""}),l=k(()=>r.value.map(({name:i})=>i).join(", ")),a=i=>`Copyright © ${new Date().getFullYear()} ${l.value} ${i?`${i} Licensed`:""}`,c=k(()=>{const{copyright:i,license:u=""}=n.value,{license:d}=e.value,{copyright:p}=t.value;return i??(u?a(u):xe(p)?p:l.value||d?a(d):!1)});return()=>o.value?f("footer",{class:"vp-footer-wrapper"},[s.value?f("div",{class:"vp-footer",innerHTML:s.value}):null,c.value?f("div",{class:"vp-copyright",innerHTML:c.value}):null]):null}}),qv=q({name:"NavbarDropdownLink",props:{config:{type:Object,required:!0}},slots:Object,setup(e,{slots:t}){const n=ge(),r=Vr(e,"config"),o=k(()=>r.value.ariaLabel||r.value.text),s=te(!1);ie(()=>n.value.path,()=>{s.value=!1});const l=a=>{a.detail===0&&(s.value=!s.value)};return()=>{var a;return f("div",{class:["dropdown-wrapper",{open:s.value}]},[f("button",{type:"button",class:"dropdown-title","aria-label":o.value,onClick:l},[((a=t.title)==null?void 0:a.call(t))||f("span",{class:"title"},[f(De,{icon:r.value.icon}),e.config.text]),f("span",{class:"arrow"}),f("ul",{class:"nav-dropdown"},r.value.children.map((c,i)=>{const u=i===r.value.children.length-1;return f("li",{class:"dropdown-item"},"children"in c?[f("h4",{class:"dropdown-subtitle"},c.link?f(Ve,{config:c,onFocusout:()=>{c.children.length===0&&u&&(s.value=!1)}}):f("span",c.text)),f("ul",{class:"dropdown-subitem-wrapper"},c.children.map((d,p)=>f("li",{class:"dropdown-subitem"},f(Ve,{config:d,onFocusout:()=>{p===c.children.length-1&&u&&(s.value=!1)}}))))]:f(Ve,{config:c,onFocusout:()=>{u&&(s.value=!1)}}))}))])])}}});const rc=(e,t="")=>xe(e)?fn(Wt(t,e)):"children"in e?{...e,...e.link&&!mn(e.link)?fn(Wt(t,e.link)):{},children:e.children.map(n=>rc(n,Wt(t,e.prefix)))}:{...e,link:mn(e.link)?e.link:fn(Wt(t,e.link)).link},oc=()=>{const e=de(),t=()=>(e.value.navbar||[]).map(n=>rc(n));return _s(()=>e.value.navbar,()=>t())},Gv=()=>{const e=de(),t=k(()=>e.value.repo||null),n=k(()=>t.value?zp(t.value):null),r=k(()=>t.value?Ai(t.value):null),o=k(()=>n.value?e.value.repoLabel??(r.value===null?"Source":r.value):null);return k(()=>!n.value||!o.value||e.value.repoDisplay===!1?null:{type:r.value||"Source",label:o.value,link:n.value})};var Kv=q({name:"NavScreenDropdown",props:{config:{type:Object,required:!0}},setup(e){const t=ge(),n=Vr(e,"config"),r=k(()=>n.value.ariaLabel||n.value.text),o=te(!1);ie(()=>t.value.path,()=>{o.value=!1});const s=(l,a)=>a[a.length-1]===l;return()=>[f("button",{type:"button",class:["nav-screen-dropdown-title",{active:o.value}],"aria-label":r.value,onClick:()=>{o.value=!o.value}},[f("span",{class:"title"},[f(De,{icon:n.value.icon}),e.config.text]),f("span",{class:["arrow",o.value?"down":"end"]})]),f("ul",{class:["nav-screen-dropdown",{hide:!o.value}]},n.value.children.map(l=>f("li",{class:"dropdown-item"},"children"in l?[f("h4",{class:"dropdown-subtitle"},l.link?f(Ve,{config:l,onFocusout:()=>{s(l,n.value.children)&&l.children.length===0&&(o.value=!1)}}):f("span",l.text)),f("ul",{class:"dropdown-subitem-wrapper"},l.children.map(a=>f("li",{class:"dropdown-subitem"},f(Ve,{config:a,onFocusout:()=>{s(a,l.children)&&s(l,n.value.children)&&(o.value=!1)}}))))]:f(Ve,{config:l,onFocusout:()=>{s(l,n.value.children)&&(o.value=!1)}}))))]}}),Yv=q({name:"NavScreenLinks",setup(){const e=oc();return()=>e.value.length?f("nav",{class:"nav-screen-links"},e.value.map(t=>f("div",{class:"navbar-links-item"},"children"in t?f(Kv,{config:t}):f(Ve,{config:t})))):null}});const sc=()=>f(Ee,{name:"dark"},()=>f("path",{d:"M524.8 938.667h-4.267a439.893 439.893 0 0 1-313.173-134.4 446.293 446.293 0 0 1-11.093-597.334A432.213 432.213 0 0 1 366.933 90.027a42.667 42.667 0 0 1 45.227 9.386 42.667 42.667 0 0 1 10.24 42.667 358.4 358.4 0 0 0 82.773 375.893 361.387 361.387 0 0 0 376.747 82.774 42.667 42.667 0 0 1 54.187 55.04 433.493 433.493 0 0 1-99.84 154.88 438.613 438.613 0 0 1-311.467 128z"}));sc.displayName="DarkIcon";const lc=()=>f(Ee,{name:"light"},()=>f("path",{d:"M952 552h-80a40 40 0 0 1 0-80h80a40 40 0 0 1 0 80zM801.88 280.08a41 41 0 0 1-57.96-57.96l57.96-58a41.04 41.04 0 0 1 58 58l-58 57.96zM512 752a240 240 0 1 1 0-480 240 240 0 0 1 0 480zm0-560a40 40 0 0 1-40-40V72a40 40 0 0 1 80 0v80a40 40 0 0 1-40 40zm-289.88 88.08-58-57.96a41.04 41.04 0 0 1 58-58l57.96 58a41 41 0 0 1-57.96 57.96zM192 512a40 40 0 0 1-40 40H72a40 40 0 0 1 0-80h80a40 40 0 0 1 40 40zm30.12 231.92a41 41 0 0 1 57.96 57.96l-57.96 58a41.04 41.04 0 0 1-58-58l58-57.96zM512 832a40 40 0 0 1 40 40v80a40 40 0 0 1-80 0v-80a40 40 0 0 1 40-40zm289.88-88.08 58 57.96a41.04 41.04 0 0 1-58 58l-57.96-58a41 41 0 0 1 57.96-57.96z"}));lc.displayName="LightIcon";const ac=()=>f(Ee,{name:"auto"},()=>f("path",{d:"M512 992C246.92 992 32 777.08 32 512S246.92 32 512 32s480 214.92 480 480-214.92 480-480 480zm0-840c-198.78 0-360 161.22-360 360 0 198.84 161.22 360 360 360s360-161.16 360-360c0-198.78-161.22-360-360-360zm0 660V212c165.72 0 300 134.34 300 300 0 165.72-134.28 300-300 300z"}));ac.displayName="AutoIcon";const ic=()=>f(Ee,{name:"enter-fullscreen"},()=>f("path",{d:"M762.773 90.24h-497.28c-96.106 0-174.4 78.293-174.4 174.4v497.28c0 96.107 78.294 174.4 174.4 174.4h497.28c96.107 0 175.04-78.293 174.4-174.4V264.64c0-96.213-78.186-174.4-174.4-174.4zm-387.2 761.173H215.04c-21.867 0-40.427-17.92-41.067-41.066V649.92c0-22.507 17.92-40.427 40.427-40.427 11.307 0 21.227 4.694 28.48 11.947 7.253 7.253 11.947 17.92 11.947 28.48v62.293l145.28-145.28c15.893-15.893 41.813-15.893 57.706 0 15.894 15.894 15.894 41.814 0 57.707l-145.28 145.28h62.294c22.506 0 40.426 17.92 40.426 40.427s-17.173 41.066-39.68 41.066zM650.24 165.76h160.427c21.866 0 40.426 17.92 41.066 41.067v160.426c0 22.507-17.92 40.427-40.426 40.427-11.307 0-21.227-4.693-28.48-11.947-7.254-7.253-11.947-17.92-11.947-28.48v-62.186L625.6 450.347c-15.893 15.893-41.813 15.893-57.707 0-15.893-15.894-15.893-41.814 0-57.707l145.28-145.28H650.88c-22.507 0-40.427-17.92-40.427-40.427s17.174-41.173 39.787-41.173z"}));ic.displayName="EnterFullScreenIcon";const cc=()=>f(Ee,{name:"cancel-fullscreen"},()=>f("path",{d:"M778.468 78.62H247.922c-102.514 0-186.027 83.513-186.027 186.027V795.08c0 102.514 83.513 186.027 186.027 186.027h530.432c102.514 0 186.71-83.513 186.026-186.027V264.647C964.494 162.02 880.981 78.62 778.468 78.62zM250.88 574.35h171.122c23.324 0 43.122 19.115 43.804 43.805v171.121c0 24.008-19.114 43.122-43.122 43.122-12.06 0-22.641-5.006-30.378-12.743s-12.743-19.115-12.743-30.379V722.83L224.597 877.91c-16.953 16.952-44.6 16.952-61.553 0-16.953-16.954-16.953-44.602 0-61.554L318.009 661.39h-66.446c-24.007 0-43.122-19.114-43.122-43.122 0-24.12 18.432-43.918 42.439-43.918zm521.899-98.873H601.657c-23.325 0-43.122-19.114-43.805-43.804V260.55c0-24.007 19.115-43.122 43.122-43.122 12.06 0 22.642 5.007 30.379 12.743s12.743 19.115 12.743 30.38v66.445l154.965-154.965c16.953-16.953 44.601-16.953 61.554 0 16.953 16.953 16.953 44.6 0 61.554L705.536 388.55h66.446c24.007 0 43.122 19.115 43.122 43.122.114 24.007-18.318 43.804-42.325 43.804z"}));cc.displayName="CancelFullScreenIcon";const uc=()=>f(Ee,{name:"outlook"},()=>[f("path",{d:"M224 800c0 9.6 3.2 44.8 6.4 54.4 6.4 48-48 76.8-48 76.8s80 41.6 147.2 0 134.4-134.4 38.4-195.2c-22.4-12.8-41.6-19.2-57.6-19.2C259.2 716.8 227.2 761.6 224 800zM560 675.2l-32 51.2c-51.2 51.2-83.2 32-83.2 32 25.6 67.2 0 112-12.8 128 25.6 6.4 51.2 9.6 80 9.6 54.4 0 102.4-9.6 150.4-32l0 0c3.2 0 3.2-3.2 3.2-3.2 22.4-16 12.8-35.2 6.4-44.8-9.6-12.8-12.8-25.6-12.8-41.6 0-54.4 60.8-99.2 137.6-99.2 6.4 0 12.8 0 22.4 0 12.8 0 38.4 9.6 48-25.6 0-3.2 0-3.2 3.2-6.4 0-3.2 3.2-6.4 3.2-6.4 6.4-16 6.4-16 6.4-19.2 9.6-35.2 16-73.6 16-115.2 0-105.6-41.6-198.4-108.8-268.8C704 396.8 560 675.2 560 675.2zM224 419.2c0-28.8 22.4-51.2 51.2-51.2 28.8 0 51.2 22.4 51.2 51.2 0 28.8-22.4 51.2-51.2 51.2C246.4 470.4 224 448 224 419.2zM320 284.8c0-22.4 19.2-41.6 41.6-41.6 22.4 0 41.6 19.2 41.6 41.6 0 22.4-19.2 41.6-41.6 41.6C339.2 326.4 320 307.2 320 284.8zM457.6 208c0-12.8 12.8-25.6 25.6-25.6 12.8 0 25.6 12.8 25.6 25.6 0 12.8-12.8 25.6-25.6 25.6C470.4 233.6 457.6 220.8 457.6 208zM128 505.6C128 592 153.6 672 201.6 736c28.8-60.8 112-60.8 124.8-60.8-16-51.2 16-99.2 16-99.2l316.8-422.4c-48-19.2-99.2-32-150.4-32C297.6 118.4 128 291.2 128 505.6zM764.8 86.4c-22.4 19.2-390.4 518.4-390.4 518.4-22.4 28.8-12.8 76.8 22.4 99.2l9.6 6.4c35.2 22.4 80 12.8 99.2-25.6 0 0 6.4-12.8 9.6-19.2 54.4-105.6 275.2-524.8 288-553.6 6.4-19.2-3.2-32-19.2-32C777.6 76.8 771.2 80 764.8 86.4z"})]);uc.displayName="OutlookIcon";var fc=q({name:"AppearanceSwitch",setup(){const{config:e,isDarkmode:t,status:n}=ur(),r=cr(),o=()=>{e.value==="switch"?n.value={light:"dark",dark:"auto",auto:"light"}[n.value]:n.value=n.value==="light"?"dark":"light"},s=async l=>{if(!(document.startViewTransition&&!window.matchMedia("(prefers-reduced-motion: reduce)").matches&&!r.value)||!l){o();return}const a=l.clientX,c=l.clientY,i=Math.hypot(Math.max(a,innerWidth-a),Math.max(c,innerHeight-c)),u=t.value;await document.startViewTransition(async()=>{o(),await Qt()}).ready,t.value!==u&&document.documentElement.animate({clipPath:t.value?[`circle(${i}px at ${a}px ${c}px)`,`circle(0px at ${a}px ${c}px)`]:[`circle(0px at ${a}px ${c}px)`,`circle(${i}px at ${a}px ${c}px)`]},{duration:400,pseudoElement:t.value?"::view-transition-old(root)":"::view-transition-new(root)"})};return()=>f("button",{type:"button",id:"appearance-switch",onClick:s},[f(ac,{style:{display:n.value==="auto"?"block":"none"}}),f(sc,{style:{display:n.value==="dark"?"block":"none"}}),f(lc,{style:{display:n.value==="light"?"block":"none"}})])}}),Jv=q({name:"AppearanceMode",setup(){const e=de(),{canToggle:t}=ur(),n=k(()=>e.value.outlookLocales.darkmode);return()=>t.value?f("div",{class:"appearance-wrapper"},[f("label",{class:"appearance-title",for:"appearance-switch"},n.value),f(fc)]):null}});const Co="VUEPRESS_THEME_COLOR";var Qv=q({name:"ThemeColorPicker",props:{themeColor:{type:Object,required:!0}},setup(e){const t=(n="")=>{const r=document.documentElement.classList,o=lr(e.themeColor);if(!n){localStorage.removeItem(Co),r.remove(...o);return}r.remove(...o.filter(s=>s!==n)),r.add(n),localStorage.setItem(Co,n)};return _e(()=>{const n=localStorage.getItem(Co);n&&t(n)}),()=>f("ul",{id:"theme-color-picker"},[f("li",f("span",{class:"theme-color",onClick:()=>t()})),bs(e.themeColor).map(([n,r])=>f("li",f("span",{style:{background:r},onClick:()=>t(n)})))])}});const dn=Ss.enableThemeColor==="true",Xv=dn?Bp(bs(Ss).filter(([e])=>e.startsWith("theme-"))):{};var Zv=q({name:"ThemeColor",setup(){const e=de(),t=k(()=>e.value.outlookLocales.themeColor);return()=>dn?f("div",{class:"theme-color-wrapper"},[f("label",{class:"theme-color-title",for:"theme-color-picker"},t.value),f(Qv,{themeColor:Xv})]):null}}),dc=q({name:"ToggleFullScreenButton",setup(){const e=de(),{isSupported:t,isFullscreen:n,toggle:r}=Cs(),o=k(()=>e.value.outlookLocales.fullscreen);return()=>t?f("div",{class:"full-screen-wrapper"},[f("label",{class:"full-screen-title",for:"full-screen-switch"},o.value),f("button",{type:"button",id:"full-screen-switch",class:"full-screen",ariaPressed:n.value,onClick:()=>r()},n.value?f(cc):f(ic))]):null}}),pc=q({name:"OutlookSettings",setup(){const e=Tn(),t=cr(),n=k(()=>!t.value&&e.value.fullscreen);return()=>f(Qr,()=>[dn?f(Zv):null,f(Jv),n.value?f(dc):null])}}),em=q({name:"NavScreen",props:{show:Boolean},emits:["close"],slots:Object,setup(e,{emit:t,slots:n}){const r=ge(),{isMobile:o}=Zr(),s=Fe(),l=Di(s);return _e(()=>{s.value=document.body,ie(o,a=>{!a&&e.show&&(l.value=!1,t("close"))}),ie(()=>r.value.path,()=>{l.value=!1,t("close")})}),En(()=>{l.value=!1}),()=>f($t,{name:"fade",onEnter:()=>{l.value=!0},onAfterLeave:()=>{l.value=!1}},()=>{var a,c;return e.show?f("div",{id:"nav-screen"},f("div",{class:"vp-nav-screen-container"},[(a=n.before)==null?void 0:a.call(n),f(Yv),f("div",{class:"vp-outlook-wrapper"},f(pc)),(c=n.after)==null?void 0:c.call(n)])):null})}}),tm=q({name:"NavbarBrand",setup(){const e=xn(),t=gs(),n=de(),r=k(()=>n.value.home||e.value),o=k(()=>t.value.title),s=k(()=>n.value.navTitle??o.value),l=k(()=>n.value.logo?Ne(n.value.logo):null),a=k(()=>n.value.logoDark?Ne(n.value.logoDark):null);return()=>f(je,{to:r.value,class:"vp-brand"},()=>[l.value?f("img",{class:["vp-nav-logo",{light:!!a.value}],src:l.value,alt:""}):null,a.value?f("img",{class:["vp-nav-logo dark"],src:a.value,alt:""}):null,s.value?f("span",{class:["vp-site-name",{"hide-in-pad":l.value&&n.value.hideSiteNameOnMobile!==!1}]},s.value):null])}}),nm=q({name:"NavbarLinks",setup(){const e=oc();return()=>e.value.length?f("nav",{class:"vp-nav-links"},e.value.map(t=>f("div",{class:"nav-item hide-in-mobile"},"children"in t?f(qv,{config:t}):f(Ve,{config:t})))):null}}),rm=q({name:"RepoLink",components:{BitbucketIcon:Ci,GiteeIcon:Ei,GitHubIcon:_i,GitLabIcon:wi,SourceIcon:xi},setup(){const e=Gv();return()=>e.value?f("div",{class:"nav-item vp-repo"},f("a",{class:"vp-repo-link",href:e.value.link,target:"_blank",rel:"noopener noreferrer","aria-label":e.value.label},f(rt(`${e.value.type}Icon`),{style:{width:"1.25rem",height:"1.25rem",verticalAlign:"middle"}}))):null}});const hc=({active:e=!1},{emit:t})=>f("button",{type:"button",class:["vp-toggle-navbar-button",{"is-active":e}],"aria-label":"Toggle Navbar","aria-expanded":e,"aria-controls":"nav-screen",onClick:()=>t("toggle")},f("span",[f("span",{class:"vp-top"}),f("span",{class:"vp-middle"}),f("span",{class:"vp-bottom"})]));hc.displayName="ToggleNavbarButton";var om=hc;const Vo=(e,{emit:t})=>f("button",{type:"button",class:"vp-toggle-sidebar-button",title:"Toggle Sidebar",onClick:()=>t("toggle")},f("span",{class:"icon"}));Vo.displayName="ToggleSidebarButton",Vo.emits=["toggle"];var sm=Vo,lm=q({name:"OutlookButton",setup(){const{isSupported:e}=Cs(),t=Tn(),n=cr(),r=ge(),{canToggle:o}=ur(),s=te(!1),l=k(()=>!n.value&&t.value.fullscreen&&e);return ie(()=>r.value.path,()=>{s.value=!1}),()=>o.value||l.value||dn?f("div",{class:"nav-item hide-in-mobile"},o.value&&!l.value&&!dn?f(fc):l.value&&!o.value&&!dn?f(dc):f("button",{type:"button",class:["outlook-button",{open:s.value}],tabindex:"-1","aria-hidden":!0},[f(uc),f("div",{class:"outlook-dropdown"},f(pc))])):null}}),am=q({name:"NavBar",emits:["toggleSidebar"],slots:Object,setup(e,{emit:t,slots:n}){const r=de(),{isMobile:o}=Zr(),s=te(!1),l=k(()=>{const{navbarAutoHide:u="mobile"}=r.value;return u!=="none"&&(u==="always"||o.value)}),a=k(()=>r.value.navbarLayout||{start:["Brand"],center:["Links"],end:["Language","Repo","Outlook","Search"]}),c={Brand:tm,Language:Eo,Links:nm,Repo:rm,Outlook:lm,Search:ot("Docsearch")?rt("Docsearch"):ot("SearchBox")?rt("SearchBox"):Eo},i=u=>c[u]??(ot(u)?rt(u):Eo);return()=>{var u,d,p,m,g,E;return[f("header",{id:"navbar",class:["vp-navbar",{"auto-hide":l.value,"hide-icon":r.value.navbarIcon===!1}]},[f("div",{class:"vp-navbar-start"},[f(sm,{onToggle:()=>{s.value&&(s.value=!1),t("toggleSidebar")}}),(u=n.startBefore)==null?void 0:u.call(n),(a.value.start||[]).map(w=>f(i(w))),(d=n.startAfter)==null?void 0:d.call(n)]),f("div",{class:"vp-navbar-center"},[(p=n.centerBefore)==null?void 0:p.call(n),(a.value.center||[]).map(w=>f(i(w))),(m=n.centerAfter)==null?void 0:m.call(n)]),f("div",{class:"vp-navbar-end"},[(g=n.endBefore)==null?void 0:g.call(n),(a.value.end||[]).map(w=>f(i(w))),(E=n.endAfter)==null?void 0:E.call(n),f(om,{active:s.value,onToggle:()=>{s.value=!s.value}})])]),f(em,{show:s.value,onClose:()=>{s.value=!1}},{before:()=>{var w;return(w=n.screenTop)==null?void 0:w.call(n)},after:()=>{var w;return(w=n.screenBottom)==null?void 0:w.call(n)}})]}}}),im=q({name:"SidebarChild",props:{config:{type:Object,required:!0}},setup(e){const t=_t();return()=>[ec(e.config,{class:["vp-sidebar-link",`vp-sidebar-${e.config.type}`,{active:yn(t,e.config,!0)}],exact:!0}),tc(e.config.children)]}}),cm=q({name:"SidebarGroup",props:{config:{type:Object,required:!0},open:{type:Boolean,required:!0}},emits:["toggle"],setup(e,{emit:t}){const n=_t(),r=k(()=>yn(n,e.config)),o=k(()=>yn(n,e.config,!0));return()=>{const{collapsible:s,children:l=[],icon:a,prefix:c,link:i,text:u}=e.config;return f("section",{class:"vp-sidebar-group"},[f(s?"button":"p",{class:["vp-sidebar-heading",{clickable:s||i,exact:o.value,active:r.value}],...s?{type:"button",onClick:()=>t("toggle"),onKeydown:d=>{d.key==="Enter"&&t("toggle")}}:{}},[f(De,{icon:a}),i?f(Ve,{class:"vp-sidebar-title",config:{text:u,link:i},noExternalLinkIcon:!0}):f("span",{class:"vp-sidebar-title"},u),s?f("span",{class:["vp-arrow",e.open?"down":"end"]}):null]),e.open||!s?f(vc,{key:c,config:l}):null])}}}),vc=q({name:"SidebarLinks",props:{config:{type:Array,required:!0}},setup(e){const t=_t(),n=te(-1),r=o=>{n.value=o===n.value?-1:o};return ie(()=>t.path,()=>{const o=e.config.findIndex(s=>Zi(t,s));n.value=o},{immediate:!0,flush:"post"}),()=>f("ul",{class:"vp-sidebar-links"},e.config.map((o,s)=>f("li",o.type==="group"?f(cm,{config:o,open:s===n.value,onToggle:()=>r(s)}):f(im,{config:o}))))}}),um=q({name:"SideBar",slots:Object,setup(e,{slots:t}){const n=_t(),r=de(),o=ks(),s=Fe();return _e(()=>{ie(()=>n.hash,l=>{const a=document.querySelector(`.vp-sidebar a.vp-sidebar-link[href="${n.path}${l}"]`);if(!a)return;const{top:c,height:i}=s.value.getBoundingClientRect(),{top:u,height:d}=a.getBoundingClientRect();uc+i&&a.scrollIntoView(!1)},{immediate:!0})}),()=>{var l,a,c;return f("aside",{ref:s,id:"sidebar",class:["vp-sidebar",{"hide-icon":r.value.sidebarIcon===!1}]},[(l=t.top)==null?void 0:l.call(t),((a=t.default)==null?void 0:a.call(t))||f(vc,{config:o.value}),(c=t.bottom)==null?void 0:c.call(t)])}}}),mc=q({name:"CommonWrapper",props:{containerClass:{type:String,default:""},noNavbar:Boolean,noSidebar:Boolean,noToc:Boolean},slots:Object,setup(e,{slots:t}){const n=Dt(),r=ge(),o=Se(),s=de(),{isMobile:l,isPC:a}=Zr(),[c,i]=Dl(!1),[u,d]=Dl(!1),p=ks(),m=te(!1),g=k(()=>e.noNavbar||o.value.navbar===!1||s.value.navbar===!1?!1:!!(r.value.title||s.value.logo||s.value.repo||s.value.navbar)),E=k(()=>e.noSidebar?!1:o.value.sidebar!==!1&&p.value.length!==0&&!o.value.home),w=k(()=>e.noToc||o.value.home?!1:o.value.toc||s.value.toc!==!1&&o.value.toc!==!1),b={x:0,y:0},S=C=>{b.x=C.changedTouches[0].clientX,b.y=C.changedTouches[0].clientY},y=C=>{const M=C.changedTouches[0].clientX-b.x,P=C.changedTouches[0].clientY-b.y;Math.abs(M)>Math.abs(P)*1.5&&Math.abs(M)>40&&(M>0&&b.x<=80?i(!0):i(!1))},x=()=>window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop||0;let $=0;return Ie("scroll",nh(()=>{const C=x();C<=58||C<$?m.value=!1:$+200{C||i(!1)}),_e(()=>{const C=Di(document.body);ie(c,P=>{C.value=P});const M=n.afterEach(()=>{i(!1)});En(()=>{C.value=!1,M()})}),()=>f(ot("GlobalEncrypt")?rt("GlobalEncrypt"):yi,()=>f("div",{class:["theme-container",{"no-navbar":!g.value,"no-sidebar":!E.value&&!(t.sidebar||t.sidebarTop||t.sidebarBottom),"has-toc":w.value,"hide-navbar":m.value,"sidebar-collapsed":!l.value&&!a.value&&u.value,"sidebar-open":l.value&&c.value},e.containerClass,o.value.containerClass||""],onTouchStart:S,onTouchEnd:y},[g.value?f(am,{onToggleSidebar:()=>i()},{startBefore:()=>{var C;return(C=t.navbarStartBefore)==null?void 0:C.call(t)},startAfter:()=>{var C;return(C=t.navbarStartAfter)==null?void 0:C.call(t)},centerBefore:()=>{var C;return(C=t.navbarCenterBefore)==null?void 0:C.call(t)},centerAfter:()=>{var C;return(C=t.navbarCenterAfter)==null?void 0:C.call(t)},endBefore:()=>{var C;return(C=t.navbarEndBefore)==null?void 0:C.call(t)},endAfter:()=>{var C;return(C=t.navbarEndAfter)==null?void 0:C.call(t)},screenTop:()=>{var C;return(C=t.navScreenTop)==null?void 0:C.call(t)},screenBottom:()=>{var C;return(C=t.navScreenBottom)==null?void 0:C.call(t)}}):null,f($t,{name:"fade"},()=>c.value?f("div",{class:"vp-sidebar-mask",onClick:()=>i(!1)}):null),f($t,{name:"fade"},()=>l.value?null:f("div",{class:"toggle-sidebar-wrapper",onClick:()=>d()},f("span",{class:["arrow",u.value?"end":"start"]}))),f(um,{},{...t.sidebar?{default:()=>t.sidebar()}:{},top:()=>{var C;return(C=t.sidebarTop)==null?void 0:C.call(t)},bottom:()=>{var C;return(C=t.sidebarBottom)==null?void 0:C.call(t)}}),t.default(),f(Uv)]))}}),on=q({name:"DropTransition",props:{type:{type:String,default:"single"},delay:{type:Number,default:0},duration:{type:Number,default:.25},appear:Boolean},slots:Object,setup(e,{slots:t}){const n=o=>{o.style.transition=`transform ${e.duration}s ease-in-out ${e.delay}s, opacity ${e.duration}s ease-in-out ${e.delay}s`,o.style.transform="translateY(-20px)",o.style.opacity="0"},r=o=>{o.style.transform="translateY(0)",o.style.opacity="1"};return()=>f(e.type==="single"?$t:rd,{name:"drop",appear:e.appear,onAppear:n,onAfterAppear:r,onEnter:n,onAfterEnter:r,onBeforeLeave:n},()=>t.default())}});const zo=({custom:e})=>f(bi,{class:["theme-hope-content",{custom:e}]});zo.displayName="MarkdownContent",zo.props={custom:Boolean};var gc=zo;const bc=()=>f(Ee,{name:"author"},()=>f("path",{d:"M649.6 633.6c86.4-48 147.2-144 147.2-249.6 0-160-128-288-288-288s-288 128-288 288c0 108.8 57.6 201.6 147.2 249.6-121.6 48-214.4 153.6-240 288-3.2 9.6 0 19.2 6.4 25.6 3.2 9.6 12.8 12.8 22.4 12.8h704c9.6 0 19.2-3.2 25.6-12.8 6.4-6.4 9.6-16 6.4-25.6-25.6-134.4-121.6-240-243.2-288z"}));bc.displayName="AuthorIcon";const yc=()=>f(Ee,{name:"calendar"},()=>f("path",{d:"M716.4 110.137c0-18.753-14.72-33.473-33.472-33.473-18.753 0-33.473 14.72-33.473 33.473v33.473h66.993v-33.473zm-334.87 0c0-18.753-14.72-33.473-33.473-33.473s-33.52 14.72-33.52 33.473v33.473h66.993v-33.473zm468.81 33.52H716.4v100.465c0 18.753-14.72 33.473-33.472 33.473a33.145 33.145 0 01-33.473-33.473V143.657H381.53v100.465c0 18.753-14.72 33.473-33.473 33.473a33.145 33.145 0 01-33.473-33.473V143.657H180.6A134.314 134.314 0 0046.66 277.595v535.756A134.314 134.314 0 00180.6 947.289h669.74a134.36 134.36 0 00133.94-133.938V277.595a134.314 134.314 0 00-133.94-133.938zm33.473 267.877H147.126a33.145 33.145 0 01-33.473-33.473c0-18.752 14.72-33.473 33.473-33.473h736.687c18.752 0 33.472 14.72 33.472 33.473a33.145 33.145 0 01-33.472 33.473z"}));yc.displayName="CalendarIcon";const _c=()=>f(Ee,{name:"category"},()=>f("path",{d:"M148.41 106.992h282.176c22.263 0 40.31 18.048 40.31 40.31V429.48c0 22.263-18.047 40.31-40.31 40.31H148.41c-22.263 0-40.311-18.047-40.311-40.31V147.302c0-22.263 18.048-40.31 40.311-40.31zM147.556 553.478H429.73c22.263 0 40.311 18.048 40.311 40.31v282.176c0 22.263-18.048 40.312-40.31 40.312H147.555c-22.263 0-40.311-18.049-40.311-40.312V593.79c0-22.263 18.048-40.311 40.31-40.311zM593.927 106.992h282.176c22.263 0 40.31 18.048 40.31 40.31V429.48c0 22.263-18.047 40.31-40.31 40.31H593.927c-22.263 0-40.311-18.047-40.311-40.31V147.302c0-22.263 18.048-40.31 40.31-40.31zM730.22 920.502H623.926c-40.925 0-74.22-33.388-74.22-74.425V623.992c0-41.038 33.387-74.424 74.425-74.424h222.085c41.038 0 74.424 33.226 74.424 74.067v114.233c0 10.244-8.304 18.548-18.547 18.548s-18.548-8.304-18.548-18.548V623.635c0-20.388-16.746-36.974-37.33-36.974H624.13c-20.585 0-37.331 16.747-37.331 37.33v222.086c0 20.585 16.654 37.331 37.126 37.331H730.22c10.243 0 18.547 8.304 18.547 18.547 0 10.244-8.304 18.547-18.547 18.547z"}));_c.displayName="CategoryIcon";const wc=()=>f(Ee,{name:"print"},()=>f("path",{d:"M819.2 364.8h-44.8V128c0-17.067-14.933-32-32-32H281.6c-17.067 0-32 14.933-32 32v236.8h-44.8C145.067 364.8 96 413.867 96 473.6v192c0 59.733 49.067 108.8 108.8 108.8h44.8V896c0 17.067 14.933 32 32 32h460.8c17.067 0 32-14.933 32-32V774.4h44.8c59.733 0 108.8-49.067 108.8-108.8v-192c0-59.733-49.067-108.8-108.8-108.8zM313.6 160h396.8v204.8H313.6V160zm396.8 704H313.6V620.8h396.8V864zM864 665.6c0 25.6-19.2 44.8-44.8 44.8h-44.8V588.8c0-17.067-14.933-32-32-32H281.6c-17.067 0-32 14.933-32 32v121.6h-44.8c-25.6 0-44.8-19.2-44.8-44.8v-192c0-25.6 19.2-44.8 44.8-44.8h614.4c25.6 0 44.8 19.2 44.8 44.8v192z"}));wc.displayName="PrintIcon";const Ec=()=>f(Ee,{name:"tag"},()=>f("path",{d:"M939.902 458.563L910.17 144.567c-1.507-16.272-14.465-29.13-30.737-30.737L565.438 84.098h-.402c-3.215 0-5.726 1.005-7.634 2.913l-470.39 470.39a10.004 10.004 0 000 14.164l365.423 365.424c1.909 1.908 4.42 2.913 7.132 2.913s5.223-1.005 7.132-2.913l470.39-470.39c2.01-2.11 3.014-5.023 2.813-8.036zm-240.067-72.121c-35.458 0-64.286-28.828-64.286-64.286s28.828-64.285 64.286-64.285 64.286 28.828 64.286 64.285-28.829 64.286-64.286 64.286z"}));Ec.displayName="TagIcon";const Cc=()=>f(Ee,{name:"timer"},()=>f("path",{d:"M799.387 122.15c4.402-2.978 7.38-7.897 7.38-13.463v-1.165c0-8.933-7.38-16.312-16.312-16.312H256.33c-8.933 0-16.311 7.38-16.311 16.312v1.165c0 5.825 2.977 10.874 7.637 13.592 4.143 194.44 97.22 354.963 220.201 392.763-122.204 37.542-214.893 196.511-220.2 389.397-4.661 5.049-7.638 11.651-7.638 19.03v5.825h566.49v-5.825c0-7.379-2.849-13.981-7.509-18.9-5.049-193.016-97.867-351.985-220.2-389.527 123.24-37.67 216.446-198.453 220.588-392.892zM531.16 450.445v352.632c117.674 1.553 211.787 40.778 211.787 88.676H304.097c0-48.286 95.149-87.382 213.728-88.676V450.445c-93.077-3.107-167.901-81.297-167.901-177.093 0-8.803 6.99-15.793 15.793-15.793 8.803 0 15.794 6.99 15.794 15.793 0 80.261 63.69 145.635 142.01 145.635s142.011-65.374 142.011-145.635c0-8.803 6.99-15.793 15.794-15.793s15.793 6.99 15.793 15.793c0 95.019-73.789 172.82-165.96 177.093z"}));Cc.displayName="TimerIcon";const xc=()=>f(Ee,{name:"word"},()=>[f("path",{d:"M518.217 432.64V73.143A73.143 73.143 0 01603.43 1.097a512 512 0 01419.474 419.474 73.143 73.143 0 01-72.046 85.212H591.36a73.143 73.143 0 01-73.143-73.143z"}),f("path",{d:"M493.714 566.857h340.297a73.143 73.143 0 0173.143 85.577A457.143 457.143 0 11371.566 117.76a73.143 73.143 0 0185.577 73.143v339.383a36.571 36.571 0 0036.571 36.571z"})]);xc.displayName="WordIcon";const Ft=()=>{const e=de();return k(()=>e.value.metaLocales)};var fm=q({name:"AuthorInfo",inheritAttrs:!1,props:{author:{type:Array,required:!0},pure:Boolean},setup(e){const t=Ft();return()=>e.author.length?f("span",{class:"page-author-info","aria-label":`${t.value.author}${e.pure?"":"🖊"}`,...e.pure?{}:{"data-balloon-pos":"down"}},[f(bc),f("span",e.author.map(n=>n.url?f("a",{class:"page-author-item",href:n.url,target:"_blank",rel:"noopener noreferrer"},n.name):f("span",{class:"page-author-item"},n.name))),f("span",{property:"author",content:e.author.map(n=>n.name).join(", ")})]):null}}),dm=q({name:"CategoryInfo",inheritAttrs:!1,props:{category:{type:Array,required:!0},pure:Boolean},setup(e){const t=Dt(),n=ge(),r=Ft(),o=(s,l="")=>{l&&n.value.path!==l&&(s.preventDefault(),t.push(l))};return()=>e.category.length?f("span",{class:"page-category-info","aria-label":`${r.value.category}${e.pure?"":"🌈"}`,...e.pure?{}:{"data-balloon-pos":"down"}},[f(_c),e.category.map(({name:s,path:l})=>f("span",{class:["page-category-item",{[`category${Si(s,9)}`]:!e.pure,clickable:l}],role:l?"navigation":"",onClick:a=>o(a,l)},s)),f("meta",{property:"articleSection",content:e.category.map(({name:s})=>s).join(",")})]):null}}),pm=q({name:"DateInfo",inheritAttrs:!1,props:{date:{type:Object,default:null},localizedDate:{type:String,default:""},pure:Boolean},setup(e){const t=hi(),n=Ft();return()=>e.date?f("span",{class:"page-date-info","aria-label":`${n.value.date}${e.pure?"":"📅"}`,...e.pure?{}:{"data-balloon-pos":"down"}},[f(yc),f("span",f(Qr,()=>e.localizedDate||e.date.toLocaleDateString(t.value))),f("meta",{property:"datePublished",content:e.date.toISOString()||""})]):null}}),hm=q({name:"OriginalInfo",inheritAttrs:!1,props:{isOriginal:Boolean},setup(e){const t=Ft();return()=>e.isOriginal?f("span",{class:"page-original-info"},t.value.origin):null}}),vm=q({name:"ReadingTimeInfo",inheritAttrs:!1,props:{readingTime:{type:Object,default:()=>null},readingTimeLocale:{type:Object,default:()=>null},pure:Boolean},setup(e){const t=Ft(),n=k(()=>{if(!e.readingTime)return null;const{minutes:r}=e.readingTime;return r<1?"PT1M":`PT${Math.round(r)}M`});return()=>{var r,o;return(r=e.readingTimeLocale)!=null&&r.time?f("span",{class:"page-reading-time-info","aria-label":`${t.value.readingTime}${e.pure?"":"⌛"}`,...e.pure?{}:{"data-balloon-pos":"down"}},[f(Cc),f("span",(o=e.readingTimeLocale)==null?void 0:o.time),f("meta",{property:"timeRequired",content:n.value})]):null}}}),mm=q({name:"TagInfo",inheritAttrs:!1,props:{tag:{type:Array,default:()=>[]},pure:Boolean},setup(e){const t=Dt(),n=ge(),r=Ft(),o=(s,l="")=>{l&&n.value.path!==l&&(s.preventDefault(),t.push(l))};return()=>e.tag.length?f("span",{class:"page-tag-info","aria-label":`${r.value.tag}${e.pure?"":"🏷"}`,...e.pure?{}:{"data-balloon-pos":"down"}},[f(Ec),e.tag.map(({name:s,path:l})=>f("span",{class:["page-tag-item",{[`tag${Si(s,9)}`]:!e.pure,clickable:l}],role:l?"navigation":"",onClick:a=>o(a,l)},s)),f("meta",{property:"keywords",content:e.tag.map(({name:s})=>s).join(",")})]):null}}),gm=q({name:"ReadTimeInfo",inheritAttrs:!1,props:{readingTime:{type:Object,default:()=>null},readingTimeLocale:{type:Object,default:()=>null},pure:Boolean},setup(e){const t=Ft();return()=>{var n,r,o;return(n=e.readingTimeLocale)!=null&&n.words?f("span",{class:"page-word-info","aria-label":`${t.value.words}${e.pure?"":"🔠"}`,...e.pure?{}:{"data-balloon-pos":"down"}},[f(xc),f("span",(r=e.readingTimeLocale)==null?void 0:r.words),f("meta",{property:"wordCount",content:(o=e.readingTime)==null?void 0:o.words})]):null}}}),bm=q({name:"PageInfo",components:{AuthorInfo:fm,CategoryInfo:dm,DateInfo:pm,OriginalInfo:hm,PageViewInfo:()=>null,ReadingTimeInfo:vm,TagInfo:mm,WordInfo:gm},props:{items:{type:[Array,Boolean],default:()=>["Author","Original","Date","PageView","ReadingTime","Category","Tag"]},info:{type:Object,required:!0}},setup(e){const t=cr();return()=>e.items?f("div",{class:"page-info"},e.items.map(n=>f(rt(`${n}Info`),{...e.info,pure:t.value}))):null}}),ym=q({name:"PrintButton",setup(){const e=Tn(),t=de();return()=>e.value.print===!1?null:f("button",{type:"button",class:"print-button",title:t.value.metaLocales.print,onClick:()=>{window.print()}},f(wc))}});const _m=({title:e,level:t,slug:n})=>f(je,{to:`#${n}`,class:["toc-link",`level${t}`]},()=>e),Wo=(e,t)=>{const n=_t();return e.length&&t>0?f("ul",{class:"toc-list"},e.map(r=>{const o=Wo(r.children,t-1);return[f("li",{class:["toc-item",{active:n.hash===`#${r.slug}`}]},_m(r)),o?f("li",o):null]})):null};var wm=q({name:"TOC",props:{items:{type:Array,default:()=>[]},headerDepth:{type:Number,default:2}},slots:Object,setup(e,{slots:t}){const n=_t(),r=ge(),o=Ft(),s=Fe(),l=te("-1.7rem"),a=i=>{var u;(u=s.value)==null||u.scrollTo({top:i,behavior:"smooth"})},c=()=>{if(s.value){const i=document.querySelector(".toc-item.active");i?l.value=`${i.getBoundingClientRect().top-s.value.getBoundingClientRect().top+s.value.scrollTop}px`:l.value="-1.7rem"}else l.value="-1.7rem"};return _e(()=>{ie(()=>n.hash,i=>{if(s.value){const u=document.querySelector(`#toc a.toc-link[href$="${i}"]`);if(!u)return;const{top:d,height:p}=s.value.getBoundingClientRect(),{top:m,height:g}=u.getBoundingClientRect();md+p&&a(s.value.scrollTop+m+g-d-p)}}),ie(()=>n.fullPath,c,{flush:"post",immediate:!0})}),()=>{var u,d;const i=e.items.length?Wo(e.items,e.headerDepth):r.value.headers?Wo(r.value.headers,e.headerDepth):null;return i?f("div",{class:"toc-place-holder"},[f("aside",{id:"toc"},[(u=t.before)==null?void 0:u.call(t),f("div",{class:"toc-header"},[o.value.toc,f(ym)]),f("div",{class:"toc-wrapper",ref:s},[i,f("div",{class:"toc-marker",style:{top:l.value}})]),(d=t.after)==null?void 0:d.call(t)])]):null}}}),Sc=q({name:"SkipLink",props:{content:{type:String,default:"main-content"}},setup(e){const t=ge(),n=de(),r=Fe(),o=({target:s})=>{const l=document.querySelector(s.hash);if(l){const a=()=>{l.removeAttribute("tabindex"),l.removeEventListener("blur",a)};l.setAttribute("tabindex","-1"),l.addEventListener("blur",a),l.focus(),window.scrollTo(0,0)}};return _e(()=>{ie(()=>t.value.path,()=>r.value.focus())}),()=>[f("span",{ref:r,tabindex:"-1"}),f("a",{href:`#${e.content}`,class:"vp-skip-link sr-only",onClick:o},n.value.routeLocales.skipToContent)]}});let xo=null,Rn=null;const Em={wait:()=>xo,pending:()=>{xo=new Promise(e=>{Rn=e})},resolve:()=>{Rn==null||Rn(),xo=null,Rn=null}},Tc=()=>Em;var Cm=q({name:"FadeSlideY",slots:Object,setup(e,{slots:t}){const{resolve:n,pending:r}=Tc();return()=>f($t,{name:"fade-slide-y",mode:"out-in",onBeforeEnter:n,onBeforeLeave:r},()=>{var o;return(o=t.default)==null?void 0:o.call(t)})}});const xm=(e,t)=>{const n=e.replace(t,"/").split("/"),r=[];let o=ps(t);return n.forEach((s,l)=>{l!==n.length-1?(o+=`${s}/`,r.push({link:o,name:s||"Home"})):s!==""&&(o+=s,r.push({link:o,name:s}))}),r},kc=(e,{slots:t})=>{var d,p;const{bgImage:n,bgImageDark:r,bgImageStyle:o,color:s,description:l,image:a,imageDark:c,header:i,features:u=[]}=e;return f("div",{class:"vp-feature-wrapper"},[n?f("div",{class:["vp-feature-bg",{light:r}],style:[{"background-image":`url(${n})`},o]}):null,r?f("div",{class:"vp-feature-bg dark",style:[{"background-image":`url(${r})`},o]}):null,f("div",{class:"vp-feature",style:s?{color:s}:{}},[((d=t.image)==null?void 0:d.call(t,e))||[a?f("img",{class:["vp-feature-image",{light:c}],src:Ne(a),alt:""}):null,c?f("img",{class:"vp-feature-image dark",src:Ne(c),alt:""}):null],((p=t.info)==null?void 0:p.call(t,e))||[i?f("h2",{class:"vp-feature-header"},i):null,l?f("p",{class:"vp-feature-description",innerHTML:l}):null],u.length?f("div",{class:"vp-features"},u.map(({icon:m,title:g,details:E,link:w})=>{const b=[f("h3",{class:"vp-feature-title"},[f(De,{icon:m}),f("span",{innerHTML:g})]),f("p",{class:"vp-feature-details",innerHTML:E})];return w?mn(w)?f("a",{class:"vp-feature-item link",href:w,"aria-label":g,target:"_blank"},b):f(je,{class:"vp-feature-item link",to:w,"aria-label":g},()=>b):f("div",{class:"vp-feature-item"},b)})):null])])};kc.displayName="FeaturePanel";var Kl=kc,Sm=q({name:"HeroInfo",slots:Object,setup(e,{slots:t}){const n=Se(),r=gs(),o=k(()=>n.value.heroFullScreen??!1),s=k(()=>{const{heroText:i,tagline:u}=n.value;return{text:i??r.value.title??"Hello",tagline:u??r.value.description??"",isFullScreen:o.value}}),l=k(()=>{const{heroText:i,heroImage:u,heroImageDark:d,heroAlt:p,heroImageStyle:m}=n.value;return{image:u?Ne(u):null,imageDark:d?Ne(d):null,heroStyle:m,alt:p||i||"",isFullScreen:o.value}}),a=k(()=>{const{bgImage:i,bgImageDark:u,bgImageStyle:d}=n.value;return{image:xe(i)?Ne(i):null,imageDark:xe(u)?Ne(u):null,bgStyle:d,isFullScreen:o.value}}),c=k(()=>n.value.actions??[]);return()=>{var i,u,d;return f("header",{class:["vp-hero-info-wrapper",{fullscreen:o.value}]},[((i=t.heroBg)==null?void 0:i.call(t,a.value))||[a.value.image?f("div",{class:["vp-hero-mask",{light:a.value.imageDark}],style:[{"background-image":`url(${a.value.image})`},a.value.bgStyle]}):null,a.value.imageDark?f("div",{class:"vp-hero-mask dark",style:[{"background-image":`url(${a.value.imageDark})`},a.value.bgStyle]}):null],f("div",{class:"vp-hero-info"},[((u=t.heroImage)==null?void 0:u.call(t,l.value))||f(on,{appear:!0,type:"group"},()=>[l.value.image?f("img",{key:"light",class:["vp-hero-image",{light:l.value.imageDark}],style:l.value.heroStyle,src:l.value.image,alt:l.value.alt}):null,l.value.imageDark?f("img",{key:"dark",class:"vp-hero-image dark",style:l.value.heroStyle,src:l.value.imageDark,alt:l.value.alt}):null]),((d=t.heroInfo)==null?void 0:d.call(t,s.value))??f("div",{class:"vp-hero-infos"},[s.value.text?f(on,{appear:!0,delay:.04},()=>f("h1",{id:"main-title"},s.value.text)):null,s.value.tagline?f(on,{appear:!0,delay:.08},()=>f("p",{id:"main-description",innerHTML:s.value.tagline})):null,c.value.length?f(on,{appear:!0,delay:.12},()=>f("p",{class:"vp-hero-actions"},c.value.map(p=>f(Ve,{class:["vp-hero-action",p.type||"default"],config:p,noExternalLinkIcon:!0},p.icon?{before:()=>f(De,{icon:p.icon})}:{})))):null])])])}}});const Ac=(e,{slots:t})=>{var p,m,g;const{bgImage:n,bgImageDark:r,bgImageStyle:o,color:s,description:l,image:a,imageDark:c,header:i,highlights:u=[],type:d="un-order"}=e;return f("div",{class:"vp-highlight-wrapper",style:s?{color:s}:{}},[n?f("div",{class:["vp-highlight-bg",{light:r}],style:[{"background-image":`url(${n})`},o]}):null,r?f("div",{class:"vp-highlight-bg dark",style:[{"background-image":`url(${r})`},o]}):null,f("div",{class:"vp-highlight"},[((p=t.image)==null?void 0:p.call(t,e))||[a?f("img",{class:["vp-highlight-image",{light:c}],src:Ne(a),alt:""}):null,c?f("img",{class:"vp-highlight-image dark",src:Ne(c),alt:""}):null],((m=t.info)==null?void 0:m.call(t,e))||[f("div",{class:"vp-highlight-info-wrapper"},f("div",{class:"vp-highlight-info"},[i?f("h2",{class:"vp-highlight-header",innerHTML:i}):null,l?f("p",{class:"vp-highlight-description",innerHTML:l}):null,((g=t.highlights)==null?void 0:g.call(t,u))||f(d==="order"?"ol":d==="no-order"?"dl":"ul",{class:"vp-highlights"},u.map(({icon:E,title:w,details:b,link:S})=>{const y=[f(d==="no-order"?"dt":"h3",{class:"vp-highlight-title"},[E?f(De,{class:"vp-highlight-icon",icon:E}):null,f("span",{innerHTML:w})]),b?f(d==="no-order"?"dd":"p",{class:"vp-highlight-details",innerHTML:b}):null];return f(d==="no-order"?"div":"li",{class:["vp-highlight-item-wrapper",{link:S}]},S?mn(S)?f("a",{class:"vp-highlight-item link",href:S,"aria-label":w,target:"_blank"},y):f(je,{class:"vp-highlight-item link",to:S,"aria-label":w},()=>y):f("div",{class:"vp-highlight-item"},y))}))]))]])])};Ac.displayName="HighlightPanel";var Tm=Ac,km=q({name:"HomePage",slots:Object,setup(e,{slots:t}){const n=cr(),r=Se(),o=k(()=>{const{features:l}=r.value;return Ho(l)?l:null}),s=k(()=>{const{highlights:l}=r.value;return Ho(l)?l:null});return()=>{var l,a,c,i;return f("main",{id:"main-content",class:["vp-project-home ",{pure:n.value}],"aria-labelledby":r.value.heroText===null?"":"main-title"},[(l=t.top)==null?void 0:l.call(t),f(Sm),((a=s.value)==null?void 0:a.map(u=>"features"in u?f(Kl,u):f(Tm,u)))||(o.value?f(on,{appear:!0,delay:.24},()=>f(Kl,{features:o.value})):null),(c=t.center)==null?void 0:c.call(t),f(on,{appear:!0,delay:.32},()=>f(gc)),(i=t.bottom)==null?void 0:i.call(t)])}}}),Am=q({name:"BreadCrumb",setup(){const e=ge(),t=xn(),n=Se(),r=de(),o=Fe([]),s=k(()=>(n.value.breadcrumb||n.value.breadcrumb!==!1&&r.value.breadcrumb!==!1)&&o.value.length>1),l=k(()=>n.value.breadcrumbIcon||n.value.breadcrumbIcon!==!1&&r.value.breadcrumbIcon!==!1),a=()=>{const c=xm(e.value.path,t.value).map(({link:i,name:u})=>{const{path:d,meta:p}=Jr(i);return p?{title:p[mt.shortTitle]||p[mt.title]||u,icon:p[mt.icon],path:d}:null}).filter(i=>i!==null);c.length>1&&(o.value=c)};return _e(()=>{ie(()=>e.value.path,a,{immediate:!0})}),()=>f("nav",{class:["vp-breadcrumb",{disable:!s.value}]},s.value?f("ol",{vocab:"https://schema.org/",typeof:"BreadcrumbList"},o.value.map((c,i)=>f("li",{class:{"is-active":o.value.length-1===i},property:"itemListElement",typeof:"ListItem"},[f(je,{to:c.path,property:"item",typeof:"WebPage"},()=>[l.value?f(De,{icon:c.icon}):null,f("span",{property:"name"},c.title||"Unknown")]),f("meta",{property:"position",content:i+1})]))):[])}});const Yl=e=>e===!1||Gr(e)?e:xe(e)?fn(e,!0):null,Uo=(e,t,n)=>{const r=e.findIndex(o=>o.link===t);if(r!==-1){const o=e[r+n];return o!=null&&o.link?o:null}for(const o of e)if(o.children){const s=Uo(o.children,t,n);if(s)return s}return null};var Lm=q({name:"PageNav",setup(){const e=de(),t=Se(),n=ks(),r=ge(),o=Iv(),s=k(()=>{const a=Yl(t.value.prev);return a===!1?null:a||(e.value.prevLink===!1?null:Uo(n.value,r.value.path,-1))}),l=k(()=>{const a=Yl(t.value.next);return a===!1?null:a||(e.value.nextLink===!1?null:Uo(n.value,r.value.path,1))});return Ie("keydown",a=>{a.altKey&&(a.key==="ArrowRight"?l.value&&(o(l.value.link),a.preventDefault()):a.key==="ArrowLeft"&&s.value&&(o(s.value.link),a.preventDefault()))}),()=>s.value||l.value?f("nav",{class:"vp-page-nav"},[s.value?f(Ve,{class:"prev",config:s.value},()=>{var a,c;return[f("div",{class:"hint"},[f("span",{class:"arrow start"}),e.value.metaLocales.prev]),f("div",{class:"link"},[f(De,{icon:(a=s.value)==null?void 0:a.icon}),(c=s.value)==null?void 0:c.text])]}):null,l.value?f(Ve,{class:"next",config:l.value},()=>{var a,c;return[f("div",{class:"hint"},[e.value.metaLocales.next,f("span",{class:"arrow end"})]),f("div",{class:"link"},[(a=l.value)==null?void 0:a.text,f(De,{icon:(c=l.value)==null?void 0:c.icon})])]}):null]):null}});const Rm={GitHub:":repo/edit/:branch/:path",GitLab:":repo/-/edit/:branch/:path",Gitee:":repo/edit/:branch/:path",Bitbucket:":repo/src/:branch/:path?mode=edit&spa=0&at=:branch&fileviewer=file-view-default"},Pm=({docsRepo:e,docsBranch:t,docsDir:n,filePathRelative:r,editLinkPattern:o})=>{if(!r)return null;const s=Ai(e);let l;return o?l=o:s!==null&&(l=Rm[s]),l?l.replace(/:repo/u,Xt(e)?e:`https://github.com/${e}`).replace(/:branch/u,t).replace(/:path/u,ri(`${ps(n)}/${r}`)):null},Im=()=>{const e=de(),t=ge(),n=Se();return k(()=>{const{repo:r,docsRepo:o=r,docsBranch:s="main",docsDir:l="",editLink:a,editLinkPattern:c=""}=e.value;if(!(n.value.editLink??a??!0)||!o)return null;const i=Pm({docsRepo:o,docsBranch:s,docsDir:l,editLinkPattern:c,filePathRelative:t.value.filePathRelative});return i?{text:e.value.metaLocales.editLink,link:i}:null})},Om=()=>{const e=gs(),t=de(),n=ge(),r=Se();return k(()=>{var o,s;return!(r.value.lastUpdated??t.value.lastUpdated??!0)||!((o=n.value.git)!=null&&o.updatedTime)?null:new Date((s=n.value.git)==null?void 0:s.updatedTime).toLocaleString(e.value.lang)})},Mm=()=>{const e=de(),t=ge(),n=Se();return k(()=>{var r;return n.value.contributors??e.value.contributors??!0?((r=t.value.git)==null?void 0:r.contributors)??null:null})};var $m=q({name:"PageTitle",setup(){const e=ge(),t=Se(),n=de(),{info:r,items:o}=Nv();return()=>f("div",{class:"vp-page-title"},[f("h1",[n.value.titleIcon===!1?null:f(De,{icon:t.value.icon}),e.value.title]),f(bm,{info:r.value,...o.value===null?{}:{items:o.value}}),f("hr")])}});const Lc=()=>f(Ee,{name:"edit"},()=>[f("path",{d:"M430.818 653.65a60.46 60.46 0 0 1-50.96-93.281l71.69-114.012 7.773-10.365L816.038 80.138A60.46 60.46 0 0 1 859.225 62a60.46 60.46 0 0 1 43.186 18.138l43.186 43.186a60.46 60.46 0 0 1 0 86.373L588.879 565.55l-8.637 8.637-117.466 68.234a60.46 60.46 0 0 1-31.958 11.229z"}),f("path",{d:"M728.802 962H252.891A190.883 190.883 0 0 1 62.008 771.98V296.934a190.883 190.883 0 0 1 190.883-192.61h267.754a60.46 60.46 0 0 1 0 120.92H252.891a69.962 69.962 0 0 0-69.098 69.099V771.98a69.962 69.962 0 0 0 69.098 69.098h475.911A69.962 69.962 0 0 0 797.9 771.98V503.363a60.46 60.46 0 1 1 120.922 0V771.98A190.883 190.883 0 0 1 728.802 962z"})]);Lc.displayName="EditIcon";var Nm=q({name:"PageMeta",setup(){const e=de(),t=Im(),n=Om(),r=Mm();return()=>{const{metaLocales:o}=e.value;return f("footer",{class:"page-meta"},[t.value?f("div",{class:"meta-item edit-link"},f(Ve,{class:"label",config:t.value},{before:()=>f(Lc)})):null,f("div",{class:"meta-item git-info"},[n.value?f("div",{class:"update-time"},[f("span",{class:"label"},`${o.lastUpdated}: `),f(Qr,()=>f("span",{class:"info"},n.value))]):null,r.value&&r.value.length?f("div",{class:"contributors"},[f("span",{class:"label"},`${o.contributors}: `),r.value.map(({email:s,name:l},a)=>[f("span",{class:"contributor",title:`email: ${s}`},l),a!==r.value.length-1?",":""])]):null])])}}}),Dm=q({name:"NormalPage",slots:Object,setup(e,{slots:t}){const n=Se(),{isDarkmode:r}=ur(),o=de(),s=k(()=>n.value.toc||n.value.toc!==!1&&o.value.toc!==!1);return()=>f("main",{id:"main-content",class:"vp-page"},f(ot("LocalEncrypt")?rt("LocalEncrypt"):yi,()=>{var l,a,c,i;return[(l=t.top)==null?void 0:l.call(t),n.value.cover?f("div",{class:"page-cover"},f("img",{src:Ne(n.value.cover),alt:"","no-view":""})):null,f(Am),f($m),s.value?f(wm,{headerDepth:n.value.headerDepth??o.value.headerDepth??2},{before:()=>{var u;return(u=t.tocBefore)==null?void 0:u.call(t)},after:()=>{var u;return(u=t.tocAfter)==null?void 0:u.call(t)}}):null,(a=t.contentBefore)==null?void 0:a.call(t),f(gc),(c=t.contentAfter)==null?void 0:c.call(t),f(Nm),f(Lm),ot("CommentService")?f(rt("CommentService"),{darkmode:r.value}):null,(i=t.bottom)==null?void 0:i.call(t)]}))}}),Fm=q({name:"Layout",slots:Object,setup(e,{slots:t}){de();const n=ge(),r=Se(),{isMobile:o}=Zr(),s=k(()=>"none");return()=>[f(Sc),f(mc,{},{default:()=>{var l;return((l=t.default)==null?void 0:l.call(t))||(r.value.home?f(km):f(Cm,()=>f(Dm,{key:n.value.path},{top:()=>{var a;return(a=t.top)==null?void 0:a.call(t)},bottom:()=>{var a;return(a=t.bottom)==null?void 0:a.call(t)},contentBefore:()=>{var a;return(a=t.contentBefore)==null?void 0:a.call(t)},contentAfter:()=>{var a;return(a=t.contentAfter)==null?void 0:a.call(t)},tocBefore:()=>{var a;return(a=t.tocBefore)==null?void 0:a.call(t)},tocAfter:()=>{var a;return(a=t.tocAfter)==null?void 0:a.call(t)}})))},...s.value==="none"?{}:{navScreenBottom:()=>f(rt("BloggerInfo"))},...!o.value&&s.value==="always"?{sidebar:()=>f(rt("BloggerInfo"))}:{}})]}}),Hm=q({name:"NotFoundHint",setup(){const e=de(),t=()=>{const n=e.value.routeLocales.notFoundMsg;return n[Math.floor(Math.random()*n.length)]};return()=>f("div",{class:"not-found-hint"},[f("p",{class:"error-code"},"404"),f("h1",{class:"error-title"},e.value.routeLocales.notFoundTitle),f("p",{class:"error-hint"},t())])}}),Bm=q({name:"NotFound",slots:Object,setup(e,{slots:t}){const n=Dt(),r=xn(),o=de();return()=>[f(Sc),f(mc,{noSidebar:!0},()=>{var s;return f("main",{id:"main-content",class:"vp-page not-found"},((s=t.default)==null?void 0:s.call(t))||[f(Hm),f("div",{class:"actions"},[f("button",{type:"button",class:"action-button",onClick:()=>{window.history.go(-1)}},o.value.routeLocales.back),f("button",{type:"button",class:"action-button",onClick:()=>{n.push(o.value.home??r.value)}},o.value.routeLocales.home)])])})]}});Ah(e=>{const t=e.t,n=e.I!==!1,r=e.i;return n?{title:t,content:r?()=>[f(De,{icon:r}),t]:null,order:e.O,index:e.I}:null});const jm=lt({enhance:({app:e,router:t})=>{const{scrollBehavior:n}=t.options;t.options.scrollBehavior=async(...r)=>(await Tc().wait(),n(...r)),Hv(e),e.component("HopeIcon",De)},setup:()=>{Bv(),Wv()},layouts:{Layout:Fm,NotFound:Bm}}),Tr=[Np,wh,kh,Oh,Nh,Bh,Wh,Yh,lv,fv,Sv,jm],Vm=JSON.parse('{"base":"/","lang":"en-US","title":"Decentralized Transport Protocol","description":"Adds Web3 features to existing Web2 data transfer apps","head":[],"locales":{}}');var In=Fe(Vm),zm=Vd,Wm=()=>{const e=Tp({history:zm(ps("/")),routes:[{name:"vuepress-route",path:"/:catchAll(.*)",components:{}}],scrollBehavior:(t,n,r)=>r||(t.hash?{el:t.hash}:{top:0})});return e.beforeResolve(async(t,n)=>{if(t.path!==n.path||n===vt){const r=Jr(t.path);if(r.path!==t.path)return r.path;const o=await r.loader();t.meta={...r.meta,_pageChunk:o}}}),e},Um=e=>{e.component("ClientOnly",Qr),e.component("Content",bi),e.component("RouteLink",je)},qm=(e,t,n)=>{const r=k(()=>t.currentRoute.value.path),o=_s(r,()=>t.currentRoute.value.meta._pageChunk),s=k(()=>jt.resolveLayouts(n)),l=k(()=>jt.resolveRouteLocale(In.value.locales,r.value)),a=k(()=>jt.resolveSiteLocaleData(In.value,l.value)),c=k(()=>o.value.comp),i=k(()=>o.value.data),u=k(()=>i.value.frontmatter),d=k(()=>jt.resolvePageHeadTitle(i.value,a.value)),p=k(()=>jt.resolvePageHead(d.value,u.value,a.value)),m=k(()=>jt.resolvePageLang(i.value,a.value)),g=k(()=>jt.resolvePageLayout(i.value,s.value)),E={layouts:s,pageData:i,pageComponent:c,pageFrontmatter:u,pageHead:p,pageHeadTitle:d,pageLang:m,pageLayout:g,redirects:mi,routeLocale:l,routePath:r,routes:Yn,siteData:In,siteLocaleData:a};return e.provide(ms,E),Object.defineProperties(e.config.globalProperties,{$frontmatter:{get:()=>u.value},$head:{get:()=>p.value},$headTitle:{get:()=>d.value},$lang:{get:()=>m.value},$page:{get:()=>i.value},$routeLocale:{get:()=>l.value},$site:{get:()=>In.value},$siteLocale:{get:()=>a.value},$withBase:{get:()=>Ne}}),E},Gm=()=>{const e=Lp(),t=hi();let n=[];const r=()=>{e.value.forEach(l=>{const a=Km(l);a&&n.push(a)})},o=()=>{const l=[];return e.value.forEach(a=>{const c=Ym(a);c&&l.push(c)}),l},s=()=>{document.documentElement.lang=t.value;const l=o();n.forEach((a,c)=>{const i=l.findIndex(u=>a.isEqualNode(u));i===-1?(a.remove(),delete n[c]):l.splice(i,1)}),l.forEach(a=>document.head.appendChild(a)),n=[...n.filter(a=>!!a),...l]};un(Ip,s),_e(()=>{r(),ie(e,s,{immediate:!1})})},Km=([e,t,n=""])=>{const r=Object.entries(t).map(([a,c])=>xe(c)?`[${a}=${JSON.stringify(c)}]`:c===!0?`[${a}]`:"").join(""),o=`head > ${e}${r}`;return Array.from(document.querySelectorAll(o)).find(a=>a.innerText===n)||null},Ym=([e,t,n])=>{if(!xe(e))return null;const r=document.createElement(e);return Gr(t)&&Object.entries(t).forEach(([o,s])=>{xe(s)?r.setAttribute(o,s):s===!0&&r.setAttribute(o,"")}),xe(n)&&r.appendChild(document.createTextNode(n)),r},Jm=ud,Qm=async()=>{var n;const e=Jm({name:"Vuepress",setup(){var s;Gm();for(const l of Tr)(s=l.setup)==null||s.call(l);const r=Tr.flatMap(({rootComponents:l=[]})=>l.map(a=>f(a))),o=Rp();return()=>[f(o.value),r]}}),t=Wm();Um(e),qm(e,t,Tr);for(const r of Tr)await((n=r.enhance)==null?void 0:n.call(r,{app:e,router:t,siteData:In}));return e.use(t),{app:e,router:t}};Qm().then(({app:e,router:t})=>{t.isReady().then(()=>{e.mount("#app")})});export{Wa as a,Ce as b,Zm as c,Qm as createVueApp,Ua as d,eg as e,Xm as o,rt as r,Au as w}; function __vite__mapDeps(indexes) { if (!__vite__mapDeps.viteFileDeps) { - __vite__mapDeps.viteFileDeps = ["assets/index.html-BGgB7rPy.js","assets/plugin-vue_export-helper-DlAUqK2U.js","assets/faq.html-wlteNg54.js","assets/intro.html-Bxgg0fO6.js","assets/index.html-BodtrdFm.js","assets/editors.html-C8UZnhJf.js","assets/index.html-D031wELU.js","assets/api_rust.html-CzB0Dlbt.js","assets/api_typescript.html-BMmh0oGQ.js","assets/design.html-CubwsOM8.js","assets/ref_broadcast-wOf-j1_D.js","assets/future_work.html-CaNaLhGO.js","assets/p2p_broadcast-DKREXEsi.js","assets/scripts.html-Bu-kSnJq.js","assets/index.html-D-JN27_M.js","assets/rpc_firewall.html-DXKxw1oe.js","assets/web3_rust.html-CtlHbOSD.js","assets/full_setup.html-D9U11CgD.js","assets/install.html-B3JszHVu.js","assets/npm_only.html-BS4zMMEQ.js","assets/runtime_only.html-BWVPrZKz.js","assets/index.html-CBpta1zV.js","assets/api_rust.html-jR6an_Pz.js","assets/api_typescript.html-BqGWlZzf.js","assets/design.html-BrbpjE_m.js","assets/future_work.html-Dp7HikED.js","assets/scripts.html-DkAQ2N11.js","assets/404.html-BL0QzlcP.js","assets/index.html-3uUFhvd2.js"] + __vite__mapDeps.viteFileDeps = ["assets/index.html-CnguV0tX.js","assets/plugin-vue_export-helper-DlAUqK2U.js","assets/faq.html-CV8sl42E.js","assets/intro.html-BxGuE4wy.js","assets/index.html-BVUfEJTo.js","assets/editors.html-CNXsfcsu.js","assets/index.html-BWOMH9gB.js","assets/rpc_firewall.html-D9Yd1Ah_.js","assets/web3_rust.html-DrfE3oTr.js","assets/index.html-CEa4pTjw.js","assets/api_rust.html-B1fR_PmW.js","assets/api_typescript.html-CDBTYfuZ.js","assets/design.html-84EaReMx.js","assets/ref_broadcast-BFGBhm9s.js","assets/future_work.html-Cj0rm1Vd.js","assets/p2p_broadcast-DKREXEsi.js","assets/scripts.html-Dj-m4wYR.js","assets/full_setup.html-Cez3e24z.js","assets/install.html-BAMq21Zx.js","assets/npm_only.html-BApcLSxE.js","assets/runtime_only.html-CuZ2LIXr.js","assets/index.html-CBcd5KzL.js","assets/api_rust.html-DgeZ6cWi.js","assets/api_typescript.html-CShx0BZb.js","assets/design.html-BDTT4CCh.js","assets/future_work.html-B07VTehy.js","assets/scripts.html-BZkBrHbZ.js","assets/404.html-2OslWyTj.js","assets/index.html-B8jhZ03x.js"] } return indexes.map((i) => __vite__mapDeps.viteFileDeps[i]) } diff --git a/assets/design.html-84EaReMx.js b/assets/design.html-84EaReMx.js new file mode 100644 index 0000000..416261a --- /dev/null +++ b/assets/design.html-84EaReMx.js @@ -0,0 +1,14 @@ +import{_ as r,a as l,b as c,c as d,d as p,e as h,f as u}from"./ref_broadcast-BFGBhm9s.js";import{_ as g}from"./plugin-vue_export-helper-DlAUqK2U.js";import{r as o,o as m,c as f,a as e,d as t,b as a,w as b,e as i}from"./app-BnFZaCe1.js";const v={},y=e("h2",{id:"target-audience",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#target-audience"},[e("span",null,"Target Audience")])],-1),w=e("p",null,"Developers should first read the API they intend to use.",-1),_=e("p",null,"This document is for developers curious about DTP inner works.",-1),T=e("h2",{id:"at-high-level-how-is-the-sui-network-used",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#at-high-level-how-is-the-sui-network-used"},[e("span",null,"At high level, how is the Sui Network used?")])],-1),k={href:"https://docs.sui.io/concepts/transactions/transaction-lifecycle",target:"_blank",rel:"noopener noreferrer"},P=i('

Data Ingress: A data stream is sliced into transactions (txns) and added to the Sui network. The txns are targeted to a destination Pipe (owned object).

Data egress: The data "exit" the network through event streams (emitted by the txns executed for the destination Pipe). The data can be "observed" by any users, but decoded only by the ones having the decryption key.

The receiving end DTP SDK re-assembles the txns into the original data stream. The stream is then forwarded to the intended end-user (a TCP server, a Rust application layer above etc...).

Slower transactions (Sui consensus) are used for most "control plane" synchronizations (e.g. opening a connection)

DTP Glossary

Client: An application that initiate a connection.

Connection: One connection allows exchanging data between two applications. The applications are localized by their Host object on the Sui network. A connection will start to exchange data only after a Transport Control and one or two Pipe objects are created (for uni or bidirectional transfer respectively).

Host Object: Any signature authority that want to transfer data must create its own Host object. This object is involved in many control plane transactions. It allows to configure the services (and SLA) that are to be provided and control some firewall functions (e.g. limit maximum number of simultaneous open connections).

',9),x=e("strong",null,"Objects:",-1),D={href:"https://docs.sui.io/concepts/object-model",target:"_blank",rel:"noopener noreferrer"},S=i('

Pipe Object: All off-chain data exchange involves an intermediate object on the Sui network. This object is the Pipe. It is owned by the sender of the data, and have its event stream observed by the receiver(s). A Pipe is loosely coupled to a Transport or Broadcast Control object for synchronization.

Server: Off-chain process intended to respond to client requests.

Service Level Agreement (SLA): Specify the costs, limitations and some behaviors for a service provided by a Host object. Example would be "sent data can be deleted from network storage after 48 hours (2 epochs)". The client signifies that it agrees to an SLA at the time the connection to the node is initiated. The SLA specs are such that DTP can enforce the agreement fairly to all parties.

Transport Control Object: Variables and state machines that exists for the lifetime of a single connection. This is a Sui shared object.

Firewall

(1) Gas cost of processing incoming traffic is paid by the sender. That includes connection creation cost and running the firewall at the Pipe Object. Most abuse can therefore be neutralized without requiring any processing/cost from the Server.

Firewall functionality also includes back pressure management to minimize initiating/paying for transactions while the server is already known offline or too busy.

(2) Optionally, the DTP Host object gather statistics from all its Pipe objects and can adjust the traffic policies, as an example to block an abusing sender. (Note: Synchronization with owned object is a logical representation. See Non-Blocking Data Plane for more design details).

(3) The server configure the firewall and does a periodical heartbeat using its shared DTP Host object. The DTP services daemon can also be configured to further actively control the firewall depending of its load (TBD).

(4) When a transmission is block because of the firewall, there is no event emitted (and sender is informed with a transaction error). Statistics are accumulated, but the Server is not impacted.

Non-Blocking Data Plane

The owned objects on the data plane (e.g. Pipe) need to synchronize periodically with the control plane. This is for forwarding traffic statistic, apply latest firewall commands and bring the escrows to resolution.

The control plane typically uses shared object. Involving a single Pipe object with a slow consensus would cause a 2-3 seconds blocking of the data plane. This is unacceptable if streaming audio/video.

Therefore, a owned Pipe is actually assisted by InnerPipe owned objects. The synchronization between InnerPipe and the slower control plane is done in two steps.

  1. Each InnerPipe is sequentially "fast synch" with its related Pipe (all fast path).
  2. The Pipe object is "slow synch" with the control plane. This is a consensus transaction.

With this design, the data plane flows at "full speed" while keeping all objects eventually synchronized.

The receiver re-assemble the data stream from what is observed from all flowing InnerPipes (DTP has sequence numbers for re-ordering).

A fast path sync looks like:

  fun fast_sync( pipe: &mut Pipe, inner_pipe: &mut InnerPipe ) 
+  {
+    // ... quickly exchange data plane stats, latest control plane commands etc...
+  }
+

The slow consensus sync is:

  fun slow_sync( pipe: &mut Pipe,                  
+                 transport_control: &mut TransportControl )
+  {
+    // ... does slow control plane operation ...
+  }
+

The fast path data flowing is:

  fun fast_data_send(inner_pipe: &mut InnerPipe, data: vector<u8>) 
+  {
+    // ... does a fast data plane transmission ...
+  }
+

Of course, the sender has to be extra careful about equivocation.

Note 1: DTP "forces" the sender (Pipe/InnerPipe owner) to collaborate. An InnerPipe will automatically block when not "sufficiently" synchronized (e.g. block after 20 transaction without sync). If the sender choose to not follow the "sync" protocol, then the whole Pipe will eventually be blocked/useless. At worst, any party can "hangup" the connection and let DTP do fair final escrows resolutions.

Note 2: All this design is encapsulated within the DTP protocol and SDKs. The complexity will not be visible at the DTP API level.

Video Streaming

A media byte stream is eventually divided into transaction. A serialization of these transactions would limit quickly the bandwidth because of the Sui finality time and maximum transaction size.

To support high bandwidth, DTP uses multiple InnerPipes for parallel fast path transactions (See Non-Blocking Data Plane).

Most of the complexity is handled off-chain by DTP when dividing and re-assembling the transactions into a data stream.

Will this be practical? There is still some cost/performance/implementation unknowns that might persist until DTP is further develop...

Gas might get too expensive, there is also some potential issues with Sui fullnodes performance... (problem at egress of the network, not with the consensus performance itself).

`,34),j={href:"https://docs.google.com/spreadsheets/d/1zBrB1ifhPpnLlsDr6nBN_N55Kkw9hX06a7EVUpogyn4/edit?usp=sharing",target:"_blank",rel:"noopener noreferrer"},q=i('

(Note: Numbers are best guess as of 02/14/24. Will be revised from time to time)

High-Availability and Load Balancing

Forwarding decision made by Pipe object when multiple end-points (servers)

Off-chain servers can share the incoming load or be each other's fallback for high-availability.

Unlike traditional network, the data is not physically pushed toward a server. Instead, the data remains on the network and an event is emitted about who should "pull it".

It is an off-chain responsibility for the application to subscribe to their respective event stream (with proper identifier filtering) and normally retrieve only its assigned data (this change in some recovery scenario).

Configuration of the end-points and health of the servers is managed through the DTP node, which in turn updates all its pipes and transport control objects.

DTP will hide the high complexity of many race conditions (assignment to a server that died) and connection migrations among all end-points belonging to the same Node.

Uni-directional Transfer

Similar to bi-directionals, but with a single Pipe object for data plane to minimize cost/complexity. Control plane still bi-directional (e.g. for encryption handshake).

Uni-Directional Data Transfer

Public Broadcasting

Similar to unidirectional, but without encryption and using Broadcast objects instead of a Pipe&Transport control.

Broadcasting Specific Objects

Broadcasters may require some different crypto-economic capability. Examples:

  • A live broadcast is wasteful if there is no one listening... one option will be to let DTP stop stream until there are enough fund from listeners to cover, say, the production cost of the next 1 minute. DTP would handle the automatic "on air" logic and fairly spread the cost among the contributors.
  • Listener may choose to tip a live broadcaster (for special requests?).
',16);function A(z,I){const n=o("ExternalLinkIcon"),s=o("RouteLink");return m(),f("div",null,[y,w,_,T,e("p",null,[t("Sui owned objects are used for unidirectional data transfer with sub-second latency (See "),e("a",k,[t("Fast Path Transactions"),a(n)]),t(" in Sui docs).")]),P,e("p",null,[x,t(" Usually refer to Sui objects (See "),e("a",D,[t("Sui Docs"),a(n)])]),S,e("p",null,[t("Some estimations (See on "),e("a",j,[t("Google Sheet"),a(n)]),t("):")]),q,e("p",null,[t("There are also some technical challenges particular to broadcasting (See "),a(s,{to:"/docs/future_work.html#broadcasting-challenges"},{default:b(()=>[t("Future Work")]),_:1}),t(").")])])}const O=g(v,[["render",A],["__file","design.html.vue"]]),C=JSON.parse('{"path":"/docs/design.html","title":"Design","lang":"en-US","frontmatter":{"title":"Design","contributors":true,"editLink":true,"headerDepth":0,"description":"Target Audience Developers should first read the API they intend to use. This document is for developers curious about DTP inner works. At high level, how is the Sui Network use...","head":[["meta",{"property":"og:url","content":"https://dtp.dev/docs/design.html"}],["meta",{"property":"og:site_name","content":"Decentralized Transport Protocol"}],["meta",{"property":"og:title","content":"Design"}],["meta",{"property":"og:description","content":"Target Audience Developers should first read the API they intend to use. This document is for developers curious about DTP inner works. At high level, how is the Sui Network use..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:image","content":"https://dtp.dev/assets/images/design_terms.png?url"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2024-02-16T03:13:55.000Z"}],["meta",{"name":"twitter:card","content":"summary_large_image"}],["meta",{"name":"twitter:image:alt","content":"Design"}],["meta",{"property":"article:author","content":"dtp.dev"}],["meta",{"property":"article:modified_time","content":"2024-02-16T03:13:55.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Design\\",\\"image\\":[\\"https://dtp.dev/assets/images/design_terms.png?url\\",\\"https://dtp.dev/assets/images/ref_firewall.png?url\\",\\"https://dtp.dev/assets/images/multi_channel_est.png?url\\",\\"https://dtp.dev/assets/images/ref_ha.png?url\\",\\"https://dtp.dev/assets/images/ref_uni.png?url\\",\\"https://dtp.dev/assets/images/ref_broadcast.png?url\\"],\\"dateModified\\":\\"2024-02-16T03:13:55.000Z\\",\\"author\\":[{\\"@type\\":\\"Person\\",\\"name\\":\\"dtp.dev\\",\\"url\\":\\"https://dtp.dev\\"}]}"]]},"headers":[{"level":2,"title":"Target Audience","slug":"target-audience","link":"#target-audience","children":[]},{"level":2,"title":"At high level, how is the Sui Network used?","slug":"at-high-level-how-is-the-sui-network-used","link":"#at-high-level-how-is-the-sui-network-used","children":[]},{"level":2,"title":"DTP Glossary","slug":"dtp-glossary","link":"#dtp-glossary","children":[]},{"level":2,"title":"Firewall","slug":"firewall","link":"#firewall","children":[]},{"level":2,"title":"Non-Blocking Data Plane","slug":"non-blocking-data-plane","link":"#non-blocking-data-plane","children":[]},{"level":2,"title":"Video Streaming","slug":"video-streaming","link":"#video-streaming","children":[]},{"level":2,"title":"High-Availability and Load Balancing","slug":"high-availability-and-load-balancing","link":"#high-availability-and-load-balancing","children":[]},{"level":2,"title":"Uni-directional Transfer","slug":"uni-directional-transfer","link":"#uni-directional-transfer","children":[]},{"level":2,"title":"Public Broadcasting","slug":"public-broadcasting","link":"#public-broadcasting","children":[]}],"git":{"createdTime":1707880270000,"updatedTime":1708053235000,"contributors":[{"name":"mario4tier","email":"mario4tier@users.noreply.github.com","commits":4}]},"readingTime":{"minutes":4.89,"words":1467},"filePathRelative":"docs/design.md","localizedDate":"February 14, 2024","autoDesc":true}');export{O as comp,C as data}; diff --git a/assets/design.html-BDTT4CCh.js b/assets/design.html-BDTT4CCh.js new file mode 100644 index 0000000..759527c --- /dev/null +++ b/assets/design.html-BDTT4CCh.js @@ -0,0 +1,14 @@ +import{_ as r,a as l,b as c,c as d,d as p,e as h,f as u}from"./ref_broadcast-BFGBhm9s.js";import{_ as g}from"./plugin-vue_export-helper-DlAUqK2U.js";import{r as o,o as m,c as f,a as e,d as t,b as n,w as b,e as i}from"./app-BnFZaCe1.js";const v={},y=e("h2",{id:"target-audience",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#target-audience"},[e("span",null,"Target Audience")])],-1),w=e("p",null,"Developers should first read the API they intend to use.",-1),_=e("p",null,"This document is for developers curious about DTP inner works.",-1),T=e("h2",{id:"at-high-level-how-is-the-sui-network-used",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#at-high-level-how-is-the-sui-network-used"},[e("span",null,"At high level, how is the Sui Network used?")])],-1),k={href:"https://docs.sui.io/concepts/transactions/transaction-lifecycle",target:"_blank",rel:"noopener noreferrer"},P=i('

Data Ingress: A data stream is sliced into transactions (txns) and added to the Sui network. The txns are targeted to a destination Pipe (owned object).

Data egress: The data "exit" the network through event streams (emitted by the txns executed for the destination Pipe). The data can be "observed" by any users, but decoded only by the ones having the decryption key.

The receiving end DTP SDK re-assembles the txns into the original data stream. The stream is then forwarded to the intended end-user (a TCP server, a Rust application layer above etc...).

Slower transactions (Sui consensus) are used for most "control plane" synchronizations (e.g. opening a connection)

DTP Glossary

Client: An application that initiate a connection.

Connection: One connection allows exchanging data between two applications. The applications are localized by their Host object on the Sui network. A connection will start to exchange data only after a Transport Control and one or two Pipe objects are created (for uni or bidirectional transfer respectively).

Host Object: Any signature authority that want to transfer data must create its own Host object. This object is involved in many control plane transactions. It allows to configure the services (and SLA) that are to be provided and control some firewall functions (e.g. limit maximum number of simultaneous open connections).

',9),x=e("strong",null,"Objects:",-1),D={href:"https://docs.sui.io/concepts/object-model",target:"_blank",rel:"noopener noreferrer"},S=i('

Pipe Object: All off-chain data exchange involves an intermediate object on the Sui network. This object is the Pipe. It is owned by the sender of the data, and have its event stream observed by the receiver(s). A Pipe is loosely coupled to a Transport or Broadcast Control object for synchronization.

Server: Off-chain process intended to respond to client requests.

Service Level Agreement (SLA): Specify the costs, limitations and some behaviors for a service provided by a Host object. Example would be "sent data can be deleted from network storage after 48 hours (2 epochs)". The client signifies that it agrees to an SLA at the time the connection to the node is initiated. The SLA specs are such that DTP can enforce the agreement fairly to all parties.

Transport Control Object: Variables and state machines that exists for the lifetime of a single connection. This is a Sui shared object.

Firewall

(1) Gas cost of processing incoming traffic is paid by the sender. That includes connection creation cost and running the firewall at the Pipe Object. Most abuse can therefore be neutralized without requiring any processing/cost from the Server.

Firewall functionality also includes back pressure management to minimize initiating/paying for transactions while the server is already known offline or too busy.

(2) Optionally, the DTP Host object gather statistics from all its Pipe objects and can adjust the traffic policies, as an example to block an abusing sender. (Note: Synchronization with owned object is a logical representation. See Non-Blocking Data Plane for more design details).

(3) The server configure the firewall and does a periodical heartbeat using its shared DTP Host object. The DTP services daemon can also be configured to further actively control the firewall depending of its load (TBD).

(4) When a transmission is block because of the firewall, there is no event emitted (and sender is informed with a transaction error). Statistics are accumulated, but the Server is not impacted.

Non-Blocking Data Plane

The owned objects on the data plane (e.g. Pipe) need to synchronize periodically with the control plane. This is for forwarding traffic statistic, apply latest firewall commands and bring the escrows to resolution.

The control plane typically uses shared object. Involving a single Pipe object with a slow consensus would cause a 2-3 seconds blocking of the data plane. This is unacceptable if streaming audio/video.

Therefore, a owned Pipe is actually assisted by InnerPipe owned objects. The synchronization between InnerPipe and the slower control plane is done in two steps.

  1. Each InnerPipe is sequentially "fast synch" with its related Pipe (all fast path).
  2. The Pipe object is "slow synch" with the control plane. This is a consensus transaction.

With this design, the data plane flows at "full speed" while keeping all objects eventually synchronized.

The receiver re-assemble the data stream from what is observed from all flowing InnerPipes (DTP has sequence numbers for re-ordering).

A fast path sync looks like:

  fun fast_sync( pipe: &mut Pipe, inner_pipe: &mut InnerPipe ) 
+  {
+    // ... quickly exchange data plane stats, latest control plane commands etc...
+  }
+

The slow consensus sync is:

  fun slow_sync( pipe: &mut Pipe,                  
+                 transport_control: &mut TransportControl )
+  {
+    // ... does slow control plane operation ...
+  }
+

The fast path data flowing is:

  fun fast_data_send(inner_pipe: &mut InnerPipe, data: vector<u8>) 
+  {
+    // ... does a fast data plane transmission ...
+  }
+

Of course, the sender has to be extra careful about equivocation.

Note 1: DTP "forces" the sender (Pipe/InnerPipe owner) to collaborate. An InnerPipe will automatically block when not "sufficiently" synchronized (e.g. block after 20 transaction without sync). If the sender choose to not follow the "sync" protocol, then the whole Pipe will eventually be blocked/useless. At worst, any party can "hangup" the connection and let DTP do fair final escrows resolutions.

Note 2: All this design is encapsulated within the DTP protocol and SDKs. The complexity will not be visible at the DTP API level.

Video Streaming

A media byte stream is eventually divided into transaction. A serialization of these transactions would limit quickly the bandwidth because of the Sui finality time and maximum transaction size.

To support high bandwidth, DTP uses multiple InnerPipes for parallel fast path transactions (See Non-Blocking Data Plane).

Most of the complexity is handled off-chain by DTP when dividing and re-assembling the transactions into a data stream.

Will this be practical? There is still some cost/performance/implementation unknowns that might persist until DTP is further develop...

Gas might get too expensive, there is also some potential issues with Sui fullnodes performance... (problem at egress of the network, not with the consensus performance itself).

`,34),j={href:"https://docs.google.com/spreadsheets/d/1zBrB1ifhPpnLlsDr6nBN_N55Kkw9hX06a7EVUpogyn4/edit?usp=sharing",target:"_blank",rel:"noopener noreferrer"},q=i('

(Note: Numbers are best guess as of 02/14/24. Will be revised from time to time)

High-Availability and Load Balancing

Forwarding decision made by Pipe object when multiple end-points (servers)

Off-chain servers can share the incoming load or be each other's fallback for high-availability.

Unlike traditional network, the data is not physically pushed toward a server. Instead, the data remains on the network and an event is emitted about who should "pull it".

It is an off-chain responsibility for the application to subscribe to their respective event stream (with proper identifier filtering) and normally retrieve only its assigned data (this change in some recovery scenario).

Configuration of the end-points and health of the servers is managed through the DTP node, which in turn updates all its pipes and transport control objects.

DTP will hide the high complexity of many race conditions (assignment to a server that died) and connection migrations among all end-points belonging to the same Node.

Uni-directional Transfer

Similar to bi-directionals, but with a single Pipe object for data plane to minimize cost/complexity. Control plane still bi-directional (e.g. for encryption handshake).

Uni-Directional Data Transfer

Public Broadcasting

Similar to unidirectional, but without encryption and using Broadcast objects instead of a Pipe&Transport control.

Broadcasting Specific Objects

Broadcasters may require some different crypto-economic capability. Examples:

  • A live broadcast is wasteful if there is no one listening... one option will be to let DTP stop stream until there are enough fund from listeners to cover, say, the production cost of the next 1 minute. DTP would handle the automatic "on air" logic and fairly spread the cost among the contributors.
  • Listener may choose to tip a live broadcaster (for special requests?).
',16);function A(I,z){const a=o("ExternalLinkIcon"),s=o("RouteLink");return m(),f("div",null,[y,w,_,T,e("p",null,[t("Sui owned objects are used for unidirectional data transfer with sub-second latency (See "),e("a",k,[t("Fast Path Transactions"),n(a)]),t(" in Sui docs).")]),P,e("p",null,[x,t(" Usually refer to Sui objects (See "),e("a",D,[t("Sui Docs"),n(a)])]),S,e("p",null,[t("Some estimations (See on "),e("a",j,[t("Google Sheet"),n(a)]),t("):")]),q,e("p",null,[t("There are also some technical challenges particular to broadcasting (See "),n(s,{to:"/ref/future_work.html#broadcasting-challenges"},{default:b(()=>[t("Future Work")]),_:1}),t(").")])])}const O=g(v,[["render",A],["__file","design.html.vue"]]),C=JSON.parse('{"path":"/ref/design.html","title":"Design","lang":"en-US","frontmatter":{"title":"Design","contributors":true,"editLink":true,"headerDepth":0,"description":"Target Audience Developers should first read the API they intend to use. This document is for developers curious about DTP inner works. At high level, how is the Sui Network use...","head":[["meta",{"property":"og:url","content":"https://dtp.dev/ref/design.html"}],["meta",{"property":"og:site_name","content":"Decentralized Transport Protocol"}],["meta",{"property":"og:title","content":"Design"}],["meta",{"property":"og:description","content":"Target Audience Developers should first read the API they intend to use. This document is for developers curious about DTP inner works. At high level, how is the Sui Network use..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:image","content":"https://dtp.dev/assets/images/design_terms.png?url"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"name":"twitter:card","content":"summary_large_image"}],["meta",{"name":"twitter:image:alt","content":"Design"}],["meta",{"property":"article:author","content":"dtp.dev"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Design\\",\\"image\\":[\\"https://dtp.dev/assets/images/design_terms.png?url\\",\\"https://dtp.dev/assets/images/ref_firewall.png?url\\",\\"https://dtp.dev/assets/images/multi_channel_est.png?url\\",\\"https://dtp.dev/assets/images/ref_ha.png?url\\",\\"https://dtp.dev/assets/images/ref_uni.png?url\\",\\"https://dtp.dev/assets/images/ref_broadcast.png?url\\"],\\"dateModified\\":null,\\"author\\":[{\\"@type\\":\\"Person\\",\\"name\\":\\"dtp.dev\\",\\"url\\":\\"https://dtp.dev\\"}]}"]]},"headers":[{"level":2,"title":"Target Audience","slug":"target-audience","link":"#target-audience","children":[]},{"level":2,"title":"At high level, how is the Sui Network used?","slug":"at-high-level-how-is-the-sui-network-used","link":"#at-high-level-how-is-the-sui-network-used","children":[]},{"level":2,"title":"DTP Glossary","slug":"dtp-glossary","link":"#dtp-glossary","children":[]},{"level":2,"title":"Firewall","slug":"firewall","link":"#firewall","children":[]},{"level":2,"title":"Non-Blocking Data Plane","slug":"non-blocking-data-plane","link":"#non-blocking-data-plane","children":[]},{"level":2,"title":"Video Streaming","slug":"video-streaming","link":"#video-streaming","children":[]},{"level":2,"title":"High-Availability and Load Balancing","slug":"high-availability-and-load-balancing","link":"#high-availability-and-load-balancing","children":[]},{"level":2,"title":"Uni-directional Transfer","slug":"uni-directional-transfer","link":"#uni-directional-transfer","children":[]},{"level":2,"title":"Public Broadcasting","slug":"public-broadcasting","link":"#public-broadcasting","children":[]}],"git":{"createdTime":null,"updatedTime":null,"contributors":[]},"readingTime":{"minutes":4.89,"words":1467},"filePathRelative":"ref/design.md","autoDesc":true}');export{O as comp,C as data}; diff --git a/assets/design.html-BrbpjE_m.js b/assets/design.html-BrbpjE_m.js deleted file mode 100644 index 3d2f0a2..0000000 --- a/assets/design.html-BrbpjE_m.js +++ /dev/null @@ -1,11 +0,0 @@ -import{_ as r,a as l,b as c,c as d,d as h,e as p,f as u}from"./ref_broadcast-wOf-j1_D.js";import{_ as g}from"./plugin-vue_export-helper-DlAUqK2U.js";import{r as o,o as m,c as f,a as e,d as t,b as n,w as b,e as i}from"./app-CKXWWpf0.js";const v={},y=e("h2",{id:"target-audience",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#target-audience"},[e("span",null,"Target Audience")])],-1),w=e("p",null,"Developers should first read the API they intend to use.",-1),_=e("p",null,"This document is for developers curious about DTP inner works.",-1),k=e("h2",{id:"at-high-level-how-is-the-sui-network-used",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#at-high-level-how-is-the-sui-network-used"},[e("span",null,"At high level, how is the Sui Network used?")])],-1),T={href:"https://docs.sui.io/concepts/transactions/transaction-lifecycle",target:"_blank",rel:"noopener noreferrer"},P=i('

Data Ingress: A data stream is sliced into transactions (txns) and added to the Sui network. The txns are targeted to a destination Pipe (owned object).

Data egress: The data "exit" the network through event streams (emitted by the txns executed for the destination Pipe). The data can be "observed" by any users, but decoded only by the ones having the decryption key.

The receiving end DTP SDK re-assembles the txns into the original data stream. The stream is then forwarded to the intended end-user (a TCP server, a Rust application layer above etc...).

Slower transactions (Sui consensus) are used for most "control plane" synchronizations (e.g. opening a connection)

DTP Glossary

Client: An application that initiate a connection.

Connection: One connection allows exchanging data between two applications. The applications are localized by their Host object on the Sui network. A connection will start to exchange data only after a Transport Control and one or two Pipe objects are created (for uni or bidirectional transfer respectively).

Host Object: Any signature authority that want to transfer data must create its own Host object. This object is involved in many control plane transactions. It allows to configure the services (and SLA) that are to be provided and control some firewall functions (e.g. limit maximum number of simultaneous open connections).

',9),x=e("strong",null,"Objects:",-1),S={href:"https://docs.sui.io/concepts/object-model",target:"_blank",rel:"noopener noreferrer"},D=i('

Pipe Object: All off-chain data exchange involves an intermediate object on the Sui network. This object is the Pipe. It is owned by the sender of the data, and have its event stream observed by the receiver(s). A Pipe is loosely coupled to a Transport or Broadcast Control object for synchronization.

Server: Off-chain process intended to respond to client requests.

Service Level Agreement (SLA): Specify the costs, limitations and some behaviors for a service provided by a Host object. Example would be "sent data can be deleted from network storage after 48 hours (2 epochs)". The client signifies that it agrees to an SLA at the time the connection to the node is initiated. The SLA specs are such that DTP can enforce the agreement fairly to all parties.

Transport Control Object: Variables and state machines that exists for the lifetime of a single connection. This is a Sui shared object.

Firewall

(1) Gas cost of processing incoming traffic is paid by the sender. That includes connection creation cost and running the firewall at the Pipe Object. Most abuse can therefore be neutralized without requiring any processing/cost from the Server.

Firewall functionality also includes back pressure management to minimize initiating/paying for transactions while the server is already known offline or too busy.

(2) Optionally, the DTP Host object gather statistics from all its Pipe objects and can adjust the traffic policies, as an example to block an abusing sender. (Note: Synchronization with owned object is a logical representation. See Non-Blocking Data Plane for more design details).

(3) The server configure the firewall and does a periodical heartbeat using its shared DTP Host object. The DTP services daemon can also be configured to further actively control the firewall depending of its load (TBD).

(4) When a transmission is block because of the firewall, there is no event emitted (and sender is informed with a transaction error). Statistics are accumulated, but the Server is not impacted.

Non-Blocking Data Plane

A single owned Pipe object used as part of a transaction requiring slow consensus would cause a blocking of the data plane in the order of seconds. This is unacceptable if streaming audio/video.

Therefore, a DTP Pipe is actually composed of independent InnerPipe owned objects. One InnerPipe can be block and used as part of a slow consensus while the others keeps "flowing" with fast path transactions.

The receiver will re-assemble the data stream coming from all flowing InnerPipes (does not matter which one, DTP has sequence numbers for re-ordering).

Note: Every InnerPipe needs periodical synchronization with the control plane to exchange statistics and enforce traffic rules. DTP "forces" the sender (object owner) to collaborate by making an InnerPipe automatically blocked if not recently synchronized with the control plane. If the sender choose to not follow the "sync" protocol, then the whole Pipe will eventually be blocked.

A Sui slow consensus synchronization will look like this:

  fun slow_sync( pipe: &mut Pipe, 
-                 inner_pipe: &mut InnerPipe, 
-                 transport_control: &mut TransportControl )
-  {
-    // ... does a slow control plane operation ...
-  }
-

A Sui fast path transaction will be:

  fun fast_data_send(inner_pipe: &mut InnerPipe, data: vector<u8>) 
-  {
-    // ... does a fast data plane transmission ...
-  }
-

Video Streaming

A media byte stream is eventually divided into transaction. A serialization of these transactions would limit quickly the bandwidth because of the Sui finality time and maximum transaction size.

To support high bandwidth, DTP uses multiple InnerPipes for parallel fast path transactions (See Non-Blocking Data Plane).

Most of the complexity is handled off-chain by DTP when dividing and re-assembling the transactions into a data stream.

Will this be practical? There is still some cost/performance/implementation unknowns that might persist until DTP is further develop...

Gas might get too expensive, there is also some potential issues with Sui fullnodes performance... (problem at egress of the network, not with the consensus performance itself).

`,27),j={href:"https://docs.google.com/spreadsheets/d/1zBrB1ifhPpnLlsDr6nBN_N55Kkw9hX06a7EVUpogyn4/edit?usp=sharing",target:"_blank",rel:"noopener noreferrer"},A=i('

(Note: Numbers are best guess as of 02/14/24. Will be revised from time to time)

High-Availability and Load Balancing

Forwarding decision made by Pipe object when multiple end-points (servers)

Off-chain servers can share the incoming load or be each other's fallback for high-availability.

Unlike traditional network, the data is not physically pushed toward a server. Instead, the data remains on the network and an event is emitted about who should "pull it".

It is an off-chain responsibility for the application to subscribe to their respective event stream (with proper identifier filtering) and normally retrieve only its assigned data (this change in some recovery scenario).

Configuration of the end-points and health of the servers is managed through the DTP node, which in turn updates all its pipes and transport control objects.

DTP will hide the high complexity of many race conditions (assignment to a server that died) and connection migrations among all end-points belonging to the same Node.

Uni-directional Transfer

Similar to bi-directionals, but with a single Pipe object for data plane to minimize cost/complexity. Control plane still bi-directional (e.g. for encryption handshake).

Uni-Directional Data Transfer

Public Broadcasting

Similar to unidirectional, but without encryption and using Broadcast objects instead of a Pipe&Transport control.

Broadcasting Specific Objects

Broadcasters may require some different crypto-economic capability. Examples:

  • A live broadcast is wasteful if there is no one listening... one option will be to let DTP stop stream until there are enough fund from listeners to cover, say, the production cost of the next 1 minute. DTP would handle the automatic "on air" logic and fairly spread the cost among the contributors.
  • Listener may choose to tip a live broadcaster (for special requests?).
',16);function q(z,N){const a=o("ExternalLinkIcon"),s=o("RouteLink");return m(),f("div",null,[y,w,_,k,e("p",null,[t("Sui owned objects are used for unidirectional data transfer with sub-second latency (See "),e("a",T,[t("Fast Path Transactions"),n(a)]),t(" in Sui docs).")]),P,e("p",null,[x,t(" Usually refer to Sui objects (See "),e("a",S,[t("Sui Docs"),n(a)])]),D,e("p",null,[t("Some estimations (See on "),e("a",j,[t("Google Sheet"),n(a)]),t("):")]),A,e("p",null,[t("There are also some technical challenges particular to broadcasting (See "),n(s,{to:"/ref/future_work.html#broadcasting-challenges"},{default:b(()=>[t("Future Work")]),_:1}),t(").")])])}const O=g(v,[["render",q],["__file","design.html.vue"]]),C=JSON.parse('{"path":"/ref/design.html","title":"Design","lang":"en-US","frontmatter":{"title":"Design","contributors":true,"editLink":true,"headerDepth":0,"description":"Target Audience Developers should first read the API they intend to use. This document is for developers curious about DTP inner works. At high level, how is the Sui Network use...","head":[["meta",{"property":"og:url","content":"https://dtp.dev/ref/design.html"}],["meta",{"property":"og:site_name","content":"Decentralized Transport Protocol"}],["meta",{"property":"og:title","content":"Design"}],["meta",{"property":"og:description","content":"Target Audience Developers should first read the API they intend to use. This document is for developers curious about DTP inner works. At high level, how is the Sui Network use..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:image","content":"https://dtp.dev/assets/images/design_terms.png?url"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"name":"twitter:card","content":"summary_large_image"}],["meta",{"name":"twitter:image:alt","content":"Design"}],["meta",{"property":"article:author","content":"dtp.dev"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Design\\",\\"image\\":[\\"https://dtp.dev/assets/images/design_terms.png?url\\",\\"https://dtp.dev/assets/images/ref_firewall.png?url\\",\\"https://dtp.dev/assets/images/multi_channel_est.png?url\\",\\"https://dtp.dev/assets/images/ref_ha.png?url\\",\\"https://dtp.dev/assets/images/ref_uni.png?url\\",\\"https://dtp.dev/assets/images/ref_broadcast.png?url\\"],\\"dateModified\\":null,\\"author\\":[{\\"@type\\":\\"Person\\",\\"name\\":\\"dtp.dev\\",\\"url\\":\\"https://dtp.dev\\"}]}"]]},"headers":[{"level":2,"title":"Target Audience","slug":"target-audience","link":"#target-audience","children":[]},{"level":2,"title":"At high level, how is the Sui Network used?","slug":"at-high-level-how-is-the-sui-network-used","link":"#at-high-level-how-is-the-sui-network-used","children":[]},{"level":2,"title":"DTP Glossary","slug":"dtp-glossary","link":"#dtp-glossary","children":[]},{"level":2,"title":"Firewall","slug":"firewall","link":"#firewall","children":[]},{"level":2,"title":"Non-Blocking Data Plane","slug":"non-blocking-data-plane","link":"#non-blocking-data-plane","children":[]},{"level":2,"title":"Video Streaming","slug":"video-streaming","link":"#video-streaming","children":[]},{"level":2,"title":"High-Availability and Load Balancing","slug":"high-availability-and-load-balancing","link":"#high-availability-and-load-balancing","children":[]},{"level":2,"title":"Uni-directional Transfer","slug":"uni-directional-transfer","link":"#uni-directional-transfer","children":[]},{"level":2,"title":"Public Broadcasting","slug":"public-broadcasting","link":"#public-broadcasting","children":[]}],"git":{"createdTime":null,"updatedTime":null,"contributors":[]},"readingTime":{"minutes":4.48,"words":1343},"filePathRelative":"ref/design.md","autoDesc":true}');export{O as comp,C as data}; diff --git a/assets/design.html-CubwsOM8.js b/assets/design.html-CubwsOM8.js deleted file mode 100644 index 9a2a477..0000000 --- a/assets/design.html-CubwsOM8.js +++ /dev/null @@ -1,11 +0,0 @@ -import{_ as r,a as l,b as c,c as d,d as p,e as h,f as u}from"./ref_broadcast-wOf-j1_D.js";import{_ as g}from"./plugin-vue_export-helper-DlAUqK2U.js";import{r as o,o as m,c as f,a as e,d as t,b as n,w as b,e as i}from"./app-CKXWWpf0.js";const v={},y=e("h2",{id:"target-audience",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#target-audience"},[e("span",null,"Target Audience")])],-1),w=e("p",null,"Developers should first read the API they intend to use.",-1),_=e("p",null,"This document is for developers curious about DTP inner works.",-1),k=e("h2",{id:"at-high-level-how-is-the-sui-network-used",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#at-high-level-how-is-the-sui-network-used"},[e("span",null,"At high level, how is the Sui Network used?")])],-1),T={href:"https://docs.sui.io/concepts/transactions/transaction-lifecycle",target:"_blank",rel:"noopener noreferrer"},P=i('

Data Ingress: A data stream is sliced into transactions (txns) and added to the Sui network. The txns are targeted to a destination Pipe (owned object).

Data egress: The data "exit" the network through event streams (emitted by the txns executed for the destination Pipe). The data can be "observed" by any users, but decoded only by the ones having the decryption key.

The receiving end DTP SDK re-assembles the txns into the original data stream. The stream is then forwarded to the intended end-user (a TCP server, a Rust application layer above etc...).

Slower transactions (Sui consensus) are used for most "control plane" synchronizations (e.g. opening a connection)

DTP Glossary

Client: An application that initiate a connection.

Connection: One connection allows exchanging data between two applications. The applications are localized by their Host object on the Sui network. A connection will start to exchange data only after a Transport Control and one or two Pipe objects are created (for uni or bidirectional transfer respectively).

Host Object: Any signature authority that want to transfer data must create its own Host object. This object is involved in many control plane transactions. It allows to configure the services (and SLA) that are to be provided and control some firewall functions (e.g. limit maximum number of simultaneous open connections).

',9),x=e("strong",null,"Objects:",-1),S={href:"https://docs.sui.io/concepts/object-model",target:"_blank",rel:"noopener noreferrer"},D=i('

Pipe Object: All off-chain data exchange involves an intermediate object on the Sui network. This object is the Pipe. It is owned by the sender of the data, and have its event stream observed by the receiver(s). A Pipe is loosely coupled to a Transport or Broadcast Control object for synchronization.

Server: Off-chain process intended to respond to client requests.

Service Level Agreement (SLA): Specify the costs, limitations and some behaviors for a service provided by a Host object. Example would be "sent data can be deleted from network storage after 48 hours (2 epochs)". The client signifies that it agrees to an SLA at the time the connection to the node is initiated. The SLA specs are such that DTP can enforce the agreement fairly to all parties.

Transport Control Object: Variables and state machines that exists for the lifetime of a single connection. This is a Sui shared object.

Firewall

(1) Gas cost of processing incoming traffic is paid by the sender. That includes connection creation cost and running the firewall at the Pipe Object. Most abuse can therefore be neutralized without requiring any processing/cost from the Server.

Firewall functionality also includes back pressure management to minimize initiating/paying for transactions while the server is already known offline or too busy.

(2) Optionally, the DTP Host object gather statistics from all its Pipe objects and can adjust the traffic policies, as an example to block an abusing sender. (Note: Synchronization with owned object is a logical representation. See Non-Blocking Data Plane for more design details).

(3) The server configure the firewall and does a periodical heartbeat using its shared DTP Host object. The DTP services daemon can also be configured to further actively control the firewall depending of its load (TBD).

(4) When a transmission is block because of the firewall, there is no event emitted (and sender is informed with a transaction error). Statistics are accumulated, but the Server is not impacted.

Non-Blocking Data Plane

A single owned Pipe object used as part of a transaction requiring slow consensus would cause a blocking of the data plane in the order of seconds. This is unacceptable if streaming audio/video.

Therefore, a DTP Pipe is actually composed of independent InnerPipe owned objects. One InnerPipe can be block and used as part of a slow consensus while the others keeps "flowing" with fast path transactions.

The receiver will re-assemble the data stream coming from all flowing InnerPipes (does not matter which one, DTP has sequence numbers for re-ordering).

Note: Every InnerPipe needs periodical synchronization with the control plane to exchange statistics and enforce traffic rules. DTP "forces" the sender (object owner) to collaborate by making an InnerPipe automatically blocked if not recently synchronized with the control plane. If the sender choose to not follow the "sync" protocol, then the whole Pipe will eventually be blocked.

A Sui slow consensus synchronization will look like this:

  fun slow_sync( pipe: &mut Pipe, 
-                 inner_pipe: &mut InnerPipe, 
-                 transport_control: &mut TransportControl )
-  {
-    // ... does a slow control plane operation ...
-  }
-

A Sui fast path transaction will be:

  fun fast_data_send(inner_pipe: &mut InnerPipe, data: vector<u8>) 
-  {
-    // ... does a fast data plane transmission ...
-  }
-

Video Streaming

A media byte stream is eventually divided into transaction. A serialization of these transactions would limit quickly the bandwidth because of the Sui finality time and maximum transaction size.

To support high bandwidth, DTP uses multiple InnerPipes for parallel fast path transactions (See Non-Blocking Data Plane).

Most of the complexity is handled off-chain by DTP when dividing and re-assembling the transactions into a data stream.

Will this be practical? There is still some cost/performance/implementation unknowns that might persist until DTP is further develop...

Gas might get too expensive, there is also some potential issues with Sui fullnodes performance... (problem at egress of the network, not with the consensus performance itself).

`,27),j={href:"https://docs.google.com/spreadsheets/d/1zBrB1ifhPpnLlsDr6nBN_N55Kkw9hX06a7EVUpogyn4/edit?usp=sharing",target:"_blank",rel:"noopener noreferrer"},A=i('

(Note: Numbers are best guess as of 02/14/24. Will be revised from time to time)

High-Availability and Load Balancing

Forwarding decision made by Pipe object when multiple end-points (servers)

Off-chain servers can share the incoming load or be each other's fallback for high-availability.

Unlike traditional network, the data is not physically pushed toward a server. Instead, the data remains on the network and an event is emitted about who should "pull it".

It is an off-chain responsibility for the application to subscribe to their respective event stream (with proper identifier filtering) and normally retrieve only its assigned data (this change in some recovery scenario).

Configuration of the end-points and health of the servers is managed through the DTP node, which in turn updates all its pipes and transport control objects.

DTP will hide the high complexity of many race conditions (assignment to a server that died) and connection migrations among all end-points belonging to the same Node.

Uni-directional Transfer

Similar to bi-directionals, but with a single Pipe object for data plane to minimize cost/complexity. Control plane still bi-directional (e.g. for encryption handshake).

Uni-Directional Data Transfer

Public Broadcasting

Similar to unidirectional, but without encryption and using Broadcast objects instead of a Pipe&Transport control.

Broadcasting Specific Objects

Broadcasters may require some different crypto-economic capability. Examples:

  • A live broadcast is wasteful if there is no one listening... one option will be to let DTP stop stream until there are enough fund from listeners to cover, say, the production cost of the next 1 minute. DTP would handle the automatic "on air" logic and fairly spread the cost among the contributors.
  • Listener may choose to tip a live broadcaster (for special requests?).
',16);function q(z,N){const a=o("ExternalLinkIcon"),s=o("RouteLink");return m(),f("div",null,[y,w,_,k,e("p",null,[t("Sui owned objects are used for unidirectional data transfer with sub-second latency (See "),e("a",T,[t("Fast Path Transactions"),n(a)]),t(" in Sui docs).")]),P,e("p",null,[x,t(" Usually refer to Sui objects (See "),e("a",S,[t("Sui Docs"),n(a)])]),D,e("p",null,[t("Some estimations (See on "),e("a",j,[t("Google Sheet"),n(a)]),t("):")]),A,e("p",null,[t("There are also some technical challenges particular to broadcasting (See "),n(s,{to:"/docs/future_work.html#broadcasting-challenges"},{default:b(()=>[t("Future Work")]),_:1}),t(").")])])}const O=g(v,[["render",q],["__file","design.html.vue"]]),C=JSON.parse('{"path":"/docs/design.html","title":"Design","lang":"en-US","frontmatter":{"title":"Design","contributors":true,"editLink":true,"headerDepth":0,"description":"Target Audience Developers should first read the API they intend to use. This document is for developers curious about DTP inner works. At high level, how is the Sui Network use...","head":[["meta",{"property":"og:url","content":"https://dtp.dev/docs/design.html"}],["meta",{"property":"og:site_name","content":"Decentralized Transport Protocol"}],["meta",{"property":"og:title","content":"Design"}],["meta",{"property":"og:description","content":"Target Audience Developers should first read the API they intend to use. This document is for developers curious about DTP inner works. At high level, how is the Sui Network use..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:image","content":"https://dtp.dev/assets/images/design_terms.png?url"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2024-02-15T22:54:53.000Z"}],["meta",{"name":"twitter:card","content":"summary_large_image"}],["meta",{"name":"twitter:image:alt","content":"Design"}],["meta",{"property":"article:author","content":"dtp.dev"}],["meta",{"property":"article:modified_time","content":"2024-02-15T22:54:53.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Design\\",\\"image\\":[\\"https://dtp.dev/assets/images/design_terms.png?url\\",\\"https://dtp.dev/assets/images/ref_firewall.png?url\\",\\"https://dtp.dev/assets/images/multi_channel_est.png?url\\",\\"https://dtp.dev/assets/images/ref_ha.png?url\\",\\"https://dtp.dev/assets/images/ref_uni.png?url\\",\\"https://dtp.dev/assets/images/ref_broadcast.png?url\\"],\\"dateModified\\":\\"2024-02-15T22:54:53.000Z\\",\\"author\\":[{\\"@type\\":\\"Person\\",\\"name\\":\\"dtp.dev\\",\\"url\\":\\"https://dtp.dev\\"}]}"]]},"headers":[{"level":2,"title":"Target Audience","slug":"target-audience","link":"#target-audience","children":[]},{"level":2,"title":"At high level, how is the Sui Network used?","slug":"at-high-level-how-is-the-sui-network-used","link":"#at-high-level-how-is-the-sui-network-used","children":[]},{"level":2,"title":"DTP Glossary","slug":"dtp-glossary","link":"#dtp-glossary","children":[]},{"level":2,"title":"Firewall","slug":"firewall","link":"#firewall","children":[]},{"level":2,"title":"Non-Blocking Data Plane","slug":"non-blocking-data-plane","link":"#non-blocking-data-plane","children":[]},{"level":2,"title":"Video Streaming","slug":"video-streaming","link":"#video-streaming","children":[]},{"level":2,"title":"High-Availability and Load Balancing","slug":"high-availability-and-load-balancing","link":"#high-availability-and-load-balancing","children":[]},{"level":2,"title":"Uni-directional Transfer","slug":"uni-directional-transfer","link":"#uni-directional-transfer","children":[]},{"level":2,"title":"Public Broadcasting","slug":"public-broadcasting","link":"#public-broadcasting","children":[]}],"git":{"createdTime":1707880270000,"updatedTime":1708037693000,"contributors":[{"name":"mario4tier","email":"mario4tier@users.noreply.github.com","commits":3}]},"readingTime":{"minutes":4.48,"words":1343},"filePathRelative":"docs/design.md","localizedDate":"February 14, 2024","autoDesc":true}');export{O as comp,C as data}; diff --git a/assets/editors.html-C8UZnhJf.js b/assets/editors.html-CNXsfcsu.js similarity index 97% rename from assets/editors.html-C8UZnhJf.js rename to assets/editors.html-CNXsfcsu.js index 0f17b17..32ba582 100644 --- a/assets/editors.html-C8UZnhJf.js +++ b/assets/editors.html-CNXsfcsu.js @@ -1,4 +1,4 @@ -import{_ as i}from"./plugin-vue_export-helper-DlAUqK2U.js";import{r as s,o as r,c as d,a as t,d as e,b as o,e as a}from"./app-CKXWWpf0.js";const c="/assets/images/propose-change.png",l={},p=t("p",null,"Anyone with a Github account can participate.",-1),h={href:"https://github.com/chainmovers/dtp/tree/main/docs",target:"_blank",rel:"noopener noreferrer"},u=a('

Open the editor with the "Edit this pages on Github" link at the bottom.

When ready to propose your changes just select "Create a new branch" and give it a name:
Propose Changes

Your proposed changes will be merged after review.

Editing the website on your machine (advanced contributors)

If you prefer to preview exactly your change, then you need to run vuepress on your machine and modify the markdown files with an editor (e.g. VSCode).

Prerequisites:

',7),m={href:"https://nodejs.dev/en/learn/how-to-install-nodejs/",target:"_blank",rel:"noopener noreferrer"},g={href:"https://pnpm.io/installation",target:"_blank",rel:"noopener noreferrer"},b={href:"https://dtp.dev/how-to/install",target:"_blank",rel:"noopener noreferrer"},f=a(`

For the one-time vuepress installation do:

$ cd ~/suibase/workdirs/common/extensions/dtp/docs
+import{_ as i}from"./plugin-vue_export-helper-DlAUqK2U.js";import{r as s,o as r,c as d,a as t,d as e,b as o,e as a}from"./app-BnFZaCe1.js";const c="/assets/images/propose-change.png",l={},p=t("p",null,"Anyone with a Github account can participate.",-1),h={href:"https://github.com/chainmovers/dtp/tree/main/docs",target:"_blank",rel:"noopener noreferrer"},u=a('

Open the editor with the "Edit this pages on Github" link at the bottom.

When ready to propose your changes just select "Create a new branch" and give it a name:
Propose Changes

Your proposed changes will be merged after review.

Editing the website on your machine (advanced contributors)

If you prefer to preview exactly your change, then you need to run vuepress on your machine and modify the markdown files with an editor (e.g. VSCode).

Prerequisites:

',7),m={href:"https://nodejs.dev/en/learn/how-to-install-nodejs/",target:"_blank",rel:"noopener noreferrer"},g={href:"https://pnpm.io/installation",target:"_blank",rel:"noopener noreferrer"},b={href:"https://dtp.dev/how-to/install",target:"_blank",rel:"noopener noreferrer"},f=a(`

For the one-time vuepress installation do:

$ cd ~/suibase/workdirs/common/extensions/dtp/docs
 $ pnpm install
 

To start vuepress (the server) do:

$ cd ~/suibase/workdirs/common/extensions/dtp/docs
 $ pnpm start
diff --git a/assets/faq.html-wlteNg54.js b/assets/faq.html-CV8sl42E.js
similarity index 99%
rename from assets/faq.html-wlteNg54.js
rename to assets/faq.html-CV8sl42E.js
index 1bc1121..0716d63 100644
--- a/assets/faq.html-wlteNg54.js
+++ b/assets/faq.html-CV8sl42E.js
@@ -1 +1 @@
-import{_ as p}from"./plugin-vue_export-helper-DlAUqK2U.js";import{r as i,o as c,c as l,a as e,d as t,b as n,w as s,e as r}from"./app-CKXWWpf0.js";const d={},h=r('

FAQ

In one sentence... What can DTP do?

It is a TCP-Like protocol facilitating data transfer between web2 applications, with additional Web3 features such as services monetization, anonymity and security.

Can DTP be used between Web3 frontend apps?

Yes. DTP can selectively connect front-ends WebApp to each other, while keeping the data transfer under the control of a dApps (transit on the Sui network).

As an example, you can use it to allow gamers exchange encrypted messages among themselves while they are on the same team in a Web3 game. In this case, DTP provides the WebApp to WebApp connectivity without making the players IP addresses visible.

What sort of data can DTP transport?

Any protocol, any data stream.

',8),m=r('

Can DTP be used with commercial application?

Yes. DTP is open-source and can freely be used in commercial application (Apache 2.0 License).

How much does it cost to use DTP?

Only the Sui gas needed to run it, expect the execution cost to be mostly driven by the number of bytes transferred.

There is no developer fee or middlemen commission collected for using DTP.

Some service provider may optionally add their own fees on top of DTP (e.g. micro-payments), but DTP standardize public disclosure (and escrow management) of these fees on-chain. There is no "fine print unexpected" fee. A provider can not change the fees on already open DTP connections.

Can DTP unexpectedly drain my account?

We are working very hard to make this impossible.

DTP protects its user by enforcing a maximum amount of fee possibly collected per day (per epoch). The user must explicitly approve and sign a change to this maximum.

Also, fee rates are determine once by a Service Level Agreement (SLA) when opening a DTP connection. You can close that connection at any time. It is not possible for a service provider to keep collecting payments after a DTP connection is closed.

(Note: The configurable maximum is tied to a wallet address and enforce on-chain).

When will DTP have its own token?

Never.

DTP operations are always paid in Sui.

dApps built on top of DTP can use tokens, but this is not within the scope of DTP itself.

Can DTP simply tunnel standard TCP, UDP, IP packets?

Transparent packets tunneling could be done, but it is not recommended.

DTP/Sui provides already reliable and ordered data transport. That would be redundant with say, what TCP would try to achieve within a tunnel.

',18),u=e("p",null,[e("strong",null,"Any plan to support another blockchain?")],-1),f=e("p",null,"No, unless a breakthrough in performance is possible with another blockchain architecture.",-1),g=e("p",null,"Sui provides stable time to finality (low jitter), parallelism and scalability (no contention between connections).",-1),b=e("p",null,"Low jitter allows small and predictable buffer size at the receivers.",-1),y=e("p",null,"Sui fast path transactions makes sub-second streaming latency possible.",-1),w=e("p",null,"For now, DTP/Sui might not be well-suited for application that depends on fast sequence of query/response (since that requires two transactions finality). DTP attempts to minimize roundtrips and protocol handshakes at every step.",-1),T=e("p",null,[e("strong",null,"Where is the code?")],-1),_={href:"https://github.com/mario4tier/dtp",target:"_blank",rel:"noopener noreferrer"},v=e("p",null,[e("strong",null,"Where can I go for more questions?")],-1),P={href:"https://discord.gg/Erb6SwsVbH",target:"_blank",rel:"noopener noreferrer"};function D(k,S){const o=i("RouteLink"),a=i("ExternalLinkIcon");return c(),l("div",null,[h,e("p",null,[t("Data can be a few bytes for a one time secret exchange for authentication/login. At another extreme, the bandwidth can be for as much as an encrypted video stream. The economic feasibility of HD video streaming on blockchain is an open question... (See "),n(o,{to:"/docs/design.html#video-streaming"},{default:s(()=>[t("Video Streaming ")]),_:1}),t(")")]),m,e("p",null,[t("Instead, look into "),n(o,{to:"/how-to/install.html#choice-1-of-3-simplified-dtp-services-deployment"},{default:s(()=>[t("DTP Services Daemon")]),_:1}),t(" to efficiently terminate/bridge standard IP protocols. That eliminates protocol redundancy and better leverage what the Sui network already provide.")]),u,f,g,b,y,w,T,e("p",null,[t("DTP still in early design phase and is not yet release. See "),e("a",_,[t("GitHub"),n(a)]),t(' development branches for "work-in-progress".')]),v,e("p",null,[t("Try the Discord channel: "),e("a",P,[t("https://discord.gg/Erb6SwsVbH"),n(a)])])])}const I=p(d,[["render",D],["__file","faq.html.vue"]]),W=JSON.parse('{"path":"/faq.html","title":"FAQ","lang":"en-US","frontmatter":{"editLink":true,"description":"FAQ In one sentence... What can DTP do? It is a TCP-Like protocol facilitating data transfer between web2 applications, with additional Web3 features such as services monetizati...","head":[["meta",{"property":"og:url","content":"https://dtp.dev/faq.html"}],["meta",{"property":"og:site_name","content":"Decentralized Transport Protocol"}],["meta",{"property":"og:title","content":"FAQ"}],["meta",{"property":"og:description","content":"FAQ In one sentence... What can DTP do? It is a TCP-Like protocol facilitating data transfer between web2 applications, with additional Web3 features such as services monetizati..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2024-02-15T22:23:30.000Z"}],["meta",{"property":"article:author","content":"dtp.dev"}],["meta",{"property":"article:modified_time","content":"2024-02-15T22:23:30.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"FAQ\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2024-02-15T22:23:30.000Z\\",\\"author\\":[{\\"@type\\":\\"Person\\",\\"name\\":\\"dtp.dev\\",\\"url\\":\\"https://dtp.dev\\"}]}"]]},"headers":[],"git":{"createdTime":1707880270000,"updatedTime":1708035810000,"contributors":[{"name":"mario4tier","email":"mario4tier@users.noreply.github.com","commits":2}]},"readingTime":{"minutes":2.11,"words":633},"filePathRelative":"faq.md","localizedDate":"February 14, 2024","autoDesc":true}');export{I as comp,W as data}; +import{_ as p}from"./plugin-vue_export-helper-DlAUqK2U.js";import{r as i,o as c,c as l,a as e,d as t,b as n,w as s,e as r}from"./app-BnFZaCe1.js";const d={},h=r('

FAQ

In one sentence... What can DTP do?

It is a TCP-Like protocol facilitating data transfer between web2 applications, with additional Web3 features such as services monetization, anonymity and security.

Can DTP be used between Web3 frontend apps?

Yes. DTP can selectively connect front-ends WebApp to each other, while keeping the data transfer under the control of a dApps (transit on the Sui network).

As an example, you can use it to allow gamers exchange encrypted messages among themselves while they are on the same team in a Web3 game. In this case, DTP provides the WebApp to WebApp connectivity without making the players IP addresses visible.

What sort of data can DTP transport?

Any protocol, any data stream.

',8),m=r('

Can DTP be used with commercial application?

Yes. DTP is open-source and can freely be used in commercial application (Apache 2.0 License).

How much does it cost to use DTP?

Only the Sui gas needed to run it, expect the execution cost to be mostly driven by the number of bytes transferred.

There is no developer fee or middlemen commission collected for using DTP.

Some service provider may optionally add their own fees on top of DTP (e.g. micro-payments), but DTP standardize public disclosure (and escrow management) of these fees on-chain. There is no "fine print unexpected" fee. A provider can not change the fees on already open DTP connections.

Can DTP unexpectedly drain my account?

We are working very hard to make this impossible.

DTP protects its user by enforcing a maximum amount of fee possibly collected per day (per epoch). The user must explicitly approve and sign a change to this maximum.

Also, fee rates are determine once by a Service Level Agreement (SLA) when opening a DTP connection. You can close that connection at any time. It is not possible for a service provider to keep collecting payments after a DTP connection is closed.

(Note: The configurable maximum is tied to a wallet address and enforce on-chain).

When will DTP have its own token?

Never.

DTP operations are always paid in Sui.

dApps built on top of DTP can use tokens, but this is not within the scope of DTP itself.

Can DTP simply tunnel standard TCP, UDP, IP packets?

Transparent packets tunneling could be done, but it is not recommended.

DTP/Sui provides already reliable and ordered data transport. That would be redundant with say, what TCP would try to achieve within a tunnel.

',18),u=e("p",null,[e("strong",null,"Any plan to support another blockchain?")],-1),f=e("p",null,"No, unless a breakthrough in performance is possible with another blockchain architecture.",-1),g=e("p",null,"Sui provides stable time to finality (low jitter), parallelism and scalability (no contention between connections).",-1),b=e("p",null,"Low jitter allows small and predictable buffer size at the receivers.",-1),y=e("p",null,"Sui fast path transactions makes sub-second streaming latency possible.",-1),w=e("p",null,"For now, DTP/Sui might not be well-suited for application that depends on fast sequence of query/response (since that requires two transactions finality). DTP attempts to minimize roundtrips and protocol handshakes at every step.",-1),T=e("p",null,[e("strong",null,"Where is the code?")],-1),_={href:"https://github.com/mario4tier/dtp",target:"_blank",rel:"noopener noreferrer"},v=e("p",null,[e("strong",null,"Where can I go for more questions?")],-1),P={href:"https://discord.gg/Erb6SwsVbH",target:"_blank",rel:"noopener noreferrer"};function D(k,S){const o=i("RouteLink"),a=i("ExternalLinkIcon");return c(),l("div",null,[h,e("p",null,[t("Data can be a few bytes for a one time secret exchange for authentication/login. At another extreme, the bandwidth can be for as much as an encrypted video stream. The economic feasibility of HD video streaming on blockchain is an open question... (See "),n(o,{to:"/docs/design.html#video-streaming"},{default:s(()=>[t("Video Streaming ")]),_:1}),t(")")]),m,e("p",null,[t("Instead, look into "),n(o,{to:"/how-to/install.html#choice-1-of-3-simplified-dtp-services-deployment"},{default:s(()=>[t("DTP Services Daemon")]),_:1}),t(" to efficiently terminate/bridge standard IP protocols. That eliminates protocol redundancy and better leverage what the Sui network already provide.")]),u,f,g,b,y,w,T,e("p",null,[t("DTP still in early design phase and is not yet release. See "),e("a",_,[t("GitHub"),n(a)]),t(' development branches for "work-in-progress".')]),v,e("p",null,[t("Try the Discord channel: "),e("a",P,[t("https://discord.gg/Erb6SwsVbH"),n(a)])])])}const I=p(d,[["render",D],["__file","faq.html.vue"]]),W=JSON.parse('{"path":"/faq.html","title":"FAQ","lang":"en-US","frontmatter":{"editLink":true,"description":"FAQ In one sentence... What can DTP do? It is a TCP-Like protocol facilitating data transfer between web2 applications, with additional Web3 features such as services monetizati...","head":[["meta",{"property":"og:url","content":"https://dtp.dev/faq.html"}],["meta",{"property":"og:site_name","content":"Decentralized Transport Protocol"}],["meta",{"property":"og:title","content":"FAQ"}],["meta",{"property":"og:description","content":"FAQ In one sentence... What can DTP do? It is a TCP-Like protocol facilitating data transfer between web2 applications, with additional Web3 features such as services monetizati..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2024-02-15T22:23:30.000Z"}],["meta",{"property":"article:author","content":"dtp.dev"}],["meta",{"property":"article:modified_time","content":"2024-02-15T22:23:30.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"FAQ\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2024-02-15T22:23:30.000Z\\",\\"author\\":[{\\"@type\\":\\"Person\\",\\"name\\":\\"dtp.dev\\",\\"url\\":\\"https://dtp.dev\\"}]}"]]},"headers":[],"git":{"createdTime":1707880270000,"updatedTime":1708035810000,"contributors":[{"name":"mario4tier","email":"mario4tier@users.noreply.github.com","commits":2}]},"readingTime":{"minutes":2.11,"words":633},"filePathRelative":"faq.md","localizedDate":"February 14, 2024","autoDesc":true}');export{I as comp,W as data}; diff --git a/assets/full_setup.html-D9U11CgD.js b/assets/full_setup.html-Cez3e24z.js similarity index 97% rename from assets/full_setup.html-D9U11CgD.js rename to assets/full_setup.html-Cez3e24z.js index ba5b203..81c66a0 100644 --- a/assets/full_setup.html-D9U11CgD.js +++ b/assets/full_setup.html-Cez3e24z.js @@ -1 +1 @@ -import{_ as o}from"./plugin-vue_export-helper-DlAUqK2U.js";import{r as s,o as l,c as a,a as e,d as n,b as i,e as r}from"./app-CKXWWpf0.js";const c={},p=e("div",{class:"hint-container warning"},[e("p",{class:"hint-container-title"},"Warning"),e("p",null,"work-in-progress. The installation process is not yet fully implemented.")],-1),d=e("h3",{id:"_1-install-suibase",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_1-install-suibase"},[e("span",null,"(1) Install Suibase")])],-1),u={href:"https://suibase.io/how-to/install",target:"_blank",rel:"noopener noreferrer"},h=r('

Suibase allows distinct Sui binaries and keystore management for each network (localnet, devnet, testnet and mainnet). It also installs the "DTP Services" daemon and "dtp" CLI command for you.

(2) Enable DTP Services for localnet

Do $ localnet enable dtp

Other useful commands:

  • Disable DTP with $ localnet disable dtp
  • Update DTP (and Suibase) to latest with $ ~/suibase/update
  • Update only the Sui binaries from Mysten Labs with $ localnet update

(3) Start local processes

Do $ localnet start

It is recommended to develop on a single machine with localnet first and (easily) migrate to testnet later for end-to-end testing.

Note: Localnet runs two instances of the DTP Services on different local port, allowing the simulation of two end-users. This is very convenient for quick development and testing of your own application on a single machine.

Other useful commands:

  • Monitor DTP services health (UP/DOWN) with $ localnet status
  • Monitor your own services status/account balance with $ dtp status
  • Reset the localnet to its genesis state with $ localnet regen

(4) Optional DTP Self-Test

Do $ dtp self-test to verify that DTP is working as expected.

You can re-run this command anytime you are trying to isolate if a problem is in your application or the DTP setup itself.

Next steps (TODO)

  • Instruction to migrate from localnet to testnet testing (should be easy).
  • Tutorial of a simple client/server "echo" service and how testing is done.
',16);function m(f,_){const t=s("ExternalLinkIcon");return l(),a("div",null,[p,d,e("p",null,[e("a",u,[n("https://suibase.io/how-to/install"),i(t)])]),h])}const v=o(c,[["render",m],["__file","full_setup.html.vue"]]),y=JSON.parse('{"path":"/how-to/full_setup.html","title":"Full Development Setup","lang":"en-US","frontmatter":{"title":"Full Development Setup","editLink":true,"headerDepth":0,"description":" Warning work-in-progress. The installation process is not yet fully implemented. (1) Install Suibase https://suibase.io/how-to/install Suibase allows distinct Sui binaries and ...","head":[["meta",{"property":"og:url","content":"https://dtp.dev/how-to/full_setup.html"}],["meta",{"property":"og:site_name","content":"Decentralized Transport Protocol"}],["meta",{"property":"og:title","content":"Full Development Setup"}],["meta",{"property":"og:description","content":" Warning work-in-progress. The installation process is not yet fully implemented. (1) Install Suibase https://suibase.io/how-to/install Suibase allows distinct Sui binaries and ..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2024-02-15T23:04:37.000Z"}],["meta",{"property":"article:author","content":"dtp.dev"}],["meta",{"property":"article:modified_time","content":"2024-02-15T23:04:37.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Full Development Setup\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2024-02-15T23:04:37.000Z\\",\\"author\\":[{\\"@type\\":\\"Person\\",\\"name\\":\\"dtp.dev\\",\\"url\\":\\"https://dtp.dev\\"}]}"]]},"headers":[{"level":3,"title":"(1) Install Suibase","slug":"_1-install-suibase","link":"#_1-install-suibase","children":[]},{"level":3,"title":"(2) Enable DTP Services for localnet","slug":"_2-enable-dtp-services-for-localnet","link":"#_2-enable-dtp-services-for-localnet","children":[]},{"level":3,"title":"(3) Start local processes","slug":"_3-start-local-processes","link":"#_3-start-local-processes","children":[]},{"level":3,"title":"(4) Optional DTP Self-Test","slug":"_4-optional-dtp-self-test","link":"#_4-optional-dtp-self-test","children":[]},{"level":3,"title":"Next steps (TODO)","slug":"next-steps-todo","link":"#next-steps-todo","children":[]}],"git":{"createdTime":1707880270000,"updatedTime":1708038277000,"contributors":[{"name":"mario4tier","email":"mario4tier@users.noreply.github.com","commits":4}]},"readingTime":{"minutes":0.86,"words":259},"filePathRelative":"how-to/full_setup.md","localizedDate":"February 14, 2024","autoDesc":true}');export{v as comp,y as data}; +import{_ as o}from"./plugin-vue_export-helper-DlAUqK2U.js";import{r as s,o as l,c as a,a as e,d as n,b as i,e as r}from"./app-BnFZaCe1.js";const c={},p=e("div",{class:"hint-container warning"},[e("p",{class:"hint-container-title"},"Warning"),e("p",null,"work-in-progress. The installation process is not yet fully implemented.")],-1),d=e("h3",{id:"_1-install-suibase",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_1-install-suibase"},[e("span",null,"(1) Install Suibase")])],-1),u={href:"https://suibase.io/how-to/install",target:"_blank",rel:"noopener noreferrer"},h=r('

Suibase allows distinct Sui binaries and keystore management for each network (localnet, devnet, testnet and mainnet). It also installs the "DTP Services" daemon and "dtp" CLI command for you.

(2) Enable DTP Services for localnet

Do $ localnet enable dtp

Other useful commands:

  • Disable DTP with $ localnet disable dtp
  • Update DTP (and Suibase) to latest with $ ~/suibase/update
  • Update only the Sui binaries from Mysten Labs with $ localnet update

(3) Start local processes

Do $ localnet start

It is recommended to develop on a single machine with localnet first and (easily) migrate to testnet later for end-to-end testing.

Note: Localnet runs two instances of the DTP Services on different local port, allowing the simulation of two end-users. This is very convenient for quick development and testing of your own application on a single machine.

Other useful commands:

  • Monitor DTP services health (UP/DOWN) with $ localnet status
  • Monitor your own services status/account balance with $ dtp status
  • Reset the localnet to its genesis state with $ localnet regen

(4) Optional DTP Self-Test

Do $ dtp self-test to verify that DTP is working as expected.

You can re-run this command anytime you are trying to isolate if a problem is in your application or the DTP setup itself.

Next steps (TODO)

  • Instruction to migrate from localnet to testnet testing (should be easy).
  • Tutorial of a simple client/server "echo" service and how testing is done.
',16);function m(f,_){const t=s("ExternalLinkIcon");return l(),a("div",null,[p,d,e("p",null,[e("a",u,[n("https://suibase.io/how-to/install"),i(t)])]),h])}const v=o(c,[["render",m],["__file","full_setup.html.vue"]]),y=JSON.parse('{"path":"/how-to/full_setup.html","title":"Full Development Setup","lang":"en-US","frontmatter":{"title":"Full Development Setup","editLink":true,"headerDepth":0,"description":" Warning work-in-progress. The installation process is not yet fully implemented. (1) Install Suibase https://suibase.io/how-to/install Suibase allows distinct Sui binaries and ...","head":[["meta",{"property":"og:url","content":"https://dtp.dev/how-to/full_setup.html"}],["meta",{"property":"og:site_name","content":"Decentralized Transport Protocol"}],["meta",{"property":"og:title","content":"Full Development Setup"}],["meta",{"property":"og:description","content":" Warning work-in-progress. The installation process is not yet fully implemented. (1) Install Suibase https://suibase.io/how-to/install Suibase allows distinct Sui binaries and ..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2024-02-15T23:04:37.000Z"}],["meta",{"property":"article:author","content":"dtp.dev"}],["meta",{"property":"article:modified_time","content":"2024-02-15T23:04:37.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Full Development Setup\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2024-02-15T23:04:37.000Z\\",\\"author\\":[{\\"@type\\":\\"Person\\",\\"name\\":\\"dtp.dev\\",\\"url\\":\\"https://dtp.dev\\"}]}"]]},"headers":[{"level":3,"title":"(1) Install Suibase","slug":"_1-install-suibase","link":"#_1-install-suibase","children":[]},{"level":3,"title":"(2) Enable DTP Services for localnet","slug":"_2-enable-dtp-services-for-localnet","link":"#_2-enable-dtp-services-for-localnet","children":[]},{"level":3,"title":"(3) Start local processes","slug":"_3-start-local-processes","link":"#_3-start-local-processes","children":[]},{"level":3,"title":"(4) Optional DTP Self-Test","slug":"_4-optional-dtp-self-test","link":"#_4-optional-dtp-self-test","children":[]},{"level":3,"title":"Next steps (TODO)","slug":"next-steps-todo","link":"#next-steps-todo","children":[]}],"git":{"createdTime":1707880270000,"updatedTime":1708038277000,"contributors":[{"name":"mario4tier","email":"mario4tier@users.noreply.github.com","commits":4}]},"readingTime":{"minutes":0.86,"words":259},"filePathRelative":"how-to/full_setup.md","localizedDate":"February 14, 2024","autoDesc":true}');export{v as comp,y as data}; diff --git a/assets/future_work.html-Dp7HikED.js b/assets/future_work.html-B07VTehy.js similarity index 99% rename from assets/future_work.html-Dp7HikED.js rename to assets/future_work.html-B07VTehy.js index f8ddac5..1c35b57 100644 --- a/assets/future_work.html-Dp7HikED.js +++ b/assets/future_work.html-B07VTehy.js @@ -1 +1 @@ -import{_ as n}from"./p2p_broadcast-DKREXEsi.js";import{_ as r}from"./plugin-vue_export-helper-DlAUqK2U.js";import{r as i,o as s,c,a as e,d as t,b as a,e as l}from"./app-CKXWWpf0.js";const d={},p=l('

Future Work

Broadcasting Challenges

Data broadcasting will put pressure on fullnodes WebSocket event streaming services.

Fullnodes may have low economic incentive to support such high bandwidth services.

The architecture should scale to match the audience size.

Consequently, one possible long term solution is for DTP/Sui to provide only the crypto-economic services and then leave the burden of broadcasting to a public peer-to-peer network.

Each peer is running a DTP app for direct connection to the Sui network (for control plane). The complexity of the data plane transiting through a peer-to-peer network should be hidden to the end-users (Peers).

The use of P2P or not remains irrelevant to the broadcaster which always interface directly to the Sui network.

Data Deletion

Once the data is confirmed consumed by the receiver(s), then it can be deleted on the L1 network to recover some storage fee.

The sender of the data can opt out from automated deletion and assume the full storage cost.

Automated deletion is controlled by DTP to provide a fair time for the receiver(s) to consume the data and can be fine tuned through the sender service level agreement (SLA).

The SLAs are published by the server (in its Host object) and one is selected by the client at the time of the connection being established.

Data Consumption Confirmation

TCP protocol includes acknowledgment of L4 delivery to the destination, but without guarantee of being consumed by the application (requires additional protocol at layer 7).

DTP layer supports both; a confirmation of the data being available on the L1 network (TCP delivery equivalent) and optional confirmation of the client consuming the data (L7 protocol equivalent).

Example of use would be to integrate in the dApps the verification that the data was persisted off-chain by the destination. There is no verification that the destination is honest, but this would be used in context where it would be in the destination best interest to act honestly.

Encrypted Broadcasting

For now, broadcast are assumed to be always public and non-encrypted.

Allowing encryption may allow alternative economic model (similar to cable and/or streaming subscription services[1]), but this is challenging and piracy can (at best) only be mitigated[2].

Only the user with the decryption key would be able to make sense of the data. More research to be done about how DTP could implement this feature.


',23),h={class:"footnotes"},u={class:"footnotes-list"},m={id:"footnote1",class:"footnote-item"},f={href:"https://en.wikipedia.org/wiki/Broadcast_encryption",target:"_blank",rel:"noopener noreferrer"},g=e("a",{href:"#footnote-ref1",class:"footnote-backref"},"↩︎",-1),b={id:"footnote2",class:"footnote-item"},y={href:"https://en.wikipedia.org/wiki/Multicast_encryption",target:"_blank",rel:"noopener noreferrer"},_=e("a",{href:"#footnote-ref2",class:"footnote-backref"},"↩︎",-1);function v(k,w){const o=i("ExternalLinkIcon");return s(),c("div",null,[p,e("section",h,[e("ol",u,[e("li",m,[e("p",null,[t("Wikipedia "),e("a",f,[t("Broadcast Encryption"),a(o)]),t(),g])]),e("li",b,[e("p",null,[t("Wikipedia "),e("a",y,[t("Multicast Encryption"),a(o)]),t(),_])])])])])}const P=r(d,[["render",v],["__file","future_work.html.vue"]]),C=JSON.parse('{"path":"/ref/future_work.html","title":"Future Work","lang":"en-US","frontmatter":{"editLink":true,"description":"Future Work Broadcasting Challenges Data broadcasting will put pressure on fullnodes WebSocket event streaming services. Fullnodes may have low economic incentive to support suc...","head":[["meta",{"property":"og:url","content":"https://dtp.dev/ref/future_work.html"}],["meta",{"property":"og:site_name","content":"Decentralized Transport Protocol"}],["meta",{"property":"og:title","content":"Future Work"}],["meta",{"property":"og:description","content":"Future Work Broadcasting Challenges Data broadcasting will put pressure on fullnodes WebSocket event streaming services. Fullnodes may have low economic incentive to support suc..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:image","content":"https://dtp.dev/assets/images/p2p_broadcast.png?url"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"name":"twitter:card","content":"summary_large_image"}],["meta",{"name":"twitter:image:alt","content":"Future Work"}],["meta",{"property":"article:author","content":"dtp.dev"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Future Work\\",\\"image\\":[\\"https://dtp.dev/assets/images/p2p_broadcast.png?url\\"],\\"dateModified\\":null,\\"author\\":[{\\"@type\\":\\"Person\\",\\"name\\":\\"dtp.dev\\",\\"url\\":\\"https://dtp.dev\\"}]}"]]},"headers":[{"level":2,"title":"Broadcasting Challenges","slug":"broadcasting-challenges","link":"#broadcasting-challenges","children":[]},{"level":2,"title":"Data Deletion","slug":"data-deletion","link":"#data-deletion","children":[]},{"level":2,"title":"Data Consumption Confirmation","slug":"data-consumption-confirmation","link":"#data-consumption-confirmation","children":[]},{"level":2,"title":"Encrypted Broadcasting","slug":"encrypted-broadcasting","link":"#encrypted-broadcasting","children":[]}],"git":{"createdTime":null,"updatedTime":null,"contributors":[]},"readingTime":{"minutes":1.42,"words":426},"filePathRelative":"ref/future_work.md","autoDesc":true}');export{P as comp,C as data}; +import{_ as n}from"./p2p_broadcast-DKREXEsi.js";import{_ as r}from"./plugin-vue_export-helper-DlAUqK2U.js";import{r as i,o as s,c,a as e,d as t,b as a,e as l}from"./app-BnFZaCe1.js";const d={},p=l('

Future Work

Broadcasting Challenges

Data broadcasting will put pressure on fullnodes WebSocket event streaming services.

Fullnodes may have low economic incentive to support such high bandwidth services.

The architecture should scale to match the audience size.

Consequently, one possible long term solution is for DTP/Sui to provide only the crypto-economic services and then leave the burden of broadcasting to a public peer-to-peer network.

Each peer is running a DTP app for direct connection to the Sui network (for control plane). The complexity of the data plane transiting through a peer-to-peer network should be hidden to the end-users (Peers).

The use of P2P or not remains irrelevant to the broadcaster which always interface directly to the Sui network.

Data Deletion

Once the data is confirmed consumed by the receiver(s), then it can be deleted on the L1 network to recover some storage fee.

The sender of the data can opt out from automated deletion and assume the full storage cost.

Automated deletion is controlled by DTP to provide a fair time for the receiver(s) to consume the data and can be fine tuned through the sender service level agreement (SLA).

The SLAs are published by the server (in its Host object) and one is selected by the client at the time of the connection being established.

Data Consumption Confirmation

TCP protocol includes acknowledgment of L4 delivery to the destination, but without guarantee of being consumed by the application (requires additional protocol at layer 7).

DTP layer supports both; a confirmation of the data being available on the L1 network (TCP delivery equivalent) and optional confirmation of the client consuming the data (L7 protocol equivalent).

Example of use would be to integrate in the dApps the verification that the data was persisted off-chain by the destination. There is no verification that the destination is honest, but this would be used in context where it would be in the destination best interest to act honestly.

Encrypted Broadcasting

For now, broadcast are assumed to be always public and non-encrypted.

Allowing encryption may allow alternative economic model (similar to cable and/or streaming subscription services[1]), but this is challenging and piracy can (at best) only be mitigated[2].

Only the user with the decryption key would be able to make sense of the data. More research to be done about how DTP could implement this feature.


',23),h={class:"footnotes"},u={class:"footnotes-list"},m={id:"footnote1",class:"footnote-item"},f={href:"https://en.wikipedia.org/wiki/Broadcast_encryption",target:"_blank",rel:"noopener noreferrer"},g=e("a",{href:"#footnote-ref1",class:"footnote-backref"},"↩︎",-1),b={id:"footnote2",class:"footnote-item"},y={href:"https://en.wikipedia.org/wiki/Multicast_encryption",target:"_blank",rel:"noopener noreferrer"},_=e("a",{href:"#footnote-ref2",class:"footnote-backref"},"↩︎",-1);function v(k,w){const o=i("ExternalLinkIcon");return s(),c("div",null,[p,e("section",h,[e("ol",u,[e("li",m,[e("p",null,[t("Wikipedia "),e("a",f,[t("Broadcast Encryption"),a(o)]),t(),g])]),e("li",b,[e("p",null,[t("Wikipedia "),e("a",y,[t("Multicast Encryption"),a(o)]),t(),_])])])])])}const P=r(d,[["render",v],["__file","future_work.html.vue"]]),C=JSON.parse('{"path":"/ref/future_work.html","title":"Future Work","lang":"en-US","frontmatter":{"editLink":true,"description":"Future Work Broadcasting Challenges Data broadcasting will put pressure on fullnodes WebSocket event streaming services. Fullnodes may have low economic incentive to support suc...","head":[["meta",{"property":"og:url","content":"https://dtp.dev/ref/future_work.html"}],["meta",{"property":"og:site_name","content":"Decentralized Transport Protocol"}],["meta",{"property":"og:title","content":"Future Work"}],["meta",{"property":"og:description","content":"Future Work Broadcasting Challenges Data broadcasting will put pressure on fullnodes WebSocket event streaming services. Fullnodes may have low economic incentive to support suc..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:image","content":"https://dtp.dev/assets/images/p2p_broadcast.png?url"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"name":"twitter:card","content":"summary_large_image"}],["meta",{"name":"twitter:image:alt","content":"Future Work"}],["meta",{"property":"article:author","content":"dtp.dev"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Future Work\\",\\"image\\":[\\"https://dtp.dev/assets/images/p2p_broadcast.png?url\\"],\\"dateModified\\":null,\\"author\\":[{\\"@type\\":\\"Person\\",\\"name\\":\\"dtp.dev\\",\\"url\\":\\"https://dtp.dev\\"}]}"]]},"headers":[{"level":2,"title":"Broadcasting Challenges","slug":"broadcasting-challenges","link":"#broadcasting-challenges","children":[]},{"level":2,"title":"Data Deletion","slug":"data-deletion","link":"#data-deletion","children":[]},{"level":2,"title":"Data Consumption Confirmation","slug":"data-consumption-confirmation","link":"#data-consumption-confirmation","children":[]},{"level":2,"title":"Encrypted Broadcasting","slug":"encrypted-broadcasting","link":"#encrypted-broadcasting","children":[]}],"git":{"createdTime":null,"updatedTime":null,"contributors":[]},"readingTime":{"minutes":1.42,"words":426},"filePathRelative":"ref/future_work.md","autoDesc":true}');export{P as comp,C as data}; diff --git a/assets/future_work.html-CaNaLhGO.js b/assets/future_work.html-Cj0rm1Vd.js similarity index 99% rename from assets/future_work.html-CaNaLhGO.js rename to assets/future_work.html-Cj0rm1Vd.js index ad0431b..1d8994e 100644 --- a/assets/future_work.html-CaNaLhGO.js +++ b/assets/future_work.html-Cj0rm1Vd.js @@ -1 +1 @@ -import{_ as n}from"./p2p_broadcast-DKREXEsi.js";import{_ as r}from"./plugin-vue_export-helper-DlAUqK2U.js";import{r as i,o as s,c,a as e,d as t,b as a,e as l}from"./app-CKXWWpf0.js";const d={},p=l('

Future Work

Broadcasting Challenges

Data broadcasting will put pressure on fullnodes WebSocket event streaming services.

Fullnodes may have low economic incentive to support such high bandwidth services.

The architecture should scale to match the audience size.

Consequently, one possible long term solution is for DTP/Sui to provide only the crypto-economic services and then leave the burden of broadcasting to a public peer-to-peer network.

Each peer is running a DTP app for direct connection to the Sui network (for control plane). The complexity of the data plane transiting through a peer-to-peer network should be hidden to the end-users (Peers).

The use of P2P or not remains irrelevant to the broadcaster which always interface directly to the Sui network.

Data Deletion

Once the data is confirmed consumed by the receiver(s), then it can be deleted on the L1 network to recover some storage fee.

The sender of the data can opt out from automated deletion and assume the full storage cost.

Automated deletion is controlled by DTP to provide a fair time for the receiver(s) to consume the data and can be fine tuned through the sender service level agreement (SLA).

The SLAs are published by the server (in its Host object) and one is selected by the client at the time of the connection being established.

Data Consumption Confirmation

TCP protocol includes acknowledgment of L4 delivery to the destination, but without guarantee of being consumed by the application (requires additional protocol at layer 7).

DTP layer supports both; a confirmation of the data being available on the L1 network (TCP delivery equivalent) and optional confirmation of the client consuming the data (L7 protocol equivalent).

Example of use would be to integrate in the dApps the verification that the data was persisted off-chain by the destination. There is no verification that the destination is honest, but this would be used in context where it would be in the destination best interest to act honestly.

Encrypted Broadcasting

For now, broadcast are assumed to be always public and non-encrypted.

Allowing encryption may allow alternative economic model (similar to cable and/or streaming subscription services[1]), but this is challenging and piracy can (at best) only be mitigated[2].

Only the user with the decryption key would be able to make sense of the data. More research to be done about how DTP could implement this feature.


',23),h={class:"footnotes"},u={class:"footnotes-list"},m={id:"footnote1",class:"footnote-item"},f={href:"https://en.wikipedia.org/wiki/Broadcast_encryption",target:"_blank",rel:"noopener noreferrer"},g=e("a",{href:"#footnote-ref1",class:"footnote-backref"},"↩︎",-1),b={id:"footnote2",class:"footnote-item"},y={href:"https://en.wikipedia.org/wiki/Multicast_encryption",target:"_blank",rel:"noopener noreferrer"},_=e("a",{href:"#footnote-ref2",class:"footnote-backref"},"↩︎",-1);function v(k,w){const o=i("ExternalLinkIcon");return s(),c("div",null,[p,e("section",h,[e("ol",u,[e("li",m,[e("p",null,[t("Wikipedia "),e("a",f,[t("Broadcast Encryption"),a(o)]),t(),g])]),e("li",b,[e("p",null,[t("Wikipedia "),e("a",y,[t("Multicast Encryption"),a(o)]),t(),_])])])])])}const P=r(d,[["render",v],["__file","future_work.html.vue"]]),C=JSON.parse('{"path":"/docs/future_work.html","title":"Future Work","lang":"en-US","frontmatter":{"editLink":true,"description":"Future Work Broadcasting Challenges Data broadcasting will put pressure on fullnodes WebSocket event streaming services. Fullnodes may have low economic incentive to support suc...","head":[["meta",{"property":"og:url","content":"https://dtp.dev/docs/future_work.html"}],["meta",{"property":"og:site_name","content":"Decentralized Transport Protocol"}],["meta",{"property":"og:title","content":"Future Work"}],["meta",{"property":"og:description","content":"Future Work Broadcasting Challenges Data broadcasting will put pressure on fullnodes WebSocket event streaming services. Fullnodes may have low economic incentive to support suc..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:image","content":"https://dtp.dev/assets/images/p2p_broadcast.png?url"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2024-02-15T22:23:30.000Z"}],["meta",{"name":"twitter:card","content":"summary_large_image"}],["meta",{"name":"twitter:image:alt","content":"Future Work"}],["meta",{"property":"article:author","content":"dtp.dev"}],["meta",{"property":"article:modified_time","content":"2024-02-15T22:23:30.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Future Work\\",\\"image\\":[\\"https://dtp.dev/assets/images/p2p_broadcast.png?url\\"],\\"dateModified\\":\\"2024-02-15T22:23:30.000Z\\",\\"author\\":[{\\"@type\\":\\"Person\\",\\"name\\":\\"dtp.dev\\",\\"url\\":\\"https://dtp.dev\\"}]}"]]},"headers":[{"level":2,"title":"Broadcasting Challenges","slug":"broadcasting-challenges","link":"#broadcasting-challenges","children":[]},{"level":2,"title":"Data Deletion","slug":"data-deletion","link":"#data-deletion","children":[]},{"level":2,"title":"Data Consumption Confirmation","slug":"data-consumption-confirmation","link":"#data-consumption-confirmation","children":[]},{"level":2,"title":"Encrypted Broadcasting","slug":"encrypted-broadcasting","link":"#encrypted-broadcasting","children":[]}],"git":{"createdTime":1707880270000,"updatedTime":1708035810000,"contributors":[{"name":"mario4tier","email":"mario4tier@users.noreply.github.com","commits":2}]},"readingTime":{"minutes":1.42,"words":426},"filePathRelative":"docs/future_work.md","localizedDate":"February 14, 2024","autoDesc":true}');export{P as comp,C as data}; +import{_ as n}from"./p2p_broadcast-DKREXEsi.js";import{_ as r}from"./plugin-vue_export-helper-DlAUqK2U.js";import{r as i,o as s,c,a as e,d as t,b as a,e as l}from"./app-BnFZaCe1.js";const d={},p=l('

Future Work

Broadcasting Challenges

Data broadcasting will put pressure on fullnodes WebSocket event streaming services.

Fullnodes may have low economic incentive to support such high bandwidth services.

The architecture should scale to match the audience size.

Consequently, one possible long term solution is for DTP/Sui to provide only the crypto-economic services and then leave the burden of broadcasting to a public peer-to-peer network.

Each peer is running a DTP app for direct connection to the Sui network (for control plane). The complexity of the data plane transiting through a peer-to-peer network should be hidden to the end-users (Peers).

The use of P2P or not remains irrelevant to the broadcaster which always interface directly to the Sui network.

Data Deletion

Once the data is confirmed consumed by the receiver(s), then it can be deleted on the L1 network to recover some storage fee.

The sender of the data can opt out from automated deletion and assume the full storage cost.

Automated deletion is controlled by DTP to provide a fair time for the receiver(s) to consume the data and can be fine tuned through the sender service level agreement (SLA).

The SLAs are published by the server (in its Host object) and one is selected by the client at the time of the connection being established.

Data Consumption Confirmation

TCP protocol includes acknowledgment of L4 delivery to the destination, but without guarantee of being consumed by the application (requires additional protocol at layer 7).

DTP layer supports both; a confirmation of the data being available on the L1 network (TCP delivery equivalent) and optional confirmation of the client consuming the data (L7 protocol equivalent).

Example of use would be to integrate in the dApps the verification that the data was persisted off-chain by the destination. There is no verification that the destination is honest, but this would be used in context where it would be in the destination best interest to act honestly.

Encrypted Broadcasting

For now, broadcast are assumed to be always public and non-encrypted.

Allowing encryption may allow alternative economic model (similar to cable and/or streaming subscription services[1]), but this is challenging and piracy can (at best) only be mitigated[2].

Only the user with the decryption key would be able to make sense of the data. More research to be done about how DTP could implement this feature.


',23),h={class:"footnotes"},u={class:"footnotes-list"},m={id:"footnote1",class:"footnote-item"},f={href:"https://en.wikipedia.org/wiki/Broadcast_encryption",target:"_blank",rel:"noopener noreferrer"},g=e("a",{href:"#footnote-ref1",class:"footnote-backref"},"↩︎",-1),b={id:"footnote2",class:"footnote-item"},y={href:"https://en.wikipedia.org/wiki/Multicast_encryption",target:"_blank",rel:"noopener noreferrer"},_=e("a",{href:"#footnote-ref2",class:"footnote-backref"},"↩︎",-1);function v(k,w){const o=i("ExternalLinkIcon");return s(),c("div",null,[p,e("section",h,[e("ol",u,[e("li",m,[e("p",null,[t("Wikipedia "),e("a",f,[t("Broadcast Encryption"),a(o)]),t(),g])]),e("li",b,[e("p",null,[t("Wikipedia "),e("a",y,[t("Multicast Encryption"),a(o)]),t(),_])])])])])}const P=r(d,[["render",v],["__file","future_work.html.vue"]]),C=JSON.parse('{"path":"/docs/future_work.html","title":"Future Work","lang":"en-US","frontmatter":{"editLink":true,"description":"Future Work Broadcasting Challenges Data broadcasting will put pressure on fullnodes WebSocket event streaming services. Fullnodes may have low economic incentive to support suc...","head":[["meta",{"property":"og:url","content":"https://dtp.dev/docs/future_work.html"}],["meta",{"property":"og:site_name","content":"Decentralized Transport Protocol"}],["meta",{"property":"og:title","content":"Future Work"}],["meta",{"property":"og:description","content":"Future Work Broadcasting Challenges Data broadcasting will put pressure on fullnodes WebSocket event streaming services. Fullnodes may have low economic incentive to support suc..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:image","content":"https://dtp.dev/assets/images/p2p_broadcast.png?url"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2024-02-15T22:23:30.000Z"}],["meta",{"name":"twitter:card","content":"summary_large_image"}],["meta",{"name":"twitter:image:alt","content":"Future Work"}],["meta",{"property":"article:author","content":"dtp.dev"}],["meta",{"property":"article:modified_time","content":"2024-02-15T22:23:30.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Future Work\\",\\"image\\":[\\"https://dtp.dev/assets/images/p2p_broadcast.png?url\\"],\\"dateModified\\":\\"2024-02-15T22:23:30.000Z\\",\\"author\\":[{\\"@type\\":\\"Person\\",\\"name\\":\\"dtp.dev\\",\\"url\\":\\"https://dtp.dev\\"}]}"]]},"headers":[{"level":2,"title":"Broadcasting Challenges","slug":"broadcasting-challenges","link":"#broadcasting-challenges","children":[]},{"level":2,"title":"Data Deletion","slug":"data-deletion","link":"#data-deletion","children":[]},{"level":2,"title":"Data Consumption Confirmation","slug":"data-consumption-confirmation","link":"#data-consumption-confirmation","children":[]},{"level":2,"title":"Encrypted Broadcasting","slug":"encrypted-broadcasting","link":"#encrypted-broadcasting","children":[]}],"git":{"createdTime":1707880270000,"updatedTime":1708035810000,"contributors":[{"name":"mario4tier","email":"mario4tier@users.noreply.github.com","commits":2}]},"readingTime":{"minutes":1.42,"words":426},"filePathRelative":"docs/future_work.md","localizedDate":"February 14, 2024","autoDesc":true}');export{P as comp,C as data}; diff --git a/assets/images/design_inner_pipe_2.png b/assets/images/design_inner_pipe_2.png new file mode 100644 index 0000000000000000000000000000000000000000..9f93f00b90767ecec02b484555cb165b1ccc8ece GIT binary patch literal 64111 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 j23o0 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 Qzll(Op)UVL);#oo0ow(iwEzGB literal 0 HcmV?d00001 diff --git a/assets/index.html-3uUFhvd2.js b/assets/index.html-B8jhZ03x.js similarity index 93% rename from assets/index.html-3uUFhvd2.js rename to assets/index.html-B8jhZ03x.js index 7da977b..bb87b39 100644 --- a/assets/index.html-3uUFhvd2.js +++ b/assets/index.html-B8jhZ03x.js @@ -1 +1 @@ -import{_ as e}from"./plugin-vue_export-helper-DlAUqK2U.js";import{r as o,o as a,c as n,b as r}from"./app-CKXWWpf0.js";const c={};function p(s,l){const t=o("Catalog");return a(),n("div",null,[r(t)])}const d=e(c,[["render",p],["__file","index.html.vue"]]),_=JSON.parse('{"path":"/how-to/","title":"How to","lang":"en-US","frontmatter":{"title":"How to","article":false,"feed":false,"sitemap":false,"description":"","head":[["meta",{"property":"og:url","content":"https://dtp.dev/how-to/"}],["meta",{"property":"og:site_name","content":"Decentralized Transport Protocol"}],["meta",{"property":"og:title","content":"How to"}],["meta",{"property":"og:type","content":"website"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"article:author","content":"dtp.dev"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"WebPage\\",\\"name\\":\\"How to\\"}"]]},"headers":[],"git":{},"readingTime":{"minutes":0,"words":1},"filePathRelative":null,"autoDesc":true}');export{d as comp,_ as data}; +import{_ as e}from"./plugin-vue_export-helper-DlAUqK2U.js";import{r as o,o as a,c as n,b as r}from"./app-BnFZaCe1.js";const c={};function p(s,l){const t=o("Catalog");return a(),n("div",null,[r(t)])}const d=e(c,[["render",p],["__file","index.html.vue"]]),_=JSON.parse('{"path":"/how-to/","title":"How to","lang":"en-US","frontmatter":{"title":"How to","article":false,"feed":false,"sitemap":false,"description":"","head":[["meta",{"property":"og:url","content":"https://dtp.dev/how-to/"}],["meta",{"property":"og:site_name","content":"Decentralized Transport Protocol"}],["meta",{"property":"og:title","content":"How to"}],["meta",{"property":"og:type","content":"website"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"article:author","content":"dtp.dev"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"WebPage\\",\\"name\\":\\"How to\\"}"]]},"headers":[],"git":{},"readingTime":{"minutes":0,"words":1},"filePathRelative":null,"autoDesc":true}');export{d as comp,_ as data}; diff --git a/assets/index.html-BodtrdFm.js b/assets/index.html-BVUfEJTo.js similarity index 98% rename from assets/index.html-BodtrdFm.js rename to assets/index.html-BVUfEJTo.js index c815cd6..2088c82 100644 --- a/assets/index.html-BodtrdFm.js +++ b/assets/index.html-BVUfEJTo.js @@ -1 +1 @@ -import{_ as i}from"./plugin-vue_export-helper-DlAUqK2U.js";import{r as n,o as a,c as s,a as e,d as t,b as r}from"./app-CKXWWpf0.js";const l={},c=e("p",null,"For DTP and any SDK/tool projects welcome to join:",-1),d={href:"https://discord.gg/Erb6SwsVbH",target:"_blank",rel:"noopener noreferrer"},u=e("p",null,"For Sui specific discussions:",-1),p={href:"https://discord.gg/sui",target:"_blank",rel:"noopener noreferrer"},m={href:"https://forums.sui.io/",target:"_blank",rel:"noopener noreferrer"},h=e("h2",{id:"contributors",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#contributors"},[e("span",null,"Contributors")])],-1),_=e("p",null,[e("strong",null,"Mario Fortier"),t(" - Lead Developer"),e("br")],-1),f={href:"https://www.linkedin.com/in/mfortier/",target:"_blank",rel:"noopener noreferrer"},b=e("br",null,null,-1),g=e("li",null,[t("Discord username : Mhax#6164"),e("br")],-1),y={href:"https://github.com/mario4tier",target:"_blank",rel:"noopener noreferrer"},D=e("p",null,"(Join, contribute and have your name added here...)",-1);function S(k,v){const o=n("ExternalLinkIcon");return a(),s("div",null,[c,e("ul",null,[e("li",null,[e("a",d,[t("ChainMovers Discord"),r(o)])])]),u,e("ul",null,[e("li",null,[e("p",null,[e("a",p,[t("Sui Official Discord"),r(o)])])]),e("li",null,[e("p",null,[e("a",m,[t("Sui Official Forum"),r(o)])])])]),h,_,e("ul",null,[e("li",null,[t("LinkedIn: "),e("a",f,[t("https://www.linkedin.com/in/mfortier/"),r(o)]),b]),g,e("li",null,[t("Github username : "),e("a",y,[t("https://github.com/mario4tier"),r(o)])])]),D])}const w=i(l,[["render",S],["__file","index.html.vue"]]),x=JSON.parse('{"path":"/community/","title":"Community","lang":"en-US","frontmatter":{"title":"Community","headerDepth":0,"editLink":true,"description":"For DTP and any SDK/tool projects welcome to join: ChainMovers Discord For Sui specific discussions: Sui Official Discord Sui Official Forum Contributors Mario Fortier - Lead De...","head":[["meta",{"property":"og:url","content":"https://dtp.dev/community/"}],["meta",{"property":"og:site_name","content":"Decentralized Transport Protocol"}],["meta",{"property":"og:title","content":"Community"}],["meta",{"property":"og:description","content":"For DTP and any SDK/tool projects welcome to join: ChainMovers Discord For Sui specific discussions: Sui Official Discord Sui Official Forum Contributors Mario Fortier - Lead De..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2024-02-14T03:11:10.000Z"}],["meta",{"property":"article:author","content":"dtp.dev"}],["meta",{"property":"article:modified_time","content":"2024-02-14T03:11:10.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Community\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2024-02-14T03:11:10.000Z\\",\\"author\\":[{\\"@type\\":\\"Person\\",\\"name\\":\\"dtp.dev\\",\\"url\\":\\"https://dtp.dev\\"}]}"]]},"headers":[{"level":2,"title":"Contributors","slug":"contributors","link":"#contributors","children":[]}],"git":{"createdTime":1707880270000,"updatedTime":1707880270000,"contributors":[{"name":"mario4tier","email":"mario4tier@users.noreply.github.com","commits":1}]},"readingTime":{"minutes":0.2,"words":60},"filePathRelative":"community/README.md","localizedDate":"February 14, 2024","autoDesc":true}');export{w as comp,x as data}; +import{_ as i}from"./plugin-vue_export-helper-DlAUqK2U.js";import{r as n,o as a,c as s,a as e,d as t,b as r}from"./app-BnFZaCe1.js";const l={},c=e("p",null,"For DTP and any SDK/tool projects welcome to join:",-1),d={href:"https://discord.gg/Erb6SwsVbH",target:"_blank",rel:"noopener noreferrer"},u=e("p",null,"For Sui specific discussions:",-1),p={href:"https://discord.gg/sui",target:"_blank",rel:"noopener noreferrer"},m={href:"https://forums.sui.io/",target:"_blank",rel:"noopener noreferrer"},h=e("h2",{id:"contributors",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#contributors"},[e("span",null,"Contributors")])],-1),_=e("p",null,[e("strong",null,"Mario Fortier"),t(" - Lead Developer"),e("br")],-1),f={href:"https://www.linkedin.com/in/mfortier/",target:"_blank",rel:"noopener noreferrer"},b=e("br",null,null,-1),g=e("li",null,[t("Discord username : Mhax#6164"),e("br")],-1),y={href:"https://github.com/mario4tier",target:"_blank",rel:"noopener noreferrer"},D=e("p",null,"(Join, contribute and have your name added here...)",-1);function S(k,v){const o=n("ExternalLinkIcon");return a(),s("div",null,[c,e("ul",null,[e("li",null,[e("a",d,[t("ChainMovers Discord"),r(o)])])]),u,e("ul",null,[e("li",null,[e("p",null,[e("a",p,[t("Sui Official Discord"),r(o)])])]),e("li",null,[e("p",null,[e("a",m,[t("Sui Official Forum"),r(o)])])])]),h,_,e("ul",null,[e("li",null,[t("LinkedIn: "),e("a",f,[t("https://www.linkedin.com/in/mfortier/"),r(o)]),b]),g,e("li",null,[t("Github username : "),e("a",y,[t("https://github.com/mario4tier"),r(o)])])]),D])}const w=i(l,[["render",S],["__file","index.html.vue"]]),x=JSON.parse('{"path":"/community/","title":"Community","lang":"en-US","frontmatter":{"title":"Community","headerDepth":0,"editLink":true,"description":"For DTP and any SDK/tool projects welcome to join: ChainMovers Discord For Sui specific discussions: Sui Official Discord Sui Official Forum Contributors Mario Fortier - Lead De...","head":[["meta",{"property":"og:url","content":"https://dtp.dev/community/"}],["meta",{"property":"og:site_name","content":"Decentralized Transport Protocol"}],["meta",{"property":"og:title","content":"Community"}],["meta",{"property":"og:description","content":"For DTP and any SDK/tool projects welcome to join: ChainMovers Discord For Sui specific discussions: Sui Official Discord Sui Official Forum Contributors Mario Fortier - Lead De..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2024-02-14T03:11:10.000Z"}],["meta",{"property":"article:author","content":"dtp.dev"}],["meta",{"property":"article:modified_time","content":"2024-02-14T03:11:10.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Community\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2024-02-14T03:11:10.000Z\\",\\"author\\":[{\\"@type\\":\\"Person\\",\\"name\\":\\"dtp.dev\\",\\"url\\":\\"https://dtp.dev\\"}]}"]]},"headers":[{"level":2,"title":"Contributors","slug":"contributors","link":"#contributors","children":[]}],"git":{"createdTime":1707880270000,"updatedTime":1707880270000,"contributors":[{"name":"mario4tier","email":"mario4tier@users.noreply.github.com","commits":1}]},"readingTime":{"minutes":0.2,"words":60},"filePathRelative":"community/README.md","localizedDate":"February 14, 2024","autoDesc":true}');export{w as comp,x as data}; diff --git a/assets/index.html-D-JN27_M.js b/assets/index.html-BWOMH9gB.js similarity index 99% rename from assets/index.html-D-JN27_M.js rename to assets/index.html-BWOMH9gB.js index 5b90d8f..f207944 100644 --- a/assets/index.html-D-JN27_M.js +++ b/assets/index.html-BWOMH9gB.js @@ -1 +1 @@ -import{_ as c}from"./plugin-vue_export-helper-DlAUqK2U.js";import{r as n,o as p,c as d,a as e,d as t,b as o,w as a,e as r}from"./app-CKXWWpf0.js";const u={},h=e("p",null,"DTP provides networking building blocks that can be applied in many ways.",-1),m=e("p",null,"You will find on this page a few inspiring ideas.",-1),w={href:"../how-to/install?url"},g=r('

Which layer do you need to work with?

DTP features are available in roughly 3 layers (by increasing level of difficulty):

  • DTP Services Daemon Similar to NGINX, Cloudflare, HAProxy... These are for proxy/forward/firewall services. You will simply be configuring how your data flows between your apps and servers. Your existing apps just use standard TCP/IP sockets (e.g. "localhost:port" URL) to interface with the DTP services daemon.

  • DTP Protocols Think "TCP". The DTP/Sui SDKs allows developers to have more control for connecting any mix of web2 apps (webapp, client/servers...). You will need to write Rust and/or Typescript apps. This is also the solution to eliminate having to install the DTP Services Daemon on your end-users' devices.

  • DTP Sui Move Packages Innovations particular to Sui, such as RPC escrows, new traffic policies, coins&call equivocation mitigation, metering etc... you will likely be deeply involve into web3 development at this point.

For most users, you will deal only with the "easiest" layer, the "DTP Services Daemon".

',4),y={href:"https://discord.gg/Erb6SwsVbH",target:"_blank",rel:"noopener noreferrer"},f=e("h2",{id:"examples-ideas",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#examples-ideas"},[e("span",null,"Examples/Ideas")])],-1),b=e("p",null,[e("strong",null,"Client/Server")],-1),v=e("p",null,[e("strong",null,"Encrypted Messaging")],-1),_=e("ul",null,[e("li",null,'Add traditional user/password login to a dApp. The goal is to allow access to the same "user account" even if done from a different wallet (client address). Implementation often requires "secret messaging" between a centralized server and the Web3 apps.'),e("li",null,"Any user-to-user data transfer "),e("li",null,"Anonymous Tips Line (with potential reward in return).")],-1),T=e("p",null,[e("strong",null,"Networking / Infrastructure")],-1),k=e("li",null,"Zookeeper, Consul, Serf-like services for discovery and consensus among off-chain servers.",-1),P=r("

Firewall

  • Rate limit access to a back-end server (either bandwidth or request)
  • Allow/block origin (using authentication)

Crypto-Economics

  • Any service charging for content access (in addition to gas cost). DTP provides generic per byte and/or per request escrow service (to meter pre-agreed cost, limit and quantity... not quality).
  • Pre-paid subscription per day/month (epoch driven?).
  • Various escrow service that allows to shift the transport cost completely at the origin or destination (gas always paid by sender, but escrow service handles fair refund).

Public Broadcasting

  • Allow live broadcasting to automatically turn on/off upon enough fund contributed (thus saving the producer from any expense when no-one is listening).
  • Public broadcast performed upon enough ticket sold.
  • Tip/Request/Message/Audience participation line attach to a public event channel.
",6);function D(x,S){const s=n("HopeIcon"),l=n("ExternalLinkIcon"),i=n("RouteLink");return p(),d("div",null,[h,m,e("p",null,[t("When ready "),e("a",w,[o(s,{icon:"arrow-right"}),t(" Go to choose your installation setup ...")]),t(".")]),g,e("p",null,[t("If not sure how to proceed for your specific need, then please open a discussion on "),e("a",y,[t("Discord"),o(l)]),t(".")]),f,b,e("ul",null,[e("li",null,[t("Web3 frontends connecting to a centralized JSON-RPC backend ("),o(i,{to:"/examples/rpc_firewall.html"},{default:a(()=>[t("More info")]),_:1}),t(")")]),e("li",null,[t("Rust/Typescript Web3 Client to centralized TCP Server ("),o(i,{to:"/examples/web3_rust.html"},{default:a(()=>[t("More info")]),_:1}),t(")")])]),v,_,T,e("ul",null,[k,e("li",null,[t("UDP, TCP, QUIC/UDP Tunneling: Transport IP protocols packets within a DTP connection for point-to-point applications (See "),o(i,{to:"/how-to/install.html#choice-1-of-3-simplified-dtp-services-deployment"},{default:a(()=>[t("DTP Services Daemon")]),_:1}),t(" for an alternative)")])]),P])}const I=c(u,[["render",D],["__file","index.html.vue"]]),A=JSON.parse('{"path":"/examples/","title":"Use Cases","lang":"en-US","frontmatter":{"title":"Use Cases","contributors":true,"editLink":true,"headerDepth":0,"description":"DTP provides networking building blocks that can be applied in many ways. You will find on this page a few inspiring ideas. When ready . Which layer do you need to work with? DT...","head":[["meta",{"property":"og:url","content":"https://dtp.dev/examples/"}],["meta",{"property":"og:site_name","content":"Decentralized Transport Protocol"}],["meta",{"property":"og:title","content":"Use Cases"}],["meta",{"property":"og:description","content":"DTP provides networking building blocks that can be applied in many ways. You will find on this page a few inspiring ideas. When ready . Which layer do you need to work with? DT..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2024-02-15T22:54:53.000Z"}],["meta",{"property":"article:author","content":"dtp.dev"}],["meta",{"property":"article:modified_time","content":"2024-02-15T22:54:53.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Use Cases\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2024-02-15T22:54:53.000Z\\",\\"author\\":[{\\"@type\\":\\"Person\\",\\"name\\":\\"dtp.dev\\",\\"url\\":\\"https://dtp.dev\\"}]}"]]},"headers":[{"level":2,"title":"Which layer do you need to work with?","slug":"which-layer-do-you-need-to-work-with","link":"#which-layer-do-you-need-to-work-with","children":[]},{"level":2,"title":"Examples/Ideas","slug":"examples-ideas","link":"#examples-ideas","children":[]}],"git":{"createdTime":1707880270000,"updatedTime":1708037693000,"contributors":[{"name":"mario4tier","email":"mario4tier@users.noreply.github.com","commits":3}]},"readingTime":{"minutes":1.7,"words":509},"filePathRelative":"examples/README.md","localizedDate":"February 14, 2024","autoDesc":true}');export{I as comp,A as data}; +import{_ as c}from"./plugin-vue_export-helper-DlAUqK2U.js";import{r as n,o as p,c as d,a as e,d as t,b as o,w as a,e as r}from"./app-BnFZaCe1.js";const u={},h=e("p",null,"DTP provides networking building blocks that can be applied in many ways.",-1),m=e("p",null,"You will find on this page a few inspiring ideas.",-1),w={href:"../how-to/install?url"},g=r('

Which layer do you need to work with?

DTP features are available in roughly 3 layers (by increasing level of difficulty):

  • DTP Services Daemon Similar to NGINX, Cloudflare, HAProxy... These are for proxy/forward/firewall services. You will simply be configuring how your data flows between your apps and servers. Your existing apps just use standard TCP/IP sockets (e.g. "localhost:port" URL) to interface with the DTP services daemon.

  • DTP Protocols Think "TCP". The DTP/Sui SDKs allows developers to have more control for connecting any mix of web2 apps (webapp, client/servers...). You will need to write Rust and/or Typescript apps. This is also the solution to eliminate having to install the DTP Services Daemon on your end-users' devices.

  • DTP Sui Move Packages Innovations particular to Sui, such as RPC escrows, new traffic policies, coins&call equivocation mitigation, metering etc... you will likely be deeply involve into web3 development at this point.

For most users, you will deal only with the "easiest" layer, the "DTP Services Daemon".

',4),y={href:"https://discord.gg/Erb6SwsVbH",target:"_blank",rel:"noopener noreferrer"},f=e("h2",{id:"examples-ideas",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#examples-ideas"},[e("span",null,"Examples/Ideas")])],-1),b=e("p",null,[e("strong",null,"Client/Server")],-1),v=e("p",null,[e("strong",null,"Encrypted Messaging")],-1),_=e("ul",null,[e("li",null,'Add traditional user/password login to a dApp. The goal is to allow access to the same "user account" even if done from a different wallet (client address). Implementation often requires "secret messaging" between a centralized server and the Web3 apps.'),e("li",null,"Any user-to-user data transfer "),e("li",null,"Anonymous Tips Line (with potential reward in return).")],-1),T=e("p",null,[e("strong",null,"Networking / Infrastructure")],-1),k=e("li",null,"Zookeeper, Consul, Serf-like services for discovery and consensus among off-chain servers.",-1),P=r("

Firewall

  • Rate limit access to a back-end server (either bandwidth or request)
  • Allow/block origin (using authentication)

Crypto-Economics

  • Any service charging for content access (in addition to gas cost). DTP provides generic per byte and/or per request escrow service (to meter pre-agreed cost, limit and quantity... not quality).
  • Pre-paid subscription per day/month (epoch driven?).
  • Various escrow service that allows to shift the transport cost completely at the origin or destination (gas always paid by sender, but escrow service handles fair refund).

Public Broadcasting

  • Allow live broadcasting to automatically turn on/off upon enough fund contributed (thus saving the producer from any expense when no-one is listening).
  • Public broadcast performed upon enough ticket sold.
  • Tip/Request/Message/Audience participation line attach to a public event channel.
",6);function D(x,S){const s=n("HopeIcon"),l=n("ExternalLinkIcon"),i=n("RouteLink");return p(),d("div",null,[h,m,e("p",null,[t("When ready "),e("a",w,[o(s,{icon:"arrow-right"}),t(" Go to choose your installation setup ...")]),t(".")]),g,e("p",null,[t("If not sure how to proceed for your specific need, then please open a discussion on "),e("a",y,[t("Discord"),o(l)]),t(".")]),f,b,e("ul",null,[e("li",null,[t("Web3 frontends connecting to a centralized JSON-RPC backend ("),o(i,{to:"/examples/rpc_firewall.html"},{default:a(()=>[t("More info")]),_:1}),t(")")]),e("li",null,[t("Rust/Typescript Web3 Client to centralized TCP Server ("),o(i,{to:"/examples/web3_rust.html"},{default:a(()=>[t("More info")]),_:1}),t(")")])]),v,_,T,e("ul",null,[k,e("li",null,[t("UDP, TCP, QUIC/UDP Tunneling: Transport IP protocols packets within a DTP connection for point-to-point applications (See "),o(i,{to:"/how-to/install.html#choice-1-of-3-simplified-dtp-services-deployment"},{default:a(()=>[t("DTP Services Daemon")]),_:1}),t(" for an alternative)")])]),P])}const I=c(u,[["render",D],["__file","index.html.vue"]]),A=JSON.parse('{"path":"/examples/","title":"Use Cases","lang":"en-US","frontmatter":{"title":"Use Cases","contributors":true,"editLink":true,"headerDepth":0,"description":"DTP provides networking building blocks that can be applied in many ways. You will find on this page a few inspiring ideas. When ready . Which layer do you need to work with? DT...","head":[["meta",{"property":"og:url","content":"https://dtp.dev/examples/"}],["meta",{"property":"og:site_name","content":"Decentralized Transport Protocol"}],["meta",{"property":"og:title","content":"Use Cases"}],["meta",{"property":"og:description","content":"DTP provides networking building blocks that can be applied in many ways. You will find on this page a few inspiring ideas. When ready . Which layer do you need to work with? DT..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2024-02-15T22:54:53.000Z"}],["meta",{"property":"article:author","content":"dtp.dev"}],["meta",{"property":"article:modified_time","content":"2024-02-15T22:54:53.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Use Cases\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2024-02-15T22:54:53.000Z\\",\\"author\\":[{\\"@type\\":\\"Person\\",\\"name\\":\\"dtp.dev\\",\\"url\\":\\"https://dtp.dev\\"}]}"]]},"headers":[{"level":2,"title":"Which layer do you need to work with?","slug":"which-layer-do-you-need-to-work-with","link":"#which-layer-do-you-need-to-work-with","children":[]},{"level":2,"title":"Examples/Ideas","slug":"examples-ideas","link":"#examples-ideas","children":[]}],"git":{"createdTime":1707880270000,"updatedTime":1708037693000,"contributors":[{"name":"mario4tier","email":"mario4tier@users.noreply.github.com","commits":3}]},"readingTime":{"minutes":1.7,"words":509},"filePathRelative":"examples/README.md","localizedDate":"February 14, 2024","autoDesc":true}');export{I as comp,A as data}; diff --git a/assets/index.html-CBpta1zV.js b/assets/index.html-CBcd5KzL.js similarity index 98% rename from assets/index.html-CBpta1zV.js rename to assets/index.html-CBcd5KzL.js index 3686ff9..1b85fff 100644 --- a/assets/index.html-CBpta1zV.js +++ b/assets/index.html-CBcd5KzL.js @@ -1 +1 @@ -import{_ as e}from"./plugin-vue_export-helper-DlAUqK2U.js";import{o as t,c as o,e as a}from"./app-CKXWWpf0.js";const n={},r=a('

Exchange of data through the SUI network can be done between any Web2 application that includes the DTP and Sui SDKs.

Alternatively, the end-users may install the DTP services daemon to handle common cases (e.g making one side of the connection be a JSON-RPC server).

An end-user will first want to establish its own "unique contact point" on the network by creating a "Host Sui Object" using the DTP API.

Note: Most operation done through the DTP API can also be done on the command line with the "dtp" script.

An application can "ping" or "connect" to other Host object created by other apps. Each Host are uniquely identified by a <Host Object ID>.

The typical <IP address>:<Port> becomes a <Host Object ID>:<Port>

On-Chain Firewall

For security reason, each Host Object are by default created "completely closed". Using the DTP API, an application can choose to open ports of its Host object to progressively add services.

End-users will be able to observe what an Host allows (or blocks) even before attempting to use the service. An attacker trying to use a non-authorized service will be rejected by the DTP Move package on-chain (no impact on the server at all).

The DTP API supports white/black listing of sender sui address and various traffic policies. Configuration are kept and applied 24/7 on-chain.

Service Level Agreements (SLA)

DTP provides traditional byte streaming (TCP-Like) connections between Host, but also the simplification of higher level connection, in particular RPC calls.

When configuring a service for your Host, you must choose a "Service Level Agreement" that DTP will enforce.

An example is to require the requester to pay for the cost of the response that your server will have to provide.

Side Note

This is a good example where adding Web3 qualities to an existing Web2 service creates API monetization without requiring huge security/edge infrastructure investments

DTP defines a set of "Typical" service level agreement to help minimize market confusion.

Service Level AgreementWho Pays
DataStream-BalancedEveryone pay for their own transactions (txns).
AudioStream-FreeBroadcaster pays all transaction costs.
JSON-RPC-BalancedEveryone pay for their own txns. Best-effort service.
JSON-RPC-RequesterPaidRPC Requester pays. Escrow for success/failure.
JSON-RPC-RequesterPaidPlusSame as above, plus the server charges additional fee.
Ping-RequesterPaidPing Requester pays. Escrow for success/failure.

The requester agree to the SLA upon creation of the connection and is enforced through DTP escrow for the connection duration. DTP handles the fund redistribution fairly with consideration of various success/failure criteria (more refinement will follow in ~2025).

',18),i=[r];function s(c,l){return t(),o("div",null,i)}const h=e(n,[["render",s],["__file","index.html.vue"]]),u=JSON.parse('{"path":"/ref/","title":"Basic Concept","lang":"en-US","frontmatter":{"title":"Basic Concept","contributors":true,"editLink":true,"headerDepth":0,"description":"Exchange of data through the SUI network can be done between any Web2 application that includes the DTP and Sui SDKs. Alternatively, the end-users may install the DTP services d...","head":[["meta",{"property":"og:url","content":"https://dtp.dev/ref/"}],["meta",{"property":"og:site_name","content":"Decentralized Transport Protocol"}],["meta",{"property":"og:title","content":"Basic Concept"}],["meta",{"property":"og:description","content":"Exchange of data through the SUI network can be done between any Web2 application that includes the DTP and Sui SDKs. Alternatively, the end-users may install the DTP services d..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"article:author","content":"dtp.dev"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Basic Concept\\",\\"image\\":[\\"\\"],\\"dateModified\\":null,\\"author\\":[{\\"@type\\":\\"Person\\",\\"name\\":\\"dtp.dev\\",\\"url\\":\\"https://dtp.dev\\"}]}"]]},"headers":[{"level":2,"title":"On-Chain Firewall","slug":"on-chain-firewall","link":"#on-chain-firewall","children":[]},{"level":2,"title":"Service Level Agreements (SLA)","slug":"service-level-agreements-sla","link":"#service-level-agreements-sla","children":[]}],"git":{"createdTime":null,"updatedTime":null,"contributors":[]},"readingTime":{"minutes":1.51,"words":452},"filePathRelative":"ref/README.md","autoDesc":true}');export{h as comp,u as data}; +import{_ as e}from"./plugin-vue_export-helper-DlAUqK2U.js";import{o as t,c as o,e as a}from"./app-BnFZaCe1.js";const n={},r=a('

Exchange of data through the SUI network can be done between any Web2 application that includes the DTP and Sui SDKs.

Alternatively, the end-users may install the DTP services daemon to handle common cases (e.g making one side of the connection be a JSON-RPC server).

An end-user will first want to establish its own "unique contact point" on the network by creating a "Host Sui Object" using the DTP API.

Note: Most operation done through the DTP API can also be done on the command line with the "dtp" script.

An application can "ping" or "connect" to other Host object created by other apps. Each Host are uniquely identified by a <Host Object ID>.

The typical <IP address>:<Port> becomes a <Host Object ID>:<Port>

On-Chain Firewall

For security reason, each Host Object are by default created "completely closed". Using the DTP API, an application can choose to open ports of its Host object to progressively add services.

End-users will be able to observe what an Host allows (or blocks) even before attempting to use the service. An attacker trying to use a non-authorized service will be rejected by the DTP Move package on-chain (no impact on the server at all).

The DTP API supports white/black listing of sender sui address and various traffic policies. Configuration are kept and applied 24/7 on-chain.

Service Level Agreements (SLA)

DTP provides traditional byte streaming (TCP-Like) connections between Host, but also the simplification of higher level connection, in particular RPC calls.

When configuring a service for your Host, you must choose a "Service Level Agreement" that DTP will enforce.

An example is to require the requester to pay for the cost of the response that your server will have to provide.

Side Note

This is a good example where adding Web3 qualities to an existing Web2 service creates API monetization without requiring huge security/edge infrastructure investments

DTP defines a set of "Typical" service level agreement to help minimize market confusion.

Service Level AgreementWho Pays
DataStream-BalancedEveryone pay for their own transactions (txns).
AudioStream-FreeBroadcaster pays all transaction costs.
JSON-RPC-BalancedEveryone pay for their own txns. Best-effort service.
JSON-RPC-RequesterPaidRPC Requester pays. Escrow for success/failure.
JSON-RPC-RequesterPaidPlusSame as above, plus the server charges additional fee.
Ping-RequesterPaidPing Requester pays. Escrow for success/failure.

The requester agree to the SLA upon creation of the connection and is enforced through DTP escrow for the connection duration. DTP handles the fund redistribution fairly with consideration of various success/failure criteria (more refinement will follow in ~2025).

',18),i=[r];function s(c,l){return t(),o("div",null,i)}const h=e(n,[["render",s],["__file","index.html.vue"]]),u=JSON.parse('{"path":"/ref/","title":"Basic Concept","lang":"en-US","frontmatter":{"title":"Basic Concept","contributors":true,"editLink":true,"headerDepth":0,"description":"Exchange of data through the SUI network can be done between any Web2 application that includes the DTP and Sui SDKs. Alternatively, the end-users may install the DTP services d...","head":[["meta",{"property":"og:url","content":"https://dtp.dev/ref/"}],["meta",{"property":"og:site_name","content":"Decentralized Transport Protocol"}],["meta",{"property":"og:title","content":"Basic Concept"}],["meta",{"property":"og:description","content":"Exchange of data through the SUI network can be done between any Web2 application that includes the DTP and Sui SDKs. Alternatively, the end-users may install the DTP services d..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"article:author","content":"dtp.dev"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Basic Concept\\",\\"image\\":[\\"\\"],\\"dateModified\\":null,\\"author\\":[{\\"@type\\":\\"Person\\",\\"name\\":\\"dtp.dev\\",\\"url\\":\\"https://dtp.dev\\"}]}"]]},"headers":[{"level":2,"title":"On-Chain Firewall","slug":"on-chain-firewall","link":"#on-chain-firewall","children":[]},{"level":2,"title":"Service Level Agreements (SLA)","slug":"service-level-agreements-sla","link":"#service-level-agreements-sla","children":[]}],"git":{"createdTime":null,"updatedTime":null,"contributors":[]},"readingTime":{"minutes":1.51,"words":452},"filePathRelative":"ref/README.md","autoDesc":true}');export{h as comp,u as data}; diff --git a/assets/index.html-D031wELU.js b/assets/index.html-CEa4pTjw.js similarity index 98% rename from assets/index.html-D031wELU.js rename to assets/index.html-CEa4pTjw.js index 5211ba4..5451c57 100644 --- a/assets/index.html-D031wELU.js +++ b/assets/index.html-CEa4pTjw.js @@ -1 +1 @@ -import{_ as e}from"./plugin-vue_export-helper-DlAUqK2U.js";import{o as t,c as o,e as a}from"./app-CKXWWpf0.js";const n={},r=a('

Exchange of data through the SUI network can be done between any Web2 application that includes the DTP and Sui SDKs.

Alternatively, the end-users may install the DTP services daemon to handle common cases (e.g making one side of the connection be a JSON-RPC server).

An end-user will first want to establish its own "unique contact point" on the network by creating a "Host Sui Object" using the DTP API.

Note: Most operation done through the DTP API can also be done on the command line with the "dtp" script.

An application can "ping" or "connect" to other Host object created by other apps. Each Host are uniquely identified by a <Host Object ID>.

The typical <IP address>:<Port> becomes a <Host Object ID>:<Port>

On-Chain Firewall

For security reason, each Host Object are by default created "completely closed". Using the DTP API, an application can choose to open ports of its Host object to progressively add services.

End-users will be able to observe what an Host allows (or blocks) even before attempting to use the service. An attacker trying to use a non-authorized service will be rejected by the DTP Move package on-chain (no impact on the server at all).

The DTP API supports white/black listing of sender sui address and various traffic policies. Configuration are kept and applied 24/7 on-chain.

Service Level Agreements (SLA)

DTP provides traditional byte streaming (TCP-Like) connections between Host, but also the simplification of higher level connection, in particular RPC calls.

When configuring a service for your Host, you must choose a "Service Level Agreement" that DTP will enforce.

An example is to require the requester to pay for the cost of the response that your server will have to provide.

Side Note

This is a good example where adding Web3 qualities to an existing Web2 service creates API monetization without requiring huge security/edge infrastructure investments

DTP defines a set of "Typical" service level agreement to help minimize market confusion.

Service Level AgreementWho Pays
DataStream-BalancedEveryone pay for their own transactions (txns).
AudioStream-FreeBroadcaster pays all transaction costs.
JSON-RPC-BalancedEveryone pay for their own txns. Best-effort service.
JSON-RPC-RequesterPaidRPC Requester pays. Escrow for success/failure.
JSON-RPC-RequesterPaidPlusSame as above, plus the server charges additional fee.
Ping-RequesterPaidPing Requester pays. Escrow for success/failure.

The requester agree to the SLA upon creation of the connection and is enforced through DTP escrow for the connection duration. DTP handles the fund redistribution fairly with consideration of various success/failure criteria (more refinement will follow in ~2025).

',18),i=[r];function s(c,l){return t(),o("div",null,i)}const h=e(n,[["render",s],["__file","index.html.vue"]]),u=JSON.parse('{"path":"/docs/","title":"Basic Concept","lang":"en-US","frontmatter":{"title":"Basic Concept","contributors":true,"editLink":true,"headerDepth":0,"description":"Exchange of data through the SUI network can be done between any Web2 application that includes the DTP and Sui SDKs. Alternatively, the end-users may install the DTP services d...","head":[["meta",{"property":"og:url","content":"https://dtp.dev/docs/"}],["meta",{"property":"og:site_name","content":"Decentralized Transport Protocol"}],["meta",{"property":"og:title","content":"Basic Concept"}],["meta",{"property":"og:description","content":"Exchange of data through the SUI network can be done between any Web2 application that includes the DTP and Sui SDKs. Alternatively, the end-users may install the DTP services d..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2024-02-15T22:23:30.000Z"}],["meta",{"property":"article:author","content":"dtp.dev"}],["meta",{"property":"article:modified_time","content":"2024-02-15T22:23:30.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Basic Concept\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2024-02-15T22:23:30.000Z\\",\\"author\\":[{\\"@type\\":\\"Person\\",\\"name\\":\\"dtp.dev\\",\\"url\\":\\"https://dtp.dev\\"}]}"]]},"headers":[{"level":2,"title":"On-Chain Firewall","slug":"on-chain-firewall","link":"#on-chain-firewall","children":[]},{"level":2,"title":"Service Level Agreements (SLA)","slug":"service-level-agreements-sla","link":"#service-level-agreements-sla","children":[]}],"git":{"createdTime":1707880270000,"updatedTime":1708035810000,"contributors":[{"name":"mario4tier","email":"mario4tier@users.noreply.github.com","commits":2}]},"readingTime":{"minutes":1.51,"words":452},"filePathRelative":"docs/README.md","localizedDate":"February 14, 2024","autoDesc":true}');export{h as comp,u as data}; +import{_ as e}from"./plugin-vue_export-helper-DlAUqK2U.js";import{o as t,c as o,e as a}from"./app-BnFZaCe1.js";const n={},r=a('

Exchange of data through the SUI network can be done between any Web2 application that includes the DTP and Sui SDKs.

Alternatively, the end-users may install the DTP services daemon to handle common cases (e.g making one side of the connection be a JSON-RPC server).

An end-user will first want to establish its own "unique contact point" on the network by creating a "Host Sui Object" using the DTP API.

Note: Most operation done through the DTP API can also be done on the command line with the "dtp" script.

An application can "ping" or "connect" to other Host object created by other apps. Each Host are uniquely identified by a <Host Object ID>.

The typical <IP address>:<Port> becomes a <Host Object ID>:<Port>

On-Chain Firewall

For security reason, each Host Object are by default created "completely closed". Using the DTP API, an application can choose to open ports of its Host object to progressively add services.

End-users will be able to observe what an Host allows (or blocks) even before attempting to use the service. An attacker trying to use a non-authorized service will be rejected by the DTP Move package on-chain (no impact on the server at all).

The DTP API supports white/black listing of sender sui address and various traffic policies. Configuration are kept and applied 24/7 on-chain.

Service Level Agreements (SLA)

DTP provides traditional byte streaming (TCP-Like) connections between Host, but also the simplification of higher level connection, in particular RPC calls.

When configuring a service for your Host, you must choose a "Service Level Agreement" that DTP will enforce.

An example is to require the requester to pay for the cost of the response that your server will have to provide.

Side Note

This is a good example where adding Web3 qualities to an existing Web2 service creates API monetization without requiring huge security/edge infrastructure investments

DTP defines a set of "Typical" service level agreement to help minimize market confusion.

Service Level AgreementWho Pays
DataStream-BalancedEveryone pay for their own transactions (txns).
AudioStream-FreeBroadcaster pays all transaction costs.
JSON-RPC-BalancedEveryone pay for their own txns. Best-effort service.
JSON-RPC-RequesterPaidRPC Requester pays. Escrow for success/failure.
JSON-RPC-RequesterPaidPlusSame as above, plus the server charges additional fee.
Ping-RequesterPaidPing Requester pays. Escrow for success/failure.

The requester agree to the SLA upon creation of the connection and is enforced through DTP escrow for the connection duration. DTP handles the fund redistribution fairly with consideration of various success/failure criteria (more refinement will follow in ~2025).

',18),i=[r];function s(c,l){return t(),o("div",null,i)}const h=e(n,[["render",s],["__file","index.html.vue"]]),u=JSON.parse('{"path":"/docs/","title":"Basic Concept","lang":"en-US","frontmatter":{"title":"Basic Concept","contributors":true,"editLink":true,"headerDepth":0,"description":"Exchange of data through the SUI network can be done between any Web2 application that includes the DTP and Sui SDKs. Alternatively, the end-users may install the DTP services d...","head":[["meta",{"property":"og:url","content":"https://dtp.dev/docs/"}],["meta",{"property":"og:site_name","content":"Decentralized Transport Protocol"}],["meta",{"property":"og:title","content":"Basic Concept"}],["meta",{"property":"og:description","content":"Exchange of data through the SUI network can be done between any Web2 application that includes the DTP and Sui SDKs. Alternatively, the end-users may install the DTP services d..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2024-02-15T22:23:30.000Z"}],["meta",{"property":"article:author","content":"dtp.dev"}],["meta",{"property":"article:modified_time","content":"2024-02-15T22:23:30.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Basic Concept\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2024-02-15T22:23:30.000Z\\",\\"author\\":[{\\"@type\\":\\"Person\\",\\"name\\":\\"dtp.dev\\",\\"url\\":\\"https://dtp.dev\\"}]}"]]},"headers":[{"level":2,"title":"On-Chain Firewall","slug":"on-chain-firewall","link":"#on-chain-firewall","children":[]},{"level":2,"title":"Service Level Agreements (SLA)","slug":"service-level-agreements-sla","link":"#service-level-agreements-sla","children":[]}],"git":{"createdTime":1707880270000,"updatedTime":1708035810000,"contributors":[{"name":"mario4tier","email":"mario4tier@users.noreply.github.com","commits":2}]},"readingTime":{"minutes":1.51,"words":452},"filePathRelative":"docs/README.md","localizedDate":"February 14, 2024","autoDesc":true}');export{h as comp,u as data}; diff --git a/assets/index.html-BGgB7rPy.js b/assets/index.html-CnguV0tX.js similarity index 98% rename from assets/index.html-BGgB7rPy.js rename to assets/index.html-CnguV0tX.js index 7482974..f16a606 100644 --- a/assets/index.html-BGgB7rPy.js +++ b/assets/index.html-CnguV0tX.js @@ -1 +1 @@ -import{_ as i}from"./plugin-vue_export-helper-DlAUqK2U.js";import{r,o as s,c as l,a as e,b as o,d as t,e as c}from"./app-CKXWWpf0.js";const p="/assets/images/free_icon.svg",d="/assets/images/total_vs_partial_order_small.PNG",h={},u=e("div",null,[e("h1",{align:"center",style:{color:"gray"}},[t("For when you want some "),e("b",null,"web2"),t(" on the "),e("b",null,"web3"),t(" playground")])],-1),f={class:"vp-feature-wrapper",style:{transition:"transform 0.25s ease-in-out 0.24s, opacity 0.25s ease-in-out 0.24s",transform:"translateY(0px)",opacity:"1"}},m={class:"vp-features"},_={class:"route-link vp-feature-item link",href:"/","aria-label":"Create Hybrid dApps",style:{"text-decoration":"none"}},y={class:"vp-feature-title"},b=e("span",{style:{position:"relative",top:"3px"}},"Create Hybrid dApps",-1),g=e("p",{class:"vp-feature-details"},[t(" Decentralized connection control, metering and crypto-economics"),e("br"),e("b",null,"              +"),e("br"),t("Your existing off-chain services and data. ")],-1),v={class:"route-link vp-feature-item link",href:"/examples/rpc_firewall","aria-label":"Security and DDoS Protection",style:{"text-decoration":"none"}},w={class:"vp-feature-title"},k=e("span",{style:{position:"relative",top:"3px"}},"Security and DDoS Protection",-1),x=e("p",{class:"vp-feature-details"},[t(" • Scalable firewall built-in the Sui network!"),e("br"),t(" • Stop DDoS attacks even before it reaches your servers."),e("br"),t(" • Keep IP addresses hidden (visible only to Sui node operators)."),e("br")],-1),S={class:"route-link vp-feature-item link",href:"/","aria-label":"Privacy & Authenticity",style:{"text-decoration":"none"}},D={class:"vp-feature-title"},P=e("span",{style:{position:"relative",top:"3px"}},"Privacy & Authenticity",-1),A=e("p",{class:"vp-feature-details"},[t(" • End-to-end encryption for on-chain secret exchanges."),e("br"),t(" • Secured key/certificate installation from centralized servers."),e("br"),t(" • Signed data transfer for authenticity."),e("br")],-1),H=c('

Open-Source

• Code from developers for developers.
• No "DTP" Tokens, middlemen or dev fee.
• Only requires smart contracts execution costs (gas fee for Sui transactions).

',1),T={class:"route-link vp-feature-item link",href:"/","aria-label":"High Availability",style:{"text-decoration":"none"}},z={class:"vp-feature-title"},E=e("span",{style:{position:"relative",top:"3px"}},"High Availability",-1),I=e("p",{class:"vp-feature-details"},[t(" • Automatic failover and/or load balancing among your backend servers."),e("br"),t(" • Maybe your service would benefit from censorship resistance of the Sui network?"),e("br"),t(" • Add serf-like coordination/governance among loosely coupled web2 servers."),e("br")],-1),N={class:"route-link vp-feature-item link",href:"/","aria-label":"Service Level Agreements",style:{"text-decoration":"none"}},q={class:"vp-feature-title"},C=e("span",{style:{position:"relative",top:"3px"}},"Service Level Agreements",-1),F=e("p",{class:"vp-feature-details"},[t(" • Add fair Tokenomics to Web2: Pay per request, per byte, per RPC call etc..."),e("br"),t(" • Escrow for fair payments depending of success/failure of a query..."),e("br")],-1),B=e("hr",null,null,-1),O=e("img",{src:d,style:{float:"left","padding-right":"20px"}},null,-1),V=e("p",null,[e("b",null," Why Sui and not blockchain 'x' ?"),e("br"),t(" SUI has good finality latency stability (low jitter) and network scalability (maintains per connection throughput regardless of total load)."),e("br")],-1),W=e("p",null,"Sui provides two type of processing:",-1),Y=e("p",null,[e("ul",{style:{"padding-left":"40px"}},[e("li",null,"Fast path transactions with sub-second finality for data plane transfer (See 'partial ordering' illustration). This facilitate async/parallel/scalable transmission."),e("li",null,"Narwhal/Bullshark consensus with 2-3 seconds finality used for slower control plane synchronization, like connection creations, services and firewall reconfiguration etc... ")])],-1),L={href:"https://www.cloudflare.com/learning/network-layer/what-is-the-control-plane/",target:"_blank",rel:"noopener noreferrer"},R={href:"https://docs.sui.io",target:"_blank",rel:"noopener noreferrer"},U=e("p",null,"Why not simply use the good old, faster and free internet?",-1),j={href:"https://discord.gg/Erb6SwsVbH",target:"_blank",rel:"noopener noreferrer"};function J(M,Z){const n=r("HopeIcon"),a=r("ExternalLinkIcon");return s(),l("div",null,[u,e("div",f,[e("div",m,[e("a",_,[e("h3",y,[o(n,{icon:"star-half-stroke",color:"light-blue"}),b]),g]),e("a",v,[e("h3",w,[o(n,{icon:"shield-halved",color:"light-blue"}),k]),x]),e("a",S,[e("h3",D,[o(n,{icon:"user-lock",color:"light-blue"}),P]),A]),H,e("a",T,[e("h3",z,[o(n,{icon:"network-wired",color:"light-blue"}),E]),I]),e("a",N,[e("h3",q,[o(n,{icon:"building-columns",color:"light-blue"}),C]),F])])]),B,O,V,W,Y,e("p",null,[t("With its flexible dual-type transactions, Sui makes practical implementing the typical data + control plane design found in IP networks ( "),e("a",L,[t("Cloudflare explains it well"),o(a)]),t(" ).")]),e("p",null,[t("See "),e("a",R,[t("How Sui Differs from Other Blockchains?"),o(a)])]),U,e("p",null,[t("Join the "),e("a",j,[t("Discord community"),o(a)]),t(" and let's talk about it!")])])}const Q=i(h,[["render",J],["__file","index.html.vue"]]),X=JSON.parse('{"path":"/","title":"Home","lang":"en-US","frontmatter":{"home":true,"icon":"home","title":"Home","heroImage":"assets/images/home_top_capy.png","heroText":"","tagline":"","description":"For when you want some web2 on the web3 playground Decentralized connection control, metering and crypto-economics + Your existing off-chain services and data. • Scalable firewa...","head":[["meta",{"property":"og:url","content":"https://dtp.dev/"}],["meta",{"property":"og:site_name","content":"Decentralized Transport Protocol"}],["meta",{"property":"og:title","content":"Home"}],["meta",{"property":"og:description","content":"For when you want some web2 on the web3 playground Decentralized connection control, metering and crypto-economics + Your existing off-chain services and data. • Scalable firewa..."}],["meta",{"property":"og:type","content":"website"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2024-02-15T22:23:30.000Z"}],["meta",{"property":"article:author","content":"dtp.dev"}],["meta",{"property":"article:modified_time","content":"2024-02-15T22:23:30.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"WebPage\\",\\"name\\":\\"Home\\",\\"description\\":\\"For when you want some web2 on the web3 playground Decentralized connection control, metering and crypto-economics + Your existing off-chain services and data. • Scalable firewa...\\"}"]]},"headers":[],"git":{"createdTime":1707880270000,"updatedTime":1708035810000,"contributors":[{"name":"mario4tier","email":"mario4tier@users.noreply.github.com","commits":4}]},"readingTime":{"minutes":2.69,"words":808},"filePathRelative":"README.md","localizedDate":"February 14, 2024","autoDesc":true}');export{Q as comp,X as data}; +import{_ as i}from"./plugin-vue_export-helper-DlAUqK2U.js";import{r,o as s,c as l,a as e,b as o,d as t,e as c}from"./app-BnFZaCe1.js";const p="/assets/images/free_icon.svg",d="/assets/images/total_vs_partial_order_small.PNG",h={},u=e("div",null,[e("h1",{align:"center",style:{color:"gray"}},[t("For when you want some "),e("b",null,"web2"),t(" on the "),e("b",null,"web3"),t(" playground")])],-1),f={class:"vp-feature-wrapper",style:{transition:"transform 0.25s ease-in-out 0.24s, opacity 0.25s ease-in-out 0.24s",transform:"translateY(0px)",opacity:"1"}},m={class:"vp-features"},_={class:"route-link vp-feature-item link",href:"/","aria-label":"Create Hybrid dApps",style:{"text-decoration":"none"}},y={class:"vp-feature-title"},b=e("span",{style:{position:"relative",top:"3px"}},"Create Hybrid dApps",-1),g=e("p",{class:"vp-feature-details"},[t(" Decentralized connection control, metering and crypto-economics"),e("br"),e("b",null,"              +"),e("br"),t("Your existing off-chain services and data. ")],-1),v={class:"route-link vp-feature-item link",href:"/examples/rpc_firewall","aria-label":"Security and DDoS Protection",style:{"text-decoration":"none"}},w={class:"vp-feature-title"},k=e("span",{style:{position:"relative",top:"3px"}},"Security and DDoS Protection",-1),x=e("p",{class:"vp-feature-details"},[t(" • Scalable firewall built-in the Sui network!"),e("br"),t(" • Stop DDoS attacks even before it reaches your servers."),e("br"),t(" • Keep IP addresses hidden (visible only to Sui node operators)."),e("br")],-1),S={class:"route-link vp-feature-item link",href:"/","aria-label":"Privacy & Authenticity",style:{"text-decoration":"none"}},D={class:"vp-feature-title"},P=e("span",{style:{position:"relative",top:"3px"}},"Privacy & Authenticity",-1),A=e("p",{class:"vp-feature-details"},[t(" • End-to-end encryption for on-chain secret exchanges."),e("br"),t(" • Secured key/certificate installation from centralized servers."),e("br"),t(" • Signed data transfer for authenticity."),e("br")],-1),H=c('

Open-Source

• Code from developers for developers.
• No "DTP" Tokens, middlemen or dev fee.
• Only requires smart contracts execution costs (gas fee for Sui transactions).

',1),T={class:"route-link vp-feature-item link",href:"/","aria-label":"High Availability",style:{"text-decoration":"none"}},z={class:"vp-feature-title"},E=e("span",{style:{position:"relative",top:"3px"}},"High Availability",-1),I=e("p",{class:"vp-feature-details"},[t(" • Automatic failover and/or load balancing among your backend servers."),e("br"),t(" • Maybe your service would benefit from censorship resistance of the Sui network?"),e("br"),t(" • Add serf-like coordination/governance among loosely coupled web2 servers."),e("br")],-1),N={class:"route-link vp-feature-item link",href:"/","aria-label":"Service Level Agreements",style:{"text-decoration":"none"}},q={class:"vp-feature-title"},C=e("span",{style:{position:"relative",top:"3px"}},"Service Level Agreements",-1),F=e("p",{class:"vp-feature-details"},[t(" • Add fair Tokenomics to Web2: Pay per request, per byte, per RPC call etc..."),e("br"),t(" • Escrow for fair payments depending of success/failure of a query..."),e("br")],-1),B=e("hr",null,null,-1),O=e("img",{src:d,style:{float:"left","padding-right":"20px"}},null,-1),V=e("p",null,[e("b",null," Why Sui and not blockchain 'x' ?"),e("br"),t(" SUI has good finality latency stability (low jitter) and network scalability (maintains per connection throughput regardless of total load)."),e("br")],-1),W=e("p",null,"Sui provides two type of processing:",-1),Y=e("p",null,[e("ul",{style:{"padding-left":"40px"}},[e("li",null,"Fast path transactions with sub-second finality for data plane transfer (See 'partial ordering' illustration). This facilitate async/parallel/scalable transmission."),e("li",null,"Narwhal/Bullshark consensus with 2-3 seconds finality used for slower control plane synchronization, like connection creations, services and firewall reconfiguration etc... ")])],-1),L={href:"https://www.cloudflare.com/learning/network-layer/what-is-the-control-plane/",target:"_blank",rel:"noopener noreferrer"},R={href:"https://docs.sui.io",target:"_blank",rel:"noopener noreferrer"},U=e("p",null,"Why not simply use the good old, faster and free internet?",-1),j={href:"https://discord.gg/Erb6SwsVbH",target:"_blank",rel:"noopener noreferrer"};function J(M,Z){const n=r("HopeIcon"),a=r("ExternalLinkIcon");return s(),l("div",null,[u,e("div",f,[e("div",m,[e("a",_,[e("h3",y,[o(n,{icon:"star-half-stroke",color:"light-blue"}),b]),g]),e("a",v,[e("h3",w,[o(n,{icon:"shield-halved",color:"light-blue"}),k]),x]),e("a",S,[e("h3",D,[o(n,{icon:"user-lock",color:"light-blue"}),P]),A]),H,e("a",T,[e("h3",z,[o(n,{icon:"network-wired",color:"light-blue"}),E]),I]),e("a",N,[e("h3",q,[o(n,{icon:"building-columns",color:"light-blue"}),C]),F])])]),B,O,V,W,Y,e("p",null,[t("With its flexible dual-type transactions, Sui makes practical implementing the typical data + control plane design found in IP networks ( "),e("a",L,[t("Cloudflare explains it well"),o(a)]),t(" ).")]),e("p",null,[t("See "),e("a",R,[t("How Sui Differs from Other Blockchains?"),o(a)])]),U,e("p",null,[t("Join the "),e("a",j,[t("Discord community"),o(a)]),t(" and let's talk about it!")])])}const Q=i(h,[["render",J],["__file","index.html.vue"]]),X=JSON.parse('{"path":"/","title":"Home","lang":"en-US","frontmatter":{"home":true,"icon":"home","title":"Home","heroImage":"assets/images/home_top_capy.png","heroText":"","tagline":"","description":"For when you want some web2 on the web3 playground Decentralized connection control, metering and crypto-economics + Your existing off-chain services and data. • Scalable firewa...","head":[["meta",{"property":"og:url","content":"https://dtp.dev/"}],["meta",{"property":"og:site_name","content":"Decentralized Transport Protocol"}],["meta",{"property":"og:title","content":"Home"}],["meta",{"property":"og:description","content":"For when you want some web2 on the web3 playground Decentralized connection control, metering and crypto-economics + Your existing off-chain services and data. • Scalable firewa..."}],["meta",{"property":"og:type","content":"website"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2024-02-15T22:23:30.000Z"}],["meta",{"property":"article:author","content":"dtp.dev"}],["meta",{"property":"article:modified_time","content":"2024-02-15T22:23:30.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"WebPage\\",\\"name\\":\\"Home\\",\\"description\\":\\"For when you want some web2 on the web3 playground Decentralized connection control, metering and crypto-economics + Your existing off-chain services and data. • Scalable firewa...\\"}"]]},"headers":[],"git":{"createdTime":1707880270000,"updatedTime":1708035810000,"contributors":[{"name":"mario4tier","email":"mario4tier@users.noreply.github.com","commits":4}]},"readingTime":{"minutes":2.69,"words":808},"filePathRelative":"README.md","localizedDate":"February 14, 2024","autoDesc":true}');export{Q as comp,X as data}; diff --git a/assets/install.html-B3JszHVu.js b/assets/install.html-BAMq21Zx.js similarity index 97% rename from assets/install.html-B3JszHVu.js rename to assets/install.html-BAMq21Zx.js index dc0b84f..5f9080d 100644 --- a/assets/install.html-B3JszHVu.js +++ b/assets/install.html-BAMq21Zx.js @@ -1 +1 @@ -import{_ as n}from"./plugin-vue_export-helper-DlAUqK2U.js";import{r as s,o as a,c as l,a as e,b as r,d as t,e as o}from"./app-CKXWWpf0.js";const p="/assets/images/setup_help_services.png",c={},d=o('

There are 3 ways to install DTP.

Choose the one that best fits your needs and you can always later switch from one to the other.

Choice 1 of 3: Full Development Setup

This is the only setup available for now.

Recommended if you need any of these:

  • Develop Sui Move package (with or without DTP)

  • Develop your own Rust application using DTP and/or Sui Rust SDK.

  • Develop a new type of DTP service (e.g. you want your own backend Rust server process and do not want to use the DTP Services daemon as an intermediate).

The setup includes a Sui development framework (Suibase), the DTP Service Daemon runtime, all the DTP SDKs and some utility scripts for quicker edit/publish/debug development cycles.

DTP is not conflicting with other Sui installations (e.g. official Mysten Labs cargo install) and can be uninstalled easily.

',8),h={href:"../how-to/full_setup?url"},u=o('

Choice 2 of 3: DTP Services Runtime (No Coding)

Not yet implemented

For now, use the Full Development setup, which includes the DTP Services runtime.

Choose this setup if you only need one or more of the following feature:

  • Make your existing server API accessible on the Sui network (e.g. REST, JSON-RPC etc...)

  • Make a local directory content accessible on the Sui network (be a "file server")

  • Allow other user on the network to discover and ping your server.

  • Have end-users (e.g. frontend app) install their own DTP runtime as a local proxy to your backend services.

This setup does not require any coding skills, just configuration in a text file and using the dtp command line tool.

Choice 3 of 3: DTP Typescript SDK (NPM Packages Only)

Not yet implemented

The DTP Typescript SDK is not yet written. Priority is to develop the Rust SDK first.

Choose this setup if you only need to develop front-end apps doing DTP connections to existing services and not require the DTP service daemon installation.

',9);function m(y,f){const i=s("HopeIcon");return a(),l("div",null,[d,e("p",null,[e("a",h,[r(i,{icon:"arrow-right"}),t(" Go to Full Setup ...")]),t(".")]),u])}const T=n(c,[["render",m],["__file","install.html.vue"]]),w=JSON.parse('{"path":"/how-to/install.html","title":"Installation","lang":"en-US","frontmatter":{"title":"Installation","editLink":true,"description":"There are 3 ways to install DTP. Choose the one that best fits your needs and you can always later switch from one to the other. Choice 1 of 3: Full Development Setup This is th...","head":[["meta",{"property":"og:url","content":"https://dtp.dev/how-to/install.html"}],["meta",{"property":"og:site_name","content":"Decentralized Transport Protocol"}],["meta",{"property":"og:title","content":"Installation"}],["meta",{"property":"og:description","content":"There are 3 ways to install DTP. Choose the one that best fits your needs and you can always later switch from one to the other. Choice 1 of 3: Full Development Setup This is th..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:image","content":"https://dtp.dev/assets/images/setup_help_services.png?url"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2024-02-15T23:04:37.000Z"}],["meta",{"name":"twitter:card","content":"summary_large_image"}],["meta",{"name":"twitter:image:alt","content":"Installation"}],["meta",{"property":"article:author","content":"dtp.dev"}],["meta",{"property":"article:modified_time","content":"2024-02-15T23:04:37.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Installation\\",\\"image\\":[\\"https://dtp.dev/assets/images/setup_help_services.png?url\\"],\\"dateModified\\":\\"2024-02-15T23:04:37.000Z\\",\\"author\\":[{\\"@type\\":\\"Person\\",\\"name\\":\\"dtp.dev\\",\\"url\\":\\"https://dtp.dev\\"}]}"]]},"headers":[{"level":2,"title":"Choice 1 of 3: Full Development Setup","slug":"choice-1-of-3-full-development-setup","link":"#choice-1-of-3-full-development-setup","children":[]},{"level":2,"title":"Choice 2 of 3: DTP Services Runtime (No Coding)","slug":"choice-2-of-3-dtp-services-runtime-no-coding","link":"#choice-2-of-3-dtp-services-runtime-no-coding","children":[]},{"level":2,"title":"Choice 3 of 3: DTP Typescript SDK (NPM Packages Only)","slug":"choice-3-of-3-dtp-typescript-sdk-npm-packages-only","link":"#choice-3-of-3-dtp-typescript-sdk-npm-packages-only","children":[]}],"git":{"createdTime":1707880270000,"updatedTime":1708038277000,"contributors":[{"name":"mario4tier","email":"mario4tier@users.noreply.github.com","commits":4}]},"readingTime":{"minutes":1.14,"words":343},"filePathRelative":"how-to/install.md","localizedDate":"February 14, 2024","autoDesc":true}');export{T as comp,w as data}; +import{_ as n}from"./plugin-vue_export-helper-DlAUqK2U.js";import{r as s,o as a,c as l,a as e,b as r,d as t,e as o}from"./app-BnFZaCe1.js";const p="/assets/images/setup_help_services.png",c={},d=o('

There are 3 ways to install DTP.

Choose the one that best fits your needs and you can always later switch from one to the other.

Choice 1 of 3: Full Development Setup

This is the only setup available for now.

Recommended if you need any of these:

  • Develop Sui Move package (with or without DTP)

  • Develop your own Rust application using DTP and/or Sui Rust SDK.

  • Develop a new type of DTP service (e.g. you want your own backend Rust server process and do not want to use the DTP Services daemon as an intermediate).

The setup includes a Sui development framework (Suibase), the DTP Service Daemon runtime, all the DTP SDKs and some utility scripts for quicker edit/publish/debug development cycles.

DTP is not conflicting with other Sui installations (e.g. official Mysten Labs cargo install) and can be uninstalled easily.

',8),h={href:"../how-to/full_setup?url"},u=o('

Choice 2 of 3: DTP Services Runtime (No Coding)

Not yet implemented

For now, use the Full Development setup, which includes the DTP Services runtime.

Choose this setup if you only need one or more of the following feature:

  • Make your existing server API accessible on the Sui network (e.g. REST, JSON-RPC etc...)

  • Make a local directory content accessible on the Sui network (be a "file server")

  • Allow other user on the network to discover and ping your server.

  • Have end-users (e.g. frontend app) install their own DTP runtime as a local proxy to your backend services.

This setup does not require any coding skills, just configuration in a text file and using the dtp command line tool.

Choice 3 of 3: DTP Typescript SDK (NPM Packages Only)

Not yet implemented

The DTP Typescript SDK is not yet written. Priority is to develop the Rust SDK first.

Choose this setup if you only need to develop front-end apps doing DTP connections to existing services and not require the DTP service daemon installation.

',9);function m(y,f){const i=s("HopeIcon");return a(),l("div",null,[d,e("p",null,[e("a",h,[r(i,{icon:"arrow-right"}),t(" Go to Full Setup ...")]),t(".")]),u])}const T=n(c,[["render",m],["__file","install.html.vue"]]),w=JSON.parse('{"path":"/how-to/install.html","title":"Installation","lang":"en-US","frontmatter":{"title":"Installation","editLink":true,"description":"There are 3 ways to install DTP. Choose the one that best fits your needs and you can always later switch from one to the other. Choice 1 of 3: Full Development Setup This is th...","head":[["meta",{"property":"og:url","content":"https://dtp.dev/how-to/install.html"}],["meta",{"property":"og:site_name","content":"Decentralized Transport Protocol"}],["meta",{"property":"og:title","content":"Installation"}],["meta",{"property":"og:description","content":"There are 3 ways to install DTP. Choose the one that best fits your needs and you can always later switch from one to the other. Choice 1 of 3: Full Development Setup This is th..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:image","content":"https://dtp.dev/assets/images/setup_help_services.png?url"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2024-02-15T23:04:37.000Z"}],["meta",{"name":"twitter:card","content":"summary_large_image"}],["meta",{"name":"twitter:image:alt","content":"Installation"}],["meta",{"property":"article:author","content":"dtp.dev"}],["meta",{"property":"article:modified_time","content":"2024-02-15T23:04:37.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Installation\\",\\"image\\":[\\"https://dtp.dev/assets/images/setup_help_services.png?url\\"],\\"dateModified\\":\\"2024-02-15T23:04:37.000Z\\",\\"author\\":[{\\"@type\\":\\"Person\\",\\"name\\":\\"dtp.dev\\",\\"url\\":\\"https://dtp.dev\\"}]}"]]},"headers":[{"level":2,"title":"Choice 1 of 3: Full Development Setup","slug":"choice-1-of-3-full-development-setup","link":"#choice-1-of-3-full-development-setup","children":[]},{"level":2,"title":"Choice 2 of 3: DTP Services Runtime (No Coding)","slug":"choice-2-of-3-dtp-services-runtime-no-coding","link":"#choice-2-of-3-dtp-services-runtime-no-coding","children":[]},{"level":2,"title":"Choice 3 of 3: DTP Typescript SDK (NPM Packages Only)","slug":"choice-3-of-3-dtp-typescript-sdk-npm-packages-only","link":"#choice-3-of-3-dtp-typescript-sdk-npm-packages-only","children":[]}],"git":{"createdTime":1707880270000,"updatedTime":1708038277000,"contributors":[{"name":"mario4tier","email":"mario4tier@users.noreply.github.com","commits":4}]},"readingTime":{"minutes":1.14,"words":343},"filePathRelative":"how-to/install.md","localizedDate":"February 14, 2024","autoDesc":true}');export{T as comp,w as data}; diff --git a/assets/intro.html-Bxgg0fO6.js b/assets/intro.html-BxGuE4wy.js similarity index 97% rename from assets/intro.html-Bxgg0fO6.js rename to assets/intro.html-BxGuE4wy.js index 2322052..f868b69 100644 --- a/assets/intro.html-Bxgg0fO6.js +++ b/assets/intro.html-BxGuE4wy.js @@ -1 +1 @@ -import{_ as i}from"./plugin-vue_export-helper-DlAUqK2U.js";import{r as n,o as r,c as s,a as t,d as e,b as o}from"./app-CKXWWpf0.js";const c="/assets/images/home_high_level.png",l={},p=t("p",null,"It is a TCP-Like protocol facilitating data transfer between any web2 applications, with additional Web3 features such as services monetization, anonymity and security.",-1),d=t("img",{src:c,style:{display:"block","margin-left":"auto","margin-right":"auto"}},null,-1),m=t("p",null,"DTP facilitate high-level data transfer, such as audio, video, RPC calls etc...",-1),h=t("p",null,"DTP can be integrated into your own Rust/Typescript apps (frontend and/or backend).",-1),u=t("p",null,'Alternatively, you can direct your TCP/IP socket (or websocket) traffic toward a local DTP Services daemon. This daemon takes care of adding Web3 capabilities to your existing Web2 traffic (e.g. handles "per request" micro-payments).',-1),y={href:"../examples/?url"},f={href:"../how-to/install?url"};function _(g,T){const a=n("HopeIcon");return r(),s("div",null,[p,d,m,h,u,t("p",null,[e("Not sure if a good fit? "),t("a",y,[o(a,{icon:"arrow-right"}),e(" Check a few use cases")]),e(".")]),t("p",null,[e("Ready to try it ? "),t("a",f,[o(a,{icon:"arrow-right"}),e(" Go to Installation")]),e(".")])])}const w=i(l,[["render",_],["__file","intro.html.vue"]]),v=JSON.parse('{"path":"/intro.html","title":"What is DTP?","lang":"en-US","frontmatter":{"title":"What is DTP?","editLink":true,"description":"It is a TCP-Like protocol facilitating data transfer between any web2 applications, with additional Web3 features such as services monetization, anonymity and security. DTP faci...","head":[["meta",{"property":"og:url","content":"https://dtp.dev/intro.html"}],["meta",{"property":"og:site_name","content":"Decentralized Transport Protocol"}],["meta",{"property":"og:title","content":"What is DTP?"}],["meta",{"property":"og:description","content":"It is a TCP-Like protocol facilitating data transfer between any web2 applications, with additional Web3 features such as services monetization, anonymity and security. DTP faci..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2024-02-15T23:04:37.000Z"}],["meta",{"property":"article:author","content":"dtp.dev"}],["meta",{"property":"article:modified_time","content":"2024-02-15T23:04:37.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"What is DTP?\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2024-02-15T23:04:37.000Z\\",\\"author\\":[{\\"@type\\":\\"Person\\",\\"name\\":\\"dtp.dev\\",\\"url\\":\\"https://dtp.dev\\"}]}"]]},"headers":[],"git":{"createdTime":1707880270000,"updatedTime":1708038277000,"contributors":[{"name":"mario4tier","email":"mario4tier@users.noreply.github.com","commits":4}]},"readingTime":{"minutes":0.49,"words":147},"filePathRelative":"intro.md","localizedDate":"February 14, 2024","autoDesc":true}');export{w as comp,v as data}; +import{_ as i}from"./plugin-vue_export-helper-DlAUqK2U.js";import{r as n,o as r,c as s,a as t,d as e,b as o}from"./app-BnFZaCe1.js";const c="/assets/images/home_high_level.png",l={},p=t("p",null,"It is a TCP-Like protocol facilitating data transfer between any web2 applications, with additional Web3 features such as services monetization, anonymity and security.",-1),d=t("img",{src:c,style:{display:"block","margin-left":"auto","margin-right":"auto"}},null,-1),m=t("p",null,"DTP facilitate high-level data transfer, such as audio, video, RPC calls etc...",-1),h=t("p",null,"DTP can be integrated into your own Rust/Typescript apps (frontend and/or backend).",-1),u=t("p",null,'Alternatively, you can direct your TCP/IP socket (or websocket) traffic toward a local DTP Services daemon. This daemon takes care of adding Web3 capabilities to your existing Web2 traffic (e.g. handles "per request" micro-payments).',-1),y={href:"../examples/?url"},f={href:"../how-to/install?url"};function _(g,T){const a=n("HopeIcon");return r(),s("div",null,[p,d,m,h,u,t("p",null,[e("Not sure if a good fit? "),t("a",y,[o(a,{icon:"arrow-right"}),e(" Check a few use cases")]),e(".")]),t("p",null,[e("Ready to try it ? "),t("a",f,[o(a,{icon:"arrow-right"}),e(" Go to Installation")]),e(".")])])}const w=i(l,[["render",_],["__file","intro.html.vue"]]),v=JSON.parse('{"path":"/intro.html","title":"What is DTP?","lang":"en-US","frontmatter":{"title":"What is DTP?","editLink":true,"description":"It is a TCP-Like protocol facilitating data transfer between any web2 applications, with additional Web3 features such as services monetization, anonymity and security. DTP faci...","head":[["meta",{"property":"og:url","content":"https://dtp.dev/intro.html"}],["meta",{"property":"og:site_name","content":"Decentralized Transport Protocol"}],["meta",{"property":"og:title","content":"What is DTP?"}],["meta",{"property":"og:description","content":"It is a TCP-Like protocol facilitating data transfer between any web2 applications, with additional Web3 features such as services monetization, anonymity and security. DTP faci..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2024-02-15T23:04:37.000Z"}],["meta",{"property":"article:author","content":"dtp.dev"}],["meta",{"property":"article:modified_time","content":"2024-02-15T23:04:37.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"What is DTP?\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2024-02-15T23:04:37.000Z\\",\\"author\\":[{\\"@type\\":\\"Person\\",\\"name\\":\\"dtp.dev\\",\\"url\\":\\"https://dtp.dev\\"}]}"]]},"headers":[],"git":{"createdTime":1707880270000,"updatedTime":1708038277000,"contributors":[{"name":"mario4tier","email":"mario4tier@users.noreply.github.com","commits":4}]},"readingTime":{"minutes":0.49,"words":147},"filePathRelative":"intro.md","localizedDate":"February 14, 2024","autoDesc":true}');export{w as comp,v as data}; diff --git a/assets/npm_only.html-BS4zMMEQ.js b/assets/npm_only.html-BApcLSxE.js similarity index 96% rename from assets/npm_only.html-BS4zMMEQ.js rename to assets/npm_only.html-BApcLSxE.js index bdb46b6..039293a 100644 --- a/assets/npm_only.html-BS4zMMEQ.js +++ b/assets/npm_only.html-BApcLSxE.js @@ -1 +1 @@ -import{_ as e}from"./plugin-vue_export-helper-DlAUqK2U.js";import{o,c as n,a as t}from"./app-CKXWWpf0.js";const r={},a=t("div",{class:"hint-container warning"},[t("p",{class:"hint-container-title"},"Not yet written")],-1),i=[a];function p(c,m){return o(),n("div",null,i)}const d=e(r,[["render",p],["__file","npm_only.html.vue"]]),h=JSON.parse('{"path":"/how-to/npm_only.html","title":"","lang":"en-US","frontmatter":{"editLink":true,"description":" Not yet written ","head":[["meta",{"property":"og:url","content":"https://dtp.dev/how-to/npm_only.html"}],["meta",{"property":"og:site_name","content":"Decentralized Transport Protocol"}],["meta",{"property":"og:description","content":" Not yet written "}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2024-02-14T03:11:10.000Z"}],["meta",{"property":"article:author","content":"dtp.dev"}],["meta",{"property":"article:modified_time","content":"2024-02-14T03:11:10.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2024-02-14T03:11:10.000Z\\",\\"author\\":[{\\"@type\\":\\"Person\\",\\"name\\":\\"dtp.dev\\",\\"url\\":\\"https://dtp.dev\\"}]}"]]},"headers":[],"git":{"createdTime":1707880270000,"updatedTime":1707880270000,"contributors":[{"name":"mario4tier","email":"mario4tier@users.noreply.github.com","commits":1}]},"readingTime":{"minutes":0.02,"words":6},"filePathRelative":"how-to/npm_only.md","localizedDate":"February 14, 2024","autoDesc":true}');export{d as comp,h as data}; +import{_ as e}from"./plugin-vue_export-helper-DlAUqK2U.js";import{o,c as n,a as t}from"./app-BnFZaCe1.js";const r={},a=t("div",{class:"hint-container warning"},[t("p",{class:"hint-container-title"},"Not yet written")],-1),i=[a];function p(c,m){return o(),n("div",null,i)}const d=e(r,[["render",p],["__file","npm_only.html.vue"]]),h=JSON.parse('{"path":"/how-to/npm_only.html","title":"","lang":"en-US","frontmatter":{"editLink":true,"description":" Not yet written ","head":[["meta",{"property":"og:url","content":"https://dtp.dev/how-to/npm_only.html"}],["meta",{"property":"og:site_name","content":"Decentralized Transport Protocol"}],["meta",{"property":"og:description","content":" Not yet written "}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2024-02-14T03:11:10.000Z"}],["meta",{"property":"article:author","content":"dtp.dev"}],["meta",{"property":"article:modified_time","content":"2024-02-14T03:11:10.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2024-02-14T03:11:10.000Z\\",\\"author\\":[{\\"@type\\":\\"Person\\",\\"name\\":\\"dtp.dev\\",\\"url\\":\\"https://dtp.dev\\"}]}"]]},"headers":[],"git":{"createdTime":1707880270000,"updatedTime":1707880270000,"contributors":[{"name":"mario4tier","email":"mario4tier@users.noreply.github.com","commits":1}]},"readingTime":{"minutes":0.02,"words":6},"filePathRelative":"how-to/npm_only.md","localizedDate":"February 14, 2024","autoDesc":true}');export{d as comp,h as data}; diff --git a/assets/ref_broadcast-BFGBhm9s.js b/assets/ref_broadcast-BFGBhm9s.js new file mode 100644 index 0000000..229885e --- /dev/null +++ b/assets/ref_broadcast-BFGBhm9s.js @@ -0,0 +1 @@ +const s="/assets/images/design_terms.png",e="/assets/images/ref_firewall.png",a="/assets/images/design_inner_pipe_2.png",t="/assets/images/multi_channel_est.png",_="/assets/images/ref_ha.png",i="/assets/images/ref_uni.png",n="/assets/images/ref_broadcast.png";export{s as _,e as a,a as b,t as c,_ as d,i as e,n as f}; diff --git a/assets/ref_broadcast-wOf-j1_D.js b/assets/ref_broadcast-wOf-j1_D.js deleted file mode 100644 index 464dba9..0000000 --- a/assets/ref_broadcast-wOf-j1_D.js +++ /dev/null @@ -1 +0,0 @@ -const s="/assets/images/design_terms.png",e="/assets/images/ref_firewall.png",a="/assets/images/design_inner_pipe.png",t="/assets/images/multi_channel_est.png",_="/assets/images/ref_ha.png",i="/assets/images/ref_uni.png",n="/assets/images/ref_broadcast.png";export{s as _,e as a,a as b,t as c,_ as d,i as e,n as f}; diff --git a/assets/rpc_firewall.html-DXKxw1oe.js b/assets/rpc_firewall.html-D9Yd1Ah_.js similarity index 98% rename from assets/rpc_firewall.html-DXKxw1oe.js rename to assets/rpc_firewall.html-D9Yd1Ah_.js index 563a621..5398b4a 100644 --- a/assets/rpc_firewall.html-DXKxw1oe.js +++ b/assets/rpc_firewall.html-D9Yd1Ah_.js @@ -1 +1 @@ -import{_ as e}from"./plugin-vue_export-helper-DlAUqK2U.js";import{o as t,c as a,e as r}from"./app-CKXWWpf0.js";const o="/assets/images/example_rpc_firewall.png",i={},n=r('

JSON-RPC Firewall

In this example, a company want to provide a JSON-RPC API service to its customer front-end applications.

One goal is to protect the web2 server from DDoS attack, in particular, hide the IP address.

A DTP Services Daemon runs as a TCP/IP proxy on the same machine as the web2 server.

Since the sender has to pay for all the data byte transmission costs through the Sui network, an attack is costly and mostly futile.

The server IP address is visible only to the Sui nodes (not to the users on the other side of the Sui network). This mitigates traditional direct IP attacks.

In this example the frontend contact the hidden web2 IP server using the <Host Object ID>:8923 address and DTP takes care of the safe data transfer.

On the drawing, everything in green and blue is provided by DTP and the Sui infrastructure respectively. The application developer provides only what is shown in yellow.

Is the DDoS protection 100% secure?

It depends... the server operator need to have some faith that its Sui node partners are honest (in similar way that one choose to trust a reputable company such as Cloudflare). To mitigate this, a company may choose to run their own Sui fullnodes, making their servers IP addresses near impossible to target by anyone.

Scalability and Reliability

DTP also supports having a single Host Object ID be resolved to more than one backend servers (failover, load-balancing...). This is done through DTP Services configuration.

',11),s=[n];function p(l,c){return t(),a("div",null,s)}const h=e(i,[["render",p],["__file","rpc_firewall.html.vue"]]),u=JSON.parse('{"path":"/examples/rpc_firewall.html","title":"JSON-RPC Firewall","lang":"en-US","frontmatter":{"editLink":true,"description":"JSON-RPC Firewall In this example, a company want to provide a JSON-RPC API service to its customer front-end applications. One goal is to protect the web2 server from DDoS atta...","head":[["meta",{"property":"og:url","content":"https://dtp.dev/examples/rpc_firewall.html"}],["meta",{"property":"og:site_name","content":"Decentralized Transport Protocol"}],["meta",{"property":"og:title","content":"JSON-RPC Firewall"}],["meta",{"property":"og:description","content":"JSON-RPC Firewall In this example, a company want to provide a JSON-RPC API service to its customer front-end applications. One goal is to protect the web2 server from DDoS atta..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:image","content":"https://dtp.dev/assets/images/example_rpc_firewall.png?url"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2024-02-14T03:11:10.000Z"}],["meta",{"name":"twitter:card","content":"summary_large_image"}],["meta",{"name":"twitter:image:alt","content":"JSON-RPC Firewall"}],["meta",{"property":"article:author","content":"dtp.dev"}],["meta",{"property":"article:modified_time","content":"2024-02-14T03:11:10.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"JSON-RPC Firewall\\",\\"image\\":[\\"https://dtp.dev/assets/images/example_rpc_firewall.png?url\\"],\\"dateModified\\":\\"2024-02-14T03:11:10.000Z\\",\\"author\\":[{\\"@type\\":\\"Person\\",\\"name\\":\\"dtp.dev\\",\\"url\\":\\"https://dtp.dev\\"}]}"]]},"headers":[],"git":{"createdTime":1707880270000,"updatedTime":1707880270000,"contributors":[{"name":"mario4tier","email":"mario4tier@users.noreply.github.com","commits":1}]},"readingTime":{"minutes":0.88,"words":263},"filePathRelative":"examples/rpc_firewall.md","localizedDate":"February 14, 2024","autoDesc":true}');export{h as comp,u as data}; +import{_ as e}from"./plugin-vue_export-helper-DlAUqK2U.js";import{o as t,c as a,e as r}from"./app-BnFZaCe1.js";const o="/assets/images/example_rpc_firewall.png",i={},n=r('

JSON-RPC Firewall

In this example, a company want to provide a JSON-RPC API service to its customer front-end applications.

One goal is to protect the web2 server from DDoS attack, in particular, hide the IP address.

A DTP Services Daemon runs as a TCP/IP proxy on the same machine as the web2 server.

Since the sender has to pay for all the data byte transmission costs through the Sui network, an attack is costly and mostly futile.

The server IP address is visible only to the Sui nodes (not to the users on the other side of the Sui network). This mitigates traditional direct IP attacks.

In this example the frontend contact the hidden web2 IP server using the <Host Object ID>:8923 address and DTP takes care of the safe data transfer.

On the drawing, everything in green and blue is provided by DTP and the Sui infrastructure respectively. The application developer provides only what is shown in yellow.

Is the DDoS protection 100% secure?

It depends... the server operator need to have some faith that its Sui node partners are honest (in similar way that one choose to trust a reputable company such as Cloudflare). To mitigate this, a company may choose to run their own Sui fullnodes, making their servers IP addresses near impossible to target by anyone.

Scalability and Reliability

DTP also supports having a single Host Object ID be resolved to more than one backend servers (failover, load-balancing...). This is done through DTP Services configuration.

',11),s=[n];function p(l,c){return t(),a("div",null,s)}const h=e(i,[["render",p],["__file","rpc_firewall.html.vue"]]),u=JSON.parse('{"path":"/examples/rpc_firewall.html","title":"JSON-RPC Firewall","lang":"en-US","frontmatter":{"editLink":true,"description":"JSON-RPC Firewall In this example, a company want to provide a JSON-RPC API service to its customer front-end applications. One goal is to protect the web2 server from DDoS atta...","head":[["meta",{"property":"og:url","content":"https://dtp.dev/examples/rpc_firewall.html"}],["meta",{"property":"og:site_name","content":"Decentralized Transport Protocol"}],["meta",{"property":"og:title","content":"JSON-RPC Firewall"}],["meta",{"property":"og:description","content":"JSON-RPC Firewall In this example, a company want to provide a JSON-RPC API service to its customer front-end applications. One goal is to protect the web2 server from DDoS atta..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:image","content":"https://dtp.dev/assets/images/example_rpc_firewall.png?url"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2024-02-14T03:11:10.000Z"}],["meta",{"name":"twitter:card","content":"summary_large_image"}],["meta",{"name":"twitter:image:alt","content":"JSON-RPC Firewall"}],["meta",{"property":"article:author","content":"dtp.dev"}],["meta",{"property":"article:modified_time","content":"2024-02-14T03:11:10.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"JSON-RPC Firewall\\",\\"image\\":[\\"https://dtp.dev/assets/images/example_rpc_firewall.png?url\\"],\\"dateModified\\":\\"2024-02-14T03:11:10.000Z\\",\\"author\\":[{\\"@type\\":\\"Person\\",\\"name\\":\\"dtp.dev\\",\\"url\\":\\"https://dtp.dev\\"}]}"]]},"headers":[],"git":{"createdTime":1707880270000,"updatedTime":1707880270000,"contributors":[{"name":"mario4tier","email":"mario4tier@users.noreply.github.com","commits":1}]},"readingTime":{"minutes":0.88,"words":263},"filePathRelative":"examples/rpc_firewall.md","localizedDate":"February 14, 2024","autoDesc":true}');export{h as comp,u as data}; diff --git a/assets/runtime_only.html-BWVPrZKz.js b/assets/runtime_only.html-CuZ2LIXr.js similarity index 96% rename from assets/runtime_only.html-BWVPrZKz.js rename to assets/runtime_only.html-CuZ2LIXr.js index f1dde07..b10f749 100644 --- a/assets/runtime_only.html-BWVPrZKz.js +++ b/assets/runtime_only.html-CuZ2LIXr.js @@ -1 +1 @@ -import{_ as e}from"./plugin-vue_export-helper-DlAUqK2U.js";import{o,c as r,a as t}from"./app-CKXWWpf0.js";const n={},i=t("div",{class:"hint-container warning"},[t("p",{class:"hint-container-title"},"Not yet written")],-1),a=[i];function c(p,m){return o(),r("div",null,a)}const d=e(n,[["render",c],["__file","runtime_only.html.vue"]]),h=JSON.parse('{"path":"/how-to/runtime_only.html","title":"","lang":"en-US","frontmatter":{"editLink":true,"description":" Not yet written ","head":[["meta",{"property":"og:url","content":"https://dtp.dev/how-to/runtime_only.html"}],["meta",{"property":"og:site_name","content":"Decentralized Transport Protocol"}],["meta",{"property":"og:description","content":" Not yet written "}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2024-02-14T03:11:10.000Z"}],["meta",{"property":"article:author","content":"dtp.dev"}],["meta",{"property":"article:modified_time","content":"2024-02-14T03:11:10.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2024-02-14T03:11:10.000Z\\",\\"author\\":[{\\"@type\\":\\"Person\\",\\"name\\":\\"dtp.dev\\",\\"url\\":\\"https://dtp.dev\\"}]}"]]},"headers":[],"git":{"createdTime":1707880270000,"updatedTime":1707880270000,"contributors":[{"name":"mario4tier","email":"mario4tier@users.noreply.github.com","commits":1}]},"readingTime":{"minutes":0.02,"words":6},"filePathRelative":"how-to/runtime_only.md","localizedDate":"February 14, 2024","autoDesc":true}');export{d as comp,h as data}; +import{_ as e}from"./plugin-vue_export-helper-DlAUqK2U.js";import{o,c as r,a as t}from"./app-BnFZaCe1.js";const n={},i=t("div",{class:"hint-container warning"},[t("p",{class:"hint-container-title"},"Not yet written")],-1),a=[i];function c(p,m){return o(),r("div",null,a)}const d=e(n,[["render",c],["__file","runtime_only.html.vue"]]),h=JSON.parse('{"path":"/how-to/runtime_only.html","title":"","lang":"en-US","frontmatter":{"editLink":true,"description":" Not yet written ","head":[["meta",{"property":"og:url","content":"https://dtp.dev/how-to/runtime_only.html"}],["meta",{"property":"og:site_name","content":"Decentralized Transport Protocol"}],["meta",{"property":"og:description","content":" Not yet written "}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2024-02-14T03:11:10.000Z"}],["meta",{"property":"article:author","content":"dtp.dev"}],["meta",{"property":"article:modified_time","content":"2024-02-14T03:11:10.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2024-02-14T03:11:10.000Z\\",\\"author\\":[{\\"@type\\":\\"Person\\",\\"name\\":\\"dtp.dev\\",\\"url\\":\\"https://dtp.dev\\"}]}"]]},"headers":[],"git":{"createdTime":1707880270000,"updatedTime":1707880270000,"contributors":[{"name":"mario4tier","email":"mario4tier@users.noreply.github.com","commits":1}]},"readingTime":{"minutes":0.02,"words":6},"filePathRelative":"how-to/runtime_only.md","localizedDate":"February 14, 2024","autoDesc":true}');export{d as comp,h as data}; diff --git a/assets/scripts.html-DkAQ2N11.js b/assets/scripts.html-BZkBrHbZ.js similarity index 95% rename from assets/scripts.html-DkAQ2N11.js rename to assets/scripts.html-BZkBrHbZ.js index 81830bd..25750db 100644 --- a/assets/scripts.html-DkAQ2N11.js +++ b/assets/scripts.html-BZkBrHbZ.js @@ -1 +1 @@ -import{_ as e}from"./plugin-vue_export-helper-DlAUqK2U.js";import{o as r,c as o,a as t}from"./app-CKXWWpf0.js";const n={},a=t("div",{class:"hint-container warning"},[t("p",{class:"hint-container-title"},"Not yet written")],-1),i=[a];function c(s,p){return r(),o("div",null,i)}const m=e(n,[["render",c],["__file","scripts.html.vue"]]),h=JSON.parse('{"path":"/ref/scripts.html","title":"","lang":"en-US","frontmatter":{"editLink":true,"description":" Not yet written ","head":[["meta",{"property":"og:url","content":"https://dtp.dev/ref/scripts.html"}],["meta",{"property":"og:site_name","content":"Decentralized Transport Protocol"}],["meta",{"property":"og:description","content":" Not yet written "}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"article:author","content":"dtp.dev"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"\\",\\"image\\":[\\"\\"],\\"dateModified\\":null,\\"author\\":[{\\"@type\\":\\"Person\\",\\"name\\":\\"dtp.dev\\",\\"url\\":\\"https://dtp.dev\\"}]}"]]},"headers":[],"git":{"createdTime":null,"updatedTime":null,"contributors":[]},"readingTime":{"minutes":0.02,"words":6},"filePathRelative":"ref/scripts.md","autoDesc":true}');export{m as comp,h as data}; +import{_ as e}from"./plugin-vue_export-helper-DlAUqK2U.js";import{o as r,c as o,a as t}from"./app-BnFZaCe1.js";const n={},a=t("div",{class:"hint-container warning"},[t("p",{class:"hint-container-title"},"Not yet written")],-1),i=[a];function c(s,p){return r(),o("div",null,i)}const m=e(n,[["render",c],["__file","scripts.html.vue"]]),h=JSON.parse('{"path":"/ref/scripts.html","title":"","lang":"en-US","frontmatter":{"editLink":true,"description":" Not yet written ","head":[["meta",{"property":"og:url","content":"https://dtp.dev/ref/scripts.html"}],["meta",{"property":"og:site_name","content":"Decentralized Transport Protocol"}],["meta",{"property":"og:description","content":" Not yet written "}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"article:author","content":"dtp.dev"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"\\",\\"image\\":[\\"\\"],\\"dateModified\\":null,\\"author\\":[{\\"@type\\":\\"Person\\",\\"name\\":\\"dtp.dev\\",\\"url\\":\\"https://dtp.dev\\"}]}"]]},"headers":[],"git":{"createdTime":null,"updatedTime":null,"contributors":[]},"readingTime":{"minutes":0.02,"words":6},"filePathRelative":"ref/scripts.md","autoDesc":true}');export{m as comp,h as data}; diff --git a/assets/scripts.html-Bu-kSnJq.js b/assets/scripts.html-Dj-m4wYR.js similarity index 96% rename from assets/scripts.html-Bu-kSnJq.js rename to assets/scripts.html-Dj-m4wYR.js index 3f2d382..3710aa4 100644 --- a/assets/scripts.html-Bu-kSnJq.js +++ b/assets/scripts.html-Dj-m4wYR.js @@ -1 +1 @@ -import{_ as e}from"./plugin-vue_export-helper-DlAUqK2U.js";import{o,c as r,a as t}from"./app-CKXWWpf0.js";const i={},a=t("div",{class:"hint-container warning"},[t("p",{class:"hint-container-title"},"Not yet written")],-1),n=[a];function c(s,p){return o(),r("div",null,n)}const l=e(i,[["render",c],["__file","scripts.html.vue"]]),h=JSON.parse('{"path":"/docs/scripts.html","title":"","lang":"en-US","frontmatter":{"editLink":true,"description":" Not yet written ","head":[["meta",{"property":"og:url","content":"https://dtp.dev/docs/scripts.html"}],["meta",{"property":"og:site_name","content":"Decentralized Transport Protocol"}],["meta",{"property":"og:description","content":" Not yet written "}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2024-02-14T03:11:10.000Z"}],["meta",{"property":"article:author","content":"dtp.dev"}],["meta",{"property":"article:modified_time","content":"2024-02-14T03:11:10.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2024-02-14T03:11:10.000Z\\",\\"author\\":[{\\"@type\\":\\"Person\\",\\"name\\":\\"dtp.dev\\",\\"url\\":\\"https://dtp.dev\\"}]}"]]},"headers":[],"git":{"createdTime":1707880270000,"updatedTime":1707880270000,"contributors":[{"name":"mario4tier","email":"mario4tier@users.noreply.github.com","commits":1}]},"readingTime":{"minutes":0.02,"words":6},"filePathRelative":"docs/scripts.md","localizedDate":"February 14, 2024","autoDesc":true}');export{l as comp,h as data}; +import{_ as e}from"./plugin-vue_export-helper-DlAUqK2U.js";import{o,c as r,a as t}from"./app-BnFZaCe1.js";const i={},a=t("div",{class:"hint-container warning"},[t("p",{class:"hint-container-title"},"Not yet written")],-1),n=[a];function c(s,p){return o(),r("div",null,n)}const l=e(i,[["render",c],["__file","scripts.html.vue"]]),h=JSON.parse('{"path":"/docs/scripts.html","title":"","lang":"en-US","frontmatter":{"editLink":true,"description":" Not yet written ","head":[["meta",{"property":"og:url","content":"https://dtp.dev/docs/scripts.html"}],["meta",{"property":"og:site_name","content":"Decentralized Transport Protocol"}],["meta",{"property":"og:description","content":" Not yet written "}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2024-02-14T03:11:10.000Z"}],["meta",{"property":"article:author","content":"dtp.dev"}],["meta",{"property":"article:modified_time","content":"2024-02-14T03:11:10.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2024-02-14T03:11:10.000Z\\",\\"author\\":[{\\"@type\\":\\"Person\\",\\"name\\":\\"dtp.dev\\",\\"url\\":\\"https://dtp.dev\\"}]}"]]},"headers":[],"git":{"createdTime":1707880270000,"updatedTime":1707880270000,"contributors":[{"name":"mario4tier","email":"mario4tier@users.noreply.github.com","commits":1}]},"readingTime":{"minutes":0.02,"words":6},"filePathRelative":"docs/scripts.md","localizedDate":"February 14, 2024","autoDesc":true}');export{l as comp,h as data}; diff --git a/assets/web3_rust.html-CtlHbOSD.js b/assets/web3_rust.html-DrfE3oTr.js similarity index 97% rename from assets/web3_rust.html-CtlHbOSD.js rename to assets/web3_rust.html-DrfE3oTr.js index 5d43a16..b9c59ab 100644 --- a/assets/web3_rust.html-CtlHbOSD.js +++ b/assets/web3_rust.html-DrfE3oTr.js @@ -1 +1 @@ -import{_ as e}from"./plugin-vue_export-helper-DlAUqK2U.js";import{o as t,c as r,e as n}from"./app-CKXWWpf0.js";const o="/assets/images/example_web3.png",a={},s=n('

Web3 Frontend / Rust Server

Connect any frontend to both a centralized and decentralized backend.

Incomplete Documentation - Work-In-Progress

',4),i=[s];function c(d,p){return t(),r("div",null,i)}const u=e(a,[["render",c],["__file","web3_rust.html.vue"]]),h=JSON.parse('{"path":"/examples/web3_rust.html","title":"Web3 Frontend / Rust Server","lang":"en-US","frontmatter":{"editLink":true,"description":"Web3 Frontend / Rust Server Connect any frontend to both a centralized and decentralized backend. Incomplete Documentation - Work-In-Progress ","head":[["meta",{"property":"og:url","content":"https://dtp.dev/examples/web3_rust.html"}],["meta",{"property":"og:site_name","content":"Decentralized Transport Protocol"}],["meta",{"property":"og:title","content":"Web3 Frontend / Rust Server"}],["meta",{"property":"og:description","content":"Web3 Frontend / Rust Server Connect any frontend to both a centralized and decentralized backend. Incomplete Documentation - Work-In-Progress "}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:image","content":"https://dtp.dev/assets/images/example_web3.png?url"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2024-02-14T03:11:10.000Z"}],["meta",{"name":"twitter:card","content":"summary_large_image"}],["meta",{"name":"twitter:image:alt","content":"Web3 Frontend / Rust Server"}],["meta",{"property":"article:author","content":"dtp.dev"}],["meta",{"property":"article:modified_time","content":"2024-02-14T03:11:10.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Web3 Frontend / Rust Server\\",\\"image\\":[\\"https://dtp.dev/assets/images/example_web3.png?url\\"],\\"dateModified\\":\\"2024-02-14T03:11:10.000Z\\",\\"author\\":[{\\"@type\\":\\"Person\\",\\"name\\":\\"dtp.dev\\",\\"url\\":\\"https://dtp.dev\\"}]}"]]},"headers":[],"git":{"createdTime":1707880270000,"updatedTime":1707880270000,"contributors":[{"name":"mario4tier","email":"mario4tier@users.noreply.github.com","commits":1}]},"readingTime":{"minutes":0.08,"words":25},"filePathRelative":"examples/web3_rust.md","localizedDate":"February 14, 2024","autoDesc":true}');export{u as comp,h as data}; +import{_ as e}from"./plugin-vue_export-helper-DlAUqK2U.js";import{o as t,c as r,e as n}from"./app-BnFZaCe1.js";const o="/assets/images/example_web3.png",a={},s=n('

Web3 Frontend / Rust Server

Connect any frontend to both a centralized and decentralized backend.

Incomplete Documentation - Work-In-Progress

',4),i=[s];function c(d,p){return t(),r("div",null,i)}const u=e(a,[["render",c],["__file","web3_rust.html.vue"]]),h=JSON.parse('{"path":"/examples/web3_rust.html","title":"Web3 Frontend / Rust Server","lang":"en-US","frontmatter":{"editLink":true,"description":"Web3 Frontend / Rust Server Connect any frontend to both a centralized and decentralized backend. Incomplete Documentation - Work-In-Progress ","head":[["meta",{"property":"og:url","content":"https://dtp.dev/examples/web3_rust.html"}],["meta",{"property":"og:site_name","content":"Decentralized Transport Protocol"}],["meta",{"property":"og:title","content":"Web3 Frontend / Rust Server"}],["meta",{"property":"og:description","content":"Web3 Frontend / Rust Server Connect any frontend to both a centralized and decentralized backend. Incomplete Documentation - Work-In-Progress "}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:image","content":"https://dtp.dev/assets/images/example_web3.png?url"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2024-02-14T03:11:10.000Z"}],["meta",{"name":"twitter:card","content":"summary_large_image"}],["meta",{"name":"twitter:image:alt","content":"Web3 Frontend / Rust Server"}],["meta",{"property":"article:author","content":"dtp.dev"}],["meta",{"property":"article:modified_time","content":"2024-02-14T03:11:10.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Web3 Frontend / Rust Server\\",\\"image\\":[\\"https://dtp.dev/assets/images/example_web3.png?url\\"],\\"dateModified\\":\\"2024-02-14T03:11:10.000Z\\",\\"author\\":[{\\"@type\\":\\"Person\\",\\"name\\":\\"dtp.dev\\",\\"url\\":\\"https://dtp.dev\\"}]}"]]},"headers":[],"git":{"createdTime":1707880270000,"updatedTime":1707880270000,"contributors":[{"name":"mario4tier","email":"mario4tier@users.noreply.github.com","commits":1}]},"readingTime":{"minutes":0.08,"words":25},"filePathRelative":"examples/web3_rust.md","localizedDate":"February 14, 2024","autoDesc":true}');export{u as comp,h as data}; diff --git a/community/editors.html b/community/editors.html index 818c66d..ae71542 100644 --- a/community/editors.html +++ b/community/editors.html @@ -30,8 +30,8 @@ How to propose fix/change to the website? | Decentralized Transport Protocol - - + +
Skip to main content

How to propose fix/change to the website?


Anyone with a Github account can participate.

The website is built from markdown files (.md) and served directly from githubopen in new window.

Open the editor with the "Edit this pages on Github" link at the bottom.

When ready to propose your changes just select "Create a new branch" and give it a name:
Propose Changes

Your proposed changes will be merged after review.

Editing the website on your machine (advanced contributors)

If you prefer to preview exactly your change, then you need to run vuepress on your machine and modify the markdown files with an editor (e.g. VSCode).

Prerequisites:

For the one-time vuepress installation do:

$ cd ~/suibase/workdirs/common/extensions/dtp/docs
@@ -41,6 +41,6 @@
 ...
 Open your browser at http://localhost:8080
 

The browser updates as you change files under docs/src

See https://theme-hope.vuejs.press/guide/open in new window for advanced markdown features.

Submit your changes as a pull request, just ask as needed (not as hard as it seems once you do it once).

- + diff --git a/community/index.html b/community/index.html index 6f3bd9f..130b584 100644 --- a/community/index.html +++ b/community/index.html @@ -30,11 +30,11 @@ Community | Decentralized Transport Protocol - - + + - + diff --git a/docs/api_rust.html b/docs/api_rust.html index c74f186..c093cb4 100644 --- a/docs/api_rust.html +++ b/docs/api_rust.html @@ -30,11 +30,11 @@ Decentralized Transport Protocol - - + + - + diff --git a/docs/api_typescript.html b/docs/api_typescript.html index 02e0ce2..306c577 100644 --- a/docs/api_typescript.html +++ b/docs/api_typescript.html @@ -30,11 +30,11 @@ Decentralized Transport Protocol - - + + - + diff --git a/docs/design.html b/docs/design.html index 09440d0..7d5589c 100644 --- a/docs/design.html +++ b/docs/design.html @@ -28,23 +28,26 @@ document.documentElement.setAttribute("data-theme", "dark"); } - Design | Decentralized Transport Protocol + Design | Decentralized Transport Protocol - - + + -
Skip to main content

Design


Target Audience

Developers should first read the API they intend to use.

This document is for developers curious about DTP inner works.

At high level, how is the Sui Network used?

Sui owned objects are used for unidirectional data transfer with sub-second latency (See Fast Path Transactionsopen in new window in Sui docs).

Data Ingress: A data stream is sliced into transactions (txns) and added to the Sui network. The txns are targeted to a destination Pipe (owned object).

Data egress: The data "exit" the network through event streams (emitted by the txns executed for the destination Pipe). The data can be "observed" by any users, but decoded only by the ones having the decryption key.

The receiving end DTP SDK re-assembles the txns into the original data stream. The stream is then forwarded to the intended end-user (a TCP server, a Rust application layer above etc...).

Slower transactions (Sui consensus) are used for most "control plane" synchronizations (e.g. opening a connection)

DTP Glossary

Client: An application that initiate a connection.

Connection: One connection allows exchanging data between two applications. The applications are localized by their Host object on the Sui network. A connection will start to exchange data only after a Transport Control and one or two Pipe objects are created (for uni or bidirectional transfer respectively).

Host Object: Any signature authority that want to transfer data must create its own Host object. This object is involved in many control plane transactions. It allows to configure the services (and SLA) that are to be provided and control some firewall functions (e.g. limit maximum number of simultaneous open connections).

Objects: Usually refer to Sui objects (See Sui Docsopen in new window

Pipe Object: All off-chain data exchange involves an intermediate object on the Sui network. This object is the Pipe. It is owned by the sender of the data, and have its event stream observed by the receiver(s). A Pipe is loosely coupled to a Transport or Broadcast Control object for synchronization.

Server: Off-chain process intended to respond to client requests.

Service Level Agreement (SLA): Specify the costs, limitations and some behaviors for a service provided by a Host object. Example would be "sent data can be deleted from network storage after 48 hours (2 epochs)". The client signifies that it agrees to an SLA at the time the connection to the node is initiated. The SLA specs are such that DTP can enforce the agreement fairly to all parties.

Transport Control Object: Variables and state machines that exists for the lifetime of a single connection. This is a Sui shared object.

Firewall

(1) Gas cost of processing incoming traffic is paid by the sender. That includes connection creation cost and running the firewall at the Pipe Object. Most abuse can therefore be neutralized without requiring any processing/cost from the Server.

Firewall functionality also includes back pressure management to minimize initiating/paying for transactions while the server is already known offline or too busy.

(2) Optionally, the DTP Host object gather statistics from all its Pipe objects and can adjust the traffic policies, as an example to block an abusing sender. (Note: Synchronization with owned object is a logical representation. See Non-Blocking Data Plane for more design details).

(3) The server configure the firewall and does a periodical heartbeat using its shared DTP Host object. The DTP services daemon can also be configured to further actively control the firewall depending of its load (TBD).

(4) When a transmission is block because of the firewall, there is no event emitted (and sender is informed with a transaction error). Statistics are accumulated, but the Server is not impacted.

Non-Blocking Data Plane

A single owned Pipe object used as part of a transaction requiring slow consensus would cause a blocking of the data plane in the order of seconds. This is unacceptable if streaming audio/video.

Therefore, a DTP Pipe is actually composed of independent InnerPipe owned objects. One InnerPipe can be block and used as part of a slow consensus while the others keeps "flowing" with fast path transactions.

The receiver will re-assemble the data stream coming from all flowing InnerPipes (does not matter which one, DTP has sequence numbers for re-ordering).

Note: Every InnerPipe needs periodical synchronization with the control plane to exchange statistics and enforce traffic rules. DTP "forces" the sender (object owner) to collaborate by making an InnerPipe automatically blocked if not recently synchronized with the control plane. If the sender choose to not follow the "sync" protocol, then the whole Pipe will eventually be blocked.

A Sui slow consensus synchronization will look like this:

  fun slow_sync( pipe: &mut Pipe, 
-                 inner_pipe: &mut InnerPipe, 
+    
Skip to main content

Design


Target Audience

Developers should first read the API they intend to use.

This document is for developers curious about DTP inner works.

At high level, how is the Sui Network used?

Sui owned objects are used for unidirectional data transfer with sub-second latency (See Fast Path Transactionsopen in new window in Sui docs).

Data Ingress: A data stream is sliced into transactions (txns) and added to the Sui network. The txns are targeted to a destination Pipe (owned object).

Data egress: The data "exit" the network through event streams (emitted by the txns executed for the destination Pipe). The data can be "observed" by any users, but decoded only by the ones having the decryption key.

The receiving end DTP SDK re-assembles the txns into the original data stream. The stream is then forwarded to the intended end-user (a TCP server, a Rust application layer above etc...).

Slower transactions (Sui consensus) are used for most "control plane" synchronizations (e.g. opening a connection)

DTP Glossary

Client: An application that initiate a connection.

Connection: One connection allows exchanging data between two applications. The applications are localized by their Host object on the Sui network. A connection will start to exchange data only after a Transport Control and one or two Pipe objects are created (for uni or bidirectional transfer respectively).

Host Object: Any signature authority that want to transfer data must create its own Host object. This object is involved in many control plane transactions. It allows to configure the services (and SLA) that are to be provided and control some firewall functions (e.g. limit maximum number of simultaneous open connections).

Objects: Usually refer to Sui objects (See Sui Docsopen in new window

Pipe Object: All off-chain data exchange involves an intermediate object on the Sui network. This object is the Pipe. It is owned by the sender of the data, and have its event stream observed by the receiver(s). A Pipe is loosely coupled to a Transport or Broadcast Control object for synchronization.

Server: Off-chain process intended to respond to client requests.

Service Level Agreement (SLA): Specify the costs, limitations and some behaviors for a service provided by a Host object. Example would be "sent data can be deleted from network storage after 48 hours (2 epochs)". The client signifies that it agrees to an SLA at the time the connection to the node is initiated. The SLA specs are such that DTP can enforce the agreement fairly to all parties.

Transport Control Object: Variables and state machines that exists for the lifetime of a single connection. This is a Sui shared object.

Firewall

(1) Gas cost of processing incoming traffic is paid by the sender. That includes connection creation cost and running the firewall at the Pipe Object. Most abuse can therefore be neutralized without requiring any processing/cost from the Server.

Firewall functionality also includes back pressure management to minimize initiating/paying for transactions while the server is already known offline or too busy.

(2) Optionally, the DTP Host object gather statistics from all its Pipe objects and can adjust the traffic policies, as an example to block an abusing sender. (Note: Synchronization with owned object is a logical representation. See Non-Blocking Data Plane for more design details).

(3) The server configure the firewall and does a periodical heartbeat using its shared DTP Host object. The DTP services daemon can also be configured to further actively control the firewall depending of its load (TBD).

(4) When a transmission is block because of the firewall, there is no event emitted (and sender is informed with a transaction error). Statistics are accumulated, but the Server is not impacted.

Non-Blocking Data Plane

The owned objects on the data plane (e.g. Pipe) need to synchronize periodically with the control plane. This is for forwarding traffic statistic, apply latest firewall commands and bring the escrows to resolution.

The control plane typically uses shared object. Involving a single Pipe object with a slow consensus would cause a 2-3 seconds blocking of the data plane. This is unacceptable if streaming audio/video.

Therefore, a owned Pipe is actually assisted by InnerPipe owned objects. The synchronization between InnerPipe and the slower control plane is done in two steps.

  1. Each InnerPipe is sequentially "fast synch" with its related Pipe (all fast path).
  2. The Pipe object is "slow synch" with the control plane. This is a consensus transaction.

With this design, the data plane flows at "full speed" while keeping all objects eventually synchronized.

The receiver re-assemble the data stream from what is observed from all flowing InnerPipes (DTP has sequence numbers for re-ordering).

A fast path sync looks like:

  fun fast_sync( pipe: &mut Pipe, inner_pipe: &mut InnerPipe ) 
+  {
+    // ... quickly exchange data plane stats, latest control plane commands etc...
+  }
+

The slow consensus sync is:

  fun slow_sync( pipe: &mut Pipe,                  
                  transport_control: &mut TransportControl )
   {
-    // ... does a slow control plane operation ...
+    // ... does slow control plane operation ...
   }
-

A Sui fast path transaction will be:

  fun fast_data_send(inner_pipe: &mut InnerPipe, data: vector<u8>) 
+

The fast path data flowing is:

  fun fast_data_send(inner_pipe: &mut InnerPipe, data: vector<u8>) 
   {
     // ... does a fast data plane transmission ...
   }
-

Video Streaming

A media byte stream is eventually divided into transaction. A serialization of these transactions would limit quickly the bandwidth because of the Sui finality time and maximum transaction size.

To support high bandwidth, DTP uses multiple InnerPipes for parallel fast path transactions (See Non-Blocking Data Plane).

Most of the complexity is handled off-chain by DTP when dividing and re-assembling the transactions into a data stream.

Will this be practical? There is still some cost/performance/implementation unknowns that might persist until DTP is further develop...

Gas might get too expensive, there is also some potential issues with Sui fullnodes performance... (problem at egress of the network, not with the consensus performance itself).

Some estimations (See on Google Sheetopen in new window):

(Note: Numbers are best guess as of 02/14/24. Will be revised from time to time)

High-Availability and Load Balancing

Forwarding decision made by Pipe object when multiple end-points (servers)

Off-chain servers can share the incoming load or be each other's fallback for high-availability.

Unlike traditional network, the data is not physically pushed toward a server. Instead, the data remains on the network and an event is emitted about who should "pull it".

It is an off-chain responsibility for the application to subscribe to their respective event stream (with proper identifier filtering) and normally retrieve only its assigned data (this change in some recovery scenario).

Configuration of the end-points and health of the servers is managed through the DTP node, which in turn updates all its pipes and transport control objects.

DTP will hide the high complexity of many race conditions (assignment to a server that died) and connection migrations among all end-points belonging to the same Node.

Uni-directional Transfer

Similar to bi-directionals, but with a single Pipe object for data plane to minimize cost/complexity. Control plane still bi-directional (e.g. for encryption handshake).

Uni-Directional Data Transfer

Public Broadcasting

Similar to unidirectional, but without encryption and using Broadcast objects instead of a Pipe&Transport control.

Broadcasting Specific Objects

Broadcasters may require some different crypto-economic capability. Examples:

  • A live broadcast is wasteful if there is no one listening... one option will be to let DTP stop stream until there are enough fund from listeners to cover, say, the production cost of the next 1 minute. DTP would handle the automatic "on air" logic and fairly spread the cost among the contributors.
  • Listener may choose to tip a live broadcaster (for special requests?).

There are also some technical challenges particular to broadcasting (See Future Work).

- +

Of course, the sender has to be extra careful about equivocation.

Note 1: DTP "forces" the sender (Pipe/InnerPipe owner) to collaborate. An InnerPipe will automatically block when not "sufficiently" synchronized (e.g. block after 20 transaction without sync). If the sender choose to not follow the "sync" protocol, then the whole Pipe will eventually be blocked/useless. At worst, any party can "hangup" the connection and let DTP do fair final escrows resolutions.

Note 2: All this design is encapsulated within the DTP protocol and SDKs. The complexity will not be visible at the DTP API level.

Video Streaming

A media byte stream is eventually divided into transaction. A serialization of these transactions would limit quickly the bandwidth because of the Sui finality time and maximum transaction size.

To support high bandwidth, DTP uses multiple InnerPipes for parallel fast path transactions (See Non-Blocking Data Plane).

Most of the complexity is handled off-chain by DTP when dividing and re-assembling the transactions into a data stream.

Will this be practical? There is still some cost/performance/implementation unknowns that might persist until DTP is further develop...

Gas might get too expensive, there is also some potential issues with Sui fullnodes performance... (problem at egress of the network, not with the consensus performance itself).

Some estimations (See on Google Sheetopen in new window):

(Note: Numbers are best guess as of 02/14/24. Will be revised from time to time)

High-Availability and Load Balancing

Forwarding decision made by Pipe object when multiple end-points (servers)

Off-chain servers can share the incoming load or be each other's fallback for high-availability.

Unlike traditional network, the data is not physically pushed toward a server. Instead, the data remains on the network and an event is emitted about who should "pull it".

It is an off-chain responsibility for the application to subscribe to their respective event stream (with proper identifier filtering) and normally retrieve only its assigned data (this change in some recovery scenario).

Configuration of the end-points and health of the servers is managed through the DTP node, which in turn updates all its pipes and transport control objects.

DTP will hide the high complexity of many race conditions (assignment to a server that died) and connection migrations among all end-points belonging to the same Node.

Uni-directional Transfer

Similar to bi-directionals, but with a single Pipe object for data plane to minimize cost/complexity. Control plane still bi-directional (e.g. for encryption handshake).

Uni-Directional Data Transfer

Public Broadcasting

Similar to unidirectional, but without encryption and using Broadcast objects instead of a Pipe&Transport control.

Broadcasting Specific Objects

Broadcasters may require some different crypto-economic capability. Examples:

  • A live broadcast is wasteful if there is no one listening... one option will be to let DTP stop stream until there are enough fund from listeners to cover, say, the production cost of the next 1 minute. DTP would handle the automatic "on air" logic and fairly spread the cost among the contributors.
  • Listener may choose to tip a live broadcaster (for special requests?).

There are also some technical challenges particular to broadcasting (See Future Work).

+ diff --git a/docs/future_work.html b/docs/future_work.html index 3e21377..23f4cde 100644 --- a/docs/future_work.html +++ b/docs/future_work.html @@ -30,11 +30,11 @@ Future Work | Decentralized Transport Protocol - - + +
Skip to main content

Future Work


Future Work

Broadcasting Challenges

Data broadcasting will put pressure on fullnodes WebSocket event streaming services.

Fullnodes may have low economic incentive to support such high bandwidth services.

The architecture should scale to match the audience size.

Consequently, one possible long term solution is for DTP/Sui to provide only the crypto-economic services and then leave the burden of broadcasting to a public peer-to-peer network.

Each peer is running a DTP app for direct connection to the Sui network (for control plane). The complexity of the data plane transiting through a peer-to-peer network should be hidden to the end-users (Peers).

The use of P2P or not remains irrelevant to the broadcaster which always interface directly to the Sui network.

Data Deletion

Once the data is confirmed consumed by the receiver(s), then it can be deleted on the L1 network to recover some storage fee.

The sender of the data can opt out from automated deletion and assume the full storage cost.

Automated deletion is controlled by DTP to provide a fair time for the receiver(s) to consume the data and can be fine tuned through the sender service level agreement (SLA).

The SLAs are published by the server (in its Host object) and one is selected by the client at the time of the connection being established.

Data Consumption Confirmation

TCP protocol includes acknowledgment of L4 delivery to the destination, but without guarantee of being consumed by the application (requires additional protocol at layer 7).

DTP layer supports both; a confirmation of the data being available on the L1 network (TCP delivery equivalent) and optional confirmation of the client consuming the data (L7 protocol equivalent).

Example of use would be to integrate in the dApps the verification that the data was persisted off-chain by the destination. There is no verification that the destination is honest, but this would be used in context where it would be in the destination best interest to act honestly.

Encrypted Broadcasting

For now, broadcast are assumed to be always public and non-encrypted.

Allowing encryption may allow alternative economic model (similar to cable and/or streaming subscription services[1]), but this is challenging and piracy can (at best) only be mitigated[2].

Only the user with the decryption key would be able to make sense of the data. More research to be done about how DTP could implement this feature.


  1. Wikipedia Broadcast Encryptionopen in new window ↩︎

  2. Wikipedia Multicast Encryptionopen in new window ↩︎

- + diff --git a/docs/index.html b/docs/index.html index 2affe64..e66b08c 100644 --- a/docs/index.html +++ b/docs/index.html @@ -30,11 +30,11 @@ Basic Concept | Decentralized Transport Protocol - - + +
Skip to main content

Basic Concept


Exchange of data through the SUI network can be done between any Web2 application that includes the DTP and Sui SDKs.

Alternatively, the end-users may install the DTP services daemon to handle common cases (e.g making one side of the connection be a JSON-RPC server).

An end-user will first want to establish its own "unique contact point" on the network by creating a "Host Sui Object" using the DTP API.

Note: Most operation done through the DTP API can also be done on the command line with the "dtp" script.

An application can "ping" or "connect" to other Host object created by other apps. Each Host are uniquely identified by a <Host Object ID>.

The typical <IP address>:<Port> becomes a <Host Object ID>:<Port>

On-Chain Firewall

For security reason, each Host Object are by default created "completely closed". Using the DTP API, an application can choose to open ports of its Host object to progressively add services.

End-users will be able to observe what an Host allows (or blocks) even before attempting to use the service. An attacker trying to use a non-authorized service will be rejected by the DTP Move package on-chain (no impact on the server at all).

The DTP API supports white/black listing of sender sui address and various traffic policies. Configuration are kept and applied 24/7 on-chain.

Service Level Agreements (SLA)

DTP provides traditional byte streaming (TCP-Like) connections between Host, but also the simplification of higher level connection, in particular RPC calls.

When configuring a service for your Host, you must choose a "Service Level Agreement" that DTP will enforce.

An example is to require the requester to pay for the cost of the response that your server will have to provide.

Side Note

This is a good example where adding Web3 qualities to an existing Web2 service creates API monetization without requiring huge security/edge infrastructure investments

DTP defines a set of "Typical" service level agreement to help minimize market confusion.

Service Level AgreementWho Pays
DataStream-BalancedEveryone pay for their own transactions (txns).
AudioStream-FreeBroadcaster pays all transaction costs.
JSON-RPC-BalancedEveryone pay for their own txns. Best-effort service.
JSON-RPC-RequesterPaidRPC Requester pays. Escrow for success/failure.
JSON-RPC-RequesterPaidPlusSame as above, plus the server charges additional fee.
Ping-RequesterPaidPing Requester pays. Escrow for success/failure.

The requester agree to the SLA upon creation of the connection and is enforced through DTP escrow for the connection duration. DTP handles the fund redistribution fairly with consideration of various success/failure criteria (more refinement will follow in ~2025).

- + diff --git a/docs/scripts.html b/docs/scripts.html index 37eac23..83c479a 100644 --- a/docs/scripts.html +++ b/docs/scripts.html @@ -30,11 +30,11 @@ Decentralized Transport Protocol - - + + - + diff --git a/examples/index.html b/examples/index.html index b9925da..d8f0087 100644 --- a/examples/index.html +++ b/examples/index.html @@ -30,11 +30,11 @@ Use Cases | Decentralized Transport Protocol - - + +
Skip to main content

Use Cases


DTP provides networking building blocks that can be applied in many ways.

You will find on this page a few inspiring ideas.

When ready Go to choose your installation setup ....

Which layer do you need to work with?

DTP features are available in roughly 3 layers (by increasing level of difficulty):

  • DTP Services Daemon Similar to NGINX, Cloudflare, HAProxy... These are for proxy/forward/firewall services. You will simply be configuring how your data flows between your apps and servers. Your existing apps just use standard TCP/IP sockets (e.g. "localhost:port" URL) to interface with the DTP services daemon.

  • DTP Protocols Think "TCP". The DTP/Sui SDKs allows developers to have more control for connecting any mix of web2 apps (webapp, client/servers...). You will need to write Rust and/or Typescript apps. This is also the solution to eliminate having to install the DTP Services Daemon on your end-users' devices.

  • DTP Sui Move Packages Innovations particular to Sui, such as RPC escrows, new traffic policies, coins&call equivocation mitigation, metering etc... you will likely be deeply involve into web3 development at this point.

For most users, you will deal only with the "easiest" layer, the "DTP Services Daemon".

If not sure how to proceed for your specific need, then please open a discussion on Discordopen in new window.

Examples/Ideas

Client/Server

  • Web3 frontends connecting to a centralized JSON-RPC backend (More info)
  • Rust/Typescript Web3 Client to centralized TCP Server (More info)

Encrypted Messaging

  • Add traditional user/password login to a dApp. The goal is to allow access to the same "user account" even if done from a different wallet (client address). Implementation often requires "secret messaging" between a centralized server and the Web3 apps.
  • Any user-to-user data transfer
  • Anonymous Tips Line (with potential reward in return).

Networking / Infrastructure

  • Zookeeper, Consul, Serf-like services for discovery and consensus among off-chain servers.
  • UDP, TCP, QUIC/UDP Tunneling: Transport IP protocols packets within a DTP connection for point-to-point applications (See DTP Services Daemon for an alternative)

Firewall

  • Rate limit access to a back-end server (either bandwidth or request)
  • Allow/block origin (using authentication)

Crypto-Economics

  • Any service charging for content access (in addition to gas cost). DTP provides generic per byte and/or per request escrow service (to meter pre-agreed cost, limit and quantity... not quality).
  • Pre-paid subscription per day/month (epoch driven?).
  • Various escrow service that allows to shift the transport cost completely at the origin or destination (gas always paid by sender, but escrow service handles fair refund).

Public Broadcasting

  • Allow live broadcasting to automatically turn on/off upon enough fund contributed (thus saving the producer from any expense when no-one is listening).
  • Public broadcast performed upon enough ticket sold.
  • Tip/Request/Message/Audience participation line attach to a public event channel.
- + diff --git a/examples/rpc_firewall.html b/examples/rpc_firewall.html index a87cb03..2b12246 100644 --- a/examples/rpc_firewall.html +++ b/examples/rpc_firewall.html @@ -30,11 +30,11 @@ JSON-RPC Firewall | Decentralized Transport Protocol - - + +
Skip to main content

JSON-RPC Firewall


JSON-RPC Firewall

In this example, a company want to provide a JSON-RPC API service to its customer front-end applications.

One goal is to protect the web2 server from DDoS attack, in particular, hide the IP address.

A DTP Services Daemon runs as a TCP/IP proxy on the same machine as the web2 server.

Since the sender has to pay for all the data byte transmission costs through the Sui network, an attack is costly and mostly futile.

The server IP address is visible only to the Sui nodes (not to the users on the other side of the Sui network). This mitigates traditional direct IP attacks.

In this example the frontend contact the hidden web2 IP server using the <Host Object ID>:8923 address and DTP takes care of the safe data transfer.

On the drawing, everything in green and blue is provided by DTP and the Sui infrastructure respectively. The application developer provides only what is shown in yellow.

Is the DDoS protection 100% secure?

It depends... the server operator need to have some faith that its Sui node partners are honest (in similar way that one choose to trust a reputable company such as Cloudflare). To mitigate this, a company may choose to run their own Sui fullnodes, making their servers IP addresses near impossible to target by anyone.

Scalability and Reliability

DTP also supports having a single Host Object ID be resolved to more than one backend servers (failover, load-balancing...). This is done through DTP Services configuration.

- + diff --git a/examples/web3_rust.html b/examples/web3_rust.html index a0af4be..e1c447f 100644 --- a/examples/web3_rust.html +++ b/examples/web3_rust.html @@ -30,11 +30,11 @@ Web3 Frontend / Rust Server | Decentralized Transport Protocol - - + + - + diff --git a/faq.html b/faq.html index 8dbada2..06f859d 100644 --- a/faq.html +++ b/faq.html @@ -30,11 +30,11 @@ FAQ | Decentralized Transport Protocol - - + +
Skip to main content

FAQ


FAQ

In one sentence... What can DTP do?

It is a TCP-Like protocol facilitating data transfer between web2 applications, with additional Web3 features such as services monetization, anonymity and security.

Can DTP be used between Web3 frontend apps?

Yes. DTP can selectively connect front-ends WebApp to each other, while keeping the data transfer under the control of a dApps (transit on the Sui network).

As an example, you can use it to allow gamers exchange encrypted messages among themselves while they are on the same team in a Web3 game. In this case, DTP provides the WebApp to WebApp connectivity without making the players IP addresses visible.

What sort of data can DTP transport?

Any protocol, any data stream.

Data can be a few bytes for a one time secret exchange for authentication/login. At another extreme, the bandwidth can be for as much as an encrypted video stream. The economic feasibility of HD video streaming on blockchain is an open question... (See Video Streaming )

Can DTP be used with commercial application?

Yes. DTP is open-source and can freely be used in commercial application (Apache 2.0 License).

How much does it cost to use DTP?

Only the Sui gas needed to run it, expect the execution cost to be mostly driven by the number of bytes transferred.

There is no developer fee or middlemen commission collected for using DTP.

Some service provider may optionally add their own fees on top of DTP (e.g. micro-payments), but DTP standardize public disclosure (and escrow management) of these fees on-chain. There is no "fine print unexpected" fee. A provider can not change the fees on already open DTP connections.

Can DTP unexpectedly drain my account?

We are working very hard to make this impossible.

DTP protects its user by enforcing a maximum amount of fee possibly collected per day (per epoch). The user must explicitly approve and sign a change to this maximum.

Also, fee rates are determine once by a Service Level Agreement (SLA) when opening a DTP connection. You can close that connection at any time. It is not possible for a service provider to keep collecting payments after a DTP connection is closed.

(Note: The configurable maximum is tied to a wallet address and enforce on-chain).

When will DTP have its own token?

Never.

DTP operations are always paid in Sui.

dApps built on top of DTP can use tokens, but this is not within the scope of DTP itself.

Can DTP simply tunnel standard TCP, UDP, IP packets?

Transparent packets tunneling could be done, but it is not recommended.

DTP/Sui provides already reliable and ordered data transport. That would be redundant with say, what TCP would try to achieve within a tunnel.

Instead, look into DTP Services Daemon to efficiently terminate/bridge standard IP protocols. That eliminates protocol redundancy and better leverage what the Sui network already provide.

Any plan to support another blockchain?

No, unless a breakthrough in performance is possible with another blockchain architecture.

Sui provides stable time to finality (low jitter), parallelism and scalability (no contention between connections).

Low jitter allows small and predictable buffer size at the receivers.

Sui fast path transactions makes sub-second streaming latency possible.

For now, DTP/Sui might not be well-suited for application that depends on fast sequence of query/response (since that requires two transactions finality). DTP attempts to minimize roundtrips and protocol handshakes at every step.

Where is the code?

DTP still in early design phase and is not yet release. See GitHubopen in new window development branches for "work-in-progress".

Where can I go for more questions?

Try the Discord channel: https://discord.gg/Erb6SwsVbHopen in new window

- + diff --git a/how-to/full_setup.html b/how-to/full_setup.html index 8ccfea6..908c69e 100644 --- a/how-to/full_setup.html +++ b/how-to/full_setup.html @@ -30,11 +30,11 @@ Full Development Setup | Decentralized Transport Protocol - - + +
Skip to main content

Full Development Setup


Warning

work-in-progress. The installation process is not yet fully implemented.

(1) Install Suibase

https://suibase.io/how-to/installopen in new window

Suibase allows distinct Sui binaries and keystore management for each network (localnet, devnet, testnet and mainnet). It also installs the "DTP Services" daemon and "dtp" CLI command for you.

(2) Enable DTP Services for localnet

Do $ localnet enable dtp

Other useful commands:

  • Disable DTP with $ localnet disable dtp
  • Update DTP (and Suibase) to latest with $ ~/suibase/update
  • Update only the Sui binaries from Mysten Labs with $ localnet update

(3) Start local processes

Do $ localnet start

It is recommended to develop on a single machine with localnet first and (easily) migrate to testnet later for end-to-end testing.

Note: Localnet runs two instances of the DTP Services on different local port, allowing the simulation of two end-users. This is very convenient for quick development and testing of your own application on a single machine.

Other useful commands:

  • Monitor DTP services health (UP/DOWN) with $ localnet status
  • Monitor your own services status/account balance with $ dtp status
  • Reset the localnet to its genesis state with $ localnet regen

(4) Optional DTP Self-Test

Do $ dtp self-test to verify that DTP is working as expected.

You can re-run this command anytime you are trying to isolate if a problem is in your application or the DTP setup itself.

Next steps (TODO)

  • Instruction to migrate from localnet to testnet testing (should be easy).
  • Tutorial of a simple client/server "echo" service and how testing is done.
- + diff --git a/how-to/index.html b/how-to/index.html index 405d6e1..c254e9b 100644 --- a/how-to/index.html +++ b/how-to/index.html @@ -30,11 +30,11 @@ How to | Decentralized Transport Protocol - - + + - + diff --git a/how-to/install.html b/how-to/install.html index f0349fb..125667c 100644 --- a/how-to/install.html +++ b/how-to/install.html @@ -30,11 +30,11 @@ Installation | Decentralized Transport Protocol - - + +
Skip to main content

Installation


There are 3 ways to install DTP.

Choose the one that best fits your needs and you can always later switch from one to the other.

Choice 1 of 3: Full Development Setup

This is the only setup available for now.

Recommended if you need any of these:

  • Develop Sui Move package (with or without DTP)

  • Develop your own Rust application using DTP and/or Sui Rust SDK.

  • Develop a new type of DTP service (e.g. you want your own backend Rust server process and do not want to use the DTP Services daemon as an intermediate).

The setup includes a Sui development framework (Suibase), the DTP Service Daemon runtime, all the DTP SDKs and some utility scripts for quicker edit/publish/debug development cycles.

DTP is not conflicting with other Sui installations (e.g. official Mysten Labs cargo install) and can be uninstalled easily.

Go to Full Setup ....

Choice 2 of 3: DTP Services Runtime (No Coding)

Not yet implemented

For now, use the Full Development setup, which includes the DTP Services runtime.

Choose this setup if you only need one or more of the following feature:

  • Make your existing server API accessible on the Sui network (e.g. REST, JSON-RPC etc...)

  • Make a local directory content accessible on the Sui network (be a "file server")

  • Allow other user on the network to discover and ping your server.

  • Have end-users (e.g. frontend app) install their own DTP runtime as a local proxy to your backend services.

This setup does not require any coding skills, just configuration in a text file and using the dtp command line tool.

Choice 3 of 3: DTP Typescript SDK (NPM Packages Only)

Not yet implemented

The DTP Typescript SDK is not yet written. Priority is to develop the Rust SDK first.

Choose this setup if you only need to develop front-end apps doing DTP connections to existing services and not require the DTP service daemon installation.

- + diff --git a/how-to/npm_only.html b/how-to/npm_only.html index 1122560..0aacd5c 100644 --- a/how-to/npm_only.html +++ b/how-to/npm_only.html @@ -30,11 +30,11 @@ Decentralized Transport Protocol - - + + - + diff --git a/how-to/runtime_only.html b/how-to/runtime_only.html index 7cdabc9..a6f0cff 100644 --- a/how-to/runtime_only.html +++ b/how-to/runtime_only.html @@ -30,11 +30,11 @@ Decentralized Transport Protocol - - + + - + diff --git a/index.html b/index.html index 028b6d1..904acfd 100644 --- a/index.html +++ b/index.html @@ -30,11 +30,11 @@ Home | Decentralized Transport Protocol - - + +
Skip to main content

For when you want some web2 on the web3 playground


Why Sui and not blockchain 'x' ?
SUI has good finality latency stability (low jitter) and network scalability (maintains per connection throughput regardless of total load).

Sui provides two type of processing:

  • Fast path transactions with sub-second finality for data plane transfer (See 'partial ordering' illustration). This facilitate async/parallel/scalable transmission.
  • Narwhal/Bullshark consensus with 2-3 seconds finality used for slower control plane synchronization, like connection creations, services and firewall reconfiguration etc...

With its flexible dual-type transactions, Sui makes practical implementing the typical data + control plane design found in IP networks ( Cloudflare explains it wellopen in new window ).

See How Sui Differs from Other Blockchains?open in new window

Why not simply use the good old, faster and free internet?

Join the Discord communityopen in new window and let's talk about it!

- + diff --git a/intro.html b/intro.html index 42e0e23..9ef45e4 100644 --- a/intro.html +++ b/intro.html @@ -30,11 +30,11 @@ What is DTP? | Decentralized Transport Protocol - - + +
Skip to main content

What is DTP?


It is a TCP-Like protocol facilitating data transfer between any web2 applications, with additional Web3 features such as services monetization, anonymity and security.

DTP facilitate high-level data transfer, such as audio, video, RPC calls etc...

DTP can be integrated into your own Rust/Typescript apps (frontend and/or backend).

Alternatively, you can direct your TCP/IP socket (or websocket) traffic toward a local DTP Services daemon. This daemon takes care of adding Web3 capabilities to your existing Web2 traffic (e.g. handles "per request" micro-payments).

Not sure if a good fit? Check a few use cases.

Ready to try it ? Go to Installation.

- + diff --git a/ref/api_rust.html b/ref/api_rust.html index e799847..0b07e0d 100644 --- a/ref/api_rust.html +++ b/ref/api_rust.html @@ -30,11 +30,11 @@ Decentralized Transport Protocol - - + + - + diff --git a/ref/api_typescript.html b/ref/api_typescript.html index 1a58811..3c0a4a2 100644 --- a/ref/api_typescript.html +++ b/ref/api_typescript.html @@ -30,11 +30,11 @@ Decentralized Transport Protocol - - + + - + diff --git a/ref/design.html b/ref/design.html index fe5f7ab..d31dc8e 100644 --- a/ref/design.html +++ b/ref/design.html @@ -30,21 +30,24 @@ Design | Decentralized Transport Protocol - - + + -
Skip to main content

Design


Target Audience

Developers should first read the API they intend to use.

This document is for developers curious about DTP inner works.

At high level, how is the Sui Network used?

Sui owned objects are used for unidirectional data transfer with sub-second latency (See Fast Path Transactionsopen in new window in Sui docs).

Data Ingress: A data stream is sliced into transactions (txns) and added to the Sui network. The txns are targeted to a destination Pipe (owned object).

Data egress: The data "exit" the network through event streams (emitted by the txns executed for the destination Pipe). The data can be "observed" by any users, but decoded only by the ones having the decryption key.

The receiving end DTP SDK re-assembles the txns into the original data stream. The stream is then forwarded to the intended end-user (a TCP server, a Rust application layer above etc...).

Slower transactions (Sui consensus) are used for most "control plane" synchronizations (e.g. opening a connection)

DTP Glossary

Client: An application that initiate a connection.

Connection: One connection allows exchanging data between two applications. The applications are localized by their Host object on the Sui network. A connection will start to exchange data only after a Transport Control and one or two Pipe objects are created (for uni or bidirectional transfer respectively).

Host Object: Any signature authority that want to transfer data must create its own Host object. This object is involved in many control plane transactions. It allows to configure the services (and SLA) that are to be provided and control some firewall functions (e.g. limit maximum number of simultaneous open connections).

Objects: Usually refer to Sui objects (See Sui Docsopen in new window

Pipe Object: All off-chain data exchange involves an intermediate object on the Sui network. This object is the Pipe. It is owned by the sender of the data, and have its event stream observed by the receiver(s). A Pipe is loosely coupled to a Transport or Broadcast Control object for synchronization.

Server: Off-chain process intended to respond to client requests.

Service Level Agreement (SLA): Specify the costs, limitations and some behaviors for a service provided by a Host object. Example would be "sent data can be deleted from network storage after 48 hours (2 epochs)". The client signifies that it agrees to an SLA at the time the connection to the node is initiated. The SLA specs are such that DTP can enforce the agreement fairly to all parties.

Transport Control Object: Variables and state machines that exists for the lifetime of a single connection. This is a Sui shared object.

Firewall

(1) Gas cost of processing incoming traffic is paid by the sender. That includes connection creation cost and running the firewall at the Pipe Object. Most abuse can therefore be neutralized without requiring any processing/cost from the Server.

Firewall functionality also includes back pressure management to minimize initiating/paying for transactions while the server is already known offline or too busy.

(2) Optionally, the DTP Host object gather statistics from all its Pipe objects and can adjust the traffic policies, as an example to block an abusing sender. (Note: Synchronization with owned object is a logical representation. See Non-Blocking Data Plane for more design details).

(3) The server configure the firewall and does a periodical heartbeat using its shared DTP Host object. The DTP services daemon can also be configured to further actively control the firewall depending of its load (TBD).

(4) When a transmission is block because of the firewall, there is no event emitted (and sender is informed with a transaction error). Statistics are accumulated, but the Server is not impacted.

Non-Blocking Data Plane

A single owned Pipe object used as part of a transaction requiring slow consensus would cause a blocking of the data plane in the order of seconds. This is unacceptable if streaming audio/video.

Therefore, a DTP Pipe is actually composed of independent InnerPipe owned objects. One InnerPipe can be block and used as part of a slow consensus while the others keeps "flowing" with fast path transactions.

The receiver will re-assemble the data stream coming from all flowing InnerPipes (does not matter which one, DTP has sequence numbers for re-ordering).

Note: Every InnerPipe needs periodical synchronization with the control plane to exchange statistics and enforce traffic rules. DTP "forces" the sender (object owner) to collaborate by making an InnerPipe automatically blocked if not recently synchronized with the control plane. If the sender choose to not follow the "sync" protocol, then the whole Pipe will eventually be blocked.

A Sui slow consensus synchronization will look like this:

  fun slow_sync( pipe: &mut Pipe, 
-                 inner_pipe: &mut InnerPipe, 
+    
Skip to main content

Design


Target Audience

Developers should first read the API they intend to use.

This document is for developers curious about DTP inner works.

At high level, how is the Sui Network used?

Sui owned objects are used for unidirectional data transfer with sub-second latency (See Fast Path Transactionsopen in new window in Sui docs).

Data Ingress: A data stream is sliced into transactions (txns) and added to the Sui network. The txns are targeted to a destination Pipe (owned object).

Data egress: The data "exit" the network through event streams (emitted by the txns executed for the destination Pipe). The data can be "observed" by any users, but decoded only by the ones having the decryption key.

The receiving end DTP SDK re-assembles the txns into the original data stream. The stream is then forwarded to the intended end-user (a TCP server, a Rust application layer above etc...).

Slower transactions (Sui consensus) are used for most "control plane" synchronizations (e.g. opening a connection)

DTP Glossary

Client: An application that initiate a connection.

Connection: One connection allows exchanging data between two applications. The applications are localized by their Host object on the Sui network. A connection will start to exchange data only after a Transport Control and one or two Pipe objects are created (for uni or bidirectional transfer respectively).

Host Object: Any signature authority that want to transfer data must create its own Host object. This object is involved in many control plane transactions. It allows to configure the services (and SLA) that are to be provided and control some firewall functions (e.g. limit maximum number of simultaneous open connections).

Objects: Usually refer to Sui objects (See Sui Docsopen in new window

Pipe Object: All off-chain data exchange involves an intermediate object on the Sui network. This object is the Pipe. It is owned by the sender of the data, and have its event stream observed by the receiver(s). A Pipe is loosely coupled to a Transport or Broadcast Control object for synchronization.

Server: Off-chain process intended to respond to client requests.

Service Level Agreement (SLA): Specify the costs, limitations and some behaviors for a service provided by a Host object. Example would be "sent data can be deleted from network storage after 48 hours (2 epochs)". The client signifies that it agrees to an SLA at the time the connection to the node is initiated. The SLA specs are such that DTP can enforce the agreement fairly to all parties.

Transport Control Object: Variables and state machines that exists for the lifetime of a single connection. This is a Sui shared object.

Firewall

(1) Gas cost of processing incoming traffic is paid by the sender. That includes connection creation cost and running the firewall at the Pipe Object. Most abuse can therefore be neutralized without requiring any processing/cost from the Server.

Firewall functionality also includes back pressure management to minimize initiating/paying for transactions while the server is already known offline or too busy.

(2) Optionally, the DTP Host object gather statistics from all its Pipe objects and can adjust the traffic policies, as an example to block an abusing sender. (Note: Synchronization with owned object is a logical representation. See Non-Blocking Data Plane for more design details).

(3) The server configure the firewall and does a periodical heartbeat using its shared DTP Host object. The DTP services daemon can also be configured to further actively control the firewall depending of its load (TBD).

(4) When a transmission is block because of the firewall, there is no event emitted (and sender is informed with a transaction error). Statistics are accumulated, but the Server is not impacted.

Non-Blocking Data Plane

The owned objects on the data plane (e.g. Pipe) need to synchronize periodically with the control plane. This is for forwarding traffic statistic, apply latest firewall commands and bring the escrows to resolution.

The control plane typically uses shared object. Involving a single Pipe object with a slow consensus would cause a 2-3 seconds blocking of the data plane. This is unacceptable if streaming audio/video.

Therefore, a owned Pipe is actually assisted by InnerPipe owned objects. The synchronization between InnerPipe and the slower control plane is done in two steps.

  1. Each InnerPipe is sequentially "fast synch" with its related Pipe (all fast path).
  2. The Pipe object is "slow synch" with the control plane. This is a consensus transaction.

With this design, the data plane flows at "full speed" while keeping all objects eventually synchronized.

The receiver re-assemble the data stream from what is observed from all flowing InnerPipes (DTP has sequence numbers for re-ordering).

A fast path sync looks like:

  fun fast_sync( pipe: &mut Pipe, inner_pipe: &mut InnerPipe ) 
+  {
+    // ... quickly exchange data plane stats, latest control plane commands etc...
+  }
+

The slow consensus sync is:

  fun slow_sync( pipe: &mut Pipe,                  
                  transport_control: &mut TransportControl )
   {
-    // ... does a slow control plane operation ...
+    // ... does slow control plane operation ...
   }
-

A Sui fast path transaction will be:

  fun fast_data_send(inner_pipe: &mut InnerPipe, data: vector<u8>) 
+

The fast path data flowing is:

  fun fast_data_send(inner_pipe: &mut InnerPipe, data: vector<u8>) 
   {
     // ... does a fast data plane transmission ...
   }
-

Video Streaming

A media byte stream is eventually divided into transaction. A serialization of these transactions would limit quickly the bandwidth because of the Sui finality time and maximum transaction size.

To support high bandwidth, DTP uses multiple InnerPipes for parallel fast path transactions (See Non-Blocking Data Plane).

Most of the complexity is handled off-chain by DTP when dividing and re-assembling the transactions into a data stream.

Will this be practical? There is still some cost/performance/implementation unknowns that might persist until DTP is further develop...

Gas might get too expensive, there is also some potential issues with Sui fullnodes performance... (problem at egress of the network, not with the consensus performance itself).

Some estimations (See on Google Sheetopen in new window):

(Note: Numbers are best guess as of 02/14/24. Will be revised from time to time)

High-Availability and Load Balancing

Forwarding decision made by Pipe object when multiple end-points (servers)

Off-chain servers can share the incoming load or be each other's fallback for high-availability.

Unlike traditional network, the data is not physically pushed toward a server. Instead, the data remains on the network and an event is emitted about who should "pull it".

It is an off-chain responsibility for the application to subscribe to their respective event stream (with proper identifier filtering) and normally retrieve only its assigned data (this change in some recovery scenario).

Configuration of the end-points and health of the servers is managed through the DTP node, which in turn updates all its pipes and transport control objects.

DTP will hide the high complexity of many race conditions (assignment to a server that died) and connection migrations among all end-points belonging to the same Node.

Uni-directional Transfer

Similar to bi-directionals, but with a single Pipe object for data plane to minimize cost/complexity. Control plane still bi-directional (e.g. for encryption handshake).

Uni-Directional Data Transfer

Public Broadcasting

Similar to unidirectional, but without encryption and using Broadcast objects instead of a Pipe&Transport control.

Broadcasting Specific Objects

Broadcasters may require some different crypto-economic capability. Examples:

  • A live broadcast is wasteful if there is no one listening... one option will be to let DTP stop stream until there are enough fund from listeners to cover, say, the production cost of the next 1 minute. DTP would handle the automatic "on air" logic and fairly spread the cost among the contributors.
  • Listener may choose to tip a live broadcaster (for special requests?).

There are also some technical challenges particular to broadcasting (See Future Work).

- +

Of course, the sender has to be extra careful about equivocation.

Note 1: DTP "forces" the sender (Pipe/InnerPipe owner) to collaborate. An InnerPipe will automatically block when not "sufficiently" synchronized (e.g. block after 20 transaction without sync). If the sender choose to not follow the "sync" protocol, then the whole Pipe will eventually be blocked/useless. At worst, any party can "hangup" the connection and let DTP do fair final escrows resolutions.

Note 2: All this design is encapsulated within the DTP protocol and SDKs. The complexity will not be visible at the DTP API level.

Video Streaming

A media byte stream is eventually divided into transaction. A serialization of these transactions would limit quickly the bandwidth because of the Sui finality time and maximum transaction size.

To support high bandwidth, DTP uses multiple InnerPipes for parallel fast path transactions (See Non-Blocking Data Plane).

Most of the complexity is handled off-chain by DTP when dividing and re-assembling the transactions into a data stream.

Will this be practical? There is still some cost/performance/implementation unknowns that might persist until DTP is further develop...

Gas might get too expensive, there is also some potential issues with Sui fullnodes performance... (problem at egress of the network, not with the consensus performance itself).

Some estimations (See on Google Sheetopen in new window):

(Note: Numbers are best guess as of 02/14/24. Will be revised from time to time)

High-Availability and Load Balancing

Forwarding decision made by Pipe object when multiple end-points (servers)

Off-chain servers can share the incoming load or be each other's fallback for high-availability.

Unlike traditional network, the data is not physically pushed toward a server. Instead, the data remains on the network and an event is emitted about who should "pull it".

It is an off-chain responsibility for the application to subscribe to their respective event stream (with proper identifier filtering) and normally retrieve only its assigned data (this change in some recovery scenario).

Configuration of the end-points and health of the servers is managed through the DTP node, which in turn updates all its pipes and transport control objects.

DTP will hide the high complexity of many race conditions (assignment to a server that died) and connection migrations among all end-points belonging to the same Node.

Uni-directional Transfer

Similar to bi-directionals, but with a single Pipe object for data plane to minimize cost/complexity. Control plane still bi-directional (e.g. for encryption handshake).

Uni-Directional Data Transfer

Public Broadcasting

Similar to unidirectional, but without encryption and using Broadcast objects instead of a Pipe&Transport control.

Broadcasting Specific Objects

Broadcasters may require some different crypto-economic capability. Examples:

  • A live broadcast is wasteful if there is no one listening... one option will be to let DTP stop stream until there are enough fund from listeners to cover, say, the production cost of the next 1 minute. DTP would handle the automatic "on air" logic and fairly spread the cost among the contributors.
  • Listener may choose to tip a live broadcaster (for special requests?).

There are also some technical challenges particular to broadcasting (See Future Work).

+ diff --git a/ref/future_work.html b/ref/future_work.html index 76b771a..d0cb206 100644 --- a/ref/future_work.html +++ b/ref/future_work.html @@ -30,11 +30,11 @@ Future Work | Decentralized Transport Protocol - - + +
Skip to main content

Future Work


Future Work

Broadcasting Challenges

Data broadcasting will put pressure on fullnodes WebSocket event streaming services.

Fullnodes may have low economic incentive to support such high bandwidth services.

The architecture should scale to match the audience size.

Consequently, one possible long term solution is for DTP/Sui to provide only the crypto-economic services and then leave the burden of broadcasting to a public peer-to-peer network.

Each peer is running a DTP app for direct connection to the Sui network (for control plane). The complexity of the data plane transiting through a peer-to-peer network should be hidden to the end-users (Peers).

The use of P2P or not remains irrelevant to the broadcaster which always interface directly to the Sui network.

Data Deletion

Once the data is confirmed consumed by the receiver(s), then it can be deleted on the L1 network to recover some storage fee.

The sender of the data can opt out from automated deletion and assume the full storage cost.

Automated deletion is controlled by DTP to provide a fair time for the receiver(s) to consume the data and can be fine tuned through the sender service level agreement (SLA).

The SLAs are published by the server (in its Host object) and one is selected by the client at the time of the connection being established.

Data Consumption Confirmation

TCP protocol includes acknowledgment of L4 delivery to the destination, but without guarantee of being consumed by the application (requires additional protocol at layer 7).

DTP layer supports both; a confirmation of the data being available on the L1 network (TCP delivery equivalent) and optional confirmation of the client consuming the data (L7 protocol equivalent).

Example of use would be to integrate in the dApps the verification that the data was persisted off-chain by the destination. There is no verification that the destination is honest, but this would be used in context where it would be in the destination best interest to act honestly.

Encrypted Broadcasting

For now, broadcast are assumed to be always public and non-encrypted.

Allowing encryption may allow alternative economic model (similar to cable and/or streaming subscription services[1]), but this is challenging and piracy can (at best) only be mitigated[2].

Only the user with the decryption key would be able to make sense of the data. More research to be done about how DTP could implement this feature.


  1. Wikipedia Broadcast Encryptionopen in new window ↩︎

  2. Wikipedia Multicast Encryptionopen in new window ↩︎

- + diff --git a/ref/index.html b/ref/index.html index fb6f487..7e17032 100644 --- a/ref/index.html +++ b/ref/index.html @@ -30,11 +30,11 @@ Basic Concept | Decentralized Transport Protocol - - + +
Skip to main content

Basic Concept


Exchange of data through the SUI network can be done between any Web2 application that includes the DTP and Sui SDKs.

Alternatively, the end-users may install the DTP services daemon to handle common cases (e.g making one side of the connection be a JSON-RPC server).

An end-user will first want to establish its own "unique contact point" on the network by creating a "Host Sui Object" using the DTP API.

Note: Most operation done through the DTP API can also be done on the command line with the "dtp" script.

An application can "ping" or "connect" to other Host object created by other apps. Each Host are uniquely identified by a <Host Object ID>.

The typical <IP address>:<Port> becomes a <Host Object ID>:<Port>

On-Chain Firewall

For security reason, each Host Object are by default created "completely closed". Using the DTP API, an application can choose to open ports of its Host object to progressively add services.

End-users will be able to observe what an Host allows (or blocks) even before attempting to use the service. An attacker trying to use a non-authorized service will be rejected by the DTP Move package on-chain (no impact on the server at all).

The DTP API supports white/black listing of sender sui address and various traffic policies. Configuration are kept and applied 24/7 on-chain.

Service Level Agreements (SLA)

DTP provides traditional byte streaming (TCP-Like) connections between Host, but also the simplification of higher level connection, in particular RPC calls.

When configuring a service for your Host, you must choose a "Service Level Agreement" that DTP will enforce.

An example is to require the requester to pay for the cost of the response that your server will have to provide.

Side Note

This is a good example where adding Web3 qualities to an existing Web2 service creates API monetization without requiring huge security/edge infrastructure investments

DTP defines a set of "Typical" service level agreement to help minimize market confusion.

Service Level AgreementWho Pays
DataStream-BalancedEveryone pay for their own transactions (txns).
AudioStream-FreeBroadcaster pays all transaction costs.
JSON-RPC-BalancedEveryone pay for their own txns. Best-effort service.
JSON-RPC-RequesterPaidRPC Requester pays. Escrow for success/failure.
JSON-RPC-RequesterPaidPlusSame as above, plus the server charges additional fee.
Ping-RequesterPaidPing Requester pays. Escrow for success/failure.

The requester agree to the SLA upon creation of the connection and is enforced through DTP escrow for the connection duration. DTP handles the fund redistribution fairly with consideration of various success/failure criteria (more refinement will follow in ~2025).

- + diff --git a/ref/scripts.html b/ref/scripts.html index 47a70e3..0bab80a 100644 --- a/ref/scripts.html +++ b/ref/scripts.html @@ -30,11 +30,11 @@ Decentralized Transport Protocol - - + + - + diff --git a/sitemap.xml b/sitemap.xml index 50d7e7d..feb2396 100644 --- a/sitemap.xml +++ b/sitemap.xml @@ -1,3 +1,3 @@ -https://dtp.dev/2024-02-15T22:23:30.000Zdailyhttps://dtp.dev/faq.html2024-02-15T22:23:30.000Zdailyhttps://dtp.dev/intro.html2024-02-15T23:04:37.000Zdailyhttps://dtp.dev/community/2024-02-14T03:11:10.000Zdailyhttps://dtp.dev/community/editors.html2024-02-14T03:11:10.000Zdailyhttps://dtp.dev/docs/2024-02-15T22:23:30.000Zdailyhttps://dtp.dev/docs/api_rust.html2024-02-14T03:11:10.000Zdailyhttps://dtp.dev/docs/api_typescript.html2024-02-14T03:11:10.000Zdailyhttps://dtp.dev/docs/design.html2024-02-15T22:54:53.000Zdailyhttps://dtp.dev/docs/future_work.html2024-02-15T22:23:30.000Zdailyhttps://dtp.dev/docs/scripts.html2024-02-14T03:11:10.000Zdailyhttps://dtp.dev/examples/2024-02-15T22:54:53.000Zdailyhttps://dtp.dev/examples/rpc_firewall.html2024-02-14T03:11:10.000Zdailyhttps://dtp.dev/examples/web3_rust.html2024-02-14T03:11:10.000Zdailyhttps://dtp.dev/how-to/full_setup.html2024-02-15T23:04:37.000Zdailyhttps://dtp.dev/how-to/install.html2024-02-15T23:04:37.000Zdailyhttps://dtp.dev/how-to/npm_only.html2024-02-14T03:11:10.000Zdailyhttps://dtp.dev/how-to/runtime_only.html2024-02-14T03:11:10.000Zdailyhttps://dtp.dev/ref/dailyhttps://dtp.dev/ref/api_rust.htmldailyhttps://dtp.dev/ref/api_typescript.htmldailyhttps://dtp.dev/ref/design.htmldailyhttps://dtp.dev/ref/future_work.htmldailyhttps://dtp.dev/ref/scripts.htmldaily \ No newline at end of file +https://dtp.dev/2024-02-15T22:23:30.000Zdailyhttps://dtp.dev/faq.html2024-02-15T22:23:30.000Zdailyhttps://dtp.dev/intro.html2024-02-15T23:04:37.000Zdailyhttps://dtp.dev/community/2024-02-14T03:11:10.000Zdailyhttps://dtp.dev/community/editors.html2024-02-14T03:11:10.000Zdailyhttps://dtp.dev/examples/2024-02-15T22:54:53.000Zdailyhttps://dtp.dev/examples/rpc_firewall.html2024-02-14T03:11:10.000Zdailyhttps://dtp.dev/examples/web3_rust.html2024-02-14T03:11:10.000Zdailyhttps://dtp.dev/docs/2024-02-15T22:23:30.000Zdailyhttps://dtp.dev/docs/api_rust.html2024-02-14T03:11:10.000Zdailyhttps://dtp.dev/docs/api_typescript.html2024-02-14T03:11:10.000Zdailyhttps://dtp.dev/docs/design.html2024-02-16T03:13:55.000Zdailyhttps://dtp.dev/docs/future_work.html2024-02-15T22:23:30.000Zdailyhttps://dtp.dev/docs/scripts.html2024-02-14T03:11:10.000Zdailyhttps://dtp.dev/how-to/full_setup.html2024-02-15T23:04:37.000Zdailyhttps://dtp.dev/how-to/install.html2024-02-15T23:04:37.000Zdailyhttps://dtp.dev/how-to/npm_only.html2024-02-14T03:11:10.000Zdailyhttps://dtp.dev/how-to/runtime_only.html2024-02-14T03:11:10.000Zdailyhttps://dtp.dev/ref/dailyhttps://dtp.dev/ref/api_rust.htmldailyhttps://dtp.dev/ref/api_typescript.htmldailyhttps://dtp.dev/ref/design.htmldailyhttps://dtp.dev/ref/future_work.htmldailyhttps://dtp.dev/ref/scripts.htmldaily \ No newline at end of file