diff --git a/404.html b/404.html index e22e1afec..8132d2851 100644 --- a/404.html +++ b/404.html @@ -4,14 +4,14 @@ Page Not Found | Weaver: DLT Interoperability Framework - - - + + +
-
Skip to main content

Page Not Found

We could not find what you were looking for.

Please contact the owner of the site that linked you to the original URL and let them know their link is broken.

- - +
Skip to main content

Page Not Found

We could not find what you were looking for.

Please contact the owner of the site that linked you to the original URL and let them know their link is broken.

+ + \ No newline at end of file diff --git a/assets/css/styles.0f9380ca.css b/assets/css/styles.26b1bc6d.css similarity index 66% rename from assets/css/styles.0f9380ca.css rename to assets/css/styles.26b1bc6d.css index 098b5a0c4..965b0911a 100644 --- a/assets/css/styles.0f9380ca.css +++ b/assets/css/styles.26b1bc6d.css @@ -1 +1 @@ -.col,.container{padding:0 var(--ifm-spacing-horizontal);width:100%}.markdown>h2,.markdown>h3,.markdown>h4,.markdown>h5,.markdown>h6{margin-bottom:calc(var(--ifm-heading-vertical-rhythm-bottom)*var(--ifm-leading))}.markdown li,body{word-wrap:break-word}body,ol ol,ol ul,ul ol,ul ul{margin:0}pre,table{overflow:auto}blockquote,pre{margin:0 0 var(--ifm-spacing-vertical)}.breadcrumbs__link,.button{transition-timing-function:var(--ifm-transition-timing-default)}.button,code{vertical-align:middle}.button--outline.button--active,.button--outline:active,.button--outline:hover,:root{--ifm-button-color:var(--ifm-font-color-base-inverse)}.menu__link:hover,a{transition:color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.navbar--dark,:root{--ifm-navbar-link-hover-color:var(--ifm-color-primary)}.menu,.navbar-sidebar{overflow-x:hidden}:root,html[data-theme=dark]{--ifm-color-emphasis-500:var(--ifm-color-gray-500)}.toggleButton_gllP,html{-webkit-tap-highlight-color:transparent}.clean-list,.containsTaskList_mC6p,.details_lb9f>summary,.dropdown__menu,.menu__list{list-style:none}:root{--ifm-color-scheme:light;--ifm-dark-value:10%;--ifm-darker-value:15%;--ifm-darkest-value:30%;--ifm-light-value:15%;--ifm-lighter-value:30%;--ifm-lightest-value:50%;--ifm-contrast-background-value:90%;--ifm-contrast-foreground-value:70%;--ifm-contrast-background-dark-value:70%;--ifm-contrast-foreground-dark-value:90%;--ifm-color-primary:#3578e5;--ifm-color-secondary:#ebedf0;--ifm-color-success:#00a400;--ifm-color-info:#54c7ec;--ifm-color-warning:#ffba00;--ifm-color-danger:#fa383e;--ifm-color-primary-dark:#306cce;--ifm-color-primary-darker:#2d66c3;--ifm-color-primary-darkest:#2554a0;--ifm-color-primary-light:#538ce9;--ifm-color-primary-lighter:#72a1ed;--ifm-color-primary-lightest:#9abcf2;--ifm-color-primary-contrast-background:#ebf2fc;--ifm-color-primary-contrast-foreground:#102445;--ifm-color-secondary-dark:#d4d5d8;--ifm-color-secondary-darker:#c8c9cc;--ifm-color-secondary-darkest:#a4a6a8;--ifm-color-secondary-light:#eef0f2;--ifm-color-secondary-lighter:#f1f2f5;--ifm-color-secondary-lightest:#f5f6f8;--ifm-color-secondary-contrast-background:#fdfdfe;--ifm-color-secondary-contrast-foreground:#474748;--ifm-color-success-dark:#009400;--ifm-color-success-darker:#008b00;--ifm-color-success-darkest:#007300;--ifm-color-success-light:#26b226;--ifm-color-success-lighter:#4dbf4d;--ifm-color-success-lightest:#80d280;--ifm-color-success-contrast-background:#e6f6e6;--ifm-color-success-contrast-foreground:#003100;--ifm-color-info-dark:#4cb3d4;--ifm-color-info-darker:#47a9c9;--ifm-color-info-darkest:#3b8ba5;--ifm-color-info-light:#6ecfef;--ifm-color-info-lighter:#87d8f2;--ifm-color-info-lightest:#aae3f6;--ifm-color-info-contrast-background:#eef9fd;--ifm-color-info-contrast-foreground:#193c47;--ifm-color-warning-dark:#e6a700;--ifm-color-warning-darker:#d99e00;--ifm-color-warning-darkest:#b38200;--ifm-color-warning-light:#ffc426;--ifm-color-warning-lighter:#ffcf4d;--ifm-color-warning-lightest:#ffdd80;--ifm-color-warning-contrast-background:#fff8e6;--ifm-color-warning-contrast-foreground:#4d3800;--ifm-color-danger-dark:#e13238;--ifm-color-danger-darker:#d53035;--ifm-color-danger-darkest:#af272b;--ifm-color-danger-light:#fb565b;--ifm-color-danger-lighter:#fb7478;--ifm-color-danger-lightest:#fd9c9f;--ifm-color-danger-contrast-background:#ffebec;--ifm-color-danger-contrast-foreground:#4b1113;--ifm-color-white:#fff;--ifm-color-black:#000;--ifm-color-gray-0:var(--ifm-color-white);--ifm-color-gray-100:#f5f6f7;--ifm-color-gray-200:#ebedf0;--ifm-color-gray-300:#dadde1;--ifm-color-gray-400:#ccd0d5;--ifm-color-gray-500:#bec3c9;--ifm-color-gray-600:#8d949e;--ifm-color-gray-700:#606770;--ifm-color-gray-800:#444950;--ifm-color-gray-900:#1c1e21;--ifm-color-gray-1000:var(--ifm-color-black);--ifm-color-emphasis-0:var(--ifm-color-gray-0);--ifm-color-emphasis-100:var(--ifm-color-gray-100);--ifm-color-emphasis-200:var(--ifm-color-gray-200);--ifm-color-emphasis-300:var(--ifm-color-gray-300);--ifm-color-emphasis-400:var(--ifm-color-gray-400);--ifm-color-emphasis-600:var(--ifm-color-gray-600);--ifm-color-emphasis-700:var(--ifm-color-gray-700);--ifm-color-emphasis-800:var(--ifm-color-gray-800);--ifm-color-emphasis-900:var(--ifm-color-gray-900);--ifm-color-emphasis-1000:var(--ifm-color-gray-1000);--ifm-color-content:var(--ifm-color-emphasis-900);--ifm-color-content-inverse:var(--ifm-color-emphasis-0);--ifm-color-content-secondary:#525860;--ifm-background-color:#0000;--ifm-background-surface-color:var(--ifm-color-content-inverse);--ifm-global-border-width:1px;--ifm-global-radius:0.4rem;--ifm-hover-overlay:#0000000d;--ifm-font-color-base:var(--ifm-color-content);--ifm-font-color-base-inverse:var(--ifm-color-content-inverse);--ifm-font-color-secondary:var(--ifm-color-content-secondary);--ifm-font-family-base:system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,sans-serif,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";--ifm-font-family-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--ifm-font-size-base:100%;--ifm-font-weight-light:300;--ifm-font-weight-normal:400;--ifm-font-weight-semibold:500;--ifm-font-weight-bold:700;--ifm-font-weight-base:var(--ifm-font-weight-normal);--ifm-line-height-base:1.65;--ifm-global-spacing:1rem;--ifm-spacing-vertical:var(--ifm-global-spacing);--ifm-spacing-horizontal:var(--ifm-global-spacing);--ifm-transition-fast:200ms;--ifm-transition-slow:400ms;--ifm-transition-timing-default:cubic-bezier(0.08,0.52,0.52,1);--ifm-global-shadow-lw:0 1px 2px 0 #0000001a;--ifm-global-shadow-md:0 5px 40px #0003;--ifm-global-shadow-tl:0 12px 28px 0 #0003,0 2px 4px 0 #0000001a;--ifm-z-index-dropdown:100;--ifm-z-index-fixed:200;--ifm-z-index-overlay:400;--ifm-container-width:1140px;--ifm-container-width-xl:1320px;--ifm-code-background:#f6f7f8;--ifm-code-border-radius:var(--ifm-global-radius);--ifm-code-font-size:90%;--ifm-code-padding-horizontal:0.1rem;--ifm-code-padding-vertical:0.1rem;--ifm-pre-background:var(--ifm-code-background);--ifm-pre-border-radius:var(--ifm-code-border-radius);--ifm-pre-color:inherit;--ifm-pre-line-height:1.45;--ifm-pre-padding:1rem;--ifm-heading-color:inherit;--ifm-heading-margin-top:0;--ifm-heading-margin-bottom:var(--ifm-spacing-vertical);--ifm-heading-font-family:var(--ifm-font-family-base);--ifm-heading-font-weight:var(--ifm-font-weight-bold);--ifm-heading-line-height:1.25;--ifm-h1-font-size:2rem;--ifm-h2-font-size:1.5rem;--ifm-h3-font-size:1.25rem;--ifm-h4-font-size:1rem;--ifm-h5-font-size:0.875rem;--ifm-h6-font-size:0.85rem;--ifm-image-alignment-padding:1.25rem;--ifm-leading-desktop:1.25;--ifm-leading:calc(var(--ifm-leading-desktop)*1rem);--ifm-list-left-padding:2rem;--ifm-list-margin:1rem;--ifm-list-item-margin:0.25rem;--ifm-list-paragraph-margin:1rem;--ifm-table-cell-padding:0.75rem;--ifm-table-background:#0000;--ifm-table-stripe-background:#00000008;--ifm-table-border-width:1px;--ifm-table-border-color:var(--ifm-color-emphasis-300);--ifm-table-head-background:inherit;--ifm-table-head-color:inherit;--ifm-table-head-font-weight:var(--ifm-font-weight-bold);--ifm-table-cell-color:inherit;--ifm-link-color:var(--ifm-color-primary);--ifm-link-decoration:none;--ifm-link-hover-color:var(--ifm-link-color);--ifm-link-hover-decoration:underline;--ifm-paragraph-margin-bottom:var(--ifm-leading);--ifm-blockquote-font-size:var(--ifm-font-size-base);--ifm-blockquote-border-left-width:2px;--ifm-blockquote-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-blockquote-padding-vertical:0;--ifm-blockquote-shadow:none;--ifm-blockquote-color:var(--ifm-color-emphasis-800);--ifm-blockquote-border-color:var(--ifm-color-emphasis-300);--ifm-hr-background-color:var(--ifm-color-emphasis-500);--ifm-hr-height:1px;--ifm-hr-margin-vertical:1.5rem;--ifm-scrollbar-size:7px;--ifm-scrollbar-track-background-color:#f1f1f1;--ifm-scrollbar-thumb-background-color:silver;--ifm-scrollbar-thumb-hover-background-color:#a7a7a7;--ifm-alert-background-color:inherit;--ifm-alert-border-color:inherit;--ifm-alert-border-radius:var(--ifm-global-radius);--ifm-alert-border-width:0px;--ifm-alert-border-left-width:5px;--ifm-alert-color:var(--ifm-font-color-base);--ifm-alert-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-alert-padding-vertical:var(--ifm-spacing-vertical);--ifm-alert-shadow:var(--ifm-global-shadow-lw);--ifm-avatar-intro-margin:1rem;--ifm-avatar-intro-alignment:inherit;--ifm-avatar-photo-size:3rem;--ifm-badge-background-color:inherit;--ifm-badge-border-color:inherit;--ifm-badge-border-radius:var(--ifm-global-radius);--ifm-badge-border-width:var(--ifm-global-border-width);--ifm-badge-color:var(--ifm-color-white);--ifm-badge-padding-horizontal:calc(var(--ifm-spacing-horizontal)*0.5);--ifm-badge-padding-vertical:calc(var(--ifm-spacing-vertical)*0.25);--ifm-breadcrumb-border-radius:1.5rem;--ifm-breadcrumb-spacing:0.5rem;--ifm-breadcrumb-color-active:var(--ifm-color-primary);--ifm-breadcrumb-item-background-active:var(--ifm-hover-overlay);--ifm-breadcrumb-padding-horizontal:0.8rem;--ifm-breadcrumb-padding-vertical:0.4rem;--ifm-breadcrumb-size-multiplier:1;--ifm-breadcrumb-separator:url('data:image/svg+xml;utf8,');--ifm-breadcrumb-separator-filter:none;--ifm-breadcrumb-separator-size:0.5rem;--ifm-breadcrumb-separator-size-multiplier:1.25;--ifm-button-background-color:inherit;--ifm-button-border-color:var(--ifm-button-background-color);--ifm-button-border-width:var(--ifm-global-border-width);--ifm-button-font-weight:var(--ifm-font-weight-bold);--ifm-button-padding-horizontal:1.5rem;--ifm-button-padding-vertical:0.375rem;--ifm-button-size-multiplier:1;--ifm-button-transition-duration:var(--ifm-transition-fast);--ifm-button-border-radius:calc(var(--ifm-global-radius)*var(--ifm-button-size-multiplier));--ifm-button-group-spacing:2px;--ifm-card-background-color:var(--ifm-background-surface-color);--ifm-card-border-radius:calc(var(--ifm-global-radius)*2);--ifm-card-horizontal-spacing:var(--ifm-global-spacing);--ifm-card-vertical-spacing:var(--ifm-global-spacing);--ifm-toc-border-color:var(--ifm-color-emphasis-300);--ifm-toc-link-color:var(--ifm-color-content-secondary);--ifm-toc-padding-vertical:0.5rem;--ifm-toc-padding-horizontal:0.5rem;--ifm-dropdown-background-color:var(--ifm-background-surface-color);--ifm-dropdown-font-weight:var(--ifm-font-weight-semibold);--ifm-dropdown-link-color:var(--ifm-font-color-base);--ifm-dropdown-hover-background-color:var(--ifm-hover-overlay);--ifm-footer-background-color:var(--ifm-color-emphasis-100);--ifm-footer-color:inherit;--ifm-footer-link-color:var(--ifm-color-emphasis-700);--ifm-footer-link-hover-color:var(--ifm-color-primary);--ifm-footer-link-horizontal-spacing:0.5rem;--ifm-footer-padding-horizontal:calc(var(--ifm-spacing-horizontal)*2);--ifm-footer-padding-vertical:calc(var(--ifm-spacing-vertical)*2);--ifm-footer-title-color:inherit;--ifm-footer-logo-max-width:min(30rem,90vw);--ifm-hero-background-color:var(--ifm-background-surface-color);--ifm-hero-text-color:var(--ifm-color-emphasis-800);--ifm-menu-color:var(--ifm-color-emphasis-700);--ifm-menu-color-active:var(--ifm-color-primary);--ifm-menu-color-background-active:var(--ifm-hover-overlay);--ifm-menu-color-background-hover:var(--ifm-hover-overlay);--ifm-menu-link-padding-horizontal:0.75rem;--ifm-menu-link-padding-vertical:0.375rem;--ifm-menu-link-sublist-icon:url('data:image/svg+xml;utf8,');--ifm-menu-link-sublist-icon-filter:none;--ifm-navbar-background-color:var(--ifm-background-surface-color);--ifm-navbar-height:3.75rem;--ifm-navbar-item-padding-horizontal:0.75rem;--ifm-navbar-item-padding-vertical:0.25rem;--ifm-navbar-link-color:var(--ifm-font-color-base);--ifm-navbar-link-active-color:var(--ifm-link-color);--ifm-navbar-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-navbar-padding-vertical:calc(var(--ifm-spacing-vertical)*0.5);--ifm-navbar-shadow:var(--ifm-global-shadow-lw);--ifm-navbar-search-input-background-color:var(--ifm-color-emphasis-200);--ifm-navbar-search-input-color:var(--ifm-color-emphasis-800);--ifm-navbar-search-input-placeholder-color:var(--ifm-color-emphasis-500);--ifm-navbar-search-input-icon:url('data:image/svg+xml;utf8,');--ifm-navbar-sidebar-width:83vw;--ifm-pagination-border-radius:var(--ifm-global-radius);--ifm-pagination-color-active:var(--ifm-color-primary);--ifm-pagination-font-size:1rem;--ifm-pagination-item-active-background:var(--ifm-hover-overlay);--ifm-pagination-page-spacing:0.2em;--ifm-pagination-padding-horizontal:calc(var(--ifm-spacing-horizontal)*1);--ifm-pagination-padding-vertical:calc(var(--ifm-spacing-vertical)*0.25);--ifm-pagination-nav-border-radius:var(--ifm-global-radius);--ifm-pagination-nav-color-hover:var(--ifm-color-primary);--ifm-pills-color-active:var(--ifm-color-primary);--ifm-pills-color-background-active:var(--ifm-hover-overlay);--ifm-pills-spacing:0.125rem;--ifm-tabs-color:var(--ifm-font-color-secondary);--ifm-tabs-color-active:var(--ifm-color-primary);--ifm-tabs-color-active-border:var(--ifm-tabs-color-active);--ifm-tabs-padding-horizontal:1rem;--ifm-tabs-padding-vertical:1rem;--docusaurus-progress-bar-color:var(--ifm-color-primary);--ifm-color-primary:#0078d7;--ifm-color-primary-dark:#3f609e;--ifm-color-primary-darker:#3b5b96;--ifm-color-primary-darkest:#314b7b;--ifm-color-primary-light:#5478bb;--ifm-color-primary-lighter:#5d7fbe;--ifm-color-primary-lightest:#7794c9;--ifm-code-font-size:95%;--docusaurus-announcement-bar-height:auto;--docusaurus-collapse-button-bg:#0000;--docusaurus-collapse-button-bg-hover:#0000001a;--doc-sidebar-width:300px;--doc-sidebar-hidden-width:30px;--docusaurus-tag-list-border:var(--ifm-color-emphasis-300)}.badge--danger,.badge--info,.badge--primary,.badge--secondary,.badge--success,.badge--warning{--ifm-badge-border-color:var(--ifm-badge-background-color)}.button--link,.button--outline{--ifm-button-background-color:#0000}*{box-sizing:border-box}html{-webkit-font-smoothing:antialiased;-webkit-text-size-adjust:100%;text-size-adjust:100%;background-color:var(--ifm-background-color);color:var(--ifm-font-color-base);color-scheme:var(--ifm-color-scheme);font:var(--ifm-font-size-base)/var(--ifm-line-height-base) var(--ifm-font-family-base);text-rendering:optimizelegibility}iframe{border:0;color-scheme:auto}.container{margin:0 auto;max-width:var(--ifm-container-width)}.container--fluid{max-width:inherit}.row{display:flex;flex-wrap:wrap;margin:0 calc(var(--ifm-spacing-horizontal)*-1)}.margin-bottom--none,.margin-vert--none,.markdown>:last-child{margin-bottom:0!important}.margin-top--none,.margin-vert--none{margin-top:0!important}.row--no-gutters{margin-left:0;margin-right:0}.margin-horiz--none,.margin-right--none{margin-right:0!important}.row--no-gutters>.col{padding-left:0;padding-right:0}.row--align-top{align-items:flex-start}.row--align-bottom{align-items:flex-end}.menuExternalLink_NmtK,.row--align-center{align-items:center}.row--align-stretch{align-items:stretch}.row--align-baseline{align-items:baseline}.col{--ifm-col-width:100%;flex:1 0;margin-left:0;max-width:var(--ifm-col-width)}.padding-bottom--none,.padding-vert--none{padding-bottom:0!important}.padding-top--none,.padding-vert--none{padding-top:0!important}.padding-horiz--none,.padding-left--none{padding-left:0!important}.padding-horiz--none,.padding-right--none{padding-right:0!important}.col[class*=col--]{flex:0 0 var(--ifm-col-width)}.col--1{--ifm-col-width:8.33333%}.col--offset-1{margin-left:8.33333%}.col--2{--ifm-col-width:16.66667%}.col--offset-2{margin-left:16.66667%}.col--3{--ifm-col-width:25%}.col--offset-3{margin-left:25%}.col--4{--ifm-col-width:33.33333%}.col--offset-4{margin-left:33.33333%}.col--5{--ifm-col-width:41.66667%}.col--offset-5{margin-left:41.66667%}.col--6{--ifm-col-width:50%}.col--offset-6{margin-left:50%}.col--7{--ifm-col-width:58.33333%}.col--offset-7{margin-left:58.33333%}.col--8{--ifm-col-width:66.66667%}.col--offset-8{margin-left:66.66667%}.col--9{--ifm-col-width:75%}.col--offset-9{margin-left:75%}.col--10{--ifm-col-width:83.33333%}.col--offset-10{margin-left:83.33333%}.col--11{--ifm-col-width:91.66667%}.col--offset-11{margin-left:91.66667%}.col--12{--ifm-col-width:100%}.col--offset-12{margin-left:100%}.margin-horiz--none,.margin-left--none{margin-left:0!important}.margin--none{margin:0!important}.margin-bottom--xs,.margin-vert--xs{margin-bottom:.25rem!important}.margin-top--xs,.margin-vert--xs{margin-top:.25rem!important}.margin-horiz--xs,.margin-left--xs{margin-left:.25rem!important}.margin-horiz--xs,.margin-right--xs{margin-right:.25rem!important}.margin--xs{margin:.25rem!important}.margin-bottom--sm,.margin-vert--sm{margin-bottom:.5rem!important}.margin-top--sm,.margin-vert--sm{margin-top:.5rem!important}.margin-horiz--sm,.margin-left--sm{margin-left:.5rem!important}.margin-horiz--sm,.margin-right--sm{margin-right:.5rem!important}.margin--sm{margin:.5rem!important}.margin-bottom--md,.margin-vert--md{margin-bottom:1rem!important}.margin-top--md,.margin-vert--md{margin-top:1rem!important}.margin-horiz--md,.margin-left--md{margin-left:1rem!important}.margin-horiz--md,.margin-right--md{margin-right:1rem!important}.margin--md{margin:1rem!important}.margin-bottom--lg,.margin-vert--lg{margin-bottom:2rem!important}.margin-top--lg,.margin-vert--lg{margin-top:2rem!important}.margin-horiz--lg,.margin-left--lg{margin-left:2rem!important}.margin-horiz--lg,.margin-right--lg{margin-right:2rem!important}.margin--lg{margin:2rem!important}.margin-bottom--xl,.margin-vert--xl{margin-bottom:5rem!important}.margin-top--xl,.margin-vert--xl{margin-top:5rem!important}.margin-horiz--xl,.margin-left--xl{margin-left:5rem!important}.margin-horiz--xl,.margin-right--xl{margin-right:5rem!important}.margin--xl{margin:5rem!important}.padding--none{padding:0!important}.padding-bottom--xs,.padding-vert--xs{padding-bottom:.25rem!important}.padding-top--xs,.padding-vert--xs{padding-top:.25rem!important}.padding-horiz--xs,.padding-left--xs{padding-left:.25rem!important}.padding-horiz--xs,.padding-right--xs{padding-right:.25rem!important}.padding--xs{padding:.25rem!important}.padding-bottom--sm,.padding-vert--sm{padding-bottom:.5rem!important}.padding-top--sm,.padding-vert--sm{padding-top:.5rem!important}.padding-horiz--sm,.padding-left--sm{padding-left:.5rem!important}.padding-horiz--sm,.padding-right--sm{padding-right:.5rem!important}.padding--sm{padding:.5rem!important}.padding-bottom--md,.padding-vert--md{padding-bottom:1rem!important}.padding-top--md,.padding-vert--md{padding-top:1rem!important}.padding-horiz--md,.padding-left--md{padding-left:1rem!important}.padding-horiz--md,.padding-right--md{padding-right:1rem!important}.padding--md{padding:1rem!important}.padding-bottom--lg,.padding-vert--lg{padding-bottom:2rem!important}.padding-top--lg,.padding-vert--lg{padding-top:2rem!important}.padding-horiz--lg,.padding-left--lg{padding-left:2rem!important}.padding-horiz--lg,.padding-right--lg{padding-right:2rem!important}.padding--lg{padding:2rem!important}.padding-bottom--xl,.padding-vert--xl{padding-bottom:5rem!important}.padding-top--xl,.padding-vert--xl{padding-top:5rem!important}.padding-horiz--xl,.padding-left--xl{padding-left:5rem!important}.padding-horiz--xl,.padding-right--xl{padding-right:5rem!important}.padding--xl{padding:5rem!important}code{background-color:var(--ifm-code-background);border:.1rem solid #0000001a;border-radius:var(--ifm-code-border-radius);font-family:var(--ifm-font-family-monospace);font-size:var(--ifm-code-font-size);padding:var(--ifm-code-padding-vertical) var(--ifm-code-padding-horizontal)}a code{color:inherit}pre{background-color:var(--ifm-pre-background);border-radius:var(--ifm-pre-border-radius);color:var(--ifm-pre-color);font:var(--ifm-code-font-size)/var(--ifm-pre-line-height) var(--ifm-font-family-monospace);padding:var(--ifm-pre-padding)}pre code{background-color:initial;border:none;font-size:100%;line-height:inherit;padding:0}kbd{background-color:var(--ifm-color-emphasis-0);border:1px solid var(--ifm-color-emphasis-400);border-radius:.2rem;box-shadow:inset 0 -1px 0 var(--ifm-color-emphasis-400);color:var(--ifm-color-emphasis-800);font:80% var(--ifm-font-family-monospace);padding:.15rem .3rem}h1,h2,h3,h4,h5,h6{color:var(--ifm-heading-color);font-family:var(--ifm-heading-font-family);font-weight:var(--ifm-heading-font-weight);line-height:var(--ifm-heading-line-height);margin:var(--ifm-heading-margin-top) 0 var(--ifm-heading-margin-bottom) 0}h1{font-size:var(--ifm-h1-font-size)}h2{font-size:var(--ifm-h2-font-size)}h3{font-size:var(--ifm-h3-font-size)}h4{font-size:var(--ifm-h4-font-size)}h5{font-size:var(--ifm-h5-font-size)}h6{font-size:var(--ifm-h6-font-size)}img{max-width:100%}img[align=right]{padding-left:var(--image-alignment-padding)}img[align=left]{padding-right:var(--image-alignment-padding)}.markdown{--ifm-h1-vertical-rhythm-top:3;--ifm-h2-vertical-rhythm-top:2;--ifm-h3-vertical-rhythm-top:1.5;--ifm-heading-vertical-rhythm-top:1.25;--ifm-h1-vertical-rhythm-bottom:1.25;--ifm-heading-vertical-rhythm-bottom:1}.markdown:after,.markdown:before{content:"";display:table}.markdown:after{clear:both}.markdown h1:first-child{--ifm-h1-font-size:3rem;margin-bottom:calc(var(--ifm-h1-vertical-rhythm-bottom)*var(--ifm-leading))}.markdown>h2{--ifm-h2-font-size:2rem;margin-top:calc(var(--ifm-h2-vertical-rhythm-top)*var(--ifm-leading))}.markdown>h3{--ifm-h3-font-size:1.5rem;margin-top:calc(var(--ifm-h3-vertical-rhythm-top)*var(--ifm-leading))}.markdown>h4,.markdown>h5,.markdown>h6{margin-top:calc(var(--ifm-heading-vertical-rhythm-top)*var(--ifm-leading))}.markdown>p,.markdown>pre,.markdown>ul{margin-bottom:var(--ifm-leading)}.markdown li>p{margin-top:var(--ifm-list-paragraph-margin)}.markdown li+li{margin-top:var(--ifm-list-item-margin)}ol,ul{margin:0 0 var(--ifm-list-margin);padding-left:var(--ifm-list-left-padding)}ol ol,ul ol{list-style-type:lower-roman}ol ol ol,ol ul ol,ul ol ol,ul ul ol{list-style-type:lower-alpha}table{border-collapse:collapse;display:block;margin-bottom:var(--ifm-spacing-vertical)}table thead tr{border-bottom:2px solid var(--ifm-table-border-color)}table thead,table tr:nth-child(2n){background-color:var(--ifm-table-stripe-background)}table tr{background-color:var(--ifm-table-background);border-top:var(--ifm-table-border-width) solid var(--ifm-table-border-color)}table td,table th{border:var(--ifm-table-border-width) solid var(--ifm-table-border-color);padding:var(--ifm-table-cell-padding)}table th{background-color:var(--ifm-table-head-background);color:var(--ifm-table-head-color);font-weight:var(--ifm-table-head-font-weight)}table td{color:var(--ifm-table-cell-color)}strong{font-weight:var(--ifm-font-weight-bold)}a{color:var(--ifm-link-color);text-decoration:var(--ifm-link-decoration)}a:hover{color:var(--ifm-link-hover-color);text-decoration:var(--ifm-link-hover-decoration)}.button:hover,.text--no-decoration,.text--no-decoration:hover,a:not([href]){text-decoration:none}p{margin:0 0 var(--ifm-paragraph-margin-bottom)}blockquote{border-left:var(--ifm-blockquote-border-left-width) solid var(--ifm-blockquote-border-color);box-shadow:var(--ifm-blockquote-shadow);color:var(--ifm-blockquote-color);font-size:var(--ifm-blockquote-font-size);padding:var(--ifm-blockquote-padding-vertical) var(--ifm-blockquote-padding-horizontal)}blockquote>:first-child{margin-top:0}blockquote>:last-child{margin-bottom:0}hr{background-color:var(--ifm-hr-background-color);border:0;height:var(--ifm-hr-height);margin:var(--ifm-hr-margin-vertical) 0}.shadow--lw{box-shadow:var(--ifm-global-shadow-lw)!important}.shadow--md{box-shadow:var(--ifm-global-shadow-md)!important}.shadow--tl{box-shadow:var(--ifm-global-shadow-tl)!important}.text--primary,.wordWrapButtonEnabled_EoeP .wordWrapButtonIcon_Bwma{color:var(--ifm-color-primary)}.text--secondary{color:var(--ifm-color-secondary)}.text--success{color:var(--ifm-color-success)}.text--info{color:var(--ifm-color-info)}.text--warning{color:var(--ifm-color-warning)}.text--danger{color:var(--ifm-color-danger)}.text--center{text-align:center}.text--left{text-align:left}.text--justify{text-align:justify}.text--right{text-align:right}.text--capitalize{text-transform:capitalize}.text--lowercase{text-transform:lowercase}.admonitionHeading_tbUL,.alert__heading,.text--uppercase{text-transform:uppercase}.text--light{font-weight:var(--ifm-font-weight-light)}.text--normal{font-weight:var(--ifm-font-weight-normal)}.text--semibold{font-weight:var(--ifm-font-weight-semibold)}.text--bold{font-weight:var(--ifm-font-weight-bold)}.text--italic{font-style:italic}.text--truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text--break{word-wrap:break-word!important;word-break:break-word!important}.clean-btn{background:none;border:none;color:inherit;cursor:pointer;font-family:inherit;padding:0}.alert,.alert .close{color:var(--ifm-alert-foreground-color)}.clean-list{padding-left:0}.alert--primary{--ifm-alert-background-color:var(--ifm-color-primary-contrast-background);--ifm-alert-background-color-highlight:#3578e526;--ifm-alert-foreground-color:var(--ifm-color-primary-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-primary-dark)}.alert--secondary{--ifm-alert-background-color:var(--ifm-color-secondary-contrast-background);--ifm-alert-background-color-highlight:#ebedf026;--ifm-alert-foreground-color:var(--ifm-color-secondary-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-secondary-dark)}.alert--success{--ifm-alert-background-color:var(--ifm-color-success-contrast-background);--ifm-alert-background-color-highlight:#00a40026;--ifm-alert-foreground-color:var(--ifm-color-success-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-success-dark)}.alert--info{--ifm-alert-background-color:var(--ifm-color-info-contrast-background);--ifm-alert-background-color-highlight:#54c7ec26;--ifm-alert-foreground-color:var(--ifm-color-info-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-info-dark)}.alert--warning{--ifm-alert-background-color:var(--ifm-color-warning-contrast-background);--ifm-alert-background-color-highlight:#ffba0026;--ifm-alert-foreground-color:var(--ifm-color-warning-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-warning-dark)}.alert--danger{--ifm-alert-background-color:var(--ifm-color-danger-contrast-background);--ifm-alert-background-color-highlight:#fa383e26;--ifm-alert-foreground-color:var(--ifm-color-danger-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-danger-dark)}.alert{--ifm-code-background:var(--ifm-alert-background-color-highlight);--ifm-link-color:var(--ifm-alert-foreground-color);--ifm-link-hover-color:var(--ifm-alert-foreground-color);--ifm-link-decoration:underline;--ifm-tabs-color:var(--ifm-alert-foreground-color);--ifm-tabs-color-active:var(--ifm-alert-foreground-color);--ifm-tabs-color-active-border:var(--ifm-alert-border-color);background-color:var(--ifm-alert-background-color);border:var(--ifm-alert-border-width) solid var(--ifm-alert-border-color);border-left-width:var(--ifm-alert-border-left-width);border-radius:var(--ifm-alert-border-radius);box-shadow:var(--ifm-alert-shadow);padding:var(--ifm-alert-padding-vertical) var(--ifm-alert-padding-horizontal)}.alert__heading{align-items:center;display:flex;font:700 var(--ifm-h5-font-size)/var(--ifm-heading-line-height) var(--ifm-heading-font-family);margin-bottom:.5rem}.alert__icon{display:inline-flex;margin-right:.4em}.alert__icon svg{fill:var(--ifm-alert-foreground-color);stroke:var(--ifm-alert-foreground-color);stroke-width:0}.alert .close{margin:calc(var(--ifm-alert-padding-vertical)*-1) calc(var(--ifm-alert-padding-horizontal)*-1) 0 0;opacity:.75}.alert .close:focus,.alert .close:hover{opacity:1}.alert a{text-decoration-color:var(--ifm-alert-border-color)}.alert a:hover{text-decoration-thickness:2px}.avatar{column-gap:var(--ifm-avatar-intro-margin);display:flex}.avatar__photo{border-radius:50%;display:block;height:var(--ifm-avatar-photo-size);overflow:hidden;width:var(--ifm-avatar-photo-size)}.card--full-height,.navbar__logo img,body,html{height:100%}.avatar__photo--sm{--ifm-avatar-photo-size:2rem}.avatar__photo--lg{--ifm-avatar-photo-size:4rem}.avatar__photo--xl{--ifm-avatar-photo-size:6rem}.avatar__intro{display:flex;flex:1 1;flex-direction:column;justify-content:center;text-align:var(--ifm-avatar-intro-alignment)}.badge,.breadcrumbs__item,.breadcrumbs__link,.button,.dropdown>.navbar__link:after{display:inline-block}.avatar__name{font:700 var(--ifm-h4-font-size)/var(--ifm-heading-line-height) var(--ifm-font-family-base)}.avatar__subtitle{margin-top:.25rem}.avatar--vertical{--ifm-avatar-intro-alignment:center;--ifm-avatar-intro-margin:0.5rem;align-items:center;flex-direction:column}.badge{background-color:var(--ifm-badge-background-color);border:var(--ifm-badge-border-width) solid var(--ifm-badge-border-color);border-radius:var(--ifm-badge-border-radius);color:var(--ifm-badge-color);font-size:75%;font-weight:var(--ifm-font-weight-bold);line-height:1;padding:var(--ifm-badge-padding-vertical) var(--ifm-badge-padding-horizontal)}.badge--primary{--ifm-badge-background-color:var(--ifm-color-primary)}.badge--secondary{--ifm-badge-background-color:var(--ifm-color-secondary);color:var(--ifm-color-black)}.breadcrumbs__link,.button.button--secondary.button--outline:not(.button--active):not(:hover){color:var(--ifm-font-color-base)}.badge--success{--ifm-badge-background-color:var(--ifm-color-success)}.badge--info{--ifm-badge-background-color:var(--ifm-color-info)}.badge--warning{--ifm-badge-background-color:var(--ifm-color-warning)}.badge--danger{--ifm-badge-background-color:var(--ifm-color-danger)}.breadcrumbs{margin-bottom:0;padding-left:0}.breadcrumbs__item:not(:last-child):after{background:var(--ifm-breadcrumb-separator) center;content:" ";display:inline-block;filter:var(--ifm-breadcrumb-separator-filter);height:calc(var(--ifm-breadcrumb-separator-size)*var(--ifm-breadcrumb-size-multiplier)*var(--ifm-breadcrumb-separator-size-multiplier));margin:0 var(--ifm-breadcrumb-spacing);opacity:.5;width:calc(var(--ifm-breadcrumb-separator-size)*var(--ifm-breadcrumb-size-multiplier)*var(--ifm-breadcrumb-separator-size-multiplier))}.breadcrumbs__item--active .breadcrumbs__link{background:var(--ifm-breadcrumb-item-background-active);color:var(--ifm-breadcrumb-color-active)}.breadcrumbs__link{border-radius:var(--ifm-breadcrumb-border-radius);font-size:calc(1rem*var(--ifm-breadcrumb-size-multiplier));padding:calc(var(--ifm-breadcrumb-padding-vertical)*var(--ifm-breadcrumb-size-multiplier)) calc(var(--ifm-breadcrumb-padding-horizontal)*var(--ifm-breadcrumb-size-multiplier));transition-duration:var(--ifm-transition-fast);transition-property:background,color}.breadcrumbs__link:any-link:hover,.breadcrumbs__link:link:hover,.breadcrumbs__link:visited:hover,area.breadcrumbs__link[href]:hover{background:var(--ifm-breadcrumb-item-background-active);text-decoration:none}.breadcrumbs--sm{--ifm-breadcrumb-size-multiplier:0.8}.breadcrumbs--lg{--ifm-breadcrumb-size-multiplier:1.2}.button{background-color:var(--ifm-button-background-color);border:var(--ifm-button-border-width) solid var(--ifm-button-border-color);border-radius:var(--ifm-button-border-radius);cursor:pointer;font-size:calc(.875rem*var(--ifm-button-size-multiplier));font-weight:var(--ifm-button-font-weight);line-height:1.5;padding:calc(var(--ifm-button-padding-vertical)*var(--ifm-button-size-multiplier)) calc(var(--ifm-button-padding-horizontal)*var(--ifm-button-size-multiplier));text-align:center;transition-duration:var(--ifm-button-transition-duration);transition-property:color,background,border-color;-webkit-user-select:none;user-select:none;white-space:nowrap}.button,.button:hover{color:var(--ifm-button-color)}.button--outline{--ifm-button-color:var(--ifm-button-border-color)}.button--outline:hover{--ifm-button-background-color:var(--ifm-button-border-color)}.button--link{--ifm-button-border-color:#0000;color:var(--ifm-link-color);text-decoration:var(--ifm-link-decoration)}.button--link.button--active,.button--link:active,.button--link:hover{color:var(--ifm-link-hover-color);text-decoration:var(--ifm-link-hover-decoration)}.button.disabled,.button:disabled,.button[disabled]{opacity:.65;pointer-events:none}.button--sm{--ifm-button-size-multiplier:0.8}.button--lg{--ifm-button-size-multiplier:1.35}.button--block{display:block;width:100%}.button.button--secondary{color:var(--ifm-color-gray-900)}:where(.button--primary){--ifm-button-background-color:var(--ifm-color-primary);--ifm-button-border-color:var(--ifm-color-primary)}:where(.button--primary):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-primary-dark);--ifm-button-border-color:var(--ifm-color-primary-dark)}.button--primary.button--active,.button--primary:active{--ifm-button-background-color:var(--ifm-color-primary-darker);--ifm-button-border-color:var(--ifm-color-primary-darker)}:where(.button--secondary){--ifm-button-background-color:var(--ifm-color-secondary);--ifm-button-border-color:var(--ifm-color-secondary)}:where(.button--secondary):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-secondary-dark);--ifm-button-border-color:var(--ifm-color-secondary-dark)}.button--secondary.button--active,.button--secondary:active{--ifm-button-background-color:var(--ifm-color-secondary-darker);--ifm-button-border-color:var(--ifm-color-secondary-darker)}:where(.button--success){--ifm-button-background-color:var(--ifm-color-success);--ifm-button-border-color:var(--ifm-color-success)}:where(.button--success):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-success-dark);--ifm-button-border-color:var(--ifm-color-success-dark)}.button--success.button--active,.button--success:active{--ifm-button-background-color:var(--ifm-color-success-darker);--ifm-button-border-color:var(--ifm-color-success-darker)}:where(.button--info){--ifm-button-background-color:var(--ifm-color-info);--ifm-button-border-color:var(--ifm-color-info)}:where(.button--info):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-info-dark);--ifm-button-border-color:var(--ifm-color-info-dark)}.button--info.button--active,.button--info:active{--ifm-button-background-color:var(--ifm-color-info-darker);--ifm-button-border-color:var(--ifm-color-info-darker)}:where(.button--warning){--ifm-button-background-color:var(--ifm-color-warning);--ifm-button-border-color:var(--ifm-color-warning)}:where(.button--warning):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-warning-dark);--ifm-button-border-color:var(--ifm-color-warning-dark)}.button--warning.button--active,.button--warning:active{--ifm-button-background-color:var(--ifm-color-warning-darker);--ifm-button-border-color:var(--ifm-color-warning-darker)}:where(.button--danger){--ifm-button-background-color:var(--ifm-color-danger);--ifm-button-border-color:var(--ifm-color-danger)}:where(.button--danger):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-danger-dark);--ifm-button-border-color:var(--ifm-color-danger-dark)}.button--danger.button--active,.button--danger:active{--ifm-button-background-color:var(--ifm-color-danger-darker);--ifm-button-border-color:var(--ifm-color-danger-darker)}.button-group{display:inline-flex;gap:var(--ifm-button-group-spacing)}.button-group>.button:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.button-group>.button:not(:last-child){border-bottom-right-radius:0;border-top-right-radius:0}.button-group--block{display:flex;justify-content:stretch}.button-group--block>.button{flex-grow:1}.card{background-color:var(--ifm-card-background-color);border-radius:var(--ifm-card-border-radius);box-shadow:var(--ifm-global-shadow-lw);display:flex;flex-direction:column;overflow:hidden}.card__image{padding-top:var(--ifm-card-vertical-spacing)}.card__image:first-child{padding-top:0}.card__body,.card__footer,.card__header{padding:var(--ifm-card-vertical-spacing) var(--ifm-card-horizontal-spacing)}.card__body:not(:last-child),.card__footer:not(:last-child),.card__header:not(:last-child){padding-bottom:0}.card__body>:last-child,.card__footer>:last-child,.card__header>:last-child{margin-bottom:0}.card__footer{margin-top:auto}.table-of-contents{font-size:.8rem;margin-bottom:0;padding:var(--ifm-toc-padding-vertical) 0}.table-of-contents,.table-of-contents ul{list-style:none;padding-left:var(--ifm-toc-padding-horizontal)}.table-of-contents li{margin:var(--ifm-toc-padding-vertical) var(--ifm-toc-padding-horizontal)}.table-of-contents__left-border{border-left:1px solid var(--ifm-toc-border-color)}.table-of-contents__link{color:var(--ifm-toc-link-color);display:block}.table-of-contents__link--active,.table-of-contents__link--active code,.table-of-contents__link:hover,.table-of-contents__link:hover code{color:var(--ifm-color-primary);text-decoration:none}.close{color:var(--ifm-color-black);float:right;font-size:1.5rem;font-weight:var(--ifm-font-weight-bold);line-height:1;opacity:.5;padding:1rem;transition:opacity var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.close:hover{opacity:.7}.close:focus,.theme-code-block-highlighted-line .codeLineNumber_Tfdd:before{opacity:.8}.dropdown{display:inline-flex;font-weight:var(--ifm-dropdown-font-weight);position:relative;vertical-align:top}.dropdown--hoverable:hover .dropdown__menu,.dropdown--show .dropdown__menu{opacity:1;pointer-events:all;transform:translateY(-1px);visibility:visible}#nprogress,.dropdown__menu,.navbar__item.dropdown .navbar__link:not([href]){pointer-events:none}.dropdown--right .dropdown__menu{left:inherit;right:0}.dropdown--nocaret .navbar__link:after{content:none!important}.dropdown__menu{background-color:var(--ifm-dropdown-background-color);border-radius:var(--ifm-global-radius);box-shadow:var(--ifm-global-shadow-md);left:0;max-height:80vh;min-width:10rem;opacity:0;overflow-y:auto;padding:.5rem;position:absolute;top:calc(100% - var(--ifm-navbar-item-padding-vertical) + .3rem);transform:translateY(-.625rem);transition-duration:var(--ifm-transition-fast);transition-property:opacity,transform,visibility;transition-timing-function:var(--ifm-transition-timing-default);visibility:hidden;z-index:var(--ifm-z-index-dropdown)}.sidebar_re4s,.tableOfContents_bqdL{max-height:calc(100vh - var(--ifm-navbar-height) - 2rem)}.menu__caret,.menu__link,.menu__list-item-collapsible{border-radius:.25rem;transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.dropdown__link{border-radius:.25rem;color:var(--ifm-dropdown-link-color);display:block;font-size:.875rem;margin-top:.2rem;padding:.25rem .5rem;white-space:nowrap}.dropdown__link--active,.dropdown__link:hover{background-color:var(--ifm-dropdown-hover-background-color);color:var(--ifm-dropdown-link-color);text-decoration:none}.dropdown__link--active,.dropdown__link--active:hover{--ifm-dropdown-link-color:var(--ifm-link-color)}.dropdown>.navbar__link:after{border-color:currentcolor #0000;border-style:solid;border-width:.4em .4em 0;content:"";margin-left:.3em;position:relative;top:2px;transform:translateY(-50%)}.footer{background-color:var(--ifm-footer-background-color);color:var(--ifm-footer-color);padding:var(--ifm-footer-padding-vertical) var(--ifm-footer-padding-horizontal)}.footer--dark{--ifm-footer-background-color:#303846;--ifm-footer-color:var(--ifm-footer-link-color);--ifm-footer-link-color:var(--ifm-color-secondary);--ifm-footer-title-color:var(--ifm-color-white)}.footer__links{margin-bottom:1rem}.footer__link-item{color:var(--ifm-footer-link-color);line-height:2}.footer__link-item:hover{color:var(--ifm-footer-link-hover-color)}.footer__link-separator{margin:0 var(--ifm-footer-link-horizontal-spacing)}.footer__logo{margin-top:1rem;max-width:var(--ifm-footer-logo-max-width)}.footer__title{color:var(--ifm-footer-title-color);font:700 var(--ifm-h4-font-size)/var(--ifm-heading-line-height) var(--ifm-font-family-base);margin-bottom:var(--ifm-heading-margin-bottom)}.menu,.navbar__link{font-weight:var(--ifm-font-weight-semibold)}.docItemContainer_Djhp article>:first-child,.docItemContainer_Djhp header+*,.footer__item{margin-top:0}.admonitionContent_S0QG>:last-child,.collapsibleContent_i85q>:last-child,.footer__items{margin-bottom:0}.codeBlockStandalone_MEMb,[type=checkbox]{padding:0}.hero{align-items:center;background-color:var(--ifm-hero-background-color);color:var(--ifm-hero-text-color);display:flex;padding:4rem 2rem}.hero--primary{--ifm-hero-background-color:var(--ifm-color-primary);--ifm-hero-text-color:var(--ifm-font-color-base-inverse)}.hero--dark{--ifm-hero-background-color:#303846;--ifm-hero-text-color:var(--ifm-color-white)}.hero__title,.title_f1Hy{font-size:3rem}.hero__subtitle{font-size:1.5rem}.menu__list{margin:0;padding-left:0}.menu__caret,.menu__link{padding:var(--ifm-menu-link-padding-vertical) var(--ifm-menu-link-padding-horizontal)}.menu__list .menu__list{flex:0 0 100%;margin-top:.25rem;padding-left:var(--ifm-menu-link-padding-horizontal)}.menu__list-item:not(:first-child){margin-top:.25rem}.menu__list-item--collapsed .menu__list{height:0;overflow:hidden}.details_lb9f[data-collapsed=false].isBrowser_bmU9>summary:before,.details_lb9f[open]:not(.isBrowser_bmU9)>summary:before,.menu__list-item--collapsed .menu__caret:before,.menu__list-item--collapsed .menu__link--sublist:after{transform:rotate(90deg)}.menu__list-item-collapsible{display:flex;flex-wrap:wrap;position:relative}.menu__caret:hover,.menu__link:hover,.menu__list-item-collapsible--active,.menu__list-item-collapsible:hover{background:var(--ifm-menu-color-background-hover)}.menu__list-item-collapsible .menu__link--active,.menu__list-item-collapsible .menu__link:hover{background:none!important}.menu__caret,.menu__link{align-items:center;display:flex}.menu__link{color:var(--ifm-menu-color);flex:1;line-height:1.25}.menu__link:hover{color:var(--ifm-menu-color);text-decoration:none}.menu__caret:before,.menu__link--sublist-caret:after{content:"";height:1.25rem;transform:rotate(180deg);transition:transform var(--ifm-transition-fast) linear;width:1.25rem;filter:var(--ifm-menu-link-sublist-icon-filter)}.menu__link--sublist-caret:after{background:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem;margin-left:auto;min-width:1.25rem}.menu__link--active,.menu__link--active:hover{color:var(--ifm-menu-color-active)}.navbar__brand,.navbar__link{color:var(--ifm-navbar-link-color)}.menu__link--active:not(.menu__link--sublist){background-color:var(--ifm-menu-color-background-active)}.menu__caret:before{background:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem}.navbar--dark,html[data-theme=dark]{--ifm-menu-link-sublist-icon-filter:invert(100%) sepia(94%) saturate(17%) hue-rotate(223deg) brightness(104%) contrast(98%)}.navbar{background-color:var(--ifm-navbar-background-color);box-shadow:var(--ifm-navbar-shadow);height:var(--ifm-navbar-height);padding:var(--ifm-navbar-padding-vertical) var(--ifm-navbar-padding-horizontal)}.docsWrapper_BCFX,.navbar,.navbar>.container,.navbar>.container-fluid{display:flex}.navbar--fixed-top{position:sticky;top:0;z-index:var(--ifm-z-index-fixed)}.navbar-sidebar,.navbar-sidebar__backdrop{bottom:0;opacity:0;position:fixed;transition-timing-function:ease-in-out;left:0;top:0;visibility:hidden}.navbar__inner{display:flex;flex-wrap:wrap;justify-content:space-between;width:100%}.navbar__brand{align-items:center;display:flex;margin-right:1rem;min-width:0}.navbar__brand:hover{color:var(--ifm-navbar-link-hover-color);text-decoration:none}.announcementBarContent_xLdY,.navbar__title{flex:1 1 auto}.navbar__toggle{display:none;margin-right:.5rem}.navbar__logo{flex:0 0 auto;height:2rem;margin-right:.5rem}.navbar__items{align-items:center;display:flex;flex:1;min-width:0}.navbar__items--center{flex:0 0 auto}.navbar__items--center .navbar__brand{margin:0}.navbar__items--center+.navbar__items--right{flex:1}.navbar__items--right{flex:0 0 auto;justify-content:flex-end}.navbar__items--right>:last-child{padding-right:0}.navbar__item{display:inline-block;padding:var(--ifm-navbar-item-padding-vertical) var(--ifm-navbar-item-padding-horizontal)}.navbar__link--active,.navbar__link:hover{color:var(--ifm-navbar-link-hover-color);text-decoration:none}.navbar--dark,.navbar--primary{--ifm-menu-color:var(--ifm-color-gray-300);--ifm-navbar-link-color:var(--ifm-color-gray-100);--ifm-navbar-search-input-background-color:#ffffff1a;--ifm-navbar-search-input-placeholder-color:#ffffff80;color:var(--ifm-color-white)}.navbar--dark{--ifm-navbar-background-color:#242526;--ifm-menu-color-background-active:#ffffff0d;--ifm-navbar-search-input-color:var(--ifm-color-white)}.navbar--primary{--ifm-navbar-background-color:var(--ifm-color-primary);--ifm-navbar-link-hover-color:var(--ifm-color-white);--ifm-menu-color-active:var(--ifm-color-white);--ifm-navbar-search-input-color:var(--ifm-color-emphasis-500)}.navbar__search-input{-webkit-appearance:none;appearance:none;background:var(--ifm-navbar-search-input-background-color) var(--ifm-navbar-search-input-icon) no-repeat .75rem center/1rem 1rem;border:none;border-radius:2rem;color:var(--ifm-navbar-search-input-color);cursor:text;display:inline-block;font-size:.9rem;height:2rem;padding:0 .5rem 0 2.25rem;width:12.5rem}.navbar__search-input::placeholder{color:var(--ifm-navbar-search-input-placeholder-color)}.navbar-sidebar{background-color:var(--ifm-navbar-background-color);box-shadow:var(--ifm-global-shadow-md);transform:translate3d(-100%,0,0);transition-duration:.25s;transition-property:opacity,visibility,transform;width:var(--ifm-navbar-sidebar-width)}.navbar-sidebar--show .navbar-sidebar,.navbar-sidebar__items{transform:translateZ(0)}.navbar-sidebar--show .navbar-sidebar,.navbar-sidebar--show .navbar-sidebar__backdrop{opacity:1;visibility:visible}.navbar-sidebar__backdrop{background-color:#0009;right:0;transition-duration:.1s;transition-property:opacity,visibility}.navbar-sidebar__brand{align-items:center;box-shadow:var(--ifm-navbar-shadow);display:flex;flex:1;height:var(--ifm-navbar-height);padding:var(--ifm-navbar-padding-vertical) var(--ifm-navbar-padding-horizontal)}.navbar-sidebar__items{display:flex;height:calc(100% - var(--ifm-navbar-height));transition:transform var(--ifm-transition-fast) ease-in-out}.navbar-sidebar__items--show-secondary{transform:translate3d(calc((var(--ifm-navbar-sidebar-width))*-1),0,0)}.navbar-sidebar__item{flex-shrink:0;padding:.5rem;width:calc(var(--ifm-navbar-sidebar-width))}.navbar-sidebar__back{background:var(--ifm-menu-color-background-active);font-size:15px;font-weight:var(--ifm-button-font-weight);margin:0 0 .2rem -.5rem;padding:.6rem 1.5rem;position:relative;text-align:left;top:-.5rem;width:calc(100% + 1rem)}.navbar-sidebar__close{display:flex;margin-left:auto}.pagination{column-gap:var(--ifm-pagination-page-spacing);display:flex;font-size:var(--ifm-pagination-font-size);padding-left:0}.pagination--sm{--ifm-pagination-font-size:0.8rem;--ifm-pagination-padding-horizontal:0.8rem;--ifm-pagination-padding-vertical:0.2rem}.pagination--lg{--ifm-pagination-font-size:1.2rem;--ifm-pagination-padding-horizontal:1.2rem;--ifm-pagination-padding-vertical:0.3rem}.pagination__item{display:inline-flex}.pagination__item>span{padding:var(--ifm-pagination-padding-vertical)}.pagination__item--active .pagination__link{color:var(--ifm-pagination-color-active)}.pagination__item--active .pagination__link,.pagination__item:not(.pagination__item--active):hover .pagination__link{background:var(--ifm-pagination-item-active-background)}.pagination__item--disabled,.pagination__item[disabled]{opacity:.25;pointer-events:none}.pagination__link{border-radius:var(--ifm-pagination-border-radius);color:var(--ifm-font-color-base);display:inline-block;padding:var(--ifm-pagination-padding-vertical) var(--ifm-pagination-padding-horizontal);transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.pagination__link:hover,.sidebarItemLink_mo7H:hover{text-decoration:none}.pagination-nav{grid-gap:var(--ifm-spacing-horizontal);display:grid;gap:var(--ifm-spacing-horizontal);grid-template-columns:repeat(2,1fr)}.pagination-nav__link{border:1px solid var(--ifm-color-emphasis-300);border-radius:var(--ifm-pagination-nav-border-radius);display:block;height:100%;line-height:var(--ifm-heading-line-height);padding:var(--ifm-global-spacing);transition:border-color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.pagination-nav__link:hover{border-color:var(--ifm-pagination-nav-color-hover);text-decoration:none}.pagination-nav__link--next{grid-column:2/3;text-align:right}.pagination-nav__label{font-size:var(--ifm-h4-font-size);font-weight:var(--ifm-heading-font-weight);word-break:break-word}.pagination-nav__link--prev .pagination-nav__label:before{content:"« "}.pagination-nav__link--next .pagination-nav__label:after{content:" »"}.pagination-nav__sublabel{color:var(--ifm-color-content-secondary);font-size:var(--ifm-h5-font-size);font-weight:var(--ifm-font-weight-semibold);margin-bottom:.25rem}.pills__item,.sidebarItemTitle_pO2u,.tabs{font-weight:var(--ifm-font-weight-bold)}.pills{display:flex;gap:var(--ifm-pills-spacing);padding-left:0}.pills__item{border-radius:.5rem;cursor:pointer;display:inline-block;padding:.25rem 1rem;transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.tabs,:not(.containsTaskList_mC6p>li)>.containsTaskList_mC6p{padding-left:0}.pills__item--active{color:var(--ifm-pills-color-active)}.pills__item--active,.pills__item:not(.pills__item--active):hover{background:var(--ifm-pills-color-background-active)}.pills--block{justify-content:stretch}.pills--block .pills__item{flex-grow:1;text-align:center}.tabs{color:var(--ifm-tabs-color);display:flex;margin-bottom:0;overflow-x:auto}.tabs__item{border-bottom:3px solid #0000;border-radius:var(--ifm-global-radius);cursor:pointer;display:inline-flex;padding:var(--ifm-tabs-padding-vertical) var(--ifm-tabs-padding-horizontal);transition:background-color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.tabs__item--active{border-bottom-color:var(--ifm-tabs-color-active-border);border-bottom-left-radius:0;border-bottom-right-radius:0;color:var(--ifm-tabs-color-active)}.tabs__item:hover{background-color:var(--ifm-hover-overlay)}.tabs--block{justify-content:stretch}.tabs--block .tabs__item{flex-grow:1;justify-content:center}html[data-theme=dark]{--ifm-color-scheme:dark;--ifm-color-emphasis-0:var(--ifm-color-gray-1000);--ifm-color-emphasis-100:var(--ifm-color-gray-900);--ifm-color-emphasis-200:var(--ifm-color-gray-800);--ifm-color-emphasis-300:var(--ifm-color-gray-700);--ifm-color-emphasis-400:var(--ifm-color-gray-600);--ifm-color-emphasis-600:var(--ifm-color-gray-400);--ifm-color-emphasis-700:var(--ifm-color-gray-300);--ifm-color-emphasis-800:var(--ifm-color-gray-200);--ifm-color-emphasis-900:var(--ifm-color-gray-100);--ifm-color-emphasis-1000:var(--ifm-color-gray-0);--ifm-background-color:#1b1b1d;--ifm-background-surface-color:#242526;--ifm-hover-overlay:#ffffff0d;--ifm-color-content:#e3e3e3;--ifm-color-content-secondary:#fff;--ifm-breadcrumb-separator-filter:invert(64%) sepia(11%) saturate(0%) hue-rotate(149deg) brightness(99%) contrast(95%);--ifm-code-background:#ffffff1a;--ifm-scrollbar-track-background-color:#444;--ifm-scrollbar-thumb-background-color:#686868;--ifm-scrollbar-thumb-hover-background-color:#7a7a7a;--ifm-table-stripe-background:#ffffff12;--ifm-toc-border-color:var(--ifm-color-emphasis-200);--ifm-color-primary-contrast-background:#102445;--ifm-color-primary-contrast-foreground:#ebf2fc;--ifm-color-secondary-contrast-background:#474748;--ifm-color-secondary-contrast-foreground:#fdfdfe;--ifm-color-success-contrast-background:#003100;--ifm-color-success-contrast-foreground:#e6f6e6;--ifm-color-info-contrast-background:#193c47;--ifm-color-info-contrast-foreground:#eef9fd;--ifm-color-warning-contrast-background:#4d3800;--ifm-color-warning-contrast-foreground:#fff8e6;--ifm-color-danger-contrast-background:#4b1113;--ifm-color-danger-contrast-foreground:#ffebec}#nprogress .bar{background:var(--docusaurus-progress-bar-color);height:2px;left:0;position:fixed;top:0;width:100%;z-index:1031}#nprogress .peg{box-shadow:0 0 10px var(--docusaurus-progress-bar-color),0 0 5px var(--docusaurus-progress-bar-color);height:100%;opacity:1;position:absolute;right:0;transform:rotate(3deg) translateY(-4px);width:100px}.docusaurus-highlight-code-line{background-color:#484d5b;display:block;margin:0 calc(var(--ifm-pre-padding)*-1);padding:0 var(--ifm-pre-padding)}body:not(.navigation-with-keyboard) :not(input):focus{outline:0}#docusaurus-base-url-issue-banner-container,.collapseSidebarButton_PEFL,.docSidebarContainer_b6E3,.sidebarLogo_isFc,.themedImage_ToTc,[data-theme=dark] .lightToggleIcon_pyhR,[data-theme=light] .darkToggleIcon_wfgR,html[data-announcement-bar-initially-dismissed=true] .announcementBar_mb4j{display:none}.skipToContent_fXgn{background-color:var(--ifm-background-surface-color);color:var(--ifm-color-emphasis-900);left:100%;padding:calc(var(--ifm-global-spacing)/2) var(--ifm-global-spacing);position:fixed;top:1rem;z-index:calc(var(--ifm-z-index-fixed) + 1)}.skipToContent_fXgn:focus{box-shadow:var(--ifm-global-shadow-md);left:1rem}.closeButton_CVFx{line-height:0;padding:0}.content_knG7{font-size:85%;padding:5px 0;text-align:center}.content_knG7 a{color:inherit;text-decoration:underline}.announcementBar_mb4j{align-items:center;background-color:var(--ifm-color-white);border-bottom:1px solid var(--ifm-color-emphasis-100);color:var(--ifm-color-black);display:flex;height:var(--docusaurus-announcement-bar-height)}.announcementBarPlaceholder_vyr4{flex:0 0 10px}.announcementBarClose_gvF7{align-self:stretch;flex:0 0 30px}.toggle_vylO{height:2rem;width:2rem}.toggleButton_gllP{align-items:center;border-radius:50%;display:flex;height:100%;justify-content:center;transition:background var(--ifm-transition-fast);width:100%}.toggleButton_gllP:hover{background:var(--ifm-color-emphasis-200)}.toggleButtonDisabled_aARS{cursor:not-allowed}[data-theme=dark] .themedImage--dark_i4oU,[data-theme=light] .themedImage--light_HNdA{display:initial}.iconExternalLink_nPIU{margin-left:.3rem}.iconLanguage_nlXk{margin-right:5px;vertical-align:text-bottom}.navbarHideable_m1mJ{transition:transform var(--ifm-transition-fast) ease}.navbarHidden_jGov{transform:translate3d(0,calc(-100% - 2px),0)}.footerLogoLink_BH7S{opacity:.5;transition:opacity var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.footerLogoLink_BH7S:hover,.hash-link:focus,:hover>.hash-link{opacity:1}.mainWrapper_z2l0{flex:1 0 auto}.docusaurus-mt-lg{margin-top:3rem}#__docusaurus{display:flex;flex-direction:column;min-height:100%}.backToTopButton_sjWU{background-color:var(--ifm-color-emphasis-200);border-radius:50%;bottom:1.3rem;box-shadow:var(--ifm-global-shadow-lw);height:3rem;opacity:0;position:fixed;right:1.3rem;transform:scale(0);transition:all var(--ifm-transition-fast) var(--ifm-transition-timing-default);visibility:hidden;width:3rem;z-index:calc(var(--ifm-z-index-fixed) - 1)}.backToTopButton_sjWU:after{background-color:var(--ifm-color-emphasis-1000);content:" ";display:inline-block;height:100%;-webkit-mask:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem no-repeat;mask:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem no-repeat;width:100%}.backToTopButtonShow_xfvO{opacity:1;transform:scale(1);visibility:visible}[data-theme=dark]:root{--docusaurus-collapse-button-bg:#ffffff0d;--docusaurus-collapse-button-bg-hover:#ffffff1a}.docMainContainer_gTbr,.docPage__5DB{display:flex;width:100%}.sidebar_re4s{overflow-y:auto;position:sticky;top:calc(var(--ifm-navbar-height) + 2rem)}.sidebarItemTitle_pO2u{font-size:var(--ifm-h3-font-size)}.container_mt6G,.sidebarItemList_Yudw{font-size:.9rem}.sidebarItem__DBe{margin-top:.7rem}.sidebarItemLink_mo7H{color:var(--ifm-font-color-base);display:block}.sidebarItemLinkActive_I1ZP{color:var(--ifm-color-primary)!important}.authorCol_Hf19{flex-grow:1!important;max-width:inherit!important}.imageOnlyAuthorRow_pa_O{display:flex;flex-flow:row wrap}.imageOnlyAuthorCol_G86a{margin-left:.3rem;margin-right:.3rem}.heroBanner_UJJx{overflow:hidden;padding:4rem 0;position:relative;text-align:center}.buttons_pzbO{justify-content:center}.buttons_pzbO,.features_keug{align-items:center;display:flex}.features_keug{padding:2rem 0;width:100%}.featureImage_yA8i{height:200px;width:200px}.getStarted_Sjon{border:2px solid #f5f6f7;color:#fff}.buttonGroup__atx button,.codeBlockContainer_Ckt0{background:var(--prism-background-color);color:var(--prism-color)}.getStarted_Sjon:hover{background-color:#fff;color:#0078d7}.heading_AAq7{font-weight:400}.codeBlockContainer_Ckt0{border-radius:var(--ifm-code-border-radius);box-shadow:var(--ifm-global-shadow-lw);margin-bottom:var(--ifm-leading)}.codeBlockContent_biex{border-radius:inherit;direction:ltr;position:relative}.codeBlockTitle_Ktv7{border-bottom:1px solid var(--ifm-color-emphasis-300);border-top-left-radius:inherit;border-top-right-radius:inherit;font-size:var(--ifm-code-font-size);font-weight:500;padding:.75rem var(--ifm-pre-padding)}.codeBlock_bY9V{--ifm-pre-background:var(--prism-background-color);margin:0;padding:0}.codeBlockTitle_Ktv7+.codeBlockContent_biex .codeBlock_bY9V{border-top-left-radius:0;border-top-right-radius:0}.codeBlockLines_e6Vv{float:left;font:inherit;min-width:100%;padding:var(--ifm-pre-padding)}.codeBlockLinesWithNumbering_o6Pm{display:table;padding:var(--ifm-pre-padding) 0}.buttonGroup__atx{column-gap:.2rem;display:flex;position:absolute;right:calc(var(--ifm-pre-padding)/2);top:calc(var(--ifm-pre-padding)/2)}.buttonGroup__atx button{align-items:center;border:1px solid var(--ifm-color-emphasis-300);border-radius:var(--ifm-global-radius);display:flex;line-height:0;opacity:0;padding:.4rem;transition:opacity .2s ease-in-out}.buttonGroup__atx button:focus-visible,.buttonGroup__atx button:hover{opacity:1!important}.theme-code-block:hover .buttonGroup__atx button{opacity:.4}.iconEdit_Z9Sw{margin-right:.3em;vertical-align:sub}:where(:root){--docusaurus-highlighted-code-line-bg:#484d5b}:where([data-theme=dark]){--docusaurus-highlighted-code-line-bg:#646464}.theme-code-block-highlighted-line{background-color:var(--docusaurus-highlighted-code-line-bg);display:block;margin:0 calc(var(--ifm-pre-padding)*-1);padding:0 var(--ifm-pre-padding)}.codeLine_lJS_{counter-increment:a;display:table-row}.codeLineNumber_Tfdd{background:var(--ifm-pre-background);display:table-cell;left:0;overflow-wrap:normal;padding:0 var(--ifm-pre-padding);position:sticky;text-align:right;width:1%}.codeLineNumber_Tfdd:before{content:counter(a);opacity:.4}.codeLineContent_feaV{padding-right:var(--ifm-pre-padding)}.tag_zVej{border:1px solid var(--docusaurus-tag-list-border);transition:border var(--ifm-transition-fast)}.tag_zVej:hover{--docusaurus-tag-list-border:var(--ifm-link-color);text-decoration:none}.tagRegular_sFm0{border-radius:var(--ifm-global-radius);font-size:90%;padding:.2rem .5rem .3rem}.tagWithCount_h2kH{align-items:center;border-left:0;display:flex;padding:0 .5rem 0 1rem;position:relative}.tagWithCount_h2kH:after,.tagWithCount_h2kH:before{border:1px solid var(--docusaurus-tag-list-border);content:"";position:absolute;top:50%;transition:inherit}.tagWithCount_h2kH:before{border-bottom:0;border-right:0;height:1.18rem;right:100%;transform:translate(50%,-50%) rotate(-45deg);width:1.18rem}.tagWithCount_h2kH:after{border-radius:50%;height:.5rem;left:0;transform:translateY(-50%);width:.5rem}.tagWithCount_h2kH span{background:var(--ifm-color-secondary);border-radius:var(--ifm-global-radius);color:var(--ifm-color-black);font-size:.7rem;line-height:1.2;margin-left:.3rem;padding:.1rem .4rem}.theme-code-block:hover .copyButtonCopied_obH4{opacity:1!important}.copyButtonIcons_eSgA{height:1.125rem;position:relative;width:1.125rem}.copyButtonIcon_y97N,.copyButtonSuccessIcon_LjdS{fill:currentColor;height:inherit;left:0;opacity:inherit;position:absolute;top:0;transition:.15s;width:inherit}.copyButtonSuccessIcon_LjdS{color:#00d600;left:50%;opacity:0;top:50%;transform:translate(-50%,-50%) scale(.33)}.copyButtonCopied_obH4 .copyButtonIcon_y97N{opacity:0;transform:scale(.33)}.copyButtonCopied_obH4 .copyButtonSuccessIcon_LjdS{opacity:1;transform:translate(-50%,-50%) scale(1);transition-delay:75ms}.tags_jXut{display:inline}.tag_QGVx{display:inline-block;margin:0 .4rem .5rem 0}.lastUpdated_vwxv{font-size:smaller;font-style:italic;margin-top:.2rem}.tocCollapsibleButton_TO0P{align-items:center;display:flex;font-size:inherit;justify-content:space-between;padding:.4rem .8rem;width:100%}.tocCollapsibleButton_TO0P:after{background:var(--ifm-menu-link-sublist-icon) 50% 50%/2rem 2rem no-repeat;content:"";filter:var(--ifm-menu-link-sublist-icon-filter);height:1.25rem;transform:rotate(180deg);transition:transform var(--ifm-transition-fast);width:1.25rem}.tocCollapsibleButtonExpanded_MG3E:after,.tocCollapsibleExpanded_sAul{transform:none}.tocCollapsible_ETCw{background-color:var(--ifm-menu-color-background-active);border-radius:var(--ifm-global-radius);margin:1rem 0}.tocCollapsibleContent_vkbj>ul{border-left:none;border-top:1px solid var(--ifm-color-emphasis-300);font-size:15px;padding:.2rem 0}.tocCollapsibleContent_vkbj ul li{margin:.4rem .8rem}.tocCollapsibleContent_vkbj a{display:block}.wordWrapButtonIcon_Bwma{height:1.2rem;width:1.2rem}.details_lb9f{--docusaurus-details-summary-arrow-size:0.38rem;--docusaurus-details-transition:transform 200ms ease;--docusaurus-details-decoration-color:grey}.details_lb9f>summary{cursor:pointer;padding-left:1rem;position:relative}.details_lb9f>summary::-webkit-details-marker{display:none}.details_lb9f>summary:before{border-color:#0000 #0000 #0000 var(--docusaurus-details-decoration-color);border-style:solid;border-width:var(--docusaurus-details-summary-arrow-size);content:"";left:0;position:absolute;top:.45rem;transform:rotate(0);transform-origin:calc(var(--docusaurus-details-summary-arrow-size)/2) 50%;transition:var(--docusaurus-details-transition)}.collapsibleContent_i85q{border-top:1px solid var(--docusaurus-details-decoration-color);margin-top:1rem;padding-top:1rem}.details_b_Ee{--docusaurus-details-decoration-color:var(--ifm-alert-border-color);--docusaurus-details-transition:transform var(--ifm-transition-fast) ease;border:1px solid var(--ifm-alert-border-color);margin:0 0 var(--ifm-spacing-vertical)}.anchorWithStickyNavbar_LWe7{scroll-margin-top:calc(var(--ifm-navbar-height) + .5rem)}.anchorWithHideOnScrollNavbar_WYt5{scroll-margin-top:.5rem}.hash-link{opacity:0;padding-left:.5rem;transition:opacity var(--ifm-transition-fast);-webkit-user-select:none;user-select:none}.hash-link:before{content:"#"}.img_ev3q{height:auto}.admonition_LlT9{margin-bottom:1em}.admonitionHeading_tbUL{font:var(--ifm-heading-font-weight) var(--ifm-h5-font-size)/var(--ifm-heading-line-height) var(--ifm-heading-font-family);margin-bottom:.3rem}.admonitionHeading_tbUL code{text-transform:none}.admonitionIcon_kALy{display:inline-block;margin-right:.4em;vertical-align:middle}.admonitionIcon_kALy svg{fill:var(--ifm-alert-foreground-color);display:inline-block;height:1.6em;width:1.6em}.blogPostFooterDetailsFull_mRVl{flex-direction:column}.tableOfContents_bqdL{overflow-y:auto;position:sticky;top:calc(var(--ifm-navbar-height) + 1rem)}.breadcrumbsContainer_Z_bl{--ifm-breadcrumb-size-multiplier:0.8;margin-bottom:.8rem}.breadcrumbHomeIcon_OVgt{height:1.1rem;position:relative;top:1px;vertical-align:top;width:1.1rem}@media (min-width:997px){.collapseSidebarButton_PEFL,.expandButton_m80_{background-color:var(--docusaurus-collapse-button-bg);position:sticky}:root{--docusaurus-announcement-bar-height:30px}.announcementBarClose_gvF7,.announcementBarPlaceholder_vyr4{flex-basis:50px}.searchBox_ZlJk{padding:var(--ifm-navbar-item-padding-vertical) var(--ifm-navbar-item-padding-horizontal)}.collapseSidebarButton_PEFL{border:1px solid var(--ifm-toc-border-color);border-radius:0;bottom:0;display:block!important;height:40px}.collapseSidebarButtonIcon_kv0_{margin-top:4px;transform:rotate(180deg)}.expandButtonIcon_BlDH,[dir=rtl] .collapseSidebarButtonIcon_kv0_{transform:rotate(0)}.collapseSidebarButton_PEFL:focus,.collapseSidebarButton_PEFL:hover,.expandButton_m80_:focus,.expandButton_m80_:hover{background-color:var(--docusaurus-collapse-button-bg-hover)}.menuHtmlItem_M9Kj{padding:var(--ifm-menu-link-padding-vertical) var(--ifm-menu-link-padding-horizontal)}.menu_SIkG{flex-grow:1;padding:.5rem}@supports (scrollbar-gutter:stable){.menu_SIkG{padding:.5rem 0 .5rem .5rem;scrollbar-gutter:stable}}.menuWithAnnouncementBar_GW3s{margin-bottom:var(--docusaurus-announcement-bar-height)}.sidebar_njMd{display:flex;flex-direction:column;height:100%;max-height:100vh;padding-top:var(--ifm-navbar-height);position:sticky;top:0;transition:opacity 50ms;width:var(--doc-sidebar-width)}.sidebarWithHideableNavbar_wUlq{padding-top:0}.sidebarHidden_VK0M{height:0;opacity:0;overflow:hidden;visibility:hidden}.sidebarLogo_isFc{align-items:center;color:inherit!important;display:flex!important;margin:0 var(--ifm-navbar-padding-horizontal);max-height:var(--ifm-navbar-height);min-height:var(--ifm-navbar-height);text-decoration:none!important}.sidebarLogo_isFc img{height:2rem;margin-right:.5rem}.expandButton_m80_{align-items:center;display:flex;height:100%;justify-content:center;max-height:100vh;top:0;transition:background-color var(--ifm-transition-fast) ease}[dir=rtl] .expandButtonIcon_BlDH{transform:rotate(180deg)}.docSidebarContainer_b6E3{border-right:1px solid var(--ifm-toc-border-color);-webkit-clip-path:inset(0);clip-path:inset(0);display:block;margin-top:calc(var(--ifm-navbar-height)*-1);transition:width var(--ifm-transition-fast) ease;width:var(--doc-sidebar-width);will-change:width}.docSidebarContainerHidden_b3ry{cursor:pointer;width:var(--doc-sidebar-hidden-width)}.docMainContainer_gTbr{flex-grow:1;max-width:calc(100% - var(--doc-sidebar-width))}.docMainContainerEnhanced_Uz_u{max-width:calc(100% - var(--doc-sidebar-hidden-width))}.docItemWrapperEnhanced_czyv{max-width:calc(var(--ifm-container-width) + var(--doc-sidebar-width))!important}.lastUpdated_vwxv{text-align:right}.tocMobile_ITEo{display:none}.docItemCol_VOVn{max-width:75%!important}}@media (min-width:1440px){.container{max-width:var(--ifm-container-width-xl)}}@media (max-width:996px){.col{--ifm-col-width:100%;flex-basis:var(--ifm-col-width);margin-left:0}.footer{--ifm-footer-padding-horizontal:0}.colorModeToggle_DEke,.footer__link-separator,.navbar__item,.sidebar_re4s,.tableOfContents_bqdL{display:none}.footer__col{margin-bottom:calc(var(--ifm-spacing-vertical)*3)}.footer__link-item{display:block}.hero{padding-left:0;padding-right:0}.navbar>.container,.navbar>.container-fluid{padding:0}.navbar__toggle{display:inherit}.navbar__search-input{width:9rem}.pills--block,.tabs--block{flex-direction:column}.searchBox_ZlJk{position:absolute;right:var(--ifm-navbar-padding-horizontal)}.docItemContainer_F8PC{padding:0 .3rem}}@media screen and (max-width:966px){.heroBanner_UJJx{padding:2rem}}@media (max-width:576px){.markdown h1:first-child{--ifm-h1-font-size:2rem}.markdown>h2{--ifm-h2-font-size:1.5rem}.markdown>h3{--ifm-h3-font-size:1.25rem}.title_f1Hy{font-size:2rem}}@media (hover:hover){.backToTopButton_sjWU:hover{background-color:var(--ifm-color-emphasis-300)}}@media (pointer:fine){.thin-scrollbar{scrollbar-width:thin}.thin-scrollbar::-webkit-scrollbar{height:var(--ifm-scrollbar-size);width:var(--ifm-scrollbar-size)}.thin-scrollbar::-webkit-scrollbar-track{background:var(--ifm-scrollbar-track-background-color);border-radius:10px}.thin-scrollbar::-webkit-scrollbar-thumb{background:var(--ifm-scrollbar-thumb-background-color);border-radius:10px}.thin-scrollbar::-webkit-scrollbar-thumb:hover{background:var(--ifm-scrollbar-thumb-hover-background-color)}}@media print{.announcementBar_mb4j,.footer,.menu,.navbar,.pagination-nav,.table-of-contents,.tocMobile_ITEo{display:none}.tabs{page-break-inside:avoid}.codeBlockLines_e6Vv{white-space:pre-wrap}} \ No newline at end of file +.col,.container{padding:0 var(--ifm-spacing-horizontal);width:100%}.markdown>h2,.markdown>h3,.markdown>h4,.markdown>h5,.markdown>h6{margin-bottom:calc(var(--ifm-heading-vertical-rhythm-bottom)*var(--ifm-leading))}.markdown li,body{word-wrap:break-word}body,ol ol,ol ul,ul ol,ul ul{margin:0}pre,table{overflow:auto}blockquote,pre{margin:0 0 var(--ifm-spacing-vertical)}.breadcrumbs__link,.button{transition-timing-function:var(--ifm-transition-timing-default)}.button,code{vertical-align:middle}.button--outline.button--active,.button--outline:active,.button--outline:hover,:root{--ifm-button-color:var(--ifm-font-color-base-inverse)}.menu__link:hover,a{transition:color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.navbar--dark,:root{--ifm-navbar-link-hover-color:var(--ifm-color-primary)}.menu,.navbar-sidebar{overflow-x:hidden}:root,html[data-theme=dark]{--ifm-color-emphasis-500:var(--ifm-color-gray-500)}.toggleButton_gllP,html{-webkit-tap-highlight-color:transparent}.clean-list,.containsTaskList_mC6p,.details_lb9f>summary,.dropdown__menu,.menu__list{list-style:none}:root{--ifm-color-scheme:light;--ifm-dark-value:10%;--ifm-darker-value:15%;--ifm-darkest-value:30%;--ifm-light-value:15%;--ifm-lighter-value:30%;--ifm-lightest-value:50%;--ifm-contrast-background-value:90%;--ifm-contrast-foreground-value:70%;--ifm-contrast-background-dark-value:70%;--ifm-contrast-foreground-dark-value:90%;--ifm-color-primary:#3578e5;--ifm-color-secondary:#ebedf0;--ifm-color-success:#00a400;--ifm-color-info:#54c7ec;--ifm-color-warning:#ffba00;--ifm-color-danger:#fa383e;--ifm-color-primary-dark:#306cce;--ifm-color-primary-darker:#2d66c3;--ifm-color-primary-darkest:#2554a0;--ifm-color-primary-light:#538ce9;--ifm-color-primary-lighter:#72a1ed;--ifm-color-primary-lightest:#9abcf2;--ifm-color-primary-contrast-background:#ebf2fc;--ifm-color-primary-contrast-foreground:#102445;--ifm-color-secondary-dark:#d4d5d8;--ifm-color-secondary-darker:#c8c9cc;--ifm-color-secondary-darkest:#a4a6a8;--ifm-color-secondary-light:#eef0f2;--ifm-color-secondary-lighter:#f1f2f5;--ifm-color-secondary-lightest:#f5f6f8;--ifm-color-secondary-contrast-background:#fdfdfe;--ifm-color-secondary-contrast-foreground:#474748;--ifm-color-success-dark:#009400;--ifm-color-success-darker:#008b00;--ifm-color-success-darkest:#007300;--ifm-color-success-light:#26b226;--ifm-color-success-lighter:#4dbf4d;--ifm-color-success-lightest:#80d280;--ifm-color-success-contrast-background:#e6f6e6;--ifm-color-success-contrast-foreground:#003100;--ifm-color-info-dark:#4cb3d4;--ifm-color-info-darker:#47a9c9;--ifm-color-info-darkest:#3b8ba5;--ifm-color-info-light:#6ecfef;--ifm-color-info-lighter:#87d8f2;--ifm-color-info-lightest:#aae3f6;--ifm-color-info-contrast-background:#eef9fd;--ifm-color-info-contrast-foreground:#193c47;--ifm-color-warning-dark:#e6a700;--ifm-color-warning-darker:#d99e00;--ifm-color-warning-darkest:#b38200;--ifm-color-warning-light:#ffc426;--ifm-color-warning-lighter:#ffcf4d;--ifm-color-warning-lightest:#ffdd80;--ifm-color-warning-contrast-background:#fff8e6;--ifm-color-warning-contrast-foreground:#4d3800;--ifm-color-danger-dark:#e13238;--ifm-color-danger-darker:#d53035;--ifm-color-danger-darkest:#af272b;--ifm-color-danger-light:#fb565b;--ifm-color-danger-lighter:#fb7478;--ifm-color-danger-lightest:#fd9c9f;--ifm-color-danger-contrast-background:#ffebec;--ifm-color-danger-contrast-foreground:#4b1113;--ifm-color-white:#fff;--ifm-color-black:#000;--ifm-color-gray-0:var(--ifm-color-white);--ifm-color-gray-100:#f5f6f7;--ifm-color-gray-200:#ebedf0;--ifm-color-gray-300:#dadde1;--ifm-color-gray-400:#ccd0d5;--ifm-color-gray-500:#bec3c9;--ifm-color-gray-600:#8d949e;--ifm-color-gray-700:#606770;--ifm-color-gray-800:#444950;--ifm-color-gray-900:#1c1e21;--ifm-color-gray-1000:var(--ifm-color-black);--ifm-color-emphasis-0:var(--ifm-color-gray-0);--ifm-color-emphasis-100:var(--ifm-color-gray-100);--ifm-color-emphasis-200:var(--ifm-color-gray-200);--ifm-color-emphasis-300:var(--ifm-color-gray-300);--ifm-color-emphasis-400:var(--ifm-color-gray-400);--ifm-color-emphasis-600:var(--ifm-color-gray-600);--ifm-color-emphasis-700:var(--ifm-color-gray-700);--ifm-color-emphasis-800:var(--ifm-color-gray-800);--ifm-color-emphasis-900:var(--ifm-color-gray-900);--ifm-color-emphasis-1000:var(--ifm-color-gray-1000);--ifm-color-content:var(--ifm-color-emphasis-900);--ifm-color-content-inverse:var(--ifm-color-emphasis-0);--ifm-color-content-secondary:#525860;--ifm-background-color:#0000;--ifm-background-surface-color:var(--ifm-color-content-inverse);--ifm-global-border-width:1px;--ifm-global-radius:0.4rem;--ifm-hover-overlay:#0000000d;--ifm-font-color-base:var(--ifm-color-content);--ifm-font-color-base-inverse:var(--ifm-color-content-inverse);--ifm-font-color-secondary:var(--ifm-color-content-secondary);--ifm-font-family-base:system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,sans-serif,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";--ifm-font-family-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--ifm-font-size-base:100%;--ifm-font-weight-light:300;--ifm-font-weight-normal:400;--ifm-font-weight-semibold:500;--ifm-font-weight-bold:700;--ifm-font-weight-base:var(--ifm-font-weight-normal);--ifm-line-height-base:1.65;--ifm-global-spacing:1rem;--ifm-spacing-vertical:var(--ifm-global-spacing);--ifm-spacing-horizontal:var(--ifm-global-spacing);--ifm-transition-fast:200ms;--ifm-transition-slow:400ms;--ifm-transition-timing-default:cubic-bezier(0.08,0.52,0.52,1);--ifm-global-shadow-lw:0 1px 2px 0 #0000001a;--ifm-global-shadow-md:0 5px 40px #0003;--ifm-global-shadow-tl:0 12px 28px 0 #0003,0 2px 4px 0 #0000001a;--ifm-z-index-dropdown:100;--ifm-z-index-fixed:200;--ifm-z-index-overlay:400;--ifm-container-width:1140px;--ifm-container-width-xl:1320px;--ifm-code-background:#f6f7f8;--ifm-code-border-radius:var(--ifm-global-radius);--ifm-code-font-size:90%;--ifm-code-padding-horizontal:0.1rem;--ifm-code-padding-vertical:0.1rem;--ifm-pre-background:var(--ifm-code-background);--ifm-pre-border-radius:var(--ifm-code-border-radius);--ifm-pre-color:inherit;--ifm-pre-line-height:1.45;--ifm-pre-padding:1rem;--ifm-heading-color:inherit;--ifm-heading-margin-top:0;--ifm-heading-margin-bottom:var(--ifm-spacing-vertical);--ifm-heading-font-family:var(--ifm-font-family-base);--ifm-heading-font-weight:var(--ifm-font-weight-bold);--ifm-heading-line-height:1.25;--ifm-h1-font-size:2rem;--ifm-h2-font-size:1.5rem;--ifm-h3-font-size:1.25rem;--ifm-h4-font-size:1rem;--ifm-h5-font-size:0.875rem;--ifm-h6-font-size:0.85rem;--ifm-image-alignment-padding:1.25rem;--ifm-leading-desktop:1.25;--ifm-leading:calc(var(--ifm-leading-desktop)*1rem);--ifm-list-left-padding:2rem;--ifm-list-margin:1rem;--ifm-list-item-margin:0.25rem;--ifm-list-paragraph-margin:1rem;--ifm-table-cell-padding:0.75rem;--ifm-table-background:#0000;--ifm-table-stripe-background:#00000008;--ifm-table-border-width:1px;--ifm-table-border-color:var(--ifm-color-emphasis-300);--ifm-table-head-background:inherit;--ifm-table-head-color:inherit;--ifm-table-head-font-weight:var(--ifm-font-weight-bold);--ifm-table-cell-color:inherit;--ifm-link-color:var(--ifm-color-primary);--ifm-link-decoration:none;--ifm-link-hover-color:var(--ifm-link-color);--ifm-link-hover-decoration:underline;--ifm-paragraph-margin-bottom:var(--ifm-leading);--ifm-blockquote-font-size:var(--ifm-font-size-base);--ifm-blockquote-border-left-width:2px;--ifm-blockquote-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-blockquote-padding-vertical:0;--ifm-blockquote-shadow:none;--ifm-blockquote-color:var(--ifm-color-emphasis-800);--ifm-blockquote-border-color:var(--ifm-color-emphasis-300);--ifm-hr-background-color:var(--ifm-color-emphasis-500);--ifm-hr-height:1px;--ifm-hr-margin-vertical:1.5rem;--ifm-scrollbar-size:7px;--ifm-scrollbar-track-background-color:#f1f1f1;--ifm-scrollbar-thumb-background-color:silver;--ifm-scrollbar-thumb-hover-background-color:#a7a7a7;--ifm-alert-background-color:inherit;--ifm-alert-border-color:inherit;--ifm-alert-border-radius:var(--ifm-global-radius);--ifm-alert-border-width:0px;--ifm-alert-border-left-width:5px;--ifm-alert-color:var(--ifm-font-color-base);--ifm-alert-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-alert-padding-vertical:var(--ifm-spacing-vertical);--ifm-alert-shadow:var(--ifm-global-shadow-lw);--ifm-avatar-intro-margin:1rem;--ifm-avatar-intro-alignment:inherit;--ifm-avatar-photo-size:3rem;--ifm-badge-background-color:inherit;--ifm-badge-border-color:inherit;--ifm-badge-border-radius:var(--ifm-global-radius);--ifm-badge-border-width:var(--ifm-global-border-width);--ifm-badge-color:var(--ifm-color-white);--ifm-badge-padding-horizontal:calc(var(--ifm-spacing-horizontal)*0.5);--ifm-badge-padding-vertical:calc(var(--ifm-spacing-vertical)*0.25);--ifm-breadcrumb-border-radius:1.5rem;--ifm-breadcrumb-spacing:0.5rem;--ifm-breadcrumb-color-active:var(--ifm-color-primary);--ifm-breadcrumb-item-background-active:var(--ifm-hover-overlay);--ifm-breadcrumb-padding-horizontal:0.8rem;--ifm-breadcrumb-padding-vertical:0.4rem;--ifm-breadcrumb-size-multiplier:1;--ifm-breadcrumb-separator:url('data:image/svg+xml;utf8,');--ifm-breadcrumb-separator-filter:none;--ifm-breadcrumb-separator-size:0.5rem;--ifm-breadcrumb-separator-size-multiplier:1.25;--ifm-button-background-color:inherit;--ifm-button-border-color:var(--ifm-button-background-color);--ifm-button-border-width:var(--ifm-global-border-width);--ifm-button-font-weight:var(--ifm-font-weight-bold);--ifm-button-padding-horizontal:1.5rem;--ifm-button-padding-vertical:0.375rem;--ifm-button-size-multiplier:1;--ifm-button-transition-duration:var(--ifm-transition-fast);--ifm-button-border-radius:calc(var(--ifm-global-radius)*var(--ifm-button-size-multiplier));--ifm-button-group-spacing:2px;--ifm-card-background-color:var(--ifm-background-surface-color);--ifm-card-border-radius:calc(var(--ifm-global-radius)*2);--ifm-card-horizontal-spacing:var(--ifm-global-spacing);--ifm-card-vertical-spacing:var(--ifm-global-spacing);--ifm-toc-border-color:var(--ifm-color-emphasis-300);--ifm-toc-link-color:var(--ifm-color-content-secondary);--ifm-toc-padding-vertical:0.5rem;--ifm-toc-padding-horizontal:0.5rem;--ifm-dropdown-background-color:var(--ifm-background-surface-color);--ifm-dropdown-font-weight:var(--ifm-font-weight-semibold);--ifm-dropdown-link-color:var(--ifm-font-color-base);--ifm-dropdown-hover-background-color:var(--ifm-hover-overlay);--ifm-footer-background-color:var(--ifm-color-emphasis-100);--ifm-footer-color:inherit;--ifm-footer-link-color:var(--ifm-color-emphasis-700);--ifm-footer-link-hover-color:var(--ifm-color-primary);--ifm-footer-link-horizontal-spacing:0.5rem;--ifm-footer-padding-horizontal:calc(var(--ifm-spacing-horizontal)*2);--ifm-footer-padding-vertical:calc(var(--ifm-spacing-vertical)*2);--ifm-footer-title-color:inherit;--ifm-footer-logo-max-width:min(30rem,90vw);--ifm-hero-background-color:var(--ifm-background-surface-color);--ifm-hero-text-color:var(--ifm-color-emphasis-800);--ifm-menu-color:var(--ifm-color-emphasis-700);--ifm-menu-color-active:var(--ifm-color-primary);--ifm-menu-color-background-active:var(--ifm-hover-overlay);--ifm-menu-color-background-hover:var(--ifm-hover-overlay);--ifm-menu-link-padding-horizontal:0.75rem;--ifm-menu-link-padding-vertical:0.375rem;--ifm-menu-link-sublist-icon:url('data:image/svg+xml;utf8,');--ifm-menu-link-sublist-icon-filter:none;--ifm-navbar-background-color:var(--ifm-background-surface-color);--ifm-navbar-height:3.75rem;--ifm-navbar-item-padding-horizontal:0.75rem;--ifm-navbar-item-padding-vertical:0.25rem;--ifm-navbar-link-color:var(--ifm-font-color-base);--ifm-navbar-link-active-color:var(--ifm-link-color);--ifm-navbar-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-navbar-padding-vertical:calc(var(--ifm-spacing-vertical)*0.5);--ifm-navbar-shadow:var(--ifm-global-shadow-lw);--ifm-navbar-search-input-background-color:var(--ifm-color-emphasis-200);--ifm-navbar-search-input-color:var(--ifm-color-emphasis-800);--ifm-navbar-search-input-placeholder-color:var(--ifm-color-emphasis-500);--ifm-navbar-search-input-icon:url('data:image/svg+xml;utf8,');--ifm-navbar-sidebar-width:83vw;--ifm-pagination-border-radius:var(--ifm-global-radius);--ifm-pagination-color-active:var(--ifm-color-primary);--ifm-pagination-font-size:1rem;--ifm-pagination-item-active-background:var(--ifm-hover-overlay);--ifm-pagination-page-spacing:0.2em;--ifm-pagination-padding-horizontal:calc(var(--ifm-spacing-horizontal)*1);--ifm-pagination-padding-vertical:calc(var(--ifm-spacing-vertical)*0.25);--ifm-pagination-nav-border-radius:var(--ifm-global-radius);--ifm-pagination-nav-color-hover:var(--ifm-color-primary);--ifm-pills-color-active:var(--ifm-color-primary);--ifm-pills-color-background-active:var(--ifm-hover-overlay);--ifm-pills-spacing:0.125rem;--ifm-tabs-color:var(--ifm-font-color-secondary);--ifm-tabs-color-active:var(--ifm-color-primary);--ifm-tabs-color-active-border:var(--ifm-tabs-color-active);--ifm-tabs-padding-horizontal:1rem;--ifm-tabs-padding-vertical:1rem;--docusaurus-progress-bar-color:var(--ifm-color-primary);--ifm-color-primary:#0078d7;--ifm-color-primary-dark:#3f609e;--ifm-color-primary-darker:#3b5b96;--ifm-color-primary-darkest:#314b7b;--ifm-color-primary-light:#5478bb;--ifm-color-primary-lighter:#5d7fbe;--ifm-color-primary-lightest:#7794c9;--ifm-code-font-size:95%;--docusaurus-announcement-bar-height:auto;--docusaurus-collapse-button-bg:#0000;--docusaurus-collapse-button-bg-hover:#0000001a;--doc-sidebar-width:300px;--doc-sidebar-hidden-width:30px;--docusaurus-tag-list-border:var(--ifm-color-emphasis-300)}.badge--danger,.badge--info,.badge--primary,.badge--secondary,.badge--success,.badge--warning{--ifm-badge-border-color:var(--ifm-badge-background-color)}.button--link,.button--outline{--ifm-button-background-color:#0000}*{box-sizing:border-box}html{-webkit-font-smoothing:antialiased;-webkit-text-size-adjust:100%;text-size-adjust:100%;background-color:var(--ifm-background-color);color:var(--ifm-font-color-base);color-scheme:var(--ifm-color-scheme);font:var(--ifm-font-size-base)/var(--ifm-line-height-base) var(--ifm-font-family-base);text-rendering:optimizelegibility}iframe{border:0;color-scheme:auto}.container{margin:0 auto;max-width:var(--ifm-container-width)}.container--fluid{max-width:inherit}.row{display:flex;flex-wrap:wrap;margin:0 calc(var(--ifm-spacing-horizontal)*-1)}.margin-bottom--none,.margin-vert--none,.markdown>:last-child{margin-bottom:0!important}.margin-top--none,.margin-vert--none{margin-top:0!important}.row--no-gutters{margin-left:0;margin-right:0}.margin-horiz--none,.margin-right--none{margin-right:0!important}.row--no-gutters>.col{padding-left:0;padding-right:0}.row--align-top{align-items:flex-start}.row--align-bottom{align-items:flex-end}.menuExternalLink_NmtK,.row--align-center{align-items:center}.row--align-stretch{align-items:stretch}.row--align-baseline{align-items:baseline}.col{--ifm-col-width:100%;flex:1 0;margin-left:0;max-width:var(--ifm-col-width)}.padding-bottom--none,.padding-vert--none{padding-bottom:0!important}.padding-top--none,.padding-vert--none{padding-top:0!important}.padding-horiz--none,.padding-left--none{padding-left:0!important}.padding-horiz--none,.padding-right--none{padding-right:0!important}.col[class*=col--]{flex:0 0 var(--ifm-col-width)}.col--1{--ifm-col-width:8.33333%}.col--offset-1{margin-left:8.33333%}.col--2{--ifm-col-width:16.66667%}.col--offset-2{margin-left:16.66667%}.col--3{--ifm-col-width:25%}.col--offset-3{margin-left:25%}.col--4{--ifm-col-width:33.33333%}.col--offset-4{margin-left:33.33333%}.col--5{--ifm-col-width:41.66667%}.col--offset-5{margin-left:41.66667%}.col--6{--ifm-col-width:50%}.col--offset-6{margin-left:50%}.col--7{--ifm-col-width:58.33333%}.col--offset-7{margin-left:58.33333%}.col--8{--ifm-col-width:66.66667%}.col--offset-8{margin-left:66.66667%}.col--9{--ifm-col-width:75%}.col--offset-9{margin-left:75%}.col--10{--ifm-col-width:83.33333%}.col--offset-10{margin-left:83.33333%}.col--11{--ifm-col-width:91.66667%}.col--offset-11{margin-left:91.66667%}.col--12{--ifm-col-width:100%}.col--offset-12{margin-left:100%}.margin-horiz--none,.margin-left--none{margin-left:0!important}.margin--none{margin:0!important}.margin-bottom--xs,.margin-vert--xs{margin-bottom:.25rem!important}.margin-top--xs,.margin-vert--xs{margin-top:.25rem!important}.margin-horiz--xs,.margin-left--xs{margin-left:.25rem!important}.margin-horiz--xs,.margin-right--xs{margin-right:.25rem!important}.margin--xs{margin:.25rem!important}.margin-bottom--sm,.margin-vert--sm{margin-bottom:.5rem!important}.margin-top--sm,.margin-vert--sm{margin-top:.5rem!important}.margin-horiz--sm,.margin-left--sm{margin-left:.5rem!important}.margin-horiz--sm,.margin-right--sm{margin-right:.5rem!important}.margin--sm{margin:.5rem!important}.margin-bottom--md,.margin-vert--md{margin-bottom:1rem!important}.margin-top--md,.margin-vert--md{margin-top:1rem!important}.margin-horiz--md,.margin-left--md{margin-left:1rem!important}.margin-horiz--md,.margin-right--md{margin-right:1rem!important}.margin--md{margin:1rem!important}.margin-bottom--lg,.margin-vert--lg{margin-bottom:2rem!important}.margin-top--lg,.margin-vert--lg{margin-top:2rem!important}.margin-horiz--lg,.margin-left--lg{margin-left:2rem!important}.margin-horiz--lg,.margin-right--lg{margin-right:2rem!important}.margin--lg{margin:2rem!important}.margin-bottom--xl,.margin-vert--xl{margin-bottom:5rem!important}.margin-top--xl,.margin-vert--xl{margin-top:5rem!important}.margin-horiz--xl,.margin-left--xl{margin-left:5rem!important}.margin-horiz--xl,.margin-right--xl{margin-right:5rem!important}.margin--xl{margin:5rem!important}.padding--none{padding:0!important}.padding-bottom--xs,.padding-vert--xs{padding-bottom:.25rem!important}.padding-top--xs,.padding-vert--xs{padding-top:.25rem!important}.padding-horiz--xs,.padding-left--xs{padding-left:.25rem!important}.padding-horiz--xs,.padding-right--xs{padding-right:.25rem!important}.padding--xs{padding:.25rem!important}.padding-bottom--sm,.padding-vert--sm{padding-bottom:.5rem!important}.padding-top--sm,.padding-vert--sm{padding-top:.5rem!important}.padding-horiz--sm,.padding-left--sm{padding-left:.5rem!important}.padding-horiz--sm,.padding-right--sm{padding-right:.5rem!important}.padding--sm{padding:.5rem!important}.padding-bottom--md,.padding-vert--md{padding-bottom:1rem!important}.padding-top--md,.padding-vert--md{padding-top:1rem!important}.padding-horiz--md,.padding-left--md{padding-left:1rem!important}.padding-horiz--md,.padding-right--md{padding-right:1rem!important}.padding--md{padding:1rem!important}.padding-bottom--lg,.padding-vert--lg{padding-bottom:2rem!important}.padding-top--lg,.padding-vert--lg{padding-top:2rem!important}.padding-horiz--lg,.padding-left--lg{padding-left:2rem!important}.padding-horiz--lg,.padding-right--lg{padding-right:2rem!important}.padding--lg{padding:2rem!important}.padding-bottom--xl,.padding-vert--xl{padding-bottom:5rem!important}.padding-top--xl,.padding-vert--xl{padding-top:5rem!important}.padding-horiz--xl,.padding-left--xl{padding-left:5rem!important}.padding-horiz--xl,.padding-right--xl{padding-right:5rem!important}.padding--xl{padding:5rem!important}code{background-color:var(--ifm-code-background);border:.1rem solid #0000001a;border-radius:var(--ifm-code-border-radius);font-family:var(--ifm-font-family-monospace);font-size:var(--ifm-code-font-size);padding:var(--ifm-code-padding-vertical) var(--ifm-code-padding-horizontal)}a code{color:inherit}pre{background-color:var(--ifm-pre-background);border-radius:var(--ifm-pre-border-radius);color:var(--ifm-pre-color);font:var(--ifm-code-font-size)/var(--ifm-pre-line-height) var(--ifm-font-family-monospace);padding:var(--ifm-pre-padding)}pre code{background-color:initial;border:none;font-size:100%;line-height:inherit;padding:0}kbd{background-color:var(--ifm-color-emphasis-0);border:1px solid var(--ifm-color-emphasis-400);border-radius:.2rem;box-shadow:inset 0 -1px 0 var(--ifm-color-emphasis-400);color:var(--ifm-color-emphasis-800);font:80% var(--ifm-font-family-monospace);padding:.15rem .3rem}h1,h2,h3,h4,h5,h6{color:var(--ifm-heading-color);font-family:var(--ifm-heading-font-family);font-weight:var(--ifm-heading-font-weight);line-height:var(--ifm-heading-line-height);margin:var(--ifm-heading-margin-top) 0 var(--ifm-heading-margin-bottom) 0}h1{font-size:var(--ifm-h1-font-size)}h2{font-size:var(--ifm-h2-font-size)}h3{font-size:var(--ifm-h3-font-size)}h4{font-size:var(--ifm-h4-font-size)}h5{font-size:var(--ifm-h5-font-size)}h6{font-size:var(--ifm-h6-font-size)}img{max-width:100%}img[align=right]{padding-left:var(--image-alignment-padding)}img[align=left]{padding-right:var(--image-alignment-padding)}.markdown{--ifm-h1-vertical-rhythm-top:3;--ifm-h2-vertical-rhythm-top:2;--ifm-h3-vertical-rhythm-top:1.5;--ifm-heading-vertical-rhythm-top:1.25;--ifm-h1-vertical-rhythm-bottom:1.25;--ifm-heading-vertical-rhythm-bottom:1}.markdown:after,.markdown:before{content:"";display:table}.markdown:after{clear:both}.markdown h1:first-child{--ifm-h1-font-size:3rem;margin-bottom:calc(var(--ifm-h1-vertical-rhythm-bottom)*var(--ifm-leading))}.markdown>h2{--ifm-h2-font-size:2rem;margin-top:calc(var(--ifm-h2-vertical-rhythm-top)*var(--ifm-leading))}.markdown>h3{--ifm-h3-font-size:1.5rem;margin-top:calc(var(--ifm-h3-vertical-rhythm-top)*var(--ifm-leading))}.markdown>h4,.markdown>h5,.markdown>h6{margin-top:calc(var(--ifm-heading-vertical-rhythm-top)*var(--ifm-leading))}.markdown>p,.markdown>pre,.markdown>ul{margin-bottom:var(--ifm-leading)}.markdown li>p{margin-top:var(--ifm-list-paragraph-margin)}.markdown li+li{margin-top:var(--ifm-list-item-margin)}ol,ul{margin:0 0 var(--ifm-list-margin);padding-left:var(--ifm-list-left-padding)}ol ol,ul ol{list-style-type:lower-roman}ol ol ol,ol ul ol,ul ol ol,ul ul ol{list-style-type:lower-alpha}table{border-collapse:collapse;display:block;margin-bottom:var(--ifm-spacing-vertical)}table thead tr{border-bottom:2px solid var(--ifm-table-border-color)}table thead,table tr:nth-child(2n){background-color:var(--ifm-table-stripe-background)}table tr{background-color:var(--ifm-table-background);border-top:var(--ifm-table-border-width) solid var(--ifm-table-border-color)}table td,table th{border:var(--ifm-table-border-width) solid var(--ifm-table-border-color);padding:var(--ifm-table-cell-padding)}table th{background-color:var(--ifm-table-head-background);color:var(--ifm-table-head-color);font-weight:var(--ifm-table-head-font-weight)}table td{color:var(--ifm-table-cell-color)}strong{font-weight:var(--ifm-font-weight-bold)}a{color:var(--ifm-link-color);text-decoration:var(--ifm-link-decoration)}a:hover{color:var(--ifm-link-hover-color);text-decoration:var(--ifm-link-hover-decoration)}.button:hover,.text--no-decoration,.text--no-decoration:hover,a:not([href]){text-decoration:none}p{margin:0 0 var(--ifm-paragraph-margin-bottom)}blockquote{border-left:var(--ifm-blockquote-border-left-width) solid var(--ifm-blockquote-border-color);box-shadow:var(--ifm-blockquote-shadow);color:var(--ifm-blockquote-color);font-size:var(--ifm-blockquote-font-size);padding:var(--ifm-blockquote-padding-vertical) var(--ifm-blockquote-padding-horizontal)}blockquote>:first-child{margin-top:0}blockquote>:last-child{margin-bottom:0}hr{background-color:var(--ifm-hr-background-color);border:0;height:var(--ifm-hr-height);margin:var(--ifm-hr-margin-vertical) 0}.shadow--lw{box-shadow:var(--ifm-global-shadow-lw)!important}.shadow--md{box-shadow:var(--ifm-global-shadow-md)!important}.shadow--tl{box-shadow:var(--ifm-global-shadow-tl)!important}.text--primary,.wordWrapButtonEnabled_EoeP .wordWrapButtonIcon_Bwma{color:var(--ifm-color-primary)}.text--secondary{color:var(--ifm-color-secondary)}.text--success{color:var(--ifm-color-success)}.text--info{color:var(--ifm-color-info)}.text--warning{color:var(--ifm-color-warning)}.text--danger{color:var(--ifm-color-danger)}.text--center{text-align:center}.text--left{text-align:left}.text--justify{text-align:justify}.text--right{text-align:right}.text--capitalize{text-transform:capitalize}.text--lowercase{text-transform:lowercase}.admonitionHeading_tbUL,.alert__heading,.text--uppercase{text-transform:uppercase}.text--light{font-weight:var(--ifm-font-weight-light)}.text--normal{font-weight:var(--ifm-font-weight-normal)}.text--semibold{font-weight:var(--ifm-font-weight-semibold)}.text--bold{font-weight:var(--ifm-font-weight-bold)}.text--italic{font-style:italic}.text--truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text--break{word-wrap:break-word!important;word-break:break-word!important}.clean-btn{background:none;border:none;color:inherit;cursor:pointer;font-family:inherit;padding:0}.alert,.alert .close{color:var(--ifm-alert-foreground-color)}.clean-list{padding-left:0}.alert--primary{--ifm-alert-background-color:var(--ifm-color-primary-contrast-background);--ifm-alert-background-color-highlight:#3578e526;--ifm-alert-foreground-color:var(--ifm-color-primary-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-primary-dark)}.alert--secondary{--ifm-alert-background-color:var(--ifm-color-secondary-contrast-background);--ifm-alert-background-color-highlight:#ebedf026;--ifm-alert-foreground-color:var(--ifm-color-secondary-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-secondary-dark)}.alert--success{--ifm-alert-background-color:var(--ifm-color-success-contrast-background);--ifm-alert-background-color-highlight:#00a40026;--ifm-alert-foreground-color:var(--ifm-color-success-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-success-dark)}.alert--info{--ifm-alert-background-color:var(--ifm-color-info-contrast-background);--ifm-alert-background-color-highlight:#54c7ec26;--ifm-alert-foreground-color:var(--ifm-color-info-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-info-dark)}.alert--warning{--ifm-alert-background-color:var(--ifm-color-warning-contrast-background);--ifm-alert-background-color-highlight:#ffba0026;--ifm-alert-foreground-color:var(--ifm-color-warning-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-warning-dark)}.alert--danger{--ifm-alert-background-color:var(--ifm-color-danger-contrast-background);--ifm-alert-background-color-highlight:#fa383e26;--ifm-alert-foreground-color:var(--ifm-color-danger-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-danger-dark)}.alert{--ifm-code-background:var(--ifm-alert-background-color-highlight);--ifm-link-color:var(--ifm-alert-foreground-color);--ifm-link-hover-color:var(--ifm-alert-foreground-color);--ifm-link-decoration:underline;--ifm-tabs-color:var(--ifm-alert-foreground-color);--ifm-tabs-color-active:var(--ifm-alert-foreground-color);--ifm-tabs-color-active-border:var(--ifm-alert-border-color);background-color:var(--ifm-alert-background-color);border:var(--ifm-alert-border-width) solid var(--ifm-alert-border-color);border-left-width:var(--ifm-alert-border-left-width);border-radius:var(--ifm-alert-border-radius);box-shadow:var(--ifm-alert-shadow);padding:var(--ifm-alert-padding-vertical) var(--ifm-alert-padding-horizontal)}.alert__heading{align-items:center;display:flex;font:700 var(--ifm-h5-font-size)/var(--ifm-heading-line-height) var(--ifm-heading-font-family);margin-bottom:.5rem}.alert__icon{display:inline-flex;margin-right:.4em}.alert__icon svg{fill:var(--ifm-alert-foreground-color);stroke:var(--ifm-alert-foreground-color);stroke-width:0}.alert .close{margin:calc(var(--ifm-alert-padding-vertical)*-1) calc(var(--ifm-alert-padding-horizontal)*-1) 0 0;opacity:.75}.alert .close:focus,.alert .close:hover{opacity:1}.alert a{text-decoration-color:var(--ifm-alert-border-color)}.alert a:hover{text-decoration-thickness:2px}.avatar{column-gap:var(--ifm-avatar-intro-margin);display:flex}.avatar__photo{border-radius:50%;display:block;height:var(--ifm-avatar-photo-size);overflow:hidden;width:var(--ifm-avatar-photo-size)}.card--full-height,.navbar__logo img,body,html{height:100%}.avatar__photo--sm{--ifm-avatar-photo-size:2rem}.avatar__photo--lg{--ifm-avatar-photo-size:4rem}.avatar__photo--xl{--ifm-avatar-photo-size:6rem}.avatar__intro{display:flex;flex:1 1;flex-direction:column;justify-content:center;text-align:var(--ifm-avatar-intro-alignment)}.badge,.breadcrumbs__item,.breadcrumbs__link,.button,.dropdown>.navbar__link:after{display:inline-block}.avatar__name{font:700 var(--ifm-h4-font-size)/var(--ifm-heading-line-height) var(--ifm-font-family-base)}.avatar__subtitle{margin-top:.25rem}.avatar--vertical{--ifm-avatar-intro-alignment:center;--ifm-avatar-intro-margin:0.5rem;align-items:center;flex-direction:column}.badge{background-color:var(--ifm-badge-background-color);border:var(--ifm-badge-border-width) solid var(--ifm-badge-border-color);border-radius:var(--ifm-badge-border-radius);color:var(--ifm-badge-color);font-size:75%;font-weight:var(--ifm-font-weight-bold);line-height:1;padding:var(--ifm-badge-padding-vertical) var(--ifm-badge-padding-horizontal)}.badge--primary{--ifm-badge-background-color:var(--ifm-color-primary)}.badge--secondary{--ifm-badge-background-color:var(--ifm-color-secondary);color:var(--ifm-color-black)}.breadcrumbs__link,.button.button--secondary.button--outline:not(.button--active):not(:hover){color:var(--ifm-font-color-base)}.badge--success{--ifm-badge-background-color:var(--ifm-color-success)}.badge--info{--ifm-badge-background-color:var(--ifm-color-info)}.badge--warning{--ifm-badge-background-color:var(--ifm-color-warning)}.badge--danger{--ifm-badge-background-color:var(--ifm-color-danger)}.breadcrumbs{margin-bottom:0;padding-left:0}.breadcrumbs__item:not(:last-child):after{background:var(--ifm-breadcrumb-separator) center;content:" ";display:inline-block;filter:var(--ifm-breadcrumb-separator-filter);height:calc(var(--ifm-breadcrumb-separator-size)*var(--ifm-breadcrumb-size-multiplier)*var(--ifm-breadcrumb-separator-size-multiplier));margin:0 var(--ifm-breadcrumb-spacing);opacity:.5;width:calc(var(--ifm-breadcrumb-separator-size)*var(--ifm-breadcrumb-size-multiplier)*var(--ifm-breadcrumb-separator-size-multiplier))}.breadcrumbs__item--active .breadcrumbs__link{background:var(--ifm-breadcrumb-item-background-active);color:var(--ifm-breadcrumb-color-active)}.breadcrumbs__link{border-radius:var(--ifm-breadcrumb-border-radius);font-size:calc(1rem*var(--ifm-breadcrumb-size-multiplier));padding:calc(var(--ifm-breadcrumb-padding-vertical)*var(--ifm-breadcrumb-size-multiplier)) calc(var(--ifm-breadcrumb-padding-horizontal)*var(--ifm-breadcrumb-size-multiplier));transition-duration:var(--ifm-transition-fast);transition-property:background,color}.breadcrumbs__link:any-link:hover,.breadcrumbs__link:link:hover,.breadcrumbs__link:visited:hover,area.breadcrumbs__link[href]:hover{background:var(--ifm-breadcrumb-item-background-active);text-decoration:none}.breadcrumbs--sm{--ifm-breadcrumb-size-multiplier:0.8}.breadcrumbs--lg{--ifm-breadcrumb-size-multiplier:1.2}.button{background-color:var(--ifm-button-background-color);border:var(--ifm-button-border-width) solid var(--ifm-button-border-color);border-radius:var(--ifm-button-border-radius);cursor:pointer;font-size:calc(.875rem*var(--ifm-button-size-multiplier));font-weight:var(--ifm-button-font-weight);line-height:1.5;padding:calc(var(--ifm-button-padding-vertical)*var(--ifm-button-size-multiplier)) calc(var(--ifm-button-padding-horizontal)*var(--ifm-button-size-multiplier));text-align:center;transition-duration:var(--ifm-button-transition-duration);transition-property:color,background,border-color;-webkit-user-select:none;user-select:none;white-space:nowrap}.button,.button:hover{color:var(--ifm-button-color)}.button--outline{--ifm-button-color:var(--ifm-button-border-color)}.button--outline:hover{--ifm-button-background-color:var(--ifm-button-border-color)}.button--link{--ifm-button-border-color:#0000;color:var(--ifm-link-color);text-decoration:var(--ifm-link-decoration)}.button--link.button--active,.button--link:active,.button--link:hover{color:var(--ifm-link-hover-color);text-decoration:var(--ifm-link-hover-decoration)}.button.disabled,.button:disabled,.button[disabled]{opacity:.65;pointer-events:none}.button--sm{--ifm-button-size-multiplier:0.8}.button--lg{--ifm-button-size-multiplier:1.35}.button--block{display:block;width:100%}.button.button--secondary{color:var(--ifm-color-gray-900)}:where(.button--primary){--ifm-button-background-color:var(--ifm-color-primary);--ifm-button-border-color:var(--ifm-color-primary)}:where(.button--primary):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-primary-dark);--ifm-button-border-color:var(--ifm-color-primary-dark)}.button--primary.button--active,.button--primary:active{--ifm-button-background-color:var(--ifm-color-primary-darker);--ifm-button-border-color:var(--ifm-color-primary-darker)}:where(.button--secondary){--ifm-button-background-color:var(--ifm-color-secondary);--ifm-button-border-color:var(--ifm-color-secondary)}:where(.button--secondary):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-secondary-dark);--ifm-button-border-color:var(--ifm-color-secondary-dark)}.button--secondary.button--active,.button--secondary:active{--ifm-button-background-color:var(--ifm-color-secondary-darker);--ifm-button-border-color:var(--ifm-color-secondary-darker)}:where(.button--success){--ifm-button-background-color:var(--ifm-color-success);--ifm-button-border-color:var(--ifm-color-success)}:where(.button--success):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-success-dark);--ifm-button-border-color:var(--ifm-color-success-dark)}.button--success.button--active,.button--success:active{--ifm-button-background-color:var(--ifm-color-success-darker);--ifm-button-border-color:var(--ifm-color-success-darker)}:where(.button--info){--ifm-button-background-color:var(--ifm-color-info);--ifm-button-border-color:var(--ifm-color-info)}:where(.button--info):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-info-dark);--ifm-button-border-color:var(--ifm-color-info-dark)}.button--info.button--active,.button--info:active{--ifm-button-background-color:var(--ifm-color-info-darker);--ifm-button-border-color:var(--ifm-color-info-darker)}:where(.button--warning){--ifm-button-background-color:var(--ifm-color-warning);--ifm-button-border-color:var(--ifm-color-warning)}:where(.button--warning):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-warning-dark);--ifm-button-border-color:var(--ifm-color-warning-dark)}.button--warning.button--active,.button--warning:active{--ifm-button-background-color:var(--ifm-color-warning-darker);--ifm-button-border-color:var(--ifm-color-warning-darker)}:where(.button--danger){--ifm-button-background-color:var(--ifm-color-danger);--ifm-button-border-color:var(--ifm-color-danger)}:where(.button--danger):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-danger-dark);--ifm-button-border-color:var(--ifm-color-danger-dark)}.button--danger.button--active,.button--danger:active{--ifm-button-background-color:var(--ifm-color-danger-darker);--ifm-button-border-color:var(--ifm-color-danger-darker)}.button-group{display:inline-flex;gap:var(--ifm-button-group-spacing)}.button-group>.button:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.button-group>.button:not(:last-child){border-bottom-right-radius:0;border-top-right-radius:0}.button-group--block{display:flex;justify-content:stretch}.button-group--block>.button{flex-grow:1}.card{background-color:var(--ifm-card-background-color);border-radius:var(--ifm-card-border-radius);box-shadow:var(--ifm-global-shadow-lw);display:flex;flex-direction:column;overflow:hidden}.card__image{padding-top:var(--ifm-card-vertical-spacing)}.card__image:first-child{padding-top:0}.card__body,.card__footer,.card__header{padding:var(--ifm-card-vertical-spacing) var(--ifm-card-horizontal-spacing)}.card__body:not(:last-child),.card__footer:not(:last-child),.card__header:not(:last-child){padding-bottom:0}.card__body>:last-child,.card__footer>:last-child,.card__header>:last-child{margin-bottom:0}.card__footer{margin-top:auto}.table-of-contents{font-size:.8rem;margin-bottom:0;padding:var(--ifm-toc-padding-vertical) 0}.table-of-contents,.table-of-contents ul{list-style:none;padding-left:var(--ifm-toc-padding-horizontal)}.table-of-contents li{margin:var(--ifm-toc-padding-vertical) var(--ifm-toc-padding-horizontal)}.table-of-contents__left-border{border-left:1px solid var(--ifm-toc-border-color)}.table-of-contents__link{color:var(--ifm-toc-link-color);display:block}.table-of-contents__link--active,.table-of-contents__link--active code,.table-of-contents__link:hover,.table-of-contents__link:hover code{color:var(--ifm-color-primary);text-decoration:none}.close{color:var(--ifm-color-black);float:right;font-size:1.5rem;font-weight:var(--ifm-font-weight-bold);line-height:1;opacity:.5;padding:1rem;transition:opacity var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.close:hover{opacity:.7}.close:focus,.theme-code-block-highlighted-line .codeLineNumber_Tfdd:before{opacity:.8}.dropdown{display:inline-flex;font-weight:var(--ifm-dropdown-font-weight);position:relative;vertical-align:top}.dropdown--hoverable:hover .dropdown__menu,.dropdown--show .dropdown__menu{opacity:1;pointer-events:all;transform:translateY(-1px);visibility:visible}#nprogress,.dropdown__menu,.navbar__item.dropdown .navbar__link:not([href]){pointer-events:none}.dropdown--right .dropdown__menu{left:inherit;right:0}.dropdown--nocaret .navbar__link:after{content:none!important}.dropdown__menu{background-color:var(--ifm-dropdown-background-color);border-radius:var(--ifm-global-radius);box-shadow:var(--ifm-global-shadow-md);left:0;max-height:80vh;min-width:10rem;opacity:0;overflow-y:auto;padding:.5rem;position:absolute;top:calc(100% - var(--ifm-navbar-item-padding-vertical) + .3rem);transform:translateY(-.625rem);transition-duration:var(--ifm-transition-fast);transition-property:opacity,transform,visibility;transition-timing-function:var(--ifm-transition-timing-default);visibility:hidden;z-index:var(--ifm-z-index-dropdown)}.sidebar_re4s,.tableOfContents_bqdL{max-height:calc(100vh - var(--ifm-navbar-height) - 2rem)}.menu__caret,.menu__link,.menu__list-item-collapsible{border-radius:.25rem;transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.dropdown__link{border-radius:.25rem;color:var(--ifm-dropdown-link-color);display:block;font-size:.875rem;margin-top:.2rem;padding:.25rem .5rem;white-space:nowrap}.dropdown__link--active,.dropdown__link:hover{background-color:var(--ifm-dropdown-hover-background-color);color:var(--ifm-dropdown-link-color);text-decoration:none}.dropdown__link--active,.dropdown__link--active:hover{--ifm-dropdown-link-color:var(--ifm-link-color)}.dropdown>.navbar__link:after{border-color:currentcolor #0000;border-style:solid;border-width:.4em .4em 0;content:"";margin-left:.3em;position:relative;top:2px;transform:translateY(-50%)}.footer{background-color:var(--ifm-footer-background-color);color:var(--ifm-footer-color);padding:var(--ifm-footer-padding-vertical) var(--ifm-footer-padding-horizontal)}.footer--dark{--ifm-footer-background-color:#303846;--ifm-footer-color:var(--ifm-footer-link-color);--ifm-footer-link-color:var(--ifm-color-secondary);--ifm-footer-title-color:var(--ifm-color-white)}.footer__links{margin-bottom:1rem}.footer__link-item{color:var(--ifm-footer-link-color);line-height:2}.footer__link-item:hover{color:var(--ifm-footer-link-hover-color)}.footer__link-separator{margin:0 var(--ifm-footer-link-horizontal-spacing)}.footer__logo{margin-top:1rem;max-width:var(--ifm-footer-logo-max-width)}.footer__title{color:var(--ifm-footer-title-color);font:700 var(--ifm-h4-font-size)/var(--ifm-heading-line-height) var(--ifm-font-family-base);margin-bottom:var(--ifm-heading-margin-bottom)}.menu,.navbar__link{font-weight:var(--ifm-font-weight-semibold)}.docItemContainer_Djhp article>:first-child,.docItemContainer_Djhp header+*,.footer__item{margin-top:0}.admonitionContent_S0QG>:last-child,.collapsibleContent_i85q>:last-child,.footer__items{margin-bottom:0}.codeBlockStandalone_MEMb,[type=checkbox]{padding:0}.hero{align-items:center;background-color:var(--ifm-hero-background-color);color:var(--ifm-hero-text-color);display:flex;padding:4rem 2rem}.hero--primary{--ifm-hero-background-color:var(--ifm-color-primary);--ifm-hero-text-color:var(--ifm-font-color-base-inverse)}.hero--dark{--ifm-hero-background-color:#303846;--ifm-hero-text-color:var(--ifm-color-white)}.hero__title,.title_f1Hy{font-size:3rem}.hero__subtitle{font-size:1.5rem}.menu__list{margin:0;padding-left:0}.menu__caret,.menu__link{padding:var(--ifm-menu-link-padding-vertical) var(--ifm-menu-link-padding-horizontal)}.menu__list .menu__list{flex:0 0 100%;margin-top:.25rem;padding-left:var(--ifm-menu-link-padding-horizontal)}.menu__list-item:not(:first-child){margin-top:.25rem}.menu__list-item--collapsed .menu__list{height:0;overflow:hidden}.details_lb9f[data-collapsed=false].isBrowser_bmU9>summary:before,.details_lb9f[open]:not(.isBrowser_bmU9)>summary:before,.menu__list-item--collapsed .menu__caret:before,.menu__list-item--collapsed .menu__link--sublist:after{transform:rotate(90deg)}.menu__list-item-collapsible{display:flex;flex-wrap:wrap;position:relative}.menu__caret:hover,.menu__link:hover,.menu__list-item-collapsible--active,.menu__list-item-collapsible:hover{background:var(--ifm-menu-color-background-hover)}.menu__list-item-collapsible .menu__link--active,.menu__list-item-collapsible .menu__link:hover{background:none!important}.menu__caret,.menu__link{align-items:center;display:flex}.menu__link{color:var(--ifm-menu-color);flex:1;line-height:1.25}.menu__link:hover{color:var(--ifm-menu-color);text-decoration:none}.menu__caret:before,.menu__link--sublist-caret:after{content:"";height:1.25rem;transform:rotate(180deg);transition:transform var(--ifm-transition-fast) linear;width:1.25rem;filter:var(--ifm-menu-link-sublist-icon-filter)}.menu__link--sublist-caret:after{background:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem;margin-left:auto;min-width:1.25rem}.menu__link--active,.menu__link--active:hover{color:var(--ifm-menu-color-active)}.navbar__brand,.navbar__link{color:var(--ifm-navbar-link-color)}.menu__link--active:not(.menu__link--sublist){background-color:var(--ifm-menu-color-background-active)}.menu__caret:before{background:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem}.navbar--dark,html[data-theme=dark]{--ifm-menu-link-sublist-icon-filter:invert(100%) sepia(94%) saturate(17%) hue-rotate(223deg) brightness(104%) contrast(98%)}.navbar{background-color:var(--ifm-navbar-background-color);box-shadow:var(--ifm-navbar-shadow);height:var(--ifm-navbar-height);padding:var(--ifm-navbar-padding-vertical) var(--ifm-navbar-padding-horizontal)}.docsWrapper_BCFX,.navbar,.navbar>.container,.navbar>.container-fluid{display:flex}.navbar--fixed-top{position:sticky;top:0;z-index:var(--ifm-z-index-fixed)}.navbar-sidebar,.navbar-sidebar__backdrop{bottom:0;opacity:0;position:fixed;transition-timing-function:ease-in-out;left:0;top:0;visibility:hidden}.navbar__inner{display:flex;flex-wrap:wrap;justify-content:space-between;width:100%}.navbar__brand{align-items:center;display:flex;margin-right:1rem;min-width:0}.navbar__brand:hover{color:var(--ifm-navbar-link-hover-color);text-decoration:none}.announcementBarContent_xLdY,.navbar__title{flex:1 1 auto}.navbar__toggle{display:none;margin-right:.5rem}.navbar__logo{flex:0 0 auto;height:2rem;margin-right:.5rem}.navbar__items{align-items:center;display:flex;flex:1;min-width:0}.navbar__items--center{flex:0 0 auto}.navbar__items--center .navbar__brand{margin:0}.navbar__items--center+.navbar__items--right{flex:1}.navbar__items--right{flex:0 0 auto;justify-content:flex-end}.navbar__items--right>:last-child{padding-right:0}.navbar__item{display:inline-block;padding:var(--ifm-navbar-item-padding-vertical) var(--ifm-navbar-item-padding-horizontal)}.navbar__link--active,.navbar__link:hover{color:var(--ifm-navbar-link-hover-color);text-decoration:none}.navbar--dark,.navbar--primary{--ifm-menu-color:var(--ifm-color-gray-300);--ifm-navbar-link-color:var(--ifm-color-gray-100);--ifm-navbar-search-input-background-color:#ffffff1a;--ifm-navbar-search-input-placeholder-color:#ffffff80;color:var(--ifm-color-white)}.navbar--dark{--ifm-navbar-background-color:#242526;--ifm-menu-color-background-active:#ffffff0d;--ifm-navbar-search-input-color:var(--ifm-color-white)}.navbar--primary{--ifm-navbar-background-color:var(--ifm-color-primary);--ifm-navbar-link-hover-color:var(--ifm-color-white);--ifm-menu-color-active:var(--ifm-color-white);--ifm-navbar-search-input-color:var(--ifm-color-emphasis-500)}.navbar__search-input{appearance:none;background:var(--ifm-navbar-search-input-background-color) var(--ifm-navbar-search-input-icon) no-repeat .75rem center/1rem 1rem;border:none;border-radius:2rem;color:var(--ifm-navbar-search-input-color);cursor:text;display:inline-block;font-size:.9rem;height:2rem;padding:0 .5rem 0 2.25rem;width:12.5rem}.navbar__search-input::placeholder{color:var(--ifm-navbar-search-input-placeholder-color)}.navbar-sidebar{background-color:var(--ifm-navbar-background-color);box-shadow:var(--ifm-global-shadow-md);transform:translate3d(-100%,0,0);transition-duration:.25s;transition-property:opacity,visibility,transform;width:var(--ifm-navbar-sidebar-width)}.navbar-sidebar--show .navbar-sidebar,.navbar-sidebar__items{transform:translateZ(0)}.navbar-sidebar--show .navbar-sidebar,.navbar-sidebar--show .navbar-sidebar__backdrop{opacity:1;visibility:visible}.navbar-sidebar__backdrop{background-color:#0009;right:0;transition-duration:.1s;transition-property:opacity,visibility}.navbar-sidebar__brand{align-items:center;box-shadow:var(--ifm-navbar-shadow);display:flex;flex:1;height:var(--ifm-navbar-height);padding:var(--ifm-navbar-padding-vertical) var(--ifm-navbar-padding-horizontal)}.navbar-sidebar__items{display:flex;height:calc(100% - var(--ifm-navbar-height));transition:transform var(--ifm-transition-fast) ease-in-out}.navbar-sidebar__items--show-secondary{transform:translate3d(calc((var(--ifm-navbar-sidebar-width))*-1),0,0)}.navbar-sidebar__item{flex-shrink:0;padding:.5rem;width:calc(var(--ifm-navbar-sidebar-width))}.navbar-sidebar__back{background:var(--ifm-menu-color-background-active);font-size:15px;font-weight:var(--ifm-button-font-weight);margin:0 0 .2rem -.5rem;padding:.6rem 1.5rem;position:relative;text-align:left;top:-.5rem;width:calc(100% + 1rem)}.navbar-sidebar__close{display:flex;margin-left:auto}.pagination{column-gap:var(--ifm-pagination-page-spacing);display:flex;font-size:var(--ifm-pagination-font-size);padding-left:0}.pagination--sm{--ifm-pagination-font-size:0.8rem;--ifm-pagination-padding-horizontal:0.8rem;--ifm-pagination-padding-vertical:0.2rem}.pagination--lg{--ifm-pagination-font-size:1.2rem;--ifm-pagination-padding-horizontal:1.2rem;--ifm-pagination-padding-vertical:0.3rem}.pagination__item{display:inline-flex}.pagination__item>span{padding:var(--ifm-pagination-padding-vertical)}.pagination__item--active .pagination__link{color:var(--ifm-pagination-color-active)}.pagination__item--active .pagination__link,.pagination__item:not(.pagination__item--active):hover .pagination__link{background:var(--ifm-pagination-item-active-background)}.pagination__item--disabled,.pagination__item[disabled]{opacity:.25;pointer-events:none}.pagination__link{border-radius:var(--ifm-pagination-border-radius);color:var(--ifm-font-color-base);display:inline-block;padding:var(--ifm-pagination-padding-vertical) var(--ifm-pagination-padding-horizontal);transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.pagination__link:hover,.sidebarItemLink_mo7H:hover{text-decoration:none}.pagination-nav{grid-gap:var(--ifm-spacing-horizontal);display:grid;gap:var(--ifm-spacing-horizontal);grid-template-columns:repeat(2,1fr)}.pagination-nav__link{border:1px solid var(--ifm-color-emphasis-300);border-radius:var(--ifm-pagination-nav-border-radius);display:block;height:100%;line-height:var(--ifm-heading-line-height);padding:var(--ifm-global-spacing);transition:border-color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.pagination-nav__link:hover{border-color:var(--ifm-pagination-nav-color-hover);text-decoration:none}.pagination-nav__link--next{grid-column:2/3;text-align:right}.pagination-nav__label{font-size:var(--ifm-h4-font-size);font-weight:var(--ifm-heading-font-weight);word-break:break-word}.pagination-nav__link--prev .pagination-nav__label:before{content:"« "}.pagination-nav__link--next .pagination-nav__label:after{content:" »"}.pagination-nav__sublabel{color:var(--ifm-color-content-secondary);font-size:var(--ifm-h5-font-size);font-weight:var(--ifm-font-weight-semibold);margin-bottom:.25rem}.pills__item,.sidebarItemTitle_pO2u,.tabs{font-weight:var(--ifm-font-weight-bold)}.pills{display:flex;gap:var(--ifm-pills-spacing);padding-left:0}.pills__item{border-radius:.5rem;cursor:pointer;display:inline-block;padding:.25rem 1rem;transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.tabs,:not(.containsTaskList_mC6p>li)>.containsTaskList_mC6p{padding-left:0}.pills__item--active{color:var(--ifm-pills-color-active)}.pills__item--active,.pills__item:not(.pills__item--active):hover{background:var(--ifm-pills-color-background-active)}.pills--block{justify-content:stretch}.pills--block .pills__item{flex-grow:1;text-align:center}.tabs{color:var(--ifm-tabs-color);display:flex;margin-bottom:0;overflow-x:auto}.tabs__item{border-bottom:3px solid #0000;border-radius:var(--ifm-global-radius);cursor:pointer;display:inline-flex;padding:var(--ifm-tabs-padding-vertical) var(--ifm-tabs-padding-horizontal);transition:background-color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.tabs__item--active{border-bottom-color:var(--ifm-tabs-color-active-border);border-bottom-left-radius:0;border-bottom-right-radius:0;color:var(--ifm-tabs-color-active)}.tabs__item:hover{background-color:var(--ifm-hover-overlay)}.tabs--block{justify-content:stretch}.tabs--block .tabs__item{flex-grow:1;justify-content:center}html[data-theme=dark]{--ifm-color-scheme:dark;--ifm-color-emphasis-0:var(--ifm-color-gray-1000);--ifm-color-emphasis-100:var(--ifm-color-gray-900);--ifm-color-emphasis-200:var(--ifm-color-gray-800);--ifm-color-emphasis-300:var(--ifm-color-gray-700);--ifm-color-emphasis-400:var(--ifm-color-gray-600);--ifm-color-emphasis-600:var(--ifm-color-gray-400);--ifm-color-emphasis-700:var(--ifm-color-gray-300);--ifm-color-emphasis-800:var(--ifm-color-gray-200);--ifm-color-emphasis-900:var(--ifm-color-gray-100);--ifm-color-emphasis-1000:var(--ifm-color-gray-0);--ifm-background-color:#1b1b1d;--ifm-background-surface-color:#242526;--ifm-hover-overlay:#ffffff0d;--ifm-color-content:#e3e3e3;--ifm-color-content-secondary:#fff;--ifm-breadcrumb-separator-filter:invert(64%) sepia(11%) saturate(0%) hue-rotate(149deg) brightness(99%) contrast(95%);--ifm-code-background:#ffffff1a;--ifm-scrollbar-track-background-color:#444;--ifm-scrollbar-thumb-background-color:#686868;--ifm-scrollbar-thumb-hover-background-color:#7a7a7a;--ifm-table-stripe-background:#ffffff12;--ifm-toc-border-color:var(--ifm-color-emphasis-200);--ifm-color-primary-contrast-background:#102445;--ifm-color-primary-contrast-foreground:#ebf2fc;--ifm-color-secondary-contrast-background:#474748;--ifm-color-secondary-contrast-foreground:#fdfdfe;--ifm-color-success-contrast-background:#003100;--ifm-color-success-contrast-foreground:#e6f6e6;--ifm-color-info-contrast-background:#193c47;--ifm-color-info-contrast-foreground:#eef9fd;--ifm-color-warning-contrast-background:#4d3800;--ifm-color-warning-contrast-foreground:#fff8e6;--ifm-color-danger-contrast-background:#4b1113;--ifm-color-danger-contrast-foreground:#ffebec}#nprogress .bar{background:var(--docusaurus-progress-bar-color);height:2px;left:0;position:fixed;top:0;width:100%;z-index:1031}#nprogress .peg{box-shadow:0 0 10px var(--docusaurus-progress-bar-color),0 0 5px var(--docusaurus-progress-bar-color);height:100%;opacity:1;position:absolute;right:0;transform:rotate(3deg) translateY(-4px);width:100px}.docusaurus-highlight-code-line{background-color:#484d5b;display:block;margin:0 calc(var(--ifm-pre-padding)*-1);padding:0 var(--ifm-pre-padding)}.skipToContent_fXgn{background-color:var(--ifm-background-surface-color);color:var(--ifm-color-emphasis-900);left:100%;padding:calc(var(--ifm-global-spacing)/2) var(--ifm-global-spacing);position:fixed;top:1rem;z-index:calc(var(--ifm-z-index-fixed) + 1)}.skipToContent_fXgn:focus{box-shadow:var(--ifm-global-shadow-md);left:1rem}.closeButton_CVFx{line-height:0;padding:0}.content_knG7{font-size:85%;padding:5px 0;text-align:center}.content_knG7 a{color:inherit;text-decoration:underline}.announcementBar_mb4j{align-items:center;background-color:var(--ifm-color-white);border-bottom:1px solid var(--ifm-color-emphasis-100);color:var(--ifm-color-black);display:flex;height:var(--docusaurus-announcement-bar-height)}#docusaurus-base-url-issue-banner-container,.collapseSidebarButton_PEFL,.docSidebarContainer_b6E3,.sidebarLogo_isFc,.themedImage_ToTc,[data-theme=dark] .lightToggleIcon_pyhR,[data-theme=light] .darkToggleIcon_wfgR,html[data-announcement-bar-initially-dismissed=true] .announcementBar_mb4j{display:none}.announcementBarPlaceholder_vyr4{flex:0 0 10px}.announcementBarClose_gvF7{align-self:stretch;flex:0 0 30px}.toggle_vylO{height:2rem;width:2rem}.toggleButton_gllP{align-items:center;border-radius:50%;display:flex;height:100%;justify-content:center;transition:background var(--ifm-transition-fast);width:100%}.toggleButton_gllP:hover{background:var(--ifm-color-emphasis-200)}.toggleButtonDisabled_aARS{cursor:not-allowed}[data-theme=dark] .themedImage--dark_i4oU,[data-theme=light] .themedImage--light_HNdA{display:initial}.iconExternalLink_nPIU{margin-left:.3rem}.iconLanguage_nlXk{margin-right:5px;vertical-align:text-bottom}.navbarHideable_m1mJ{transition:transform var(--ifm-transition-fast) ease}.navbarHidden_jGov{transform:translate3d(0,calc(-100% - 2px),0)}body:not(.navigation-with-keyboard) :not(input):focus{outline:0}.footerLogoLink_BH7S{opacity:.5;transition:opacity var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.footerLogoLink_BH7S:hover,.hash-link:focus,:hover>.hash-link{opacity:1}.mainWrapper_z2l0{flex:1 0 auto}.docusaurus-mt-lg{margin-top:3rem}#__docusaurus{display:flex;flex-direction:column;min-height:100%}.backToTopButton_sjWU{background-color:var(--ifm-color-emphasis-200);border-radius:50%;bottom:1.3rem;box-shadow:var(--ifm-global-shadow-lw);height:3rem;opacity:0;position:fixed;right:1.3rem;transform:scale(0);transition:all var(--ifm-transition-fast) var(--ifm-transition-timing-default);visibility:hidden;width:3rem;z-index:calc(var(--ifm-z-index-fixed) - 1)}.backToTopButton_sjWU:after{background-color:var(--ifm-color-emphasis-1000);content:" ";display:inline-block;height:100%;-webkit-mask:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem no-repeat;mask:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem no-repeat;width:100%}.backToTopButtonShow_xfvO{opacity:1;transform:scale(1);visibility:visible}[data-theme=dark]:root{--docusaurus-collapse-button-bg:#ffffff0d;--docusaurus-collapse-button-bg-hover:#ffffff1a}.docMainContainer_gTbr,.docPage__5DB{display:flex;width:100%}.sidebar_re4s{overflow-y:auto;position:sticky;top:calc(var(--ifm-navbar-height) + 2rem)}.sidebarItemTitle_pO2u{font-size:var(--ifm-h3-font-size)}.container_mt6G,.sidebarItemList_Yudw{font-size:.9rem}.sidebarItem__DBe{margin-top:.7rem}.sidebarItemLink_mo7H{color:var(--ifm-font-color-base);display:block}.sidebarItemLinkActive_I1ZP{color:var(--ifm-color-primary)!important}.authorCol_Hf19{flex-grow:1!important;max-width:inherit!important}.imageOnlyAuthorRow_pa_O{display:flex;flex-flow:row wrap}.imageOnlyAuthorCol_G86a{margin-left:.3rem;margin-right:.3rem}.heroBanner_UJJx{overflow:hidden;padding:4rem 0;position:relative;text-align:center}.buttons_pzbO{justify-content:center}.buttons_pzbO,.features_keug{align-items:center;display:flex}.features_keug{padding:2rem 0;width:100%}.featureImage_yA8i{height:200px;width:200px}.getStarted_Sjon{border:2px solid #f5f6f7;color:#fff}.buttonGroup__atx button,.codeBlockContainer_Ckt0{background:var(--prism-background-color);color:var(--prism-color)}.getStarted_Sjon:hover{background-color:#fff;color:#0078d7}.heading_AAq7{font-weight:400}.codeBlockContainer_Ckt0{border-radius:var(--ifm-code-border-radius);box-shadow:var(--ifm-global-shadow-lw);margin-bottom:var(--ifm-leading)}.codeBlockContent_biex{border-radius:inherit;direction:ltr;position:relative}.codeBlockTitle_Ktv7{border-bottom:1px solid var(--ifm-color-emphasis-300);border-top-left-radius:inherit;border-top-right-radius:inherit;font-size:var(--ifm-code-font-size);font-weight:500;padding:.75rem var(--ifm-pre-padding)}.codeBlock_bY9V{--ifm-pre-background:var(--prism-background-color);margin:0;padding:0}.codeBlockTitle_Ktv7+.codeBlockContent_biex .codeBlock_bY9V{border-top-left-radius:0;border-top-right-radius:0}.codeBlockLines_e6Vv{float:left;font:inherit;min-width:100%;padding:var(--ifm-pre-padding)}.codeBlockLinesWithNumbering_o6Pm{display:table;padding:var(--ifm-pre-padding) 0}.buttonGroup__atx{column-gap:.2rem;display:flex;position:absolute;right:calc(var(--ifm-pre-padding)/2);top:calc(var(--ifm-pre-padding)/2)}.buttonGroup__atx button{align-items:center;border:1px solid var(--ifm-color-emphasis-300);border-radius:var(--ifm-global-radius);display:flex;line-height:0;opacity:0;padding:.4rem;transition:opacity .2s ease-in-out}.buttonGroup__atx button:focus-visible,.buttonGroup__atx button:hover{opacity:1!important}.theme-code-block:hover .buttonGroup__atx button{opacity:.4}.iconEdit_Z9Sw{margin-right:.3em;vertical-align:sub}:where(:root){--docusaurus-highlighted-code-line-bg:#484d5b}:where([data-theme=dark]){--docusaurus-highlighted-code-line-bg:#646464}.theme-code-block-highlighted-line{background-color:var(--docusaurus-highlighted-code-line-bg);display:block;margin:0 calc(var(--ifm-pre-padding)*-1);padding:0 var(--ifm-pre-padding)}.codeLine_lJS_{counter-increment:a;display:table-row}.codeLineNumber_Tfdd{background:var(--ifm-pre-background);display:table-cell;left:0;overflow-wrap:normal;padding:0 var(--ifm-pre-padding);position:sticky;text-align:right;width:1%}.codeLineNumber_Tfdd:before{content:counter(a);opacity:.4}.codeLineContent_feaV{padding-right:var(--ifm-pre-padding)}.tag_zVej{border:1px solid var(--docusaurus-tag-list-border);transition:border var(--ifm-transition-fast)}.tag_zVej:hover{--docusaurus-tag-list-border:var(--ifm-link-color);text-decoration:none}.tagRegular_sFm0{border-radius:var(--ifm-global-radius);font-size:90%;padding:.2rem .5rem .3rem}.tagWithCount_h2kH{align-items:center;border-left:0;display:flex;padding:0 .5rem 0 1rem;position:relative}.tagWithCount_h2kH:after,.tagWithCount_h2kH:before{border:1px solid var(--docusaurus-tag-list-border);content:"";position:absolute;top:50%;transition:inherit}.tagWithCount_h2kH:before{border-bottom:0;border-right:0;height:1.18rem;right:100%;transform:translate(50%,-50%) rotate(-45deg);width:1.18rem}.tagWithCount_h2kH:after{border-radius:50%;height:.5rem;left:0;transform:translateY(-50%);width:.5rem}.tagWithCount_h2kH span{background:var(--ifm-color-secondary);border-radius:var(--ifm-global-radius);color:var(--ifm-color-black);font-size:.7rem;line-height:1.2;margin-left:.3rem;padding:.1rem .4rem}.theme-code-block:hover .copyButtonCopied_obH4{opacity:1!important}.copyButtonIcons_eSgA{height:1.125rem;position:relative;width:1.125rem}.copyButtonIcon_y97N,.copyButtonSuccessIcon_LjdS{fill:currentColor;height:inherit;left:0;opacity:inherit;position:absolute;top:0;transition:.15s;width:inherit}.copyButtonSuccessIcon_LjdS{color:#00d600;left:50%;opacity:0;top:50%;transform:translate(-50%,-50%) scale(.33)}.copyButtonCopied_obH4 .copyButtonIcon_y97N{opacity:0;transform:scale(.33)}.copyButtonCopied_obH4 .copyButtonSuccessIcon_LjdS{opacity:1;transform:translate(-50%,-50%) scale(1);transition-delay:75ms}.tags_jXut{display:inline}.tag_QGVx{display:inline-block;margin:0 .4rem .5rem 0}.lastUpdated_vwxv{font-size:smaller;font-style:italic;margin-top:.2rem}.tocCollapsibleButton_TO0P{align-items:center;display:flex;font-size:inherit;justify-content:space-between;padding:.4rem .8rem;width:100%}.tocCollapsibleButton_TO0P:after{background:var(--ifm-menu-link-sublist-icon) 50% 50%/2rem 2rem no-repeat;content:"";filter:var(--ifm-menu-link-sublist-icon-filter);height:1.25rem;transform:rotate(180deg);transition:transform var(--ifm-transition-fast);width:1.25rem}.tocCollapsibleButtonExpanded_MG3E:after,.tocCollapsibleExpanded_sAul{transform:none}.tocCollapsible_ETCw{background-color:var(--ifm-menu-color-background-active);border-radius:var(--ifm-global-radius);margin:1rem 0}.tocCollapsibleContent_vkbj>ul{border-left:none;border-top:1px solid var(--ifm-color-emphasis-300);font-size:15px;padding:.2rem 0}.tocCollapsibleContent_vkbj ul li{margin:.4rem .8rem}.tocCollapsibleContent_vkbj a{display:block}.wordWrapButtonIcon_Bwma{height:1.2rem;width:1.2rem}.details_lb9f{--docusaurus-details-summary-arrow-size:0.38rem;--docusaurus-details-transition:transform 200ms ease;--docusaurus-details-decoration-color:grey}.details_lb9f>summary{cursor:pointer;padding-left:1rem;position:relative}.details_lb9f>summary::-webkit-details-marker{display:none}.details_lb9f>summary:before{border-color:#0000 #0000 #0000 var(--docusaurus-details-decoration-color);border-style:solid;border-width:var(--docusaurus-details-summary-arrow-size);content:"";left:0;position:absolute;top:.45rem;transform:rotate(0);transform-origin:calc(var(--docusaurus-details-summary-arrow-size)/2) 50%;transition:var(--docusaurus-details-transition)}.collapsibleContent_i85q{border-top:1px solid var(--docusaurus-details-decoration-color);margin-top:1rem;padding-top:1rem}.details_b_Ee{--docusaurus-details-decoration-color:var(--ifm-alert-border-color);--docusaurus-details-transition:transform var(--ifm-transition-fast) ease;border:1px solid var(--ifm-alert-border-color);margin:0 0 var(--ifm-spacing-vertical)}.anchorWithStickyNavbar_LWe7{scroll-margin-top:calc(var(--ifm-navbar-height) + .5rem)}.anchorWithHideOnScrollNavbar_WYt5{scroll-margin-top:.5rem}.hash-link{opacity:0;padding-left:.5rem;transition:opacity var(--ifm-transition-fast);-webkit-user-select:none;user-select:none}.hash-link:before{content:"#"}.img_ev3q{height:auto}.admonition_LlT9{margin-bottom:1em}.admonitionHeading_tbUL{font:var(--ifm-heading-font-weight) var(--ifm-h5-font-size)/var(--ifm-heading-line-height) var(--ifm-heading-font-family);margin-bottom:.3rem}.admonitionHeading_tbUL code{text-transform:none}.admonitionIcon_kALy{display:inline-block;margin-right:.4em;vertical-align:middle}.admonitionIcon_kALy svg{fill:var(--ifm-alert-foreground-color);display:inline-block;height:1.6em;width:1.6em}.blogPostFooterDetailsFull_mRVl{flex-direction:column}.tableOfContents_bqdL{overflow-y:auto;position:sticky;top:calc(var(--ifm-navbar-height) + 1rem)}.breadcrumbsContainer_Z_bl{--ifm-breadcrumb-size-multiplier:0.8;margin-bottom:.8rem}.breadcrumbHomeIcon_OVgt{height:1.1rem;position:relative;top:1px;vertical-align:top;width:1.1rem}@media (min-width:997px){.collapseSidebarButton_PEFL,.expandButton_m80_{background-color:var(--docusaurus-collapse-button-bg);position:sticky}:root{--docusaurus-announcement-bar-height:30px}.announcementBarClose_gvF7,.announcementBarPlaceholder_vyr4{flex-basis:50px}.searchBox_ZlJk{padding:var(--ifm-navbar-item-padding-vertical) var(--ifm-navbar-item-padding-horizontal)}.collapseSidebarButton_PEFL{border:1px solid var(--ifm-toc-border-color);border-radius:0;bottom:0;display:block!important;height:40px}.collapseSidebarButtonIcon_kv0_{margin-top:4px;transform:rotate(180deg)}.expandButtonIcon_BlDH,[dir=rtl] .collapseSidebarButtonIcon_kv0_{transform:rotate(0)}.collapseSidebarButton_PEFL:focus,.collapseSidebarButton_PEFL:hover,.expandButton_m80_:focus,.expandButton_m80_:hover{background-color:var(--docusaurus-collapse-button-bg-hover)}.menuHtmlItem_M9Kj{padding:var(--ifm-menu-link-padding-vertical) var(--ifm-menu-link-padding-horizontal)}.menu_SIkG{flex-grow:1;padding:.5rem}@supports (scrollbar-gutter:stable){.menu_SIkG{padding:.5rem 0 .5rem .5rem;scrollbar-gutter:stable}}.menuWithAnnouncementBar_GW3s{margin-bottom:var(--docusaurus-announcement-bar-height)}.sidebar_njMd{display:flex;flex-direction:column;height:100%;max-height:100vh;padding-top:var(--ifm-navbar-height);position:sticky;top:0;transition:opacity 50ms;width:var(--doc-sidebar-width)}.sidebarWithHideableNavbar_wUlq{padding-top:0}.sidebarHidden_VK0M{height:0;opacity:0;overflow:hidden;visibility:hidden}.sidebarLogo_isFc{align-items:center;color:inherit!important;display:flex!important;margin:0 var(--ifm-navbar-padding-horizontal);max-height:var(--ifm-navbar-height);min-height:var(--ifm-navbar-height);text-decoration:none!important}.sidebarLogo_isFc img{height:2rem;margin-right:.5rem}.expandButton_m80_{align-items:center;display:flex;height:100%;justify-content:center;max-height:100vh;top:0;transition:background-color var(--ifm-transition-fast) ease}[dir=rtl] .expandButtonIcon_BlDH{transform:rotate(180deg)}.docSidebarContainer_b6E3{border-right:1px solid var(--ifm-toc-border-color);clip-path:inset(0);display:block;margin-top:calc(var(--ifm-navbar-height)*-1);transition:width var(--ifm-transition-fast) ease;width:var(--doc-sidebar-width);will-change:width}.docSidebarContainerHidden_b3ry{cursor:pointer;width:var(--doc-sidebar-hidden-width)}.docMainContainer_gTbr{flex-grow:1;max-width:calc(100% - var(--doc-sidebar-width))}.docMainContainerEnhanced_Uz_u{max-width:calc(100% - var(--doc-sidebar-hidden-width))}.docItemWrapperEnhanced_czyv{max-width:calc(var(--ifm-container-width) + var(--doc-sidebar-width))!important}.lastUpdated_vwxv{text-align:right}.tocMobile_ITEo{display:none}.docItemCol_VOVn{max-width:75%!important}}@media (min-width:1440px){.container{max-width:var(--ifm-container-width-xl)}}@media (max-width:996px){.col{--ifm-col-width:100%;flex-basis:var(--ifm-col-width);margin-left:0}.footer{--ifm-footer-padding-horizontal:0}.colorModeToggle_DEke,.footer__link-separator,.navbar__item,.sidebar_re4s,.tableOfContents_bqdL{display:none}.footer__col{margin-bottom:calc(var(--ifm-spacing-vertical)*3)}.footer__link-item{display:block}.hero{padding-left:0;padding-right:0}.navbar>.container,.navbar>.container-fluid{padding:0}.navbar__toggle{display:inherit}.navbar__search-input{width:9rem}.pills--block,.tabs--block{flex-direction:column}.searchBox_ZlJk{position:absolute;right:var(--ifm-navbar-padding-horizontal)}.docItemContainer_F8PC{padding:0 .3rem}}@media screen and (max-width:966px){.heroBanner_UJJx{padding:2rem}}@media (max-width:576px){.markdown h1:first-child{--ifm-h1-font-size:2rem}.markdown>h2{--ifm-h2-font-size:1.5rem}.markdown>h3{--ifm-h3-font-size:1.25rem}.title_f1Hy{font-size:2rem}}@media (hover:hover){.backToTopButton_sjWU:hover{background-color:var(--ifm-color-emphasis-300)}}@media (pointer:fine){.thin-scrollbar{scrollbar-width:thin}.thin-scrollbar::-webkit-scrollbar{height:var(--ifm-scrollbar-size);width:var(--ifm-scrollbar-size)}.thin-scrollbar::-webkit-scrollbar-track{background:var(--ifm-scrollbar-track-background-color);border-radius:10px}.thin-scrollbar::-webkit-scrollbar-thumb{background:var(--ifm-scrollbar-thumb-background-color);border-radius:10px}.thin-scrollbar::-webkit-scrollbar-thumb:hover{background:var(--ifm-scrollbar-thumb-hover-background-color)}}@media print{.announcementBar_mb4j,.footer,.menu,.navbar,.pagination-nav,.table-of-contents,.tocMobile_ITEo{display:none}.tabs{page-break-inside:avoid}.codeBlockLines_e6Vv{white-space:pre-wrap}} \ No newline at end of file diff --git a/assets/js/071be86b.09bd0961.js b/assets/js/071be86b.0b670ef9.js similarity index 69% rename from assets/js/071be86b.09bd0961.js rename to assets/js/071be86b.0b670ef9.js index 09217edfb..916ccf20b 100644 --- a/assets/js/071be86b.09bd0961.js +++ b/assets/js/071be86b.0b670ef9.js @@ -1 +1 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[8922],{3905:(e,t,r)=>{r.d(t,{Zo:()=>d,kt:()=>u});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function s(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var l=n.createContext({}),c=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},d=function(e){var t=c(e.components);return n.createElement(l.Provider,{value:t},e.children)},p="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,i=e.originalType,l=e.parentName,d=o(e,["components","mdxType","originalType","parentName"]),p=c(r),m=a,u=p["".concat(l,".").concat(m)]||p[m]||h[m]||i;return r?n.createElement(u,s(s({ref:t},d),{},{components:r})):n.createElement(u,s({ref:t},d))}));function u(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=r.length,s=new Array(i);s[0]=m;var o={};for(var l in t)hasOwnProperty.call(t,l)&&(o[l]=t[l]);o.originalType=e,o[p]="string"==typeof e?e:a,s[1]=o;for(var c=2;c{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>s,default:()=>h,frontMatter:()=>i,metadata:()=>o,toc:()=>c});var n=r(7462),a=(r(7294),r(3905));const i={id:"financial-markets",title:"DvP in Financial Markets"},s=void 0,o={unversionedId:"external/user-stories/financial-markets",id:"external/user-stories/financial-markets",title:"DvP in Financial Markets",description:"\x3c!--",source:"@site/docs/external/user-stories/financial-markets.md",sourceDirName:"external/user-stories",slug:"/external/user-stories/financial-markets",permalink:"/weaver-dlt-interoperability/docs/external/user-stories/financial-markets",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/user-stories/financial-markets.md",tags:[],version:"current",frontMatter:{id:"financial-markets",title:"DvP in Financial Markets"},sidebar:"Documentation",previous:{title:"Global Trade",permalink:"/weaver-dlt-interoperability/docs/external/user-stories/global-trade"},next:{title:"Legacy Integration",permalink:"/weaver-dlt-interoperability/docs/external/user-stories/legacy-integration"}},l={},c=[],d={toc:c},p="wrapper";function h(e){let{components:t,...i}=e;return(0,a.kt)(p,(0,n.Z)({},d,i,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"In traditional financial markets parties trade assets such as securities and derivatives for cash or other assets. To reduce risk, various clearing and settlement processes and intermediaries are often involved. One form of settlement is a DvP (delivery versus payment) where the transfer of securities is performed only in the event of a corresponding payment. This arrangement reduces principal risk by ensuring that both parties receive their end of the exchange. However, settlement in financial markets are slow and time consuming. It also involves counterparty risks and requires intermediaries."),(0,a.kt)("p",null,"Over the past few years, we have been seeing significant efforts in digitising and tokenising both currencies and securities on Distributed Ledger Technology (DLT) infrastructures. On the one hand we have seen concerted efforts around Central Bank Digital Currencies (CBDC) being added to the landscape of other blockchain based payment networks. On the other hand, we have also seen efforts such as that from the Australian Stock Exchange (ASX) to replace its current settlement system--Clearing House Electronic Subregister System (CHESS) with a DLT based platform by 2021."),(0,a.kt)("p",null,"Against this backdrop, a number of central banks have been exploring the potential of performing DvP settlement across a currency ledger and a securities ledger. In this use case, we use this as a motivating use-case for our discussions. The scenario involves two decentralised ledgers, namely, a currency ledger and a securities ledger, based on different DLT protocols performing a coordinated transfer of assets in their respective ledgers."),(0,a.kt)("p",null,"The figure below depicts this scenario in the context of two organisations--",(0,a.kt)("em",{parentName:"p"},"Org-A")," and ",(0,a.kt)("em",{parentName:"p"},"Org-B"),". ",(0,a.kt)("em",{parentName:"p"},"Org-B")," wants to purchase some securities owned by ",(0,a.kt)("em",{parentName:"p"},"Org-A")," and both organisations have accounts on both ledgers. This scenario is simplified and leaves out a number of additional real world processes. For instance, the buyer and seller for securities need to discover each other and agree on the price and terms of a sale. In addition, an offer to sell securities might be fulfilled by multiple buyers taking smaller portions of the amount for sale. Such capabilities are often offered by centralised exchanges that offer capabilities such as order books and matching engines to address these needs. In this scenario we instead focus on the settlement process that follows such steps, once the parties of an exchange and the price of the exchange for an asset are determined."),(0,a.kt)("p",null,"To effect the settlement of this exchange between ",(0,a.kt)("em",{parentName:"p"},"Org-A")," and ",(0,a.kt)("em",{parentName:"p"},"Org-B"),", the following two transactions will have to happen atomically across both networks: i) transfer of payment from ",(0,a.kt)("em",{parentName:"p"},"Org-B"),"'s currency account in the CBDC ledger to ",(0,a.kt)("em",{parentName:"p"},"Org-A")," while at the same time ii) the entitlements of the designated securities are transferred from ",(0,a.kt)("em",{parentName:"p"},"Org-A")," to ",(0,a.kt)("em",{parentName:"p"},"Org-B"),". The scenario would need to guarantee that after the transaction execution, either both parties have their end of the exchange or neither does and that this exchange is performed in a timely manner."),(0,a.kt)("p",null,(0,a.kt)("img",{alt:"Simple DvP scenario in financial markets",src:r(336).Z,width:"1356",height:"554"})),(0,a.kt)("p",null,"The settlement of the exchange of securities from ",(0,a.kt)("em",{parentName:"p"},"Org-A")," to ",(0,a.kt)("em",{parentName:"p"},"Org-B")," in the Financial Securities Network for a simultaneous payment from ",(0,a.kt)("em",{parentName:"p"},"Org-B")," to ",(0,a.kt)("em",{parentName:"p"},"Org-A")," in the CBDC network is coordinated by Weaver using ",(0,a.kt)("a",{parentName:"p",href:"https://en.bitcoin.it/wiki/Hash_Time_Locked_Contracts"},"Hashed Time Lock Contracts"),".\nThis protocol essentially has three phases:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Fund locking: To initialise an asset exchange, it is common for one or both parties to first lock up funds with a fund-withholding party on his or her own blockchain. Temporary fund locking ensures the locked fund cannot be used for other purposes while the exchange is being executed. This scheme is often used with a specified timeout to provide flexibility for reclaiming locked funds if the exchange does not take place."),(0,a.kt)("li",{parentName:"ul"},"Fund redeeming: In general, the execution requires a pair of transactions to occur on both blockchains, e.g., from Org-A to Org-B on the FSN ledger and from Org-B to Org-A in CBDC ledger. When certain conditions are met, the locked funds can be redeemed by, or paid to the respective users. The execution of the exchange can be carried out by users themselves, or through other trusted third parties. These trusted third parties can be stand-alone parties that are not otherwise involved in both blockchains, or part of either blockchain.\xa0"),(0,a.kt)("li",{parentName:"ul"},"Refund: For protocols that are initialised with a temporary fund-locking, the locked funds can usually be reclaimed by the initial owner after a specified timeout, if a redemption has not occurred.\xa0")),(0,a.kt)("p",null,"The process proceeds as follows, and is further illustrated in the figure below:"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("strong",{parentName:"li"},"Org-A locks its securities in FSN ledger"),": ",(0,a.kt)("em",{parentName:"li"},"Org-A")," first creates some secret S, known only to it and locks its securities using the hash of S. The securities are configured to redeemable by ",(0,a.kt)("em",{parentName:"li"},"Org-B")," if it presents S within some specified time threshold."),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("strong",{parentName:"li"},"Org-B locks payments tokens in CBDC ledger"),": Org-B, observes that ",(0,a.kt)("em",{parentName:"li"},"Org-A")," has locked its securities in the FSN network and does a corresponding lock of its payment tokens with the hash of S, used by ",(0,a.kt)("em",{parentName:"li"},"Org-A")," in locking its securities. The payment tokens are redeemable only by Org-A, if it submits a transaction that reveals S within a specified time."),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("strong",{parentName:"li"},"Org-A checks Org-B's contract in CBDC ledger"),": ",(0,a.kt)("em",{parentName:"li"},"Org-A")," checks the CBDC network to ensure that the payments tokens are locked by Org-B."),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("strong",{parentName:"li"},"Org-A claims payments in CBDC ledger"),": ",(0,a.kt)("em",{parentName:"li"},"Org-A")," submits a transaction to claim the payments tokens, by revealing the secret S."),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("strong",{parentName:"li"},"Org-B claims securities in FSN ledger"),": ",(0,a.kt)("em",{parentName:"li"},"Org-B")," observes that the value of S has been revealed in the CBDC network by ",(0,a.kt)("em",{parentName:"li"},"Org-A")," in step 4, and submits a transaction to claim the securities in the FSN network using the revealed secret.")),(0,a.kt)("p",null,(0,a.kt)("img",{alt:"Simple DvP scenario in financial markets",src:r(8036).Z,width:"1479",height:"806"})))}h.isMDXComponent=!0},336:(e,t,r)=>{r.d(t,{Z:()=>n});const n=r.p+"assets/images/financial-markets-1-727232876fe39abb878c66140efba138.png"},8036:(e,t,r)=>{r.d(t,{Z:()=>n});const n=r.p+"assets/images/financial-markets-2-d97d5011d3bfd31f3efb142189c7902f.png"}}]); \ No newline at end of file +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[5730],{5680:(e,t,r)=>{r.d(t,{xA:()=>d,yg:()=>g});var n=r(6540);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function s(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var l=n.createContext({}),c=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},d=function(e){var t=c(e.components);return n.createElement(l.Provider,{value:t},e.children)},p="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,i=e.originalType,l=e.parentName,d=o(e,["components","mdxType","originalType","parentName"]),p=c(r),m=a,g=p["".concat(l,".").concat(m)]||p[m]||h[m]||i;return r?n.createElement(g,s(s({ref:t},d),{},{components:r})):n.createElement(g,s({ref:t},d))}));function g(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=r.length,s=new Array(i);s[0]=m;var o={};for(var l in t)hasOwnProperty.call(t,l)&&(o[l]=t[l]);o.originalType=e,o[p]="string"==typeof e?e:a,s[1]=o;for(var c=2;c{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>s,default:()=>h,frontMatter:()=>i,metadata:()=>o,toc:()=>c});var n=r(8168),a=(r(6540),r(5680));const i={id:"financial-markets",title:"DvP in Financial Markets"},s=void 0,o={unversionedId:"external/user-stories/financial-markets",id:"external/user-stories/financial-markets",title:"DvP in Financial Markets",description:"\x3c!--",source:"@site/docs/external/user-stories/financial-markets.md",sourceDirName:"external/user-stories",slug:"/external/user-stories/financial-markets",permalink:"/weaver-dlt-interoperability/docs/external/user-stories/financial-markets",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/user-stories/financial-markets.md",tags:[],version:"current",frontMatter:{id:"financial-markets",title:"DvP in Financial Markets"},sidebar:"Documentation",previous:{title:"Global Trade",permalink:"/weaver-dlt-interoperability/docs/external/user-stories/global-trade"},next:{title:"Legacy Integration",permalink:"/weaver-dlt-interoperability/docs/external/user-stories/legacy-integration"}},l={},c=[],d={toc:c},p="wrapper";function h(e){let{components:t,...i}=e;return(0,a.yg)(p,(0,n.A)({},d,i,{components:t,mdxType:"MDXLayout"}),(0,a.yg)("p",null,"In traditional financial markets parties trade assets such as securities and derivatives for cash or other assets. To reduce risk, various clearing and settlement processes and intermediaries are often involved. One form of settlement is a DvP (delivery versus payment) where the transfer of securities is performed only in the event of a corresponding payment. This arrangement reduces principal risk by ensuring that both parties receive their end of the exchange. However, settlement in financial markets are slow and time consuming. It also involves counterparty risks and requires intermediaries."),(0,a.yg)("p",null,"Over the past few years, we have been seeing significant efforts in digitising and tokenising both currencies and securities on Distributed Ledger Technology (DLT) infrastructures. On the one hand we have seen concerted efforts around Central Bank Digital Currencies (CBDC) being added to the landscape of other blockchain based payment networks. On the other hand, we have also seen efforts such as that from the Australian Stock Exchange (ASX) to replace its current settlement system--Clearing House Electronic Subregister System (CHESS) with a DLT based platform by 2021."),(0,a.yg)("p",null,"Against this backdrop, a number of central banks have been exploring the potential of performing DvP settlement across a currency ledger and a securities ledger. In this use case, we use this as a motivating use-case for our discussions. The scenario involves two decentralised ledgers, namely, a currency ledger and a securities ledger, based on different DLT protocols performing a coordinated transfer of assets in their respective ledgers."),(0,a.yg)("p",null,"The figure below depicts this scenario in the context of two organisations--",(0,a.yg)("em",{parentName:"p"},"Org-A")," and ",(0,a.yg)("em",{parentName:"p"},"Org-B"),". ",(0,a.yg)("em",{parentName:"p"},"Org-B")," wants to purchase some securities owned by ",(0,a.yg)("em",{parentName:"p"},"Org-A")," and both organisations have accounts on both ledgers. This scenario is simplified and leaves out a number of additional real world processes. For instance, the buyer and seller for securities need to discover each other and agree on the price and terms of a sale. In addition, an offer to sell securities might be fulfilled by multiple buyers taking smaller portions of the amount for sale. Such capabilities are often offered by centralised exchanges that offer capabilities such as order books and matching engines to address these needs. In this scenario we instead focus on the settlement process that follows such steps, once the parties of an exchange and the price of the exchange for an asset are determined."),(0,a.yg)("p",null,"To effect the settlement of this exchange between ",(0,a.yg)("em",{parentName:"p"},"Org-A")," and ",(0,a.yg)("em",{parentName:"p"},"Org-B"),", the following two transactions will have to happen atomically across both networks: i) transfer of payment from ",(0,a.yg)("em",{parentName:"p"},"Org-B"),"'s currency account in the CBDC ledger to ",(0,a.yg)("em",{parentName:"p"},"Org-A")," while at the same time ii) the entitlements of the designated securities are transferred from ",(0,a.yg)("em",{parentName:"p"},"Org-A")," to ",(0,a.yg)("em",{parentName:"p"},"Org-B"),". The scenario would need to guarantee that after the transaction execution, either both parties have their end of the exchange or neither does and that this exchange is performed in a timely manner."),(0,a.yg)("p",null,(0,a.yg)("img",{alt:"Simple DvP scenario in financial markets",src:r(556).A,width:"1356",height:"554"})),(0,a.yg)("p",null,"The settlement of the exchange of securities from ",(0,a.yg)("em",{parentName:"p"},"Org-A")," to ",(0,a.yg)("em",{parentName:"p"},"Org-B")," in the Financial Securities Network for a simultaneous payment from ",(0,a.yg)("em",{parentName:"p"},"Org-B")," to ",(0,a.yg)("em",{parentName:"p"},"Org-A")," in the CBDC network is coordinated by Weaver using ",(0,a.yg)("a",{parentName:"p",href:"https://en.bitcoin.it/wiki/Hash_Time_Locked_Contracts"},"Hashed Time Lock Contracts"),".\nThis protocol essentially has three phases:"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},"Fund locking: To initialise an asset exchange, it is common for one or both parties to first lock up funds with a fund-withholding party on his or her own blockchain. Temporary fund locking ensures the locked fund cannot be used for other purposes while the exchange is being executed. This scheme is often used with a specified timeout to provide flexibility for reclaiming locked funds if the exchange does not take place."),(0,a.yg)("li",{parentName:"ul"},"Fund redeeming: In general, the execution requires a pair of transactions to occur on both blockchains, e.g., from Org-A to Org-B on the FSN ledger and from Org-B to Org-A in CBDC ledger. When certain conditions are met, the locked funds can be redeemed by, or paid to the respective users. The execution of the exchange can be carried out by users themselves, or through other trusted third parties. These trusted third parties can be stand-alone parties that are not otherwise involved in both blockchains, or part of either blockchain.\xa0"),(0,a.yg)("li",{parentName:"ul"},"Refund: For protocols that are initialised with a temporary fund-locking, the locked funds can usually be reclaimed by the initial owner after a specified timeout, if a redemption has not occurred.\xa0")),(0,a.yg)("p",null,"The process proceeds as follows, and is further illustrated in the figure below:"),(0,a.yg)("ol",null,(0,a.yg)("li",{parentName:"ol"},(0,a.yg)("strong",{parentName:"li"},"Org-A locks its securities in FSN ledger"),": ",(0,a.yg)("em",{parentName:"li"},"Org-A")," first creates some secret S, known only to it and locks its securities using the hash of S. The securities are configured to redeemable by ",(0,a.yg)("em",{parentName:"li"},"Org-B")," if it presents S within some specified time threshold."),(0,a.yg)("li",{parentName:"ol"},(0,a.yg)("strong",{parentName:"li"},"Org-B locks payments tokens in CBDC ledger"),": Org-B, observes that ",(0,a.yg)("em",{parentName:"li"},"Org-A")," has locked its securities in the FSN network and does a corresponding lock of its payment tokens with the hash of S, used by ",(0,a.yg)("em",{parentName:"li"},"Org-A")," in locking its securities. The payment tokens are redeemable only by Org-A, if it submits a transaction that reveals S within a specified time."),(0,a.yg)("li",{parentName:"ol"},(0,a.yg)("strong",{parentName:"li"},"Org-A checks Org-B's contract in CBDC ledger"),": ",(0,a.yg)("em",{parentName:"li"},"Org-A")," checks the CBDC network to ensure that the payments tokens are locked by Org-B."),(0,a.yg)("li",{parentName:"ol"},(0,a.yg)("strong",{parentName:"li"},"Org-A claims payments in CBDC ledger"),": ",(0,a.yg)("em",{parentName:"li"},"Org-A")," submits a transaction to claim the payments tokens, by revealing the secret S."),(0,a.yg)("li",{parentName:"ol"},(0,a.yg)("strong",{parentName:"li"},"Org-B claims securities in FSN ledger"),": ",(0,a.yg)("em",{parentName:"li"},"Org-B")," observes that the value of S has been revealed in the CBDC network by ",(0,a.yg)("em",{parentName:"li"},"Org-A")," in step 4, and submits a transaction to claim the securities in the FSN network using the revealed secret.")),(0,a.yg)("p",null,(0,a.yg)("img",{alt:"Simple DvP scenario in financial markets",src:r(8135).A,width:"1479",height:"806"})))}h.isMDXComponent=!0},556:(e,t,r)=>{r.d(t,{A:()=>n});const n=r.p+"assets/images/financial-markets-1-727232876fe39abb878c66140efba138.png"},8135:(e,t,r)=>{r.d(t,{A:()=>n});const n=r.p+"assets/images/financial-markets-2-d97d5011d3bfd31f3efb142189c7902f.png"}}]); \ No newline at end of file diff --git a/assets/js/13886346.66fd0c0d.js b/assets/js/13886346.66fd0c0d.js new file mode 100644 index 000000000..a0b9db0a9 --- /dev/null +++ b/assets/js/13886346.66fd0c0d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[4568],{5680:(e,r,n)=>{n.d(r,{xA:()=>c,yg:()=>b});var t=n(6540);function a(e,r,n){return r in e?Object.defineProperty(e,r,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[r]=n,e}function i(e,r){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var t=Object.getOwnPropertySymbols(e);r&&(t=t.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),n.push.apply(n,t)}return n}function o(e){for(var r=1;r=0||(a[n]=e[n]);return a}(e,r);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(t=0;t=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var p=t.createContext({}),s=function(e){var r=t.useContext(p),n=r;return e&&(n="function"==typeof e?e(r):o(o({},r),e)),n},c=function(e){var r=s(e.components);return t.createElement(p.Provider,{value:r},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var r=e.children;return t.createElement(t.Fragment,{},r)}},y=t.forwardRef((function(e,r){var n=e.components,a=e.mdxType,i=e.originalType,p=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),d=s(n),y=a,b=d["".concat(p,".").concat(y)]||d[y]||u[y]||i;return n?t.createElement(b,o(o({ref:r},c),{},{components:n})):t.createElement(b,o({ref:r},c))}));function b(e,r){var n=arguments,a=r&&r.mdxType;if("string"==typeof e||a){var i=n.length,o=new Array(i);o[0]=y;var l={};for(var p in r)hasOwnProperty.call(r,p)&&(l[p]=r[p]);l.originalType=e,l[d]="string"==typeof e?e:a,o[1]=l;for(var s=2;s{n.r(r),n.d(r,{assets:()=>p,contentTitle:()=>o,default:()=>u,frontMatter:()=>i,metadata:()=>l,toc:()=>s});var t=n(8168),a=(n(6540),n(5680));const i={id:"publications",title:"Publications"},o=void 0,l={unversionedId:"external/publications",id:"external/publications",title:"Publications",description:"\x3c!--",source:"@site/docs/external/publications.md",sourceDirName:"external",slug:"/external/publications",permalink:"/weaver-dlt-interoperability/docs/external/publications",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/publications.md",tags:[],version:"current",frontMatter:{id:"publications",title:"Publications"},sidebar:"Documentation",previous:{title:"Roadmap",permalink:"/weaver-dlt-interoperability/docs/external/roadmap"}},p={},s=[{value:"2021",id:"2021",level:2},{value:"Verifiable Observation of Permissioned Ledgers",id:"verifiable-observation-of-permissioned-ledgers",level:3},{value:"Decentralized Cross-Network Identity Management for Blockchain Interoperation",id:"decentralized-cross-network-identity-management-for-blockchain-interoperation",level:3},{value:"2019",id:"2019",level:2},{value:"Enabling Enterprise Blockchain Interoperability with Trusted Data Transfer",id:"enabling-enterprise-blockchain-interoperability-with-trusted-data-transfer",level:3},{value:"On the Interoperability of Distributed Ledgers, Medium",id:"on-the-interoperability-of-distributed-ledgers-medium",level:3}],c={toc:s},d="wrapper";function u(e){let{components:r,...n}=e;return(0,a.yg)(d,(0,t.A)({},c,n,{components:r,mdxType:"MDXLayout"}),(0,a.yg)("h2",{id:"2021"},"2021"),(0,a.yg)("h3",{id:"verifiable-observation-of-permissioned-ledgers"},"Verifiable Observation of Permissioned Ledgers"),(0,a.yg)("p",null,(0,a.yg)("em",{parentName:"p"},"IEEE International Conference on Blockchain and Cryptocurrency"),", 2021"),(0,a.yg)("p",null,"Ermyas Abebe, Yining Hu, Allison Irvin, Dileban Karunamoorthy, Vinayaka Pandit, Venkatraman Ramakrishna, Jiangshan Yu"),(0,a.yg)("p",null,(0,a.yg)("a",{parentName:"p",href:"https://arxiv.org/abs/2012.07339"},(0,a.yg)("inlineCode",{parentName:"a"},"[arXiv]"))),(0,a.yg)("h3",{id:"decentralized-cross-network-identity-management-for-blockchain-interoperation"},"Decentralized Cross-Network Identity Management for Blockchain Interoperation"),(0,a.yg)("p",null,(0,a.yg)("em",{parentName:"p"},"IEEE International Conference on Blockchain and Cryptocurrency"),", 2021"),(0,a.yg)("p",null,"Bishakh Chandra Ghosh, Sandip Chakraborty, Venkatraman Ramakrishna, Chander Govindarajan,Dushyant Behl, Dileban Karunamoorthy, Ermyas Abebe"),(0,a.yg)("p",null,(0,a.yg)("a",{parentName:"p",href:"https://arxiv.org/abs/2104.03277"},(0,a.yg)("inlineCode",{parentName:"a"},"[arXiv]"))),(0,a.yg)("h2",{id:"2019"},"2019"),(0,a.yg)("h3",{id:"enabling-enterprise-blockchain-interoperability-with-trusted-data-transfer"},"Enabling Enterprise Blockchain Interoperability with Trusted Data Transfer"),(0,a.yg)("p",null,(0,a.yg)("em",{parentName:"p"},"Proceedings of the 20th International Middleware Conference Industrial Track"),", 2019"),(0,a.yg)("p",null,"Ermyas Abebe, Dushyant Behl, Chander Govindarajan, Yining Hu, Dileban Karunamoorthy, Petr Novotny, Vinayaka Pandit, Venkatraman Ramakrishna, Christian Vecchiola"),(0,a.yg)("p",null,(0,a.yg)("a",{parentName:"p",href:"https://dl.acm.org/doi/abs/10.1145/3366626.3368129"},(0,a.yg)("inlineCode",{parentName:"a"},"[Proceedings]"))," ",(0,a.yg)("a",{parentName:"p",href:"https://arxiv.org/abs/1911.01064"},(0,a.yg)("inlineCode",{parentName:"a"},"[arXiv]"))),(0,a.yg)("h3",{id:"on-the-interoperability-of-distributed-ledgers-medium"},"On the Interoperability of Distributed Ledgers, Medium"),(0,a.yg)("p",null,"Dileban Karunamoorthy, Ermyas Abebe"),(0,a.yg)("p",null,(0,a.yg)("a",{parentName:"p",href:"https://medium.com/thinkdecentralized/on-the-interoperability-of-distributed-ledgers-15f584b79808"},(0,a.yg)("inlineCode",{parentName:"a"},"[Medium]"))))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/13886346.894568f7.js b/assets/js/13886346.894568f7.js deleted file mode 100644 index b4c34092a..000000000 --- a/assets/js/13886346.894568f7.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[231],{3905:(e,t,r)=>{r.d(t,{Zo:()=>c,kt:()=>m});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function o(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var p=n.createContext({}),s=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},c=function(e){var t=s(e.components);return n.createElement(p.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},b=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,i=e.originalType,p=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),d=s(r),b=a,m=d["".concat(p,".").concat(b)]||d[b]||u[b]||i;return r?n.createElement(m,o(o({ref:t},c),{},{components:r})):n.createElement(m,o({ref:t},c))}));function m(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=r.length,o=new Array(i);o[0]=b;var l={};for(var p in t)hasOwnProperty.call(t,p)&&(l[p]=t[p]);l.originalType=e,l[d]="string"==typeof e?e:a,o[1]=l;for(var s=2;s{r.r(t),r.d(t,{assets:()=>p,contentTitle:()=>o,default:()=>u,frontMatter:()=>i,metadata:()=>l,toc:()=>s});var n=r(7462),a=(r(7294),r(3905));const i={id:"publications",title:"Publications"},o=void 0,l={unversionedId:"external/publications",id:"external/publications",title:"Publications",description:"\x3c!--",source:"@site/docs/external/publications.md",sourceDirName:"external",slug:"/external/publications",permalink:"/weaver-dlt-interoperability/docs/external/publications",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/publications.md",tags:[],version:"current",frontMatter:{id:"publications",title:"Publications"},sidebar:"Documentation",previous:{title:"Roadmap",permalink:"/weaver-dlt-interoperability/docs/external/roadmap"}},p={},s=[{value:"2021",id:"2021",level:2},{value:"Verifiable Observation of Permissioned Ledgers",id:"verifiable-observation-of-permissioned-ledgers",level:3},{value:"Decentralized Cross-Network Identity Management for Blockchain Interoperation",id:"decentralized-cross-network-identity-management-for-blockchain-interoperation",level:3},{value:"2019",id:"2019",level:2},{value:"Enabling Enterprise Blockchain Interoperability with Trusted Data Transfer",id:"enabling-enterprise-blockchain-interoperability-with-trusted-data-transfer",level:3},{value:"On the Interoperability of Distributed Ledgers, Medium",id:"on-the-interoperability-of-distributed-ledgers-medium",level:3}],c={toc:s},d="wrapper";function u(e){let{components:t,...r}=e;return(0,a.kt)(d,(0,n.Z)({},c,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h2",{id:"2021"},"2021"),(0,a.kt)("h3",{id:"verifiable-observation-of-permissioned-ledgers"},"Verifiable Observation of Permissioned Ledgers"),(0,a.kt)("p",null,(0,a.kt)("em",{parentName:"p"},"IEEE International Conference on Blockchain and Cryptocurrency"),", 2021"),(0,a.kt)("p",null,"Ermyas Abebe, Yining Hu, Allison Irvin, Dileban Karunamoorthy, Vinayaka Pandit, Venkatraman Ramakrishna, Jiangshan Yu"),(0,a.kt)("p",null,(0,a.kt)("a",{parentName:"p",href:"https://arxiv.org/abs/2012.07339"},(0,a.kt)("inlineCode",{parentName:"a"},"[arXiv]"))),(0,a.kt)("h3",{id:"decentralized-cross-network-identity-management-for-blockchain-interoperation"},"Decentralized Cross-Network Identity Management for Blockchain Interoperation"),(0,a.kt)("p",null,(0,a.kt)("em",{parentName:"p"},"IEEE International Conference on Blockchain and Cryptocurrency"),", 2021"),(0,a.kt)("p",null,"Bishakh Chandra Ghosh, Sandip Chakraborty, Venkatraman Ramakrishna, Chander Govindarajan,Dushyant Behl, Dileban Karunamoorthy, Ermyas Abebe"),(0,a.kt)("p",null,(0,a.kt)("a",{parentName:"p",href:"https://arxiv.org/abs/2104.03277"},(0,a.kt)("inlineCode",{parentName:"a"},"[arXiv]"))),(0,a.kt)("h2",{id:"2019"},"2019"),(0,a.kt)("h3",{id:"enabling-enterprise-blockchain-interoperability-with-trusted-data-transfer"},"Enabling Enterprise Blockchain Interoperability with Trusted Data Transfer"),(0,a.kt)("p",null,(0,a.kt)("em",{parentName:"p"},"Proceedings of the 20th International Middleware Conference Industrial Track"),", 2019"),(0,a.kt)("p",null,"Ermyas Abebe, Dushyant Behl, Chander Govindarajan, Yining Hu, Dileban Karunamoorthy, Petr Novotny, Vinayaka Pandit, Venkatraman Ramakrishna, Christian Vecchiola"),(0,a.kt)("p",null,(0,a.kt)("a",{parentName:"p",href:"https://dl.acm.org/doi/abs/10.1145/3366626.3368129"},(0,a.kt)("inlineCode",{parentName:"a"},"[Proceedings]"))," ",(0,a.kt)("a",{parentName:"p",href:"https://arxiv.org/abs/1911.01064"},(0,a.kt)("inlineCode",{parentName:"a"},"[arXiv]"))),(0,a.kt)("h3",{id:"on-the-interoperability-of-distributed-ledgers-medium"},"On the Interoperability of Distributed Ledgers, Medium"),(0,a.kt)("p",null,"Dileban Karunamoorthy, Ermyas Abebe"),(0,a.kt)("p",null,(0,a.kt)("a",{parentName:"p",href:"https://medium.com/thinkdecentralized/on-the-interoperability-of-distributed-ledgers-15f584b79808"},(0,a.kt)("inlineCode",{parentName:"a"},"[Medium]"))))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/15bfa0c2.76426347.js b/assets/js/15bfa0c2.76426347.js deleted file mode 100644 index 1b1786a47..000000000 --- a/assets/js/15bfa0c2.76426347.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[350],{3905:(e,r,t)=>{t.d(r,{Zo:()=>c,kt:()=>m});var n=t(7294);function o(e,r,t){return r in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function a(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);r&&(n=n.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),t.push.apply(t,n)}return t}function s(e){for(var r=1;r=0||(o[t]=e[t]);return o}(e,r);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var l=n.createContext({}),p=function(e){var r=n.useContext(l),t=r;return e&&(t="function"==typeof e?e(r):s(s({},r),e)),t},c=function(e){var r=p(e.components);return n.createElement(l.Provider,{value:r},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var r=e.children;return n.createElement(n.Fragment,{},r)}},f=n.forwardRef((function(e,r){var t=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,c=i(e,["components","mdxType","originalType","parentName"]),u=p(t),f=o,m=u["".concat(l,".").concat(f)]||u[f]||d[f]||a;return t?n.createElement(m,s(s({ref:r},c),{},{components:t})):n.createElement(m,s({ref:r},c))}));function m(e,r){var t=arguments,o=r&&r.mdxType;if("string"==typeof e||o){var a=t.length,s=new Array(a);s[0]=f;var i={};for(var l in r)hasOwnProperty.call(r,l)&&(i[l]=r[l]);i.originalType=e,i[u]="string"==typeof e?e:o,s[1]=i;for(var p=2;p{t.r(r),t.d(r,{assets:()=>l,contentTitle:()=>s,default:()=>d,frontMatter:()=>a,metadata:()=>i,toc:()=>p});var n=t(7462),o=(t(7294),t(3905));const a={},s=void 0,i={unversionedId:"internal/development/cordapp-interop/cordapp-interop-rest-api",id:"internal/development/cordapp-interop/cordapp-interop-rest-api",title:"cordapp-interop-rest-api",description:"\x3c!--",source:"@site/docs/internal/development/cordapp-interop/cordapp-interop-rest-api.md",sourceDirName:"internal/development/cordapp-interop",slug:"/internal/development/cordapp-interop/cordapp-interop-rest-api",permalink:"/weaver-dlt-interoperability/docs/internal/development/cordapp-interop/cordapp-interop-rest-api",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/internal/development/cordapp-interop/cordapp-interop-rest-api.md",tags:[],version:"current",frontMatter:{}},l={},p=[],c={toc:p},u="wrapper";function d(e){let{components:r,...t}=e;return(0,o.kt)(u,(0,n.Z)({},c,t,{components:r,mdxType:"MDXLayout"}),(0,o.kt)("hr",null),(0,o.kt)("p",null,"id: cordapp-interop-rest-api\ntitle: REST API"),(0,o.kt)("hr",null),(0,o.kt)("p",null,"Documentation of the REST API that is intended to be called from the MarcoPolo CordApp with the underlying\nflows noted."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"GET networkMapSnapshot\nreq: {}\nres: List, or failure\ncalls: proxy.networkMapSnapshot\n\nGET registeredFlows\nreq: {}\nres: List, or failure\ncalls: proxy.registeredFlows\n\nGET foreignNetworkInfos\nreq: {}\nres: List, or failure\ncalls: QueryForeignNetworkInformationManagementStates\n\nGET foreignNetworkInfos/{id}\nreq: {}\nres: ForeignNetworkInformationManagementState, or failure\ncalls: QueryForeignNetworkInformationManagementStatesById\n\nPOST foreignNetworkInfos\nreq: FNIMStateRequest\nres: FNIMStateResponse, or failure\ncalls: FNIMInitiator\n\nDELETE foreignNetworkInfos/{id}\nreq: {}\nres: id, or failure\ncalls: FNIMExitInitiator\n\nGET accessControlRequests\nreq: {}\nres: AccessControlIssueRequestStateResponse, or failure\ncalls: QueryAccessControlIssueRequestStateByLinearId\n\nPOST accessControlRequests/new\nreq: AccessControlIssueRequestStateRequest\nres: AccessControlIssueRequestStateResponse, or failure\ncalls: AccessControlIssueRequestInitiator\n\nPOST /accessControlRequests/approve/{id}\nreq: id\nres: AccessControlIssueRequestStateResponse, or failure\ncalls: AccessControlIssueRequestApprover\n\nGET accessControlStates\nreq: {}\nres: List, or failure\ncalls: QueryAccessControlStates\n\nGET accessControlStates/{id}\nreq: {}\nres: AccessControlStateResponse, or failure\ncalls: QueryAccessControlIssueRequestStateByLinearId\n\nPOST externalNetworkRequest\nreq: ExternalNetworkRequest\nres: LinearIdResponseObject, or failure\ncalls: StateQueryInitiator\n\nPOST externalNetworkRequestByTxId\nreq: ExternalNetworkRequestWithTxId\nres: TxIdResponseObject, or failure\ncalls: GetLinearIdsFromTxId\n\nGET getNetworkMap/{id}\nreq: {}\nres: NetworkMapObject, or failure\ncalls: proxy.networkMapSnapshot\n\nPOST requestExternalState\nreq: ExternalStateRequest\nres: UniqueIdentifier, or failure\ncalls: WriteExternalStateInitiator\n\nGET storeFNIM\nreq: {}\nres: ForeignNetworkMapInformationIntermediateResponse, or failure\ncalls: QueryForeignNetworkInformationManagementStateByNetworkId\n")))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/15db90ce.85b54811.js b/assets/js/15db90ce.85b54811.js new file mode 100644 index 000000000..b01e6a78d --- /dev/null +++ b/assets/js/15db90ce.85b54811.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[7088],{5680:(e,n,t)=>{t.d(n,{xA:()=>p,yg:()=>y});var a=t(6540);function i(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function r(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function o(e){for(var n=1;n=0||(i[t]=e[t]);return i}(e,n);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(i[t]=e[t])}return i}var s=a.createContext({}),c=function(e){var n=a.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):o(o({},n),e)),t},p=function(e){var n=c(e.components);return a.createElement(s.Provider,{value:n},e.children)},d="mdxType",g={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},m=a.forwardRef((function(e,n){var t=e.components,i=e.mdxType,r=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),d=c(t),m=i,y=d["".concat(s,".").concat(m)]||d[m]||g[m]||r;return t?a.createElement(y,o(o({ref:n},p),{},{components:t})):a.createElement(y,o({ref:n},p))}));function y(e,n){var t=arguments,i=n&&n.mdxType;if("string"==typeof e||i){var r=t.length,o=new Array(r);o[0]=m;var l={};for(var s in n)hasOwnProperty.call(n,s)&&(l[s]=n[s]);l.originalType=e,l[d]="string"==typeof e?e:i,o[1]=l;for(var c=2;c{t.r(n),t.d(n,{assets:()=>s,contentTitle:()=>o,default:()=>g,frontMatter:()=>r,metadata:()=>l,toc:()=>c});var a=t(8168),i=(t(6540),t(5680));const r={id:"corda-besu",title:"Asset Exchange: Corda with Besu",sidebar_label:"Corda with Besu",pagination_label:"Corda with Besu",pagination_prev:"external/getting-started/interop/asset-exchange/overview"},o=void 0,l={unversionedId:"external/getting-started/interop/asset-exchange/corda-besu",id:"external/getting-started/interop/asset-exchange/corda-besu",title:"Asset Exchange: Corda with Besu",description:"We will demonstrate asset exchange of an AliceERC721 NFT in Besu network1 with 10 tokens on Corda_Network.",source:"@site/docs/external/getting-started/interop/asset-exchange/corda-besu.md",sourceDirName:"external/getting-started/interop/asset-exchange",slug:"/external/getting-started/interop/asset-exchange/corda-besu",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/corda-besu",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/getting-started/interop/asset-exchange/corda-besu.md",tags:[],version:"current",frontMatter:{id:"corda-besu",title:"Asset Exchange: Corda with Besu",sidebar_label:"Corda with Besu",pagination_label:"Corda with Besu",pagination_prev:"external/getting-started/interop/asset-exchange/overview"},sidebar:"Documentation",previous:{title:"Asset Exchange",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview"},next:{title:"Besu with Besu",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/besu-besu"}},s={},c=[],p={toc:c},d="wrapper";function g(e){let{components:n,...t}=e;return(0,i.yg)(d,(0,a.A)({},p,t,{components:n,mdxType:"MDXLayout"}),(0,i.yg)("p",null,"We will demonstrate asset exchange of an ",(0,i.yg)("inlineCode",{parentName:"p"},"AliceERC721")," NFT in Besu ",(0,i.yg)("inlineCode",{parentName:"p"},"network1")," with ",(0,i.yg)("inlineCode",{parentName:"p"},"10")," tokens on ",(0,i.yg)("inlineCode",{parentName:"p"},"Corda_Network"),".\nFor Besu commands, run from ",(0,i.yg)("inlineCode",{parentName:"p"},"samples/besu/besu-cli")," folder, and for Corda commands, run from ",(0,i.yg)("inlineCode",{parentName:"p"},"samples/corda/corda-simple-application")," folder. Here ",(0,i.yg)("inlineCode",{parentName:"p"},"Alice")," with account ",(0,i.yg)("inlineCode",{parentName:"p"},"1")," and ",(0,i.yg)("inlineCode",{parentName:"p"},"Bob")," with account ",(0,i.yg)("inlineCode",{parentName:"p"},"2")," in Besu ",(0,i.yg)("inlineCode",{parentName:"p"},"network1")," correspond to ",(0,i.yg)("inlineCode",{parentName:"p"},"PartyA")," (",(0,i.yg)("inlineCode",{parentName:"p"},"CORDA_PORT=10006"),") and ",(0,i.yg)("inlineCode",{parentName:"p"},"PartyB")," (",(0,i.yg)("inlineCode",{parentName:"p"},"CORDA_PORT=10009"),") in ",(0,i.yg)("inlineCode",{parentName:"p"},"Corda_Network")," respectively. Following are the step-by-step asset exchange process:"),(0,i.yg)("ol",null,(0,i.yg)("li",{parentName:"ol"},"From corda client, generate secret-hash pair using following command (prints hash in base64):",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre"},"./clients/build/install/clients/bin/clients utils hash --hash-fn=SHA256 -s secrettext\n"))),(0,i.yg)("li",{parentName:"ol"},"Run the following to verify the status of the tokens owned by ",(0,i.yg)("inlineCode",{parentName:"li"},"PartyA")," and ",(0,i.yg)("inlineCode",{parentName:"li"},"PartyB")," in the ",(0,i.yg)("inlineCode",{parentName:"li"},"Corda_Network")," and ",(0,i.yg)("inlineCode",{parentName:"li"},"Corda_Network2"),":",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./scripts/getAssetStatus.sh 2\n"))),(0,i.yg)("li",{parentName:"ol"},"Run the following in ",(0,i.yg)("inlineCode",{parentName:"li"},"besu-cli"),", to verify the status of the assets owned by ",(0,i.yg)("inlineCode",{parentName:"li"},"Alice")," and ",(0,i.yg)("inlineCode",{parentName:"li"},"Bob")," in the Besu networks:",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset get-balance --network=network1 --account=1\n./bin/besu-cli asset get-balance --network=network1 --account=2\n"))),(0,i.yg)("li",{parentName:"ol"},"Complete the asset exchange using following steps:")),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},"Run the following to trigger ",(0,i.yg)("inlineCode",{parentName:"li"},"alice")," locking ",(0,i.yg)("inlineCode",{parentName:"li"},"AliceERC721")," token with id ",(0,i.yg)("inlineCode",{parentName:"li"},"0")," for ",(0,i.yg)("inlineCode",{parentName:"li"},"bob")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"network1")," for 1 hour",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset lock --network=network1 --sender_account=1 --recipient_account=2 --token_id=0 --asset_type=ERC721 --timeout=3600 --hash_base64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs=\n")),"Note the ",(0,i.yg)("inlineCode",{parentName:"li"},"contract-id")," printed as output in above command. The output line containing ",(0,i.yg)("inlineCode",{parentName:"li"},"contract-id")," (text in base64 after ",(0,i.yg)("inlineCode",{parentName:"li"},"Lock contract ID:"),") would like this:",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"Lock contract ID: 48f59da2ac632117bf79b4aa986f5ece8a2439dc143d576965c17bc8275b0925\n"))),(0,i.yg)("li",{parentName:"ul"},"Run the following to verify ",(0,i.yg)("inlineCode",{parentName:"li"},"alice"),"'s lock, replacing ",(0,i.yg)("inlineCode",{parentName:"li"},"")," with actual ",(0,i.yg)("inlineCode",{parentName:"li"},"contract-id"),":",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset is-locked --network=network1 --lock_contract_id=\n"))),(0,i.yg)("li",{parentName:"ul"},"Run the following to trigger ",(0,i.yg)("inlineCode",{parentName:"li"},"PartyB")," locking ",(0,i.yg)("inlineCode",{parentName:"li"},"50")," units of token type ",(0,i.yg)("inlineCode",{parentName:"li"},"t1")," for ",(0,i.yg)("inlineCode",{parentName:"li"},"PartyA")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"Corda_Network")," for 30 mins:",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},'CORDA_PORT=10009 ./clients/build/install/clients/bin/clients lock-asset --fungible --hashBase64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs= --timeout=1800 --recipient="O=PartyA,L=London,C=GB" --param=t1:50\n')),"Note the ",(0,i.yg)("inlineCode",{parentName:"li"},"contract-id")," displayed after successful execution of the command, will be used in next steps. The output containing ",(0,i.yg)("inlineCode",{parentName:"li"},"contract-id")," would like this:",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"HTLC Lock State created with contract ID Right(b=10448674_80d2bee7-5a5d-45df-b14e-60bac4ba1bf3).\n")),(0,i.yg)("inlineCode",{parentName:"li"},"contract-id")," is the alphanumeric text (with underscore and hyphens) after ",(0,i.yg)("inlineCode",{parentName:"li"},"b=")," within parenthesis. Let's refer it ",(0,i.yg)("inlineCode",{parentName:"li"},"")," for this demonstration."),(0,i.yg)("li",{parentName:"ul"},"Run the following to verify ",(0,i.yg)("inlineCode",{parentName:"li"},"PartyB"),"'s lock (can be verified by both parties):",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"CORDA_PORT=10006 ./clients/build/install/clients/bin/clients is-asset-locked --contract-id=\n"))),(0,i.yg)("li",{parentName:"ul"},"Run the following to trigger ",(0,i.yg)("inlineCode",{parentName:"li"},"PartyA"),"'s claim for ",(0,i.yg)("inlineCode",{parentName:"li"},"50")," units of token type ",(0,i.yg)("inlineCode",{parentName:"li"},"t1")," locked by ",(0,i.yg)("inlineCode",{parentName:"li"},"PartyB")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"Corda_Network"),":",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"CORDA_PORT=10006 ./clients/build/install/clients/bin/clients claim-asset --secret=secrettext --contract-id=\n")),(0,i.yg)("inlineCode",{parentName:"li"},"PartyB")," can see its node's logs to get the revealed hash preimage, and use it to claim in the Besu network."),(0,i.yg)("li",{parentName:"ul"},"Run the following to trigger ",(0,i.yg)("inlineCode",{parentName:"li"},"bob"),"'s claim for ",(0,i.yg)("inlineCode",{parentName:"li"},"AliceERC721")," NFT with id ",(0,i.yg)("inlineCode",{parentName:"li"},"0")," locked by ",(0,i.yg)("inlineCode",{parentName:"li"},"alice")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"network1"),":",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset claim --network=network1 --recipient_account=2 --preimage=secrettext --token_id=0 --lock_contract_id=\n")),"The above steps complete a successful asset exchange between two Besu networks.\nIn addition to the above commands, following commands can be run if specified timeout has expired and the locked asset remains unclaimed."),(0,i.yg)("li",{parentName:"ul"},"If ",(0,i.yg)("inlineCode",{parentName:"li"},"alice")," wants to unlock the asset, run the following to trigger ",(0,i.yg)("inlineCode",{parentName:"li"},"alice"),"'s re-claim for ",(0,i.yg)("inlineCode",{parentName:"li"},"AliceERC721")," NFT with id ",(0,i.yg)("inlineCode",{parentName:"li"},"0")," locked in ",(0,i.yg)("inlineCode",{parentName:"li"},"network1"),":",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset unlock --network=network1 --lock_contract_id= --sender_account=1 --token_id=0\n"))),(0,i.yg)("li",{parentName:"ul"},"If ",(0,i.yg)("inlineCode",{parentName:"li"},"PartyB")," wants to unlock the token asset, run the following to trigger unlock for ",(0,i.yg)("inlineCode",{parentName:"li"},"t1:50")," locked in ",(0,i.yg)("inlineCode",{parentName:"li"},"Corda_Network"),":",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"CORDA_PORT=10009 ./clients/build/install/clients/bin/clients unlock-asset --contract-id=\n")))),(0,i.yg)("ol",{start:5},(0,i.yg)("li",{parentName:"ol"},"Run the following to verify the status of the tokens owned by ",(0,i.yg)("inlineCode",{parentName:"li"},"PartyA")," and ",(0,i.yg)("inlineCode",{parentName:"li"},"PartyB")," in the ",(0,i.yg)("inlineCode",{parentName:"li"},"Corda_Network")," and ",(0,i.yg)("inlineCode",{parentName:"li"},"Corda_Network2"),":",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./scripts/getAssetStatus.sh 2\n"))),(0,i.yg)("li",{parentName:"ol"},"Run the following in ",(0,i.yg)("inlineCode",{parentName:"li"},"besu-cli"),", to verify the status of the assets owned by ",(0,i.yg)("inlineCode",{parentName:"li"},"Alice")," and ",(0,i.yg)("inlineCode",{parentName:"li"},"Bob")," in the Besu networks:",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset get-balance --network=network1 --account=1\n./bin/besu-cli asset get-balance --network=network1 --account=2\n")))))}g.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/15db90ce.e1099e01.js b/assets/js/15db90ce.e1099e01.js deleted file mode 100644 index 030cfa73f..000000000 --- a/assets/js/15db90ce.e1099e01.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[8039],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>u});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=a.createContext({}),c=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=c(e.components);return a.createElement(s.Provider,{value:t},e.children)},d="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},k=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,r=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),d=c(n),k=i,u=d["".concat(s,".").concat(k)]||d[k]||m[k]||r;return n?a.createElement(u,o(o({ref:t},p),{},{components:n})):a.createElement(u,o({ref:t},p))}));function u(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=n.length,o=new Array(r);o[0]=k;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[d]="string"==typeof e?e:i,o[1]=l;for(var c=2;c{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>m,frontMatter:()=>r,metadata:()=>l,toc:()=>c});var a=n(7462),i=(n(7294),n(3905));const r={id:"corda-besu",title:"Asset Exchange: Corda with Besu",sidebar_label:"Corda with Besu",pagination_label:"Corda with Besu",pagination_prev:"external/getting-started/interop/asset-exchange/overview"},o=void 0,l={unversionedId:"external/getting-started/interop/asset-exchange/corda-besu",id:"external/getting-started/interop/asset-exchange/corda-besu",title:"Asset Exchange: Corda with Besu",description:"We will demonstrate asset exchange of an AliceERC721 NFT in Besu network1 with 10 tokens on Corda_Network.",source:"@site/docs/external/getting-started/interop/asset-exchange/corda-besu.md",sourceDirName:"external/getting-started/interop/asset-exchange",slug:"/external/getting-started/interop/asset-exchange/corda-besu",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/corda-besu",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/getting-started/interop/asset-exchange/corda-besu.md",tags:[],version:"current",frontMatter:{id:"corda-besu",title:"Asset Exchange: Corda with Besu",sidebar_label:"Corda with Besu",pagination_label:"Corda with Besu",pagination_prev:"external/getting-started/interop/asset-exchange/overview"},sidebar:"Documentation",previous:{title:"Asset Exchange",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview"},next:{title:"Besu with Besu",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/besu-besu"}},s={},c=[],p={toc:c},d="wrapper";function m(e){let{components:t,...n}=e;return(0,i.kt)(d,(0,a.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"We will demonstrate asset exchange of an ",(0,i.kt)("inlineCode",{parentName:"p"},"AliceERC721")," NFT in Besu ",(0,i.kt)("inlineCode",{parentName:"p"},"network1")," with ",(0,i.kt)("inlineCode",{parentName:"p"},"10")," tokens on ",(0,i.kt)("inlineCode",{parentName:"p"},"Corda_Network"),".\nFor Besu commands, run from ",(0,i.kt)("inlineCode",{parentName:"p"},"samples/besu/besu-cli")," folder, and for Corda commands, run from ",(0,i.kt)("inlineCode",{parentName:"p"},"samples/corda/corda-simple-application")," folder. Here ",(0,i.kt)("inlineCode",{parentName:"p"},"Alice")," with account ",(0,i.kt)("inlineCode",{parentName:"p"},"1")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"Bob")," with account ",(0,i.kt)("inlineCode",{parentName:"p"},"2")," in Besu ",(0,i.kt)("inlineCode",{parentName:"p"},"network1")," correspond to ",(0,i.kt)("inlineCode",{parentName:"p"},"PartyA")," (",(0,i.kt)("inlineCode",{parentName:"p"},"CORDA_PORT=10006"),") and ",(0,i.kt)("inlineCode",{parentName:"p"},"PartyB")," (",(0,i.kt)("inlineCode",{parentName:"p"},"CORDA_PORT=10009"),") in ",(0,i.kt)("inlineCode",{parentName:"p"},"Corda_Network")," respectively. Following are the step-by-step asset exchange process:"),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},"From corda client, generate secret-hash pair using following command (prints hash in base64):",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre"},"./clients/build/install/clients/bin/clients utils hash --hash-fn=SHA256 -s secrettext\n"))),(0,i.kt)("li",{parentName:"ol"},"Run the following to verify the status of the tokens owned by ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyA")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyB")," in the ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network2"),":",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./scripts/getAssetStatus.sh 2\n"))),(0,i.kt)("li",{parentName:"ol"},"Run the following in ",(0,i.kt)("inlineCode",{parentName:"li"},"besu-cli"),", to verify the status of the assets owned by ",(0,i.kt)("inlineCode",{parentName:"li"},"Alice")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"Bob")," in the Besu networks:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset get-balance --network=network1 --account=1\n./bin/besu-cli asset get-balance --network=network1 --account=2\n"))),(0,i.kt)("li",{parentName:"ol"},"Complete the asset exchange using following steps:")),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Run the following to trigger ",(0,i.kt)("inlineCode",{parentName:"li"},"alice")," locking ",(0,i.kt)("inlineCode",{parentName:"li"},"AliceERC721")," token with id ",(0,i.kt)("inlineCode",{parentName:"li"},"0")," for ",(0,i.kt)("inlineCode",{parentName:"li"},"bob")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"network1")," for 1 hour",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset lock --network=network1 --sender_account=1 --recipient_account=2 --token_id=0 --asset_type=ERC721 --timeout=3600 --hash_base64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs=\n")),"Note the ",(0,i.kt)("inlineCode",{parentName:"li"},"contract-id")," printed as output in above command. The output line containing ",(0,i.kt)("inlineCode",{parentName:"li"},"contract-id")," (text in base64 after ",(0,i.kt)("inlineCode",{parentName:"li"},"Lock contract ID:"),") would like this:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"Lock contract ID: 48f59da2ac632117bf79b4aa986f5ece8a2439dc143d576965c17bc8275b0925\n"))),(0,i.kt)("li",{parentName:"ul"},"Run the following to verify ",(0,i.kt)("inlineCode",{parentName:"li"},"alice"),"'s lock, replacing ",(0,i.kt)("inlineCode",{parentName:"li"},"")," with actual ",(0,i.kt)("inlineCode",{parentName:"li"},"contract-id"),":",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset is-locked --network=network1 --lock_contract_id=\n"))),(0,i.kt)("li",{parentName:"ul"},"Run the following to trigger ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyB")," locking ",(0,i.kt)("inlineCode",{parentName:"li"},"50")," units of token type ",(0,i.kt)("inlineCode",{parentName:"li"},"t1")," for ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyA")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network")," for 30 mins:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},'CORDA_PORT=10009 ./clients/build/install/clients/bin/clients lock-asset --fungible --hashBase64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs= --timeout=1800 --recipient="O=PartyA,L=London,C=GB" --param=t1:50\n')),"Note the ",(0,i.kt)("inlineCode",{parentName:"li"},"contract-id")," displayed after successful execution of the command, will be used in next steps. The output containing ",(0,i.kt)("inlineCode",{parentName:"li"},"contract-id")," would like this:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"HTLC Lock State created with contract ID Right(b=10448674_80d2bee7-5a5d-45df-b14e-60bac4ba1bf3).\n")),(0,i.kt)("inlineCode",{parentName:"li"},"contract-id")," is the alphanumeric text (with underscore and hyphens) after ",(0,i.kt)("inlineCode",{parentName:"li"},"b=")," within parenthesis. Let's refer it ",(0,i.kt)("inlineCode",{parentName:"li"},"")," for this demonstration."),(0,i.kt)("li",{parentName:"ul"},"Run the following to verify ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyB"),"'s lock (can be verified by both parties):",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"CORDA_PORT=10006 ./clients/build/install/clients/bin/clients is-asset-locked --contract-id=\n"))),(0,i.kt)("li",{parentName:"ul"},"Run the following to trigger ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyA"),"'s claim for ",(0,i.kt)("inlineCode",{parentName:"li"},"50")," units of token type ",(0,i.kt)("inlineCode",{parentName:"li"},"t1")," locked by ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyB")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network"),":",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"CORDA_PORT=10006 ./clients/build/install/clients/bin/clients claim-asset --secret=secrettext --contract-id=\n")),(0,i.kt)("inlineCode",{parentName:"li"},"PartyB")," can see its node's logs to get the revealed hash preimage, and use it to claim in the Besu network."),(0,i.kt)("li",{parentName:"ul"},"Run the following to trigger ",(0,i.kt)("inlineCode",{parentName:"li"},"bob"),"'s claim for ",(0,i.kt)("inlineCode",{parentName:"li"},"AliceERC721")," NFT with id ",(0,i.kt)("inlineCode",{parentName:"li"},"0")," locked by ",(0,i.kt)("inlineCode",{parentName:"li"},"alice")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"network1"),":",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset claim --network=network1 --recipient_account=2 --preimage=secrettext --token_id=0 --lock_contract_id=\n")),"The above steps complete a successful asset exchange between two Besu networks.\nIn addition to the above commands, following commands can be run if specified timeout has expired and the locked asset remains unclaimed."),(0,i.kt)("li",{parentName:"ul"},"If ",(0,i.kt)("inlineCode",{parentName:"li"},"alice")," wants to unlock the asset, run the following to trigger ",(0,i.kt)("inlineCode",{parentName:"li"},"alice"),"'s re-claim for ",(0,i.kt)("inlineCode",{parentName:"li"},"AliceERC721")," NFT with id ",(0,i.kt)("inlineCode",{parentName:"li"},"0")," locked in ",(0,i.kt)("inlineCode",{parentName:"li"},"network1"),":",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset unlock --network=network1 --lock_contract_id= --sender_account=1 --token_id=0\n"))),(0,i.kt)("li",{parentName:"ul"},"If ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyB")," wants to unlock the token asset, run the following to trigger unlock for ",(0,i.kt)("inlineCode",{parentName:"li"},"t1:50")," locked in ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network"),":",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"CORDA_PORT=10009 ./clients/build/install/clients/bin/clients unlock-asset --contract-id=\n")))),(0,i.kt)("ol",{start:5},(0,i.kt)("li",{parentName:"ol"},"Run the following to verify the status of the tokens owned by ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyA")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyB")," in the ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network2"),":",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./scripts/getAssetStatus.sh 2\n"))),(0,i.kt)("li",{parentName:"ol"},"Run the following in ",(0,i.kt)("inlineCode",{parentName:"li"},"besu-cli"),", to verify the status of the assets owned by ",(0,i.kt)("inlineCode",{parentName:"li"},"Alice")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"Bob")," in the Besu networks:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset get-balance --network=network1 --account=1\n./bin/besu-cli asset get-balance --network=network1 --account=2\n")))))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/1774.7d4a2879.js b/assets/js/1774.7d4a2879.js new file mode 100644 index 000000000..3086c4101 --- /dev/null +++ b/assets/js/1774.7d4a2879.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[1774],{1774:(e,t,a)=>{a.r(t),a.d(t,{default:()=>i});var n=a(6540),l=a(1312),r=a(1003),o=a(5713);function i(){return n.createElement(n.Fragment,null,n.createElement(r.be,{title:(0,l.T)({id:"theme.NotFound.title",message:"Page Not Found"})}),n.createElement(o.A,null,n.createElement("main",{className:"container margin-vert--xl"},n.createElement("div",{className:"row"},n.createElement("div",{className:"col col--6 col--offset-3"},n.createElement("h1",{className:"hero__title"},n.createElement(l.A,{id:"theme.NotFound.title",description:"The title of the 404 page"},"Page Not Found")),n.createElement("p",null,n.createElement(l.A,{id:"theme.NotFound.p1",description:"The first paragraph of the 404 page"},"We could not find what you were looking for.")),n.createElement("p",null,n.createElement(l.A,{id:"theme.NotFound.p2",description:"The 2nd paragraph of the 404 page"},"Please contact the owner of the site that linked you to the original URL and let them know their link is broken.")))))))}}}]); \ No newline at end of file diff --git a/assets/js/17896441.5f598f0f.js b/assets/js/17896441.5f598f0f.js deleted file mode 100644 index 29da96981..000000000 --- a/assets/js/17896441.5f598f0f.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[7918],{9055:(e,t,n)=>{n.r(t),n.d(t,{default:()=>ce});var a=n(7294),l=n(1944),o=n(902);const r=a.createContext(null);function s(e){let{children:t,content:n}=e;const l=function(e){return(0,a.useMemo)((()=>({metadata:e.metadata,frontMatter:e.frontMatter,assets:e.assets,contentTitle:e.contentTitle,toc:e.toc})),[e])}(n);return a.createElement(r.Provider,{value:l},t)}function c(){const e=(0,a.useContext)(r);if(null===e)throw new o.i6("DocProvider");return e}function i(){const{metadata:e,frontMatter:t,assets:n}=c();return a.createElement(l.d,{title:e.title,description:e.description,keywords:t.keywords,image:n.image??t.image})}var d=n(6010),m=n(7524),u=n(7462),v=n(5999),b=n(2244);function p(e){const{previous:t,next:n}=e;return a.createElement("nav",{className:"pagination-nav docusaurus-mt-lg","aria-label":(0,v.I)({id:"theme.docs.paginator.navAriaLabel",message:"Docs pages navigation",description:"The ARIA label for the docs pagination"})},t&&a.createElement(b.Z,(0,u.Z)({},t,{subLabel:a.createElement(v.Z,{id:"theme.docs.paginator.previous",description:"The label used to navigate to the previous doc"},"Previous")})),n&&a.createElement(b.Z,(0,u.Z)({},n,{subLabel:a.createElement(v.Z,{id:"theme.docs.paginator.next",description:"The label used to navigate to the next doc"},"Next"),isNext:!0})))}function h(){const{metadata:e}=c();return a.createElement(p,{previous:e.previous,next:e.next})}var f=n(2263),E=n(9960),g=n(143),L=n(5281),C=n(373),N=n(4477);const _={unreleased:function(e){let{siteTitle:t,versionMetadata:n}=e;return a.createElement(v.Z,{id:"theme.docs.versions.unreleasedVersionLabel",description:"The label used to tell the user that he's browsing an unreleased doc version",values:{siteTitle:t,versionLabel:a.createElement("b",null,n.label)}},"This is unreleased documentation for {siteTitle} {versionLabel} version.")},unmaintained:function(e){let{siteTitle:t,versionMetadata:n}=e;return a.createElement(v.Z,{id:"theme.docs.versions.unmaintainedVersionLabel",description:"The label used to tell the user that he's browsing an unmaintained doc version",values:{siteTitle:t,versionLabel:a.createElement("b",null,n.label)}},"This is documentation for {siteTitle} {versionLabel}, which is no longer actively maintained.")}};function k(e){const t=_[e.versionMetadata.banner];return a.createElement(t,e)}function Z(e){let{versionLabel:t,to:n,onClick:l}=e;return a.createElement(v.Z,{id:"theme.docs.versions.latestVersionSuggestionLabel",description:"The label used to tell the user to check the latest version",values:{versionLabel:t,latestVersionLink:a.createElement("b",null,a.createElement(E.Z,{to:n,onClick:l},a.createElement(v.Z,{id:"theme.docs.versions.latestVersionLinkLabel",description:"The label used for the latest version suggestion link label"},"latest version")))}},"For up-to-date documentation, see the {latestVersionLink} ({versionLabel}).")}function x(e){let{className:t,versionMetadata:n}=e;const{siteConfig:{title:l}}=(0,f.Z)(),{pluginId:o}=(0,g.gA)({failfast:!0}),{savePreferredVersionName:r}=(0,C.J)(o),{latestDocSuggestion:s,latestVersionSuggestion:c}=(0,g.Jo)(o),i=s??(m=c).docs.find((e=>e.id===m.mainDocId));var m;return a.createElement("div",{className:(0,d.Z)(t,L.k.docs.docVersionBanner,"alert alert--warning margin-bottom--md"),role:"alert"},a.createElement("div",null,a.createElement(k,{siteTitle:l,versionMetadata:n})),a.createElement("div",{className:"margin-top--md"},a.createElement(Z,{versionLabel:c.label,to:i.path,onClick:()=>r(c.name)})))}function T(e){let{className:t}=e;const n=(0,N.E)();return n.banner?a.createElement(x,{className:t,versionMetadata:n}):null}function H(e){let{className:t}=e;const n=(0,N.E)();return n.badge?a.createElement("span",{className:(0,d.Z)(t,L.k.docs.docVersionBadge,"badge badge--secondary")},a.createElement(v.Z,{id:"theme.docs.versionBadge.label",values:{versionLabel:n.label}},"Version: {versionLabel}")):null}function U(e){let{lastUpdatedAt:t,formattedLastUpdatedAt:n}=e;return a.createElement(v.Z,{id:"theme.lastUpdated.atDate",description:"The words used to describe on which date a page has been last updated",values:{date:a.createElement("b",null,a.createElement("time",{dateTime:new Date(1e3*t).toISOString()},n))}}," on {date}")}function y(e){let{lastUpdatedBy:t}=e;return a.createElement(v.Z,{id:"theme.lastUpdated.byUser",description:"The words used to describe by who the page has been last updated",values:{user:a.createElement("b",null,t)}}," by {user}")}function w(e){let{lastUpdatedAt:t,formattedLastUpdatedAt:n,lastUpdatedBy:l}=e;return a.createElement("span",{className:L.k.common.lastUpdated},a.createElement(v.Z,{id:"theme.lastUpdated.lastUpdatedAtBy",description:"The sentence used to display when a page has been last updated, and by who",values:{atDate:t&&n?a.createElement(U,{lastUpdatedAt:t,formattedLastUpdatedAt:n}):"",byUser:l?a.createElement(y,{lastUpdatedBy:l}):""}},"Last updated{atDate}{byUser}"),!1)}var A=n(4881),I=n(6233);const M={lastUpdated:"lastUpdated_vwxv"};function B(e){return a.createElement("div",{className:(0,d.Z)(L.k.docs.docFooterTagsRow,"row margin-bottom--sm")},a.createElement("div",{className:"col"},a.createElement(I.Z,e)))}function O(e){let{editUrl:t,lastUpdatedAt:n,lastUpdatedBy:l,formattedLastUpdatedAt:o}=e;return a.createElement("div",{className:(0,d.Z)(L.k.docs.docFooterEditMetaRow,"row")},a.createElement("div",{className:"col"},t&&a.createElement(A.Z,{editUrl:t})),a.createElement("div",{className:(0,d.Z)("col",M.lastUpdated)},(n||l)&&a.createElement(w,{lastUpdatedAt:n,formattedLastUpdatedAt:o,lastUpdatedBy:l})))}function V(){const{metadata:e}=c(),{editUrl:t,lastUpdatedAt:n,formattedLastUpdatedAt:l,lastUpdatedBy:o,tags:r}=e,s=r.length>0,i=!!(t||n||o);return s||i?a.createElement("footer",{className:(0,d.Z)(L.k.docs.docFooter,"docusaurus-mt-lg")},s&&a.createElement(B,{tags:r}),i&&a.createElement(O,{editUrl:t,lastUpdatedAt:n,lastUpdatedBy:o,formattedLastUpdatedAt:l})):null}var P=n(6043),S=n(3743);const D={tocCollapsibleButton:"tocCollapsibleButton_TO0P",tocCollapsibleButtonExpanded:"tocCollapsibleButtonExpanded_MG3E"};function R(e){let{collapsed:t,...n}=e;return a.createElement("button",(0,u.Z)({type:"button"},n,{className:(0,d.Z)("clean-btn",D.tocCollapsibleButton,!t&&D.tocCollapsibleButtonExpanded,n.className)}),a.createElement(v.Z,{id:"theme.TOCCollapsible.toggleButtonLabel",description:"The label used by the button on the collapsible TOC component"},"On this page"))}const F={tocCollapsible:"tocCollapsible_ETCw",tocCollapsibleContent:"tocCollapsibleContent_vkbj",tocCollapsibleExpanded:"tocCollapsibleExpanded_sAul"};function z(e){let{toc:t,className:n,minHeadingLevel:l,maxHeadingLevel:o}=e;const{collapsed:r,toggleCollapsed:s}=(0,P.u)({initialState:!0});return a.createElement("div",{className:(0,d.Z)(F.tocCollapsible,!r&&F.tocCollapsibleExpanded,n)},a.createElement(R,{collapsed:r,onClick:s}),a.createElement(P.z,{lazy:!0,className:F.tocCollapsibleContent,collapsed:r},a.createElement(S.Z,{toc:t,minHeadingLevel:l,maxHeadingLevel:o})))}const q={tocMobile:"tocMobile_ITEo"};function j(){const{toc:e,frontMatter:t}=c();return a.createElement(z,{toc:e,minHeadingLevel:t.toc_min_heading_level,maxHeadingLevel:t.toc_max_heading_level,className:(0,d.Z)(L.k.docs.docTocMobile,q.tocMobile)})}var $=n(9407);function G(){const{toc:e,frontMatter:t}=c();return a.createElement($.Z,{toc:e,minHeadingLevel:t.toc_min_heading_level,maxHeadingLevel:t.toc_max_heading_level,className:L.k.docs.docTocDesktop})}var J=n(7955),K=n(210);function Q(e){let{children:t}=e;const n=function(){const{metadata:e,frontMatter:t,contentTitle:n}=c();return t.hide_title||void 0!==n?null:e.title}();return a.createElement("div",{className:(0,d.Z)(L.k.docs.docMarkdown,"markdown")},n&&a.createElement("header",null,a.createElement(J.Z,{as:"h1"},n)),a.createElement(K.Z,null,t))}var W=n(2802),X=n(8596),Y=n(4996);function ee(e){return a.createElement("svg",(0,u.Z)({viewBox:"0 0 24 24"},e),a.createElement("path",{d:"M10 19v-5h4v5c0 .55.45 1 1 1h3c.55 0 1-.45 1-1v-7h1.7c.46 0 .68-.57.33-.87L12.67 3.6c-.38-.34-.96-.34-1.34 0l-8.36 7.53c-.34.3-.13.87.33.87H5v7c0 .55.45 1 1 1h3c.55 0 1-.45 1-1z",fill:"currentColor"}))}const te={breadcrumbsContainer:"breadcrumbsContainer_Z_bl",breadcrumbHomeIcon:"breadcrumbHomeIcon_OVgt"};function ne(e){let{children:t,href:n,isLast:l}=e;const o="breadcrumbs__link";return l?a.createElement("span",{className:o,itemProp:"name"},t):n?a.createElement(E.Z,{className:o,href:n,itemProp:"item"},a.createElement("span",{itemProp:"name"},t)):a.createElement("span",{className:o},t)}function ae(e){let{children:t,active:n,index:l,addMicrodata:o}=e;return a.createElement("li",(0,u.Z)({},o&&{itemScope:!0,itemProp:"itemListElement",itemType:"https://schema.org/ListItem"},{className:(0,d.Z)("breadcrumbs__item",{"breadcrumbs__item--active":n})}),t,a.createElement("meta",{itemProp:"position",content:String(l+1)}))}function le(){const e=(0,Y.Z)("/");return a.createElement("li",{className:"breadcrumbs__item"},a.createElement(E.Z,{"aria-label":(0,v.I)({id:"theme.docs.breadcrumbs.home",message:"Home page",description:"The ARIA label for the home page in the breadcrumbs"}),className:(0,d.Z)("breadcrumbs__link",te.breadcrumbsItemLink),href:e},a.createElement(ee,{className:te.breadcrumbHomeIcon})))}function oe(){const e=(0,W.s1)(),t=(0,X.Ns)();return e?a.createElement("nav",{className:(0,d.Z)(L.k.docs.docBreadcrumbs,te.breadcrumbsContainer),"aria-label":(0,v.I)({id:"theme.docs.breadcrumbs.navAriaLabel",message:"Breadcrumbs",description:"The ARIA label for the breadcrumbs"})},a.createElement("ul",{className:"breadcrumbs",itemScope:!0,itemType:"https://schema.org/BreadcrumbList"},t&&a.createElement(le,null),e.map(((t,n)=>{const l=n===e.length-1;return a.createElement(ae,{key:n,active:l,index:n,addMicrodata:!!t.href},a.createElement(ne,{href:t.href,isLast:l},t.label))})))):null}const re={docItemContainer:"docItemContainer_Djhp",docItemCol:"docItemCol_VOVn"};function se(e){let{children:t}=e;const n=function(){const{frontMatter:e,toc:t}=c(),n=(0,m.i)(),l=e.hide_table_of_contents,o=!l&&t.length>0;return{hidden:l,mobile:o?a.createElement(j,null):void 0,desktop:!o||"desktop"!==n&&"ssr"!==n?void 0:a.createElement(G,null)}}();return a.createElement("div",{className:"row"},a.createElement("div",{className:(0,d.Z)("col",!n.hidden&&re.docItemCol)},a.createElement(T,null),a.createElement("div",{className:re.docItemContainer},a.createElement("article",null,a.createElement(oe,null),a.createElement(H,null),n.mobile,a.createElement(Q,null,t),a.createElement(V,null)),a.createElement(h,null))),n.desktop&&a.createElement("div",{className:"col col--3"},n.desktop))}function ce(e){const t=`docs-doc-id-${e.content.metadata.unversionedId}`,n=e.content;return a.createElement(s,{content:e.content},a.createElement(l.FG,{className:t},a.createElement(i,null),a.createElement(se,null,a.createElement(n,null))))}},9407:(e,t,n)=>{n.d(t,{Z:()=>d});var a=n(7462),l=n(7294),o=n(6010),r=n(3743);const s={tableOfContents:"tableOfContents_bqdL",docItemContainer:"docItemContainer_F8PC"},c="table-of-contents__link toc-highlight",i="table-of-contents__link--active";function d(e){let{className:t,...n}=e;return l.createElement("div",{className:(0,o.Z)(s.tableOfContents,"thin-scrollbar",t)},l.createElement(r.Z,(0,a.Z)({},n,{linkClassName:c,linkActiveClassName:i})))}},3743:(e,t,n)=>{n.d(t,{Z:()=>b});var a=n(7462),l=n(7294),o=n(6668);function r(e){const t=e.map((e=>({...e,parentIndex:-1,children:[]}))),n=Array(7).fill(-1);t.forEach(((e,t)=>{const a=n.slice(2,e.level);e.parentIndex=Math.max(...a),n[e.level]=t}));const a=[];return t.forEach((e=>{const{parentIndex:n,...l}=e;n>=0?t[n].children.push(l):a.push(l)})),a}function s(e){let{toc:t,minHeadingLevel:n,maxHeadingLevel:a}=e;return t.flatMap((e=>{const t=s({toc:e.children,minHeadingLevel:n,maxHeadingLevel:a});return function(e){return e.level>=n&&e.level<=a}(e)?[{...e,children:t}]:t}))}function c(e){const t=e.getBoundingClientRect();return t.top===t.bottom?c(e.parentNode):t}function i(e,t){let{anchorTopOffset:n}=t;const a=e.find((e=>c(e).top>=n));if(a){return function(e){return e.top>0&&e.bottom{e.current=t?0:document.querySelector(".navbar").clientHeight}),[t]),e}function m(e){const t=(0,l.useRef)(void 0),n=d();(0,l.useEffect)((()=>{if(!e)return()=>{};const{linkClassName:a,linkActiveClassName:l,minHeadingLevel:o,maxHeadingLevel:r}=e;function s(){const e=function(e){return Array.from(document.getElementsByClassName(e))}(a),s=function(e){let{minHeadingLevel:t,maxHeadingLevel:n}=e;const a=[];for(let l=t;l<=n;l+=1)a.push(`h${l}.anchor`);return Array.from(document.querySelectorAll(a.join()))}({minHeadingLevel:o,maxHeadingLevel:r}),c=i(s,{anchorTopOffset:n.current}),d=e.find((e=>c&&c.id===function(e){return decodeURIComponent(e.href.substring(e.href.indexOf("#")+1))}(e)));e.forEach((e=>{!function(e,n){n?(t.current&&t.current!==e&&t.current.classList.remove(l),e.classList.add(l),t.current=e):e.classList.remove(l)}(e,e===d)}))}return document.addEventListener("scroll",s),document.addEventListener("resize",s),s(),()=>{document.removeEventListener("scroll",s),document.removeEventListener("resize",s)}}),[e,n])}function u(e){let{toc:t,className:n,linkClassName:a,isChild:o}=e;return t.length?l.createElement("ul",{className:o?void 0:n},t.map((e=>l.createElement("li",{key:e.id},l.createElement("a",{href:`#${e.id}`,className:a??void 0,dangerouslySetInnerHTML:{__html:e.value}}),l.createElement(u,{isChild:!0,toc:e.children,className:n,linkClassName:a}))))):null}const v=l.memo(u);function b(e){let{toc:t,className:n="table-of-contents table-of-contents__left-border",linkClassName:c="table-of-contents__link",linkActiveClassName:i,minHeadingLevel:d,maxHeadingLevel:u,...b}=e;const p=(0,o.L)(),h=d??p.tableOfContents.minHeadingLevel,f=u??p.tableOfContents.maxHeadingLevel,E=function(e){let{toc:t,minHeadingLevel:n,maxHeadingLevel:a}=e;return(0,l.useMemo)((()=>s({toc:r(t),minHeadingLevel:n,maxHeadingLevel:a})),[t,n,a])}({toc:t,minHeadingLevel:h,maxHeadingLevel:f});return m((0,l.useMemo)((()=>{if(c&&i)return{linkClassName:c,linkActiveClassName:i,minHeadingLevel:h,maxHeadingLevel:f}}),[c,i,h,f])),l.createElement(v,(0,a.Z)({toc:E,className:n,linkClassName:c},b))}},4477:(e,t,n)=>{n.d(t,{E:()=>s,q:()=>r});var a=n(7294),l=n(902);const o=a.createContext(null);function r(e){let{children:t,version:n}=e;return a.createElement(o.Provider,{value:n},t)}function s(){const e=(0,a.useContext)(o);if(null===e)throw new l.i6("DocsVersionProvider");return e}}}]); \ No newline at end of file diff --git a/assets/js/17896441.790eadcd.js b/assets/js/17896441.790eadcd.js new file mode 100644 index 000000000..4bedcea20 --- /dev/null +++ b/assets/js/17896441.790eadcd.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[8401],{3597:(e,t,n)=>{n.r(t),n.d(t,{default:()=>ce});var a=n(6540),l=n(1003),r=n(9532);const o=a.createContext(null);function s(e){let{children:t,content:n}=e;const l=function(e){return(0,a.useMemo)((()=>({metadata:e.metadata,frontMatter:e.frontMatter,assets:e.assets,contentTitle:e.contentTitle,toc:e.toc})),[e])}(n);return a.createElement(o.Provider,{value:l},t)}function c(){const e=(0,a.useContext)(o);if(null===e)throw new r.dV("DocProvider");return e}function i(){const{metadata:e,frontMatter:t,assets:n}=c();return a.createElement(l.be,{title:e.title,description:e.description,keywords:t.keywords,image:n.image??t.image})}var d=n(53),m=n(4581),u=n(8168),v=n(1312),b=n(9022);function p(e){const{previous:t,next:n}=e;return a.createElement("nav",{className:"pagination-nav docusaurus-mt-lg","aria-label":(0,v.T)({id:"theme.docs.paginator.navAriaLabel",message:"Docs pages navigation",description:"The ARIA label for the docs pagination"})},t&&a.createElement(b.A,(0,u.A)({},t,{subLabel:a.createElement(v.A,{id:"theme.docs.paginator.previous",description:"The label used to navigate to the previous doc"},"Previous")})),n&&a.createElement(b.A,(0,u.A)({},n,{subLabel:a.createElement(v.A,{id:"theme.docs.paginator.next",description:"The label used to navigate to the next doc"},"Next"),isNext:!0})))}function h(){const{metadata:e}=c();return a.createElement(p,{previous:e.previous,next:e.next})}var f=n(4586),E=n(5489),g=n(4070),A=n(7559),L=n(5597),C=n(2252);const N={unreleased:function(e){let{siteTitle:t,versionMetadata:n}=e;return a.createElement(v.A,{id:"theme.docs.versions.unreleasedVersionLabel",description:"The label used to tell the user that he's browsing an unreleased doc version",values:{siteTitle:t,versionLabel:a.createElement("b",null,n.label)}},"This is unreleased documentation for {siteTitle} {versionLabel} version.")},unmaintained:function(e){let{siteTitle:t,versionMetadata:n}=e;return a.createElement(v.A,{id:"theme.docs.versions.unmaintainedVersionLabel",description:"The label used to tell the user that he's browsing an unmaintained doc version",values:{siteTitle:t,versionLabel:a.createElement("b",null,n.label)}},"This is documentation for {siteTitle} {versionLabel}, which is no longer actively maintained.")}};function _(e){const t=N[e.versionMetadata.banner];return a.createElement(t,e)}function x(e){let{versionLabel:t,to:n,onClick:l}=e;return a.createElement(v.A,{id:"theme.docs.versions.latestVersionSuggestionLabel",description:"The label used to tell the user to check the latest version",values:{versionLabel:t,latestVersionLink:a.createElement("b",null,a.createElement(E.A,{to:n,onClick:l},a.createElement(v.A,{id:"theme.docs.versions.latestVersionLinkLabel",description:"The label used for the latest version suggestion link label"},"latest version")))}},"For up-to-date documentation, see the {latestVersionLink} ({versionLabel}).")}function T(e){let{className:t,versionMetadata:n}=e;const{siteConfig:{title:l}}=(0,f.A)(),{pluginId:r}=(0,g.vT)({failfast:!0}),{savePreferredVersionName:o}=(0,L.g1)(r),{latestDocSuggestion:s,latestVersionSuggestion:c}=(0,g.HW)(r),i=s??(m=c).docs.find((e=>e.id===m.mainDocId));var m;return a.createElement("div",{className:(0,d.A)(t,A.G.docs.docVersionBanner,"alert alert--warning margin-bottom--md"),role:"alert"},a.createElement("div",null,a.createElement(_,{siteTitle:l,versionMetadata:n})),a.createElement("div",{className:"margin-top--md"},a.createElement(x,{versionLabel:c.label,to:i.path,onClick:()=>o(c.name)})))}function k(e){let{className:t}=e;const n=(0,C.r)();return n.banner?a.createElement(T,{className:t,versionMetadata:n}):null}function H(e){let{className:t}=e;const n=(0,C.r)();return n.badge?a.createElement("span",{className:(0,d.A)(t,A.G.docs.docVersionBadge,"badge badge--secondary")},a.createElement(v.A,{id:"theme.docs.versionBadge.label",values:{versionLabel:n.label}},"Version: {versionLabel}")):null}function U(e){let{lastUpdatedAt:t,formattedLastUpdatedAt:n}=e;return a.createElement(v.A,{id:"theme.lastUpdated.atDate",description:"The words used to describe on which date a page has been last updated",values:{date:a.createElement("b",null,a.createElement("time",{dateTime:new Date(1e3*t).toISOString()},n))}}," on {date}")}function y(e){let{lastUpdatedBy:t}=e;return a.createElement(v.A,{id:"theme.lastUpdated.byUser",description:"The words used to describe by who the page has been last updated",values:{user:a.createElement("b",null,t)}}," by {user}")}function w(e){let{lastUpdatedAt:t,formattedLastUpdatedAt:n,lastUpdatedBy:l}=e;return a.createElement("span",{className:A.G.common.lastUpdated},a.createElement(v.A,{id:"theme.lastUpdated.lastUpdatedAtBy",description:"The sentence used to display when a page has been last updated, and by who",values:{atDate:t&&n?a.createElement(U,{lastUpdatedAt:t,formattedLastUpdatedAt:n}):"",byUser:l?a.createElement(y,{lastUpdatedBy:l}):""}},"Last updated{atDate}{byUser}"),!1)}var M=n(1943),I=n(8046);const B={lastUpdated:"lastUpdated_vwxv"};function O(e){return a.createElement("div",{className:(0,d.A)(A.G.docs.docFooterTagsRow,"row margin-bottom--sm")},a.createElement("div",{className:"col"},a.createElement(I.A,e)))}function V(e){let{editUrl:t,lastUpdatedAt:n,lastUpdatedBy:l,formattedLastUpdatedAt:r}=e;return a.createElement("div",{className:(0,d.A)(A.G.docs.docFooterEditMetaRow,"row")},a.createElement("div",{className:"col"},t&&a.createElement(M.A,{editUrl:t})),a.createElement("div",{className:(0,d.A)("col",B.lastUpdated)},(n||l)&&a.createElement(w,{lastUpdatedAt:n,formattedLastUpdatedAt:r,lastUpdatedBy:l})))}function P(){const{metadata:e}=c(),{editUrl:t,lastUpdatedAt:n,formattedLastUpdatedAt:l,lastUpdatedBy:r,tags:o}=e,s=o.length>0,i=!!(t||n||r);return s||i?a.createElement("footer",{className:(0,d.A)(A.G.docs.docFooter,"docusaurus-mt-lg")},s&&a.createElement(O,{tags:o}),i&&a.createElement(V,{editUrl:t,lastUpdatedAt:n,lastUpdatedBy:r,formattedLastUpdatedAt:l})):null}var S=n(1422),D=n(5195);const G={tocCollapsibleButton:"tocCollapsibleButton_TO0P",tocCollapsibleButtonExpanded:"tocCollapsibleButtonExpanded_MG3E"};function R(e){let{collapsed:t,...n}=e;return a.createElement("button",(0,u.A)({type:"button"},n,{className:(0,d.A)("clean-btn",G.tocCollapsibleButton,!t&&G.tocCollapsibleButtonExpanded,n.className)}),a.createElement(v.A,{id:"theme.TOCCollapsible.toggleButtonLabel",description:"The label used by the button on the collapsible TOC component"},"On this page"))}const F={tocCollapsible:"tocCollapsible_ETCw",tocCollapsibleContent:"tocCollapsibleContent_vkbj",tocCollapsibleExpanded:"tocCollapsibleExpanded_sAul"};function z(e){let{toc:t,className:n,minHeadingLevel:l,maxHeadingLevel:r}=e;const{collapsed:o,toggleCollapsed:s}=(0,S.u)({initialState:!0});return a.createElement("div",{className:(0,d.A)(F.tocCollapsible,!o&&F.tocCollapsibleExpanded,n)},a.createElement(R,{collapsed:o,onClick:s}),a.createElement(S.N,{lazy:!0,className:F.tocCollapsibleContent,collapsed:o},a.createElement(D.A,{toc:t,minHeadingLevel:l,maxHeadingLevel:r})))}const j={tocMobile:"tocMobile_ITEo"};function q(){const{toc:e,frontMatter:t}=c();return a.createElement(z,{toc:e,minHeadingLevel:t.toc_min_heading_level,maxHeadingLevel:t.toc_max_heading_level,className:(0,d.A)(A.G.docs.docTocMobile,j.tocMobile)})}var $=n(7763);function W(){const{toc:e,frontMatter:t}=c();return a.createElement($.A,{toc:e,minHeadingLevel:t.toc_min_heading_level,maxHeadingLevel:t.toc_max_heading_level,className:A.G.docs.docTocDesktop})}var Z=n(1107),J=n(9717);function K(e){let{children:t}=e;const n=function(){const{metadata:e,frontMatter:t,contentTitle:n}=c();return t.hide_title||void 0!==n?null:e.title}();return a.createElement("div",{className:(0,d.A)(A.G.docs.docMarkdown,"markdown")},n&&a.createElement("header",null,a.createElement(Z.A,{as:"h1"},n)),a.createElement(J.A,null,t))}var Q=n(1754),X=n(9169),Y=n(6025);function ee(e){return a.createElement("svg",(0,u.A)({viewBox:"0 0 24 24"},e),a.createElement("path",{d:"M10 19v-5h4v5c0 .55.45 1 1 1h3c.55 0 1-.45 1-1v-7h1.7c.46 0 .68-.57.33-.87L12.67 3.6c-.38-.34-.96-.34-1.34 0l-8.36 7.53c-.34.3-.13.87.33.87H5v7c0 .55.45 1 1 1h3c.55 0 1-.45 1-1z",fill:"currentColor"}))}const te={breadcrumbsContainer:"breadcrumbsContainer_Z_bl",breadcrumbHomeIcon:"breadcrumbHomeIcon_OVgt"};function ne(e){let{children:t,href:n,isLast:l}=e;const r="breadcrumbs__link";return l?a.createElement("span",{className:r,itemProp:"name"},t):n?a.createElement(E.A,{className:r,href:n,itemProp:"item"},a.createElement("span",{itemProp:"name"},t)):a.createElement("span",{className:r},t)}function ae(e){let{children:t,active:n,index:l,addMicrodata:r}=e;return a.createElement("li",(0,u.A)({},r&&{itemScope:!0,itemProp:"itemListElement",itemType:"https://schema.org/ListItem"},{className:(0,d.A)("breadcrumbs__item",{"breadcrumbs__item--active":n})}),t,a.createElement("meta",{itemProp:"position",content:String(l+1)}))}function le(){const e=(0,Y.A)("/");return a.createElement("li",{className:"breadcrumbs__item"},a.createElement(E.A,{"aria-label":(0,v.T)({id:"theme.docs.breadcrumbs.home",message:"Home page",description:"The ARIA label for the home page in the breadcrumbs"}),className:(0,d.A)("breadcrumbs__link",te.breadcrumbsItemLink),href:e},a.createElement(ee,{className:te.breadcrumbHomeIcon})))}function re(){const e=(0,Q.OF)(),t=(0,X.Dt)();return e?a.createElement("nav",{className:(0,d.A)(A.G.docs.docBreadcrumbs,te.breadcrumbsContainer),"aria-label":(0,v.T)({id:"theme.docs.breadcrumbs.navAriaLabel",message:"Breadcrumbs",description:"The ARIA label for the breadcrumbs"})},a.createElement("ul",{className:"breadcrumbs",itemScope:!0,itemType:"https://schema.org/BreadcrumbList"},t&&a.createElement(le,null),e.map(((t,n)=>{const l=n===e.length-1;return a.createElement(ae,{key:n,active:l,index:n,addMicrodata:!!t.href},a.createElement(ne,{href:t.href,isLast:l},t.label))})))):null}const oe={docItemContainer:"docItemContainer_Djhp",docItemCol:"docItemCol_VOVn"};function se(e){let{children:t}=e;const n=function(){const{frontMatter:e,toc:t}=c(),n=(0,m.l)(),l=e.hide_table_of_contents,r=!l&&t.length>0;return{hidden:l,mobile:r?a.createElement(q,null):void 0,desktop:!r||"desktop"!==n&&"ssr"!==n?void 0:a.createElement(W,null)}}();return a.createElement("div",{className:"row"},a.createElement("div",{className:(0,d.A)("col",!n.hidden&&oe.docItemCol)},a.createElement(k,null),a.createElement("div",{className:oe.docItemContainer},a.createElement("article",null,a.createElement(re,null),a.createElement(H,null),n.mobile,a.createElement(K,null,t),a.createElement(P,null)),a.createElement(h,null))),n.desktop&&a.createElement("div",{className:"col col--3"},n.desktop))}function ce(e){const t=`docs-doc-id-${e.content.metadata.unversionedId}`,n=e.content;return a.createElement(s,{content:e.content},a.createElement(l.e3,{className:t},a.createElement(i,null),a.createElement(se,null,a.createElement(n,null))))}},7763:(e,t,n)=>{n.d(t,{A:()=>d});var a=n(8168),l=n(6540),r=n(53),o=n(5195);const s={tableOfContents:"tableOfContents_bqdL",docItemContainer:"docItemContainer_F8PC"},c="table-of-contents__link toc-highlight",i="table-of-contents__link--active";function d(e){let{className:t,...n}=e;return l.createElement("div",{className:(0,r.A)(s.tableOfContents,"thin-scrollbar",t)},l.createElement(o.A,(0,a.A)({},n,{linkClassName:c,linkActiveClassName:i})))}},5195:(e,t,n)=>{n.d(t,{A:()=>b});var a=n(8168),l=n(6540),r=n(6342);function o(e){const t=e.map((e=>({...e,parentIndex:-1,children:[]}))),n=Array(7).fill(-1);t.forEach(((e,t)=>{const a=n.slice(2,e.level);e.parentIndex=Math.max(...a),n[e.level]=t}));const a=[];return t.forEach((e=>{const{parentIndex:n,...l}=e;n>=0?t[n].children.push(l):a.push(l)})),a}function s(e){let{toc:t,minHeadingLevel:n,maxHeadingLevel:a}=e;return t.flatMap((e=>{const t=s({toc:e.children,minHeadingLevel:n,maxHeadingLevel:a});return function(e){return e.level>=n&&e.level<=a}(e)?[{...e,children:t}]:t}))}function c(e){const t=e.getBoundingClientRect();return t.top===t.bottom?c(e.parentNode):t}function i(e,t){let{anchorTopOffset:n}=t;const a=e.find((e=>c(e).top>=n));if(a){return function(e){return e.top>0&&e.bottom{e.current=t?0:document.querySelector(".navbar").clientHeight}),[t]),e}function m(e){const t=(0,l.useRef)(void 0),n=d();(0,l.useEffect)((()=>{if(!e)return()=>{};const{linkClassName:a,linkActiveClassName:l,minHeadingLevel:r,maxHeadingLevel:o}=e;function s(){const e=function(e){return Array.from(document.getElementsByClassName(e))}(a),s=function(e){let{minHeadingLevel:t,maxHeadingLevel:n}=e;const a=[];for(let l=t;l<=n;l+=1)a.push(`h${l}.anchor`);return Array.from(document.querySelectorAll(a.join()))}({minHeadingLevel:r,maxHeadingLevel:o}),c=i(s,{anchorTopOffset:n.current}),d=e.find((e=>c&&c.id===function(e){return decodeURIComponent(e.href.substring(e.href.indexOf("#")+1))}(e)));e.forEach((e=>{!function(e,n){n?(t.current&&t.current!==e&&t.current.classList.remove(l),e.classList.add(l),t.current=e):e.classList.remove(l)}(e,e===d)}))}return document.addEventListener("scroll",s),document.addEventListener("resize",s),s(),()=>{document.removeEventListener("scroll",s),document.removeEventListener("resize",s)}}),[e,n])}function u(e){let{toc:t,className:n,linkClassName:a,isChild:r}=e;return t.length?l.createElement("ul",{className:r?void 0:n},t.map((e=>l.createElement("li",{key:e.id},l.createElement("a",{href:`#${e.id}`,className:a??void 0,dangerouslySetInnerHTML:{__html:e.value}}),l.createElement(u,{isChild:!0,toc:e.children,className:n,linkClassName:a}))))):null}const v=l.memo(u);function b(e){let{toc:t,className:n="table-of-contents table-of-contents__left-border",linkClassName:c="table-of-contents__link",linkActiveClassName:i,minHeadingLevel:d,maxHeadingLevel:u,...b}=e;const p=(0,r.p)(),h=d??p.tableOfContents.minHeadingLevel,f=u??p.tableOfContents.maxHeadingLevel,E=function(e){let{toc:t,minHeadingLevel:n,maxHeadingLevel:a}=e;return(0,l.useMemo)((()=>s({toc:o(t),minHeadingLevel:n,maxHeadingLevel:a})),[t,n,a])}({toc:t,minHeadingLevel:h,maxHeadingLevel:f});return m((0,l.useMemo)((()=>{if(c&&i)return{linkClassName:c,linkActiveClassName:i,minHeadingLevel:h,maxHeadingLevel:f}}),[c,i,h,f])),l.createElement(v,(0,a.A)({toc:E,className:n,linkClassName:c},b))}},2252:(e,t,n)=>{n.d(t,{n:()=>o,r:()=>s});var a=n(6540),l=n(9532);const r=a.createContext(null);function o(e){let{children:t,version:n}=e;return a.createElement(r.Provider,{value:n},t)}function s(){const e=(0,a.useContext)(r);if(null===e)throw new l.dV("DocsVersionProvider");return e}}}]); \ No newline at end of file diff --git a/assets/js/1be78505.e390b67c.js b/assets/js/1be78505.e390b67c.js deleted file mode 100644 index 316a893f3..000000000 --- a/assets/js/1be78505.e390b67c.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[9514,4972],{9963:(e,t,n)=>{n.r(t),n.d(t,{default:()=>fe});var a=n(7294),l=n(6010),o=n(1944),r=n(5281),c=n(3320),i=n(2802),s=n(4477),d=n(1116),m=n(3285),u=n(5999),b=n(2466),p=n(5936);const h={backToTopButton:"backToTopButton_sjWU",backToTopButtonShow:"backToTopButtonShow_xfvO"};function E(){const{shown:e,scrollToTop:t}=function(e){let{threshold:t}=e;const[n,l]=(0,a.useState)(!1),o=(0,a.useRef)(!1),{startScroll:r,cancelScroll:c}=(0,b.Ct)();return(0,b.RF)(((e,n)=>{let{scrollY:a}=e;const r=n?.scrollY;r&&(o.current?o.current=!1:a>=r?(c(),l(!1)):a{e.location.hash&&(o.current=!0,l(!1))})),{shown:n,scrollToTop:()=>r(0)}}({threshold:300});return a.createElement("button",{"aria-label":(0,u.I)({id:"theme.BackToTopButton.buttonAriaLabel",message:"Scroll back to top",description:"The ARIA label for the back to top button"}),className:(0,l.Z)("clean-btn",r.k.common.backToTopButton,h.backToTopButton,e&&h.backToTopButtonShow),type:"button",onClick:t})}var f=n(6550),g=n(7524),v=n(6668),k=n(1327),_=n(7462);function C(e){return a.createElement("svg",(0,_.Z)({width:"20",height:"20","aria-hidden":"true"},e),a.createElement("g",{fill:"#7a7a7a"},a.createElement("path",{d:"M9.992 10.023c0 .2-.062.399-.172.547l-4.996 7.492a.982.982 0 01-.828.454H1c-.55 0-1-.453-1-1 0-.2.059-.403.168-.551l4.629-6.942L.168 3.078A.939.939 0 010 2.528c0-.548.45-.997 1-.997h2.996c.352 0 .649.18.828.45L9.82 9.472c.11.148.172.347.172.55zm0 0"}),a.createElement("path",{d:"M19.98 10.023c0 .2-.058.399-.168.547l-4.996 7.492a.987.987 0 01-.828.454h-3c-.547 0-.996-.453-.996-1 0-.2.059-.403.168-.551l4.625-6.942-4.625-6.945a.939.939 0 01-.168-.55 1 1 0 01.996-.997h3c.348 0 .649.18.828.45l4.996 7.492c.11.148.168.347.168.55zm0 0"})))}const S={collapseSidebarButton:"collapseSidebarButton_PEFL",collapseSidebarButtonIcon:"collapseSidebarButtonIcon_kv0_"};function I(e){let{onClick:t}=e;return a.createElement("button",{type:"button",title:(0,u.I)({id:"theme.docs.sidebar.collapseButtonTitle",message:"Collapse sidebar",description:"The title attribute for collapse button of doc sidebar"}),"aria-label":(0,u.I)({id:"theme.docs.sidebar.collapseButtonAriaLabel",message:"Collapse sidebar",description:"The title attribute for collapse button of doc sidebar"}),className:(0,l.Z)("button button--secondary button--outline",S.collapseSidebarButton),onClick:t},a.createElement(C,{className:S.collapseSidebarButtonIcon}))}var N=n(9689),T=n(902);const x=Symbol("EmptyContext"),Z=a.createContext(x);function B(e){let{children:t}=e;const[n,l]=(0,a.useState)(null),o=(0,a.useMemo)((()=>({expandedItem:n,setExpandedItem:l})),[n]);return a.createElement(Z.Provider,{value:o},t)}var y=n(6043),w=n(8596),L=n(9960),A=n(2389);function M(e){let{categoryLabel:t,onClick:n}=e;return a.createElement("button",{"aria-label":(0,u.I)({id:"theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel",message:"Toggle the collapsible sidebar category '{label}'",description:"The ARIA label to toggle the collapsible sidebar category"},{label:t}),type:"button",className:"clean-btn menu__caret",onClick:n})}function F(e){let{item:t,onItemClick:n,activePath:o,level:c,index:s,...d}=e;const{items:m,label:u,collapsible:b,className:p,href:h}=t,{docs:{sidebar:{autoCollapseCategories:E}}}=(0,v.L)(),f=function(e){const t=(0,A.Z)();return(0,a.useMemo)((()=>e.href?e.href:!t&&e.collapsible?(0,i.Wl)(e):void 0),[e,t])}(t),g=(0,i._F)(t,o),k=(0,w.Mg)(h,o),{collapsed:C,setCollapsed:S}=(0,y.u)({initialState:()=>!!b&&(!g&&t.collapsed)}),{expandedItem:I,setExpandedItem:N}=function(){const e=(0,a.useContext)(Z);if(e===x)throw new T.i6("DocSidebarItemsExpandedStateProvider");return e}(),B=function(e){void 0===e&&(e=!C),N(e?null:s),S(e)};return function(e){let{isActive:t,collapsed:n,updateCollapsed:l}=e;const o=(0,T.D9)(t);(0,a.useEffect)((()=>{t&&!o&&n&&l(!1)}),[t,o,n,l])}({isActive:g,collapsed:C,updateCollapsed:B}),(0,a.useEffect)((()=>{b&&null!=I&&I!==s&&E&&S(!0)}),[b,I,s,S,E]),a.createElement("li",{className:(0,l.Z)(r.k.docs.docSidebarItemCategory,r.k.docs.docSidebarItemCategoryLevel(c),"menu__list-item",{"menu__list-item--collapsed":C},p)},a.createElement("div",{className:(0,l.Z)("menu__list-item-collapsible",{"menu__list-item-collapsible--active":k})},a.createElement(L.Z,(0,_.Z)({className:(0,l.Z)("menu__link",{"menu__link--sublist":b,"menu__link--sublist-caret":!h&&b,"menu__link--active":g}),onClick:b?e=>{n?.(t),h?B(!1):(e.preventDefault(),B())}:()=>{n?.(t)},"aria-current":k?"page":void 0,"aria-expanded":b?!C:void 0,href:b?f??"#":f},d),u),h&&b&&a.createElement(M,{categoryLabel:u,onClick:e=>{e.preventDefault(),B()}})),a.createElement(y.z,{lazy:!0,as:"ul",className:"menu__list",collapsed:C},a.createElement(K,{items:m,tabIndex:C?-1:0,onItemClick:n,activePath:o,level:c+1})))}var H=n(3919),P=n(9471);const W={menuExternalLink:"menuExternalLink_NmtK"};function D(e){let{item:t,onItemClick:n,activePath:o,level:c,index:s,...d}=e;const{href:m,label:u,className:b,autoAddBaseUrl:p}=t,h=(0,i._F)(t,o),E=(0,H.Z)(m);return a.createElement("li",{className:(0,l.Z)(r.k.docs.docSidebarItemLink,r.k.docs.docSidebarItemLinkLevel(c),"menu__list-item",b),key:u},a.createElement(L.Z,(0,_.Z)({className:(0,l.Z)("menu__link",!E&&W.menuExternalLink,{"menu__link--active":h}),autoAddBaseUrl:p,"aria-current":h?"page":void 0,to:m},E&&{onClick:n?()=>n(t):void 0},d),u,!E&&a.createElement(P.Z,null)))}const R={menuHtmlItem:"menuHtmlItem_M9Kj"};function z(e){let{item:t,level:n,index:o}=e;const{value:c,defaultStyle:i,className:s}=t;return a.createElement("li",{className:(0,l.Z)(r.k.docs.docSidebarItemLink,r.k.docs.docSidebarItemLinkLevel(n),i&&[R.menuHtmlItem,"menu__list-item"],s),key:o,dangerouslySetInnerHTML:{__html:c}})}function U(e){let{item:t,...n}=e;switch(t.type){case"category":return a.createElement(F,(0,_.Z)({item:t},n));case"html":return a.createElement(z,(0,_.Z)({item:t},n));default:return a.createElement(D,(0,_.Z)({item:t},n))}}function V(e){let{items:t,...n}=e;return a.createElement(B,null,t.map(((e,t)=>a.createElement(U,(0,_.Z)({key:t,item:e,index:t},n)))))}const K=(0,a.memo)(V),j={menu:"menu_SIkG",menuWithAnnouncementBar:"menuWithAnnouncementBar_GW3s"};function q(e){let{path:t,sidebar:n,className:o}=e;const c=function(){const{isActive:e}=(0,N.nT)(),[t,n]=(0,a.useState)(e);return(0,b.RF)((t=>{let{scrollY:a}=t;e&&n(0===a)}),[e]),e&&t}();return a.createElement("nav",{className:(0,l.Z)("menu thin-scrollbar",j.menu,c&&j.menuWithAnnouncementBar,o)},a.createElement("ul",{className:(0,l.Z)(r.k.docs.docSidebarMenu,"menu__list")},a.createElement(K,{items:n,activePath:t,level:1})))}const G="sidebar_njMd",Y="sidebarWithHideableNavbar_wUlq",O="sidebarHidden_VK0M",X="sidebarLogo_isFc";function J(e){let{path:t,sidebar:n,onCollapse:o,isHidden:r}=e;const{navbar:{hideOnScroll:c},docs:{sidebar:{hideable:i}}}=(0,v.L)();return a.createElement("div",{className:(0,l.Z)(G,c&&Y,r&&O)},c&&a.createElement(k.Z,{tabIndex:-1,className:X}),a.createElement(q,{path:t,sidebar:n}),i&&a.createElement(I,{onClick:o}))}const Q=a.memo(J);var $=n(3102),ee=n(2961);const te=e=>{let{sidebar:t,path:n}=e;const o=(0,ee.e)();return a.createElement("ul",{className:(0,l.Z)(r.k.docs.docSidebarMenu,"menu__list")},a.createElement(K,{items:t,activePath:n,onItemClick:e=>{"category"===e.type&&e.href&&o.toggle(),"link"===e.type&&o.toggle()},level:1}))};function ne(e){return a.createElement($.Zo,{component:te,props:e})}const ae=a.memo(ne);function le(e){const t=(0,g.i)(),n="desktop"===t||"ssr"===t,l="mobile"===t;return a.createElement(a.Fragment,null,n&&a.createElement(Q,e),l&&a.createElement(ae,e))}const oe={expandButton:"expandButton_m80_",expandButtonIcon:"expandButtonIcon_BlDH"};function re(e){let{toggleSidebar:t}=e;return a.createElement("div",{className:oe.expandButton,title:(0,u.I)({id:"theme.docs.sidebar.expandButtonTitle",message:"Expand sidebar",description:"The ARIA label and title attribute for expand button of doc sidebar"}),"aria-label":(0,u.I)({id:"theme.docs.sidebar.expandButtonAriaLabel",message:"Expand sidebar",description:"The ARIA label and title attribute for expand button of doc sidebar"}),tabIndex:0,role:"button",onKeyDown:t,onClick:t},a.createElement(C,{className:oe.expandButtonIcon}))}const ce={docSidebarContainer:"docSidebarContainer_b6E3",docSidebarContainerHidden:"docSidebarContainerHidden_b3ry"};function ie(e){let{children:t}=e;const n=(0,d.V)();return a.createElement(a.Fragment,{key:n?.name??"noSidebar"},t)}function se(e){let{sidebar:t,hiddenSidebarContainer:n,setHiddenSidebarContainer:o}=e;const{pathname:c}=(0,f.TH)(),[i,s]=(0,a.useState)(!1),d=(0,a.useCallback)((()=>{i&&s(!1),o((e=>!e))}),[o,i]);return a.createElement("aside",{className:(0,l.Z)(r.k.docs.docSidebarContainer,ce.docSidebarContainer,n&&ce.docSidebarContainerHidden),onTransitionEnd:e=>{e.currentTarget.classList.contains(ce.docSidebarContainer)&&n&&s(!0)}},a.createElement(ie,null,a.createElement(le,{sidebar:t,path:c,onCollapse:d,isHidden:i})),i&&a.createElement(re,{toggleSidebar:d}))}const de={docMainContainer:"docMainContainer_gTbr",docMainContainerEnhanced:"docMainContainerEnhanced_Uz_u",docItemWrapperEnhanced:"docItemWrapperEnhanced_czyv"};function me(e){let{hiddenSidebarContainer:t,children:n}=e;const o=(0,d.V)();return a.createElement("main",{className:(0,l.Z)(de.docMainContainer,(t||!o)&&de.docMainContainerEnhanced)},a.createElement("div",{className:(0,l.Z)("container padding-top--md padding-bottom--lg",de.docItemWrapper,t&&de.docItemWrapperEnhanced)},n))}const ue={docPage:"docPage__5DB",docsWrapper:"docsWrapper_BCFX"};function be(e){let{children:t}=e;const n=(0,d.V)(),[l,o]=(0,a.useState)(!1);return a.createElement(m.Z,{wrapperClassName:ue.docsWrapper},a.createElement(E,null),a.createElement("div",{className:ue.docPage},n&&a.createElement(se,{sidebar:n.items,hiddenSidebarContainer:l,setHiddenSidebarContainer:o}),a.createElement(me,{hiddenSidebarContainer:l},t)))}var pe=n(4972),he=n(197);function Ee(e){const{versionMetadata:t}=e;return a.createElement(a.Fragment,null,a.createElement(he.Z,{version:t.version,tag:(0,c.os)(t.pluginId,t.version)}),a.createElement(o.d,null,t.noIndex&&a.createElement("meta",{name:"robots",content:"noindex, nofollow"})))}function fe(e){const{versionMetadata:t}=e,n=(0,i.hI)(e);if(!n)return a.createElement(pe.default,null);const{docElement:c,sidebarName:m,sidebarItems:u}=n;return a.createElement(a.Fragment,null,a.createElement(Ee,e),a.createElement(o.FG,{className:(0,l.Z)(r.k.wrapper.docsPages,r.k.page.docsDocPage,e.versionMetadata.className)},a.createElement(s.q,{version:t},a.createElement(d.b,{name:m,items:u},a.createElement(be,null,c)))))}},4972:(e,t,n)=>{n.r(t),n.d(t,{default:()=>c});var a=n(7294),l=n(5999),o=n(1944),r=n(3285);function c(){return a.createElement(a.Fragment,null,a.createElement(o.d,{title:(0,l.I)({id:"theme.NotFound.title",message:"Page Not Found"})}),a.createElement(r.Z,null,a.createElement("main",{className:"container margin-vert--xl"},a.createElement("div",{className:"row"},a.createElement("div",{className:"col col--6 col--offset-3"},a.createElement("h1",{className:"hero__title"},a.createElement(l.Z,{id:"theme.NotFound.title",description:"The title of the 404 page"},"Page Not Found")),a.createElement("p",null,a.createElement(l.Z,{id:"theme.NotFound.p1",description:"The first paragraph of the 404 page"},"We could not find what you were looking for.")),a.createElement("p",null,a.createElement(l.Z,{id:"theme.NotFound.p2",description:"The 2nd paragraph of the 404 page"},"Please contact the owner of the site that linked you to the original URL and let them know their link is broken.")))))))}},4477:(e,t,n)=>{n.d(t,{E:()=>c,q:()=>r});var a=n(7294),l=n(902);const o=a.createContext(null);function r(e){let{children:t,version:n}=e;return a.createElement(o.Provider,{value:n},t)}function c(){const e=(0,a.useContext)(o);if(null===e)throw new l.i6("DocsVersionProvider");return e}}}]); \ No newline at end of file diff --git a/assets/js/1be78505.eb7aad6b.js b/assets/js/1be78505.eb7aad6b.js new file mode 100644 index 000000000..a587c791e --- /dev/null +++ b/assets/js/1be78505.eb7aad6b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[8714,1774],{10:(e,t,n)=>{n.r(t),n.d(t,{default:()=>fe});var a=n(6540),l=n(53),o=n(1003),r=n(7559),c=n(2967),i=n(1754),s=n(2252),d=n(6588),m=n(5713),u=n(1312),b=n(3104),p=n(5062);const h={backToTopButton:"backToTopButton_sjWU",backToTopButtonShow:"backToTopButtonShow_xfvO"};function E(){const{shown:e,scrollToTop:t}=function(e){let{threshold:t}=e;const[n,l]=(0,a.useState)(!1),o=(0,a.useRef)(!1),{startScroll:r,cancelScroll:c}=(0,b.gk)();return(0,b.Mq)(((e,n)=>{let{scrollY:a}=e;const r=n?.scrollY;r&&(o.current?o.current=!1:a>=r?(c(),l(!1)):a{e.location.hash&&(o.current=!0,l(!1))})),{shown:n,scrollToTop:()=>r(0)}}({threshold:300});return a.createElement("button",{"aria-label":(0,u.T)({id:"theme.BackToTopButton.buttonAriaLabel",message:"Scroll back to top",description:"The ARIA label for the back to top button"}),className:(0,l.A)("clean-btn",r.G.common.backToTopButton,h.backToTopButton,e&&h.backToTopButtonShow),type:"button",onClick:t})}var f=n(6347),g=n(4581),v=n(6342),_=n(3465),C=n(8168);function k(e){return a.createElement("svg",(0,C.A)({width:"20",height:"20","aria-hidden":"true"},e),a.createElement("g",{fill:"#7a7a7a"},a.createElement("path",{d:"M9.992 10.023c0 .2-.062.399-.172.547l-4.996 7.492a.982.982 0 01-.828.454H1c-.55 0-1-.453-1-1 0-.2.059-.403.168-.551l4.629-6.942L.168 3.078A.939.939 0 010 2.528c0-.548.45-.997 1-.997h2.996c.352 0 .649.18.828.45L9.82 9.472c.11.148.172.347.172.55zm0 0"}),a.createElement("path",{d:"M19.98 10.023c0 .2-.058.399-.168.547l-4.996 7.492a.987.987 0 01-.828.454h-3c-.547 0-.996-.453-.996-1 0-.2.059-.403.168-.551l4.625-6.942-4.625-6.945a.939.939 0 01-.168-.55 1 1 0 01.996-.997h3c.348 0 .649.18.828.45l4.996 7.492c.11.148.168.347.168.55zm0 0"})))}const A={collapseSidebarButton:"collapseSidebarButton_PEFL",collapseSidebarButtonIcon:"collapseSidebarButtonIcon_kv0_"};function S(e){let{onClick:t}=e;return a.createElement("button",{type:"button",title:(0,u.T)({id:"theme.docs.sidebar.collapseButtonTitle",message:"Collapse sidebar",description:"The title attribute for collapse button of doc sidebar"}),"aria-label":(0,u.T)({id:"theme.docs.sidebar.collapseButtonAriaLabel",message:"Collapse sidebar",description:"The title attribute for collapse button of doc sidebar"}),className:(0,l.A)("button button--secondary button--outline",A.collapseSidebarButton),onClick:t},a.createElement(k,{className:A.collapseSidebarButtonIcon}))}var N=n(5041),T=n(9532);const I=Symbol("EmptyContext"),x=a.createContext(I);function y(e){let{children:t}=e;const[n,l]=(0,a.useState)(null),o=(0,a.useMemo)((()=>({expandedItem:n,setExpandedItem:l})),[n]);return a.createElement(x.Provider,{value:o},t)}var B=n(1422),w=n(9169),L=n(5489),M=n(2303);function P(e){let{categoryLabel:t,onClick:n}=e;return a.createElement("button",{"aria-label":(0,u.T)({id:"theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel",message:"Toggle the collapsible sidebar category '{label}'",description:"The ARIA label to toggle the collapsible sidebar category"},{label:t}),type:"button",className:"clean-btn menu__caret",onClick:n})}function H(e){let{item:t,onItemClick:n,activePath:o,level:c,index:s,...d}=e;const{items:m,label:u,collapsible:b,className:p,href:h}=t,{docs:{sidebar:{autoCollapseCategories:E}}}=(0,v.p)(),f=function(e){const t=(0,M.A)();return(0,a.useMemo)((()=>e.href?e.href:!t&&e.collapsible?(0,i._o)(e):void 0),[e,t])}(t),g=(0,i.w8)(t,o),_=(0,w.ys)(h,o),{collapsed:k,setCollapsed:A}=(0,B.u)({initialState:()=>!!b&&(!g&&t.collapsed)}),{expandedItem:S,setExpandedItem:N}=function(){const e=(0,a.useContext)(x);if(e===I)throw new T.dV("DocSidebarItemsExpandedStateProvider");return e}(),y=function(e){void 0===e&&(e=!k),N(e?null:s),A(e)};return function(e){let{isActive:t,collapsed:n,updateCollapsed:l}=e;const o=(0,T.ZC)(t);(0,a.useEffect)((()=>{t&&!o&&n&&l(!1)}),[t,o,n,l])}({isActive:g,collapsed:k,updateCollapsed:y}),(0,a.useEffect)((()=>{b&&null!=S&&S!==s&&E&&A(!0)}),[b,S,s,A,E]),a.createElement("li",{className:(0,l.A)(r.G.docs.docSidebarItemCategory,r.G.docs.docSidebarItemCategoryLevel(c),"menu__list-item",{"menu__list-item--collapsed":k},p)},a.createElement("div",{className:(0,l.A)("menu__list-item-collapsible",{"menu__list-item-collapsible--active":_})},a.createElement(L.A,(0,C.A)({className:(0,l.A)("menu__link",{"menu__link--sublist":b,"menu__link--sublist-caret":!h&&b,"menu__link--active":g}),onClick:b?e=>{n?.(t),h?y(!1):(e.preventDefault(),y())}:()=>{n?.(t)},"aria-current":_?"page":void 0,"aria-expanded":b?!k:void 0,href:b?f??"#":f},d),u),h&&b&&a.createElement(P,{categoryLabel:u,onClick:e=>{e.preventDefault(),y()}})),a.createElement(B.N,{lazy:!0,as:"ul",className:"menu__list",collapsed:k},a.createElement(j,{items:m,tabIndex:k?-1:0,onItemClick:n,activePath:o,level:c+1})))}var G=n(6654),F=n(3186);const W={menuExternalLink:"menuExternalLink_NmtK"};function D(e){let{item:t,onItemClick:n,activePath:o,level:c,index:s,...d}=e;const{href:m,label:u,className:b,autoAddBaseUrl:p}=t,h=(0,i.w8)(t,o),E=(0,G.A)(m);return a.createElement("li",{className:(0,l.A)(r.G.docs.docSidebarItemLink,r.G.docs.docSidebarItemLinkLevel(c),"menu__list-item",b),key:u},a.createElement(L.A,(0,C.A)({className:(0,l.A)("menu__link",!E&&W.menuExternalLink,{"menu__link--active":h}),autoAddBaseUrl:p,"aria-current":h?"page":void 0,to:m},E&&{onClick:n?()=>n(t):void 0},d),u,!E&&a.createElement(F.A,null)))}const z={menuHtmlItem:"menuHtmlItem_M9Kj"};function U(e){let{item:t,level:n,index:o}=e;const{value:c,defaultStyle:i,className:s}=t;return a.createElement("li",{className:(0,l.A)(r.G.docs.docSidebarItemLink,r.G.docs.docSidebarItemLinkLevel(n),i&&[z.menuHtmlItem,"menu__list-item"],s),key:o,dangerouslySetInnerHTML:{__html:c}})}function R(e){let{item:t,...n}=e;switch(t.type){case"category":return a.createElement(H,(0,C.A)({item:t},n));case"html":return a.createElement(U,(0,C.A)({item:t},n));default:return a.createElement(D,(0,C.A)({item:t},n))}}function V(e){let{items:t,...n}=e;return a.createElement(y,null,t.map(((e,t)=>a.createElement(R,(0,C.A)({key:t,item:e,index:t},n)))))}const j=(0,a.memo)(V),K={menu:"menu_SIkG",menuWithAnnouncementBar:"menuWithAnnouncementBar_GW3s"};function q(e){let{path:t,sidebar:n,className:o}=e;const c=function(){const{isActive:e}=(0,N.Mj)(),[t,n]=(0,a.useState)(e);return(0,b.Mq)((t=>{let{scrollY:a}=t;e&&n(0===a)}),[e]),e&&t}();return a.createElement("nav",{className:(0,l.A)("menu thin-scrollbar",K.menu,c&&K.menuWithAnnouncementBar,o)},a.createElement("ul",{className:(0,l.A)(r.G.docs.docSidebarMenu,"menu__list")},a.createElement(j,{items:n,activePath:t,level:1})))}const Y="sidebar_njMd",O="sidebarWithHideableNavbar_wUlq",X="sidebarHidden_VK0M",Z="sidebarLogo_isFc";function $(e){let{path:t,sidebar:n,onCollapse:o,isHidden:r}=e;const{navbar:{hideOnScroll:c},docs:{sidebar:{hideable:i}}}=(0,v.p)();return a.createElement("div",{className:(0,l.A)(Y,c&&O,r&&X)},c&&a.createElement(_.A,{tabIndex:-1,className:Z}),a.createElement(q,{path:t,sidebar:n}),i&&a.createElement(S,{onClick:o}))}const J=a.memo($);var Q=n(5600),ee=n(9876);const te=e=>{let{sidebar:t,path:n}=e;const o=(0,ee.M)();return a.createElement("ul",{className:(0,l.A)(r.G.docs.docSidebarMenu,"menu__list")},a.createElement(j,{items:t,activePath:n,onItemClick:e=>{"category"===e.type&&e.href&&o.toggle(),"link"===e.type&&o.toggle()},level:1}))};function ne(e){return a.createElement(Q.GX,{component:te,props:e})}const ae=a.memo(ne);function le(e){const t=(0,g.l)(),n="desktop"===t||"ssr"===t,l="mobile"===t;return a.createElement(a.Fragment,null,n&&a.createElement(J,e),l&&a.createElement(ae,e))}const oe={expandButton:"expandButton_m80_",expandButtonIcon:"expandButtonIcon_BlDH"};function re(e){let{toggleSidebar:t}=e;return a.createElement("div",{className:oe.expandButton,title:(0,u.T)({id:"theme.docs.sidebar.expandButtonTitle",message:"Expand sidebar",description:"The ARIA label and title attribute for expand button of doc sidebar"}),"aria-label":(0,u.T)({id:"theme.docs.sidebar.expandButtonAriaLabel",message:"Expand sidebar",description:"The ARIA label and title attribute for expand button of doc sidebar"}),tabIndex:0,role:"button",onKeyDown:t,onClick:t},a.createElement(k,{className:oe.expandButtonIcon}))}const ce={docSidebarContainer:"docSidebarContainer_b6E3",docSidebarContainerHidden:"docSidebarContainerHidden_b3ry"};function ie(e){let{children:t}=e;const n=(0,d.t)();return a.createElement(a.Fragment,{key:n?.name??"noSidebar"},t)}function se(e){let{sidebar:t,hiddenSidebarContainer:n,setHiddenSidebarContainer:o}=e;const{pathname:c}=(0,f.zy)(),[i,s]=(0,a.useState)(!1),d=(0,a.useCallback)((()=>{i&&s(!1),o((e=>!e))}),[o,i]);return a.createElement("aside",{className:(0,l.A)(r.G.docs.docSidebarContainer,ce.docSidebarContainer,n&&ce.docSidebarContainerHidden),onTransitionEnd:e=>{e.currentTarget.classList.contains(ce.docSidebarContainer)&&n&&s(!0)}},a.createElement(ie,null,a.createElement(le,{sidebar:t,path:c,onCollapse:d,isHidden:i})),i&&a.createElement(re,{toggleSidebar:d}))}const de={docMainContainer:"docMainContainer_gTbr",docMainContainerEnhanced:"docMainContainerEnhanced_Uz_u",docItemWrapperEnhanced:"docItemWrapperEnhanced_czyv"};function me(e){let{hiddenSidebarContainer:t,children:n}=e;const o=(0,d.t)();return a.createElement("main",{className:(0,l.A)(de.docMainContainer,(t||!o)&&de.docMainContainerEnhanced)},a.createElement("div",{className:(0,l.A)("container padding-top--md padding-bottom--lg",de.docItemWrapper,t&&de.docItemWrapperEnhanced)},n))}const ue={docPage:"docPage__5DB",docsWrapper:"docsWrapper_BCFX"};function be(e){let{children:t}=e;const n=(0,d.t)(),[l,o]=(0,a.useState)(!1);return a.createElement(m.A,{wrapperClassName:ue.docsWrapper},a.createElement(E,null),a.createElement("div",{className:ue.docPage},n&&a.createElement(se,{sidebar:n.items,hiddenSidebarContainer:l,setHiddenSidebarContainer:o}),a.createElement(me,{hiddenSidebarContainer:l},t)))}var pe=n(1774),he=n(1463);function Ee(e){const{versionMetadata:t}=e;return a.createElement(a.Fragment,null,a.createElement(he.A,{version:t.version,tag:(0,c.tU)(t.pluginId,t.version)}),a.createElement(o.be,null,t.noIndex&&a.createElement("meta",{name:"robots",content:"noindex, nofollow"})))}function fe(e){const{versionMetadata:t}=e,n=(0,i.mz)(e);if(!n)return a.createElement(pe.default,null);const{docElement:c,sidebarName:m,sidebarItems:u}=n;return a.createElement(a.Fragment,null,a.createElement(Ee,e),a.createElement(o.e3,{className:(0,l.A)(r.G.wrapper.docsPages,r.G.page.docsDocPage,e.versionMetadata.className)},a.createElement(s.n,{version:t},a.createElement(d.V,{name:m,items:u},a.createElement(be,null,c)))))}},1774:(e,t,n)=>{n.r(t),n.d(t,{default:()=>c});var a=n(6540),l=n(1312),o=n(1003),r=n(5713);function c(){return a.createElement(a.Fragment,null,a.createElement(o.be,{title:(0,l.T)({id:"theme.NotFound.title",message:"Page Not Found"})}),a.createElement(r.A,null,a.createElement("main",{className:"container margin-vert--xl"},a.createElement("div",{className:"row"},a.createElement("div",{className:"col col--6 col--offset-3"},a.createElement("h1",{className:"hero__title"},a.createElement(l.A,{id:"theme.NotFound.title",description:"The title of the 404 page"},"Page Not Found")),a.createElement("p",null,a.createElement(l.A,{id:"theme.NotFound.p1",description:"The first paragraph of the 404 page"},"We could not find what you were looking for.")),a.createElement("p",null,a.createElement(l.A,{id:"theme.NotFound.p2",description:"The 2nd paragraph of the 404 page"},"Please contact the owner of the site that linked you to the original URL and let them know their link is broken.")))))))}},2252:(e,t,n)=>{n.d(t,{n:()=>r,r:()=>c});var a=n(6540),l=n(9532);const o=a.createContext(null);function r(e){let{children:t,version:n}=e;return a.createElement(o.Provider,{value:n},t)}function c(){const e=(0,a.useContext)(o);if(null===e)throw new l.dV("DocsVersionProvider");return e}}}]); \ No newline at end of file diff --git a/assets/js/2004.13abbb5c.js b/assets/js/2004.13abbb5c.js deleted file mode 100644 index ff8b8ed6b..000000000 --- a/assets/js/2004.13abbb5c.js +++ /dev/null @@ -1 +0,0 @@ -(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[2004],{3905:(e,t,n)=>{"use strict";n.d(t,{Zo:()=>u,kt:()=>f});var o=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function l(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var i=o.createContext({}),s=function(e){var t=o.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},u=function(e){var t=s(e.components);return o.createElement(i.Provider,{value:t},e.children)},m="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},p=o.forwardRef((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,i=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),m=s(n),p=a,f=m["".concat(i,".").concat(p)]||m[p]||d[p]||r;return n?o.createElement(f,l(l({ref:t},u),{},{components:n})):o.createElement(f,l({ref:t},u))}));function f(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,l=new Array(r);l[0]=p;var c={};for(var i in t)hasOwnProperty.call(t,i)&&(c[i]=t[i]);c.originalType=e,c[m]="string"==typeof e?e:a,l[1]=c;for(var s=2;s{"use strict";n.d(t,{Z:()=>u});var o=n(7294),a=n(5999),r=n(5281),l=n(7462),c=n(6010);const i={iconEdit:"iconEdit_Z9Sw"};function s(e){let{className:t,...n}=e;return o.createElement("svg",(0,l.Z)({fill:"currentColor",height:"20",width:"20",viewBox:"0 0 40 40",className:(0,c.Z)(i.iconEdit,t),"aria-hidden":"true"},n),o.createElement("g",null,o.createElement("path",{d:"m34.5 11.7l-3 3.1-6.3-6.3 3.1-3q0.5-0.5 1.2-0.5t1.1 0.5l3.9 3.9q0.5 0.4 0.5 1.1t-0.5 1.2z m-29.5 17.1l18.4-18.5 6.3 6.3-18.4 18.4h-6.3v-6.2z"})))}function u(e){let{editUrl:t}=e;return o.createElement("a",{href:t,target:"_blank",rel:"noreferrer noopener",className:r.k.common.editThisPage},o.createElement(s,null),o.createElement(a.Z,{id:"theme.common.editThisPage",description:"The link label to edit the current page"},"Edit this page"))}},7955:(e,t,n)=>{"use strict";n.d(t,{Z:()=>s});var o=n(7462),a=n(7294),r=n(6010),l=n(5999),c=n(6668);const i={anchorWithStickyNavbar:"anchorWithStickyNavbar_LWe7",anchorWithHideOnScrollNavbar:"anchorWithHideOnScrollNavbar_WYt5"};function s(e){let{as:t,id:n,...s}=e;const{navbar:{hideOnScroll:u}}=(0,c.L)();return"h1"!==t&&n?a.createElement(t,(0,o.Z)({},s,{className:(0,r.Z)("anchor",u?i.anchorWithHideOnScrollNavbar:i.anchorWithStickyNavbar),id:n}),s.children,a.createElement("a",{className:"hash-link",href:`#${n}`,title:(0,l.I)({id:"theme.common.headingLinkTitle",message:"Direct link to heading",description:"Title for link to heading"})},"\u200b")):a.createElement(t,(0,o.Z)({},s,{id:void 0}))}},210:(e,t,n)=>{"use strict";n.d(t,{Z:()=>pe});var o=n(7294),a=n(3905),r=n(7462),l=n(5742);var c=n(2389),i=n(6010),s=n(2949),u=n(6668);function m(){const{prism:e}=(0,u.L)(),{colorMode:t}=(0,s.I)(),n=e.theme,o=e.darkTheme||n;return"dark"===t?o:n}var d=n(5281),p=n(7594),f=n.n(p);const g=/title=(?["'])(?.*?)\1/,h=/\{(?<range>[\d,-]+)\}/,y={js:{start:"\\/\\/",end:""},jsBlock:{start:"\\/\\*",end:"\\*\\/"},jsx:{start:"\\{\\s*\\/\\*",end:"\\*\\/\\s*\\}"},bash:{start:"#",end:""},html:{start:"\x3c!--",end:"--\x3e"}};function b(e,t){const n=e.map((e=>{const{start:n,end:o}=y[e];return`(?:${n}\\s*(${t.flatMap((e=>[e.line,e.block?.start,e.block?.end].filter(Boolean))).join("|")})\\s*${o})`})).join("|");return new RegExp(`^\\s*(?:${n})\\s*$`)}function v(e,t){let n=e.replace(/\n$/,"");const{language:o,magicComments:a,metastring:r}=t;if(r&&h.test(r)){const e=r.match(h).groups.range;if(0===a.length)throw new Error(`A highlight range has been given in code block's metastring (\`\`\` ${r}), but no magic comment config is available. Docusaurus applies the first magic comment entry's className for metastring ranges.`);const t=a[0].className,o=f()(e).filter((e=>e>0)).map((e=>[e-1,[t]]));return{lineClassNames:Object.fromEntries(o),code:n}}if(void 0===o)return{lineClassNames:{},code:n};const l=function(e,t){switch(e){case"js":case"javascript":case"ts":case"typescript":return b(["js","jsBlock"],t);case"jsx":case"tsx":return b(["js","jsBlock","jsx"],t);case"html":return b(["js","jsBlock","html"],t);case"python":case"py":case"bash":return b(["bash"],t);case"markdown":case"md":return b(["html","jsx","bash"],t);default:return b(Object.keys(y),t)}}(o,a),c=n.split("\n"),i=Object.fromEntries(a.map((e=>[e.className,{start:0,range:""}]))),s=Object.fromEntries(a.filter((e=>e.line)).map((e=>{let{className:t,line:n}=e;return[n,t]}))),u=Object.fromEntries(a.filter((e=>e.block)).map((e=>{let{className:t,block:n}=e;return[n.start,t]}))),m=Object.fromEntries(a.filter((e=>e.block)).map((e=>{let{className:t,block:n}=e;return[n.end,t]})));for(let p=0;p<c.length;){const e=c[p].match(l);if(!e){p+=1;continue}const t=e.slice(1).find((e=>void 0!==e));s[t]?i[s[t]].range+=`${p},`:u[t]?i[u[t]].start=p:m[t]&&(i[m[t]].range+=`${i[m[t]].start}-${p-1},`),c.splice(p,1)}n=c.join("\n");const d={};return Object.entries(i).forEach((e=>{let[t,{range:n}]=e;f()(n).forEach((e=>{d[e]??=[],d[e].push(t)}))})),{lineClassNames:d,code:n}}const E={codeBlockContainer:"codeBlockContainer_Ckt0"};function k(e){let{as:t,...n}=e;const a=function(e){const t={color:"--prism-color",backgroundColor:"--prism-background-color"},n={};return Object.entries(e.plain).forEach((e=>{let[o,a]=e;const r=t[o];r&&"string"==typeof a&&(n[r]=a)})),n}(m());return o.createElement(t,(0,r.Z)({},n,{style:a,className:(0,i.Z)(n.className,E.codeBlockContainer,d.k.common.codeBlock)}))}const N={codeBlockContent:"codeBlockContent_biex",codeBlockTitle:"codeBlockTitle_Ktv7",codeBlock:"codeBlock_bY9V",codeBlockStandalone:"codeBlockStandalone_MEMb",codeBlockLines:"codeBlockLines_e6Vv",codeBlockLinesWithNumbering:"codeBlockLinesWithNumbering_o6Pm",buttonGroup:"buttonGroup__atx"};function C(e){let{children:t,className:n}=e;return o.createElement(k,{as:"pre",tabIndex:0,className:(0,i.Z)(N.codeBlockStandalone,"thin-scrollbar",n)},o.createElement("code",{className:N.codeBlockLines},t))}var w=n(902);const B={attributes:!0,characterData:!0,childList:!0,subtree:!0};function T(e,t){const[n,a]=(0,o.useState)(),r=(0,o.useCallback)((()=>{a(e.current?.closest("[role=tabpanel][hidden]"))}),[e,a]);(0,o.useEffect)((()=>{r()}),[r]),function(e,t,n){void 0===n&&(n=B);const a=(0,w.zX)(t),r=(0,w.Ql)(n);(0,o.useEffect)((()=>{const t=new MutationObserver(a);return e&&t.observe(e,r),()=>t.disconnect()}),[e,a,r])}(n,(e=>{e.forEach((e=>{"attributes"===e.type&&"hidden"===e.attributeName&&(t(),r())}))}),{attributes:!0,characterData:!1,childList:!1,subtree:!1})}const Z={plain:{backgroundColor:"#2a2734",color:"#9a86fd"},styles:[{types:["comment","prolog","doctype","cdata","punctuation"],style:{color:"#6c6783"}},{types:["namespace"],style:{opacity:.7}},{types:["tag","operator","number"],style:{color:"#e09142"}},{types:["property","function"],style:{color:"#9a86fd"}},{types:["tag-id","selector","atrule-id"],style:{color:"#eeebff"}},{types:["attr-name"],style:{color:"#c4b9fe"}},{types:["boolean","string","entity","url","attr-value","keyword","control","directive","unit","statement","regex","atrule","placeholder","variable"],style:{color:"#ffcc99"}},{types:["deleted"],style:{textDecorationLine:"line-through"}},{types:["inserted"],style:{textDecorationLine:"underline"}},{types:["italic"],style:{fontStyle:"italic"}},{types:["important","bold"],style:{fontWeight:"bold"}},{types:["important"],style:{color:"#c4b9fe"}}]};var L={Prism:n(7410).Z,theme:Z};function _(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function j(){return j=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var o in n)Object.prototype.hasOwnProperty.call(n,o)&&(e[o]=n[o])}return e},j.apply(this,arguments)}var x=/\r\n|\r|\n/,O=function(e){0===e.length?e.push({types:["plain"],content:"\n",empty:!0}):1===e.length&&""===e[0].content&&(e[0].content="\n",e[0].empty=!0)},S=function(e,t){var n=e.length;return n>0&&e[n-1]===t?e:e.concat(t)};function P(e,t){var n={};for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&-1===t.indexOf(o)&&(n[o]=e[o]);return n}var z=function(e){function t(){for(var t=this,n=[],o=arguments.length;o--;)n[o]=arguments[o];e.apply(this,n),_(this,"getThemeDict",(function(e){if(void 0!==t.themeDict&&e.theme===t.prevTheme&&e.language===t.prevLanguage)return t.themeDict;t.prevTheme=e.theme,t.prevLanguage=e.language;var n=e.theme?function(e,t){var n=e.plain,o=Object.create(null),a=e.styles.reduce((function(e,n){var o=n.languages,a=n.style;return o&&!o.includes(t)||n.types.forEach((function(t){var n=j({},e[t],a);e[t]=n})),e}),o);return a.root=n,a.plain=j({},n,{backgroundColor:null}),a}(e.theme,e.language):void 0;return t.themeDict=n})),_(this,"getLineProps",(function(e){var n=e.key,o=e.className,a=e.style,r=j({},P(e,["key","className","style","line"]),{className:"token-line",style:void 0,key:void 0}),l=t.getThemeDict(t.props);return void 0!==l&&(r.style=l.plain),void 0!==a&&(r.style=void 0!==r.style?j({},r.style,a):a),void 0!==n&&(r.key=n),o&&(r.className+=" "+o),r})),_(this,"getStyleForToken",(function(e){var n=e.types,o=e.empty,a=n.length,r=t.getThemeDict(t.props);if(void 0!==r){if(1===a&&"plain"===n[0])return o?{display:"inline-block"}:void 0;if(1===a&&!o)return r[n[0]];var l=o?{display:"inline-block"}:{},c=n.map((function(e){return r[e]}));return Object.assign.apply(Object,[l].concat(c))}})),_(this,"getTokenProps",(function(e){var n=e.key,o=e.className,a=e.style,r=e.token,l=j({},P(e,["key","className","style","token"]),{className:"token "+r.types.join(" "),children:r.content,style:t.getStyleForToken(r),key:void 0});return void 0!==a&&(l.style=void 0!==l.style?j({},l.style,a):a),void 0!==n&&(l.key=n),o&&(l.className+=" "+o),l})),_(this,"tokenize",(function(e,t,n,o){var a={code:t,grammar:n,language:o,tokens:[]};e.hooks.run("before-tokenize",a);var r=a.tokens=e.tokenize(a.code,a.grammar,a.language);return e.hooks.run("after-tokenize",a),r}))}return e&&(t.__proto__=e),t.prototype=Object.create(e&&e.prototype),t.prototype.constructor=t,t.prototype.render=function(){var e=this.props,t=e.Prism,n=e.language,o=e.code,a=e.children,r=this.getThemeDict(this.props),l=t.languages[n];return a({tokens:function(e){for(var t=[[]],n=[e],o=[0],a=[e.length],r=0,l=0,c=[],i=[c];l>-1;){for(;(r=o[l]++)<a[l];){var s=void 0,u=t[l],m=n[l][r];if("string"==typeof m?(u=l>0?u:["plain"],s=m):(u=S(u,m.type),m.alias&&(u=S(u,m.alias)),s=m.content),"string"==typeof s){var d=s.split(x),p=d.length;c.push({types:u,content:d[0]});for(var f=1;f<p;f++)O(c),i.push(c=[]),c.push({types:u,content:d[f]})}else l++,t.push(u),n.push(s),o.push(0),a.push(s.length)}l--,t.pop(),n.pop(),o.pop(),a.pop()}return O(c),i}(void 0!==l?this.tokenize(t,o,l,n):[o]),className:"prism-code language-"+n,style:void 0!==r?r.root:{},getLineProps:this.getLineProps,getTokenProps:this.getTokenProps})},t}(o.Component);const A=z,I={codeLine:"codeLine_lJS_",codeLineNumber:"codeLineNumber_Tfdd",codeLineContent:"codeLineContent_feaV"};function W(e){let{line:t,classNames:n,showLineNumbers:a,getLineProps:l,getTokenProps:c}=e;1===t.length&&"\n"===t[0].content&&(t[0].content="");const s=l({line:t,className:(0,i.Z)(n,a&&I.codeLine)}),u=t.map(((e,t)=>o.createElement("span",(0,r.Z)({key:t},c({token:e,key:t})))));return o.createElement("span",s,a?o.createElement(o.Fragment,null,o.createElement("span",{className:I.codeLineNumber}),o.createElement("span",{className:I.codeLineContent},u)):u,o.createElement("br",null))}var M=n(5999);const H={copyButtonCopied:"copyButtonCopied_obH4",copyButtonIcons:"copyButtonIcons_eSgA",copyButtonIcon:"copyButtonIcon_y97N",copyButtonSuccessIcon:"copyButtonSuccessIcon_LjdS"};function D(e){let{code:t,className:n}=e;const[a,r]=(0,o.useState)(!1),l=(0,o.useRef)(void 0),c=(0,o.useCallback)((()=>{!function(e,t){let{target:n=document.body}=void 0===t?{}:t;if("string"!=typeof e)throw new TypeError(`Expected parameter \`text\` to be a \`string\`, got \`${typeof e}\`.`);const o=document.createElement("textarea"),a=document.activeElement;o.value=e,o.setAttribute("readonly",""),o.style.contain="strict",o.style.position="absolute",o.style.left="-9999px",o.style.fontSize="12pt";const r=document.getSelection(),l=r.rangeCount>0&&r.getRangeAt(0);n.append(o),o.select(),o.selectionStart=0,o.selectionEnd=e.length;let c=!1;try{c=document.execCommand("copy")}catch{}o.remove(),l&&(r.removeAllRanges(),r.addRange(l)),a&&a.focus()}(t),r(!0),l.current=window.setTimeout((()=>{r(!1)}),1e3)}),[t]);return(0,o.useEffect)((()=>()=>window.clearTimeout(l.current)),[]),o.createElement("button",{type:"button","aria-label":a?(0,M.I)({id:"theme.CodeBlock.copied",message:"Copied",description:"The copied button label on code blocks"}):(0,M.I)({id:"theme.CodeBlock.copyButtonAriaLabel",message:"Copy code to clipboard",description:"The ARIA label for copy code blocks button"}),title:(0,M.I)({id:"theme.CodeBlock.copy",message:"Copy",description:"The copy button label on code blocks"}),className:(0,i.Z)("clean-btn",n,H.copyButton,a&&H.copyButtonCopied),onClick:c},o.createElement("span",{className:H.copyButtonIcons,"aria-hidden":"true"},o.createElement("svg",{className:H.copyButtonIcon,viewBox:"0 0 24 24"},o.createElement("path",{d:"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"})),o.createElement("svg",{className:H.copyButtonSuccessIcon,viewBox:"0 0 24 24"},o.createElement("path",{d:"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"}))))}const R={wordWrapButtonIcon:"wordWrapButtonIcon_Bwma",wordWrapButtonEnabled:"wordWrapButtonEnabled_EoeP"};function V(e){let{className:t,onClick:n,isEnabled:a}=e;const r=(0,M.I)({id:"theme.CodeBlock.wordWrapToggle",message:"Toggle word wrap",description:"The title attribute for toggle word wrapping button of code block lines"});return o.createElement("button",{type:"button",onClick:n,className:(0,i.Z)("clean-btn",t,a&&R.wordWrapButtonEnabled),"aria-label":r,title:r},o.createElement("svg",{className:R.wordWrapButtonIcon,viewBox:"0 0 24 24","aria-hidden":"true"},o.createElement("path",{fill:"currentColor",d:"M4 19h6v-2H4v2zM20 5H4v2h16V5zm-3 6H4v2h13.25c1.1 0 2 .9 2 2s-.9 2-2 2H15v-2l-3 3l3 3v-2h2c2.21 0 4-1.79 4-4s-1.79-4-4-4z"})))}function $(e){let{children:t,className:n="",metastring:a,title:l,showLineNumbers:c,language:s}=e;const{prism:{defaultLanguage:d,magicComments:p}}=(0,u.L)(),f=s??function(e){const t=e.split(" ").find((e=>e.startsWith("language-")));return t?.replace(/language-/,"")}(n)??d,h=m(),y=function(){const[e,t]=(0,o.useState)(!1),[n,a]=(0,o.useState)(!1),r=(0,o.useRef)(null),l=(0,o.useCallback)((()=>{const n=r.current.querySelector("code");e?n.removeAttribute("style"):(n.style.whiteSpace="pre-wrap",n.style.overflowWrap="anywhere"),t((e=>!e))}),[r,e]),c=(0,o.useCallback)((()=>{const{scrollWidth:e,clientWidth:t}=r.current,n=e>t||r.current.querySelector("code").hasAttribute("style");a(n)}),[r]);return T(r,c),(0,o.useEffect)((()=>{c()}),[e,c]),(0,o.useEffect)((()=>(window.addEventListener("resize",c,{passive:!0}),()=>{window.removeEventListener("resize",c)})),[c]),{codeBlockRef:r,isEnabled:e,isCodeScrollable:n,toggle:l}}(),b=function(e){return e?.match(g)?.groups.title??""}(a)||l,{lineClassNames:E,code:C}=v(t,{metastring:a,language:f,magicComments:p}),w=c??function(e){return Boolean(e?.includes("showLineNumbers"))}(a);return o.createElement(k,{as:"div",className:(0,i.Z)(n,f&&!n.includes(`language-${f}`)&&`language-${f}`)},b&&o.createElement("div",{className:N.codeBlockTitle},b),o.createElement("div",{className:N.codeBlockContent},o.createElement(A,(0,r.Z)({},L,{theme:h,code:C,language:f??"text"}),(e=>{let{className:t,tokens:n,getLineProps:a,getTokenProps:r}=e;return o.createElement("pre",{tabIndex:0,ref:y.codeBlockRef,className:(0,i.Z)(t,N.codeBlock,"thin-scrollbar")},o.createElement("code",{className:(0,i.Z)(N.codeBlockLines,w&&N.codeBlockLinesWithNumbering)},n.map(((e,t)=>o.createElement(W,{key:t,line:e,getLineProps:a,getTokenProps:r,classNames:E[t],showLineNumbers:w})))))})),o.createElement("div",{className:N.buttonGroup},(y.isEnabled||y.isCodeScrollable)&&o.createElement(V,{className:N.codeButton,onClick:()=>y.toggle(),isEnabled:y.isEnabled}),o.createElement(D,{className:N.codeButton,code:C}))))}function F(e){let{children:t,...n}=e;const a=(0,c.Z)(),l=function(e){return o.Children.toArray(e).some((e=>(0,o.isValidElement)(e)))?e:Array.isArray(e)?e.join(""):e}(t),i="string"==typeof l?$:C;return o.createElement(i,(0,r.Z)({key:String(a)},n),l)}var q=n(9960);var G=n(6043);const U={details:"details_lb9f",isBrowser:"isBrowser_bmU9",collapsibleContent:"collapsibleContent_i85q"};function Q(e){return!!e&&("SUMMARY"===e.tagName||Q(e.parentElement))}function X(e,t){return!!e&&(e===t||X(e.parentElement,t))}function Y(e){let{summary:t,children:n,...a}=e;const l=(0,c.Z)(),s=(0,o.useRef)(null),{collapsed:u,setCollapsed:m}=(0,G.u)({initialState:!a.open}),[d,p]=(0,o.useState)(a.open);return o.createElement("details",(0,r.Z)({},a,{ref:s,open:d,"data-collapsed":u,className:(0,i.Z)(U.details,l&&U.isBrowser,a.className),onMouseDown:e=>{Q(e.target)&&e.detail>1&&e.preventDefault()},onClick:e=>{e.stopPropagation();const t=e.target;Q(t)&&X(t,s.current)&&(e.preventDefault(),u?(m(!1),p(!0)):m(!0))}}),t??o.createElement("summary",null,"Details"),o.createElement(G.z,{lazy:!1,collapsed:u,disableSSRStyle:!0,onCollapseTransitionEnd:e=>{m(e),p(!e)}},o.createElement("div",{className:U.collapsibleContent},n)))}const J={details:"details_b_Ee"},K="alert alert--info";function ee(e){let{...t}=e;return o.createElement(Y,(0,r.Z)({},t,{className:(0,i.Z)(K,J.details,t.className)}))}var te=n(7955);function ne(e){return o.createElement(te.Z,e)}const oe={containsTaskList:"containsTaskList_mC6p"};const ae={img:"img_ev3q"};const re="admonition_LlT9",le="admonitionHeading_tbUL",ce="admonitionIcon_kALy",ie="admonitionContent_S0QG";const se={note:{infimaClassName:"secondary",iconComponent:function(){return o.createElement("svg",{viewBox:"0 0 14 16"},o.createElement("path",{fillRule:"evenodd",d:"M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"}))},label:o.createElement(M.Z,{id:"theme.admonition.note",description:"The default label used for the Note admonition (:::note)"},"note")},tip:{infimaClassName:"success",iconComponent:function(){return o.createElement("svg",{viewBox:"0 0 12 16"},o.createElement("path",{fillRule:"evenodd",d:"M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"}))},label:o.createElement(M.Z,{id:"theme.admonition.tip",description:"The default label used for the Tip admonition (:::tip)"},"tip")},danger:{infimaClassName:"danger",iconComponent:function(){return o.createElement("svg",{viewBox:"0 0 12 16"},o.createElement("path",{fillRule:"evenodd",d:"M5.05.31c.81 2.17.41 3.38-.52 4.31C3.55 5.67 1.98 6.45.9 7.98c-1.45 2.05-1.7 6.53 3.53 7.7-2.2-1.16-2.67-4.52-.3-6.61-.61 2.03.53 3.33 1.94 2.86 1.39-.47 2.3.53 2.27 1.67-.02.78-.31 1.44-1.13 1.81 3.42-.59 4.78-3.42 4.78-5.56 0-2.84-2.53-3.22-1.25-5.61-1.52.13-2.03 1.13-1.89 2.75.09 1.08-1.02 1.8-1.86 1.33-.67-.41-.66-1.19-.06-1.78C8.18 5.31 8.68 2.45 5.05.32L5.03.3l.02.01z"}))},label:o.createElement(M.Z,{id:"theme.admonition.danger",description:"The default label used for the Danger admonition (:::danger)"},"danger")},info:{infimaClassName:"info",iconComponent:function(){return o.createElement("svg",{viewBox:"0 0 14 16"},o.createElement("path",{fillRule:"evenodd",d:"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"}))},label:o.createElement(M.Z,{id:"theme.admonition.info",description:"The default label used for the Info admonition (:::info)"},"info")},caution:{infimaClassName:"warning",iconComponent:function(){return o.createElement("svg",{viewBox:"0 0 16 16"},o.createElement("path",{fillRule:"evenodd",d:"M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"}))},label:o.createElement(M.Z,{id:"theme.admonition.caution",description:"The default label used for the Caution admonition (:::caution)"},"caution")}},ue={secondary:"note",important:"info",success:"tip",warning:"danger"};function me(e){const{mdxAdmonitionTitle:t,rest:n}=function(e){const t=o.Children.toArray(e),n=t.find((e=>o.isValidElement(e)&&"mdxAdmonitionTitle"===e.props?.mdxType)),a=o.createElement(o.Fragment,null,t.filter((e=>e!==n)));return{mdxAdmonitionTitle:n,rest:a}}(e.children);return{...e,title:e.title??t,children:n}}const de={head:function(e){const t=o.Children.map(e.children,(e=>o.isValidElement(e)?function(e){if(e.props?.mdxType&&e.props.originalType){const{mdxType:t,originalType:n,...a}=e.props;return o.createElement(e.props.originalType,a)}return e}(e):e));return o.createElement(l.Z,e,t)},code:function(e){const t=["a","abbr","b","br","button","cite","code","del","dfn","em","i","img","input","ins","kbd","label","object","output","q","ruby","s","small","span","strong","sub","sup","time","u","var","wbr"];return o.Children.toArray(e.children).every((e=>"string"==typeof e&&!e.includes("\n")||(0,o.isValidElement)(e)&&t.includes(e.props?.mdxType)))?o.createElement("code",e):o.createElement(F,e)},a:function(e){return o.createElement(q.Z,e)},pre:function(e){return o.createElement(F,(0,o.isValidElement)(e.children)&&"code"===e.children.props?.originalType?e.children.props:{...e})},details:function(e){const t=o.Children.toArray(e.children),n=t.find((e=>o.isValidElement(e)&&"summary"===e.props?.mdxType)),a=o.createElement(o.Fragment,null,t.filter((e=>e!==n)));return o.createElement(ee,(0,r.Z)({},e,{summary:n}),a)},ul:function(e){return o.createElement("ul",(0,r.Z)({},e,{className:(t=e.className,(0,i.Z)(t,t?.includes("contains-task-list")&&oe.containsTaskList))}));var t},img:function(e){return o.createElement("img",(0,r.Z)({loading:"lazy"},e,{className:(t=e.className,(0,i.Z)(t,ae.img))}));var t},h1:e=>o.createElement(ne,(0,r.Z)({as:"h1"},e)),h2:e=>o.createElement(ne,(0,r.Z)({as:"h2"},e)),h3:e=>o.createElement(ne,(0,r.Z)({as:"h3"},e)),h4:e=>o.createElement(ne,(0,r.Z)({as:"h4"},e)),h5:e=>o.createElement(ne,(0,r.Z)({as:"h5"},e)),h6:e=>o.createElement(ne,(0,r.Z)({as:"h6"},e)),admonition:function(e){const{children:t,type:n,title:a,icon:r}=me(e),l=function(e){const t=ue[e]??e,n=se[t];return n||(console.warn(`No admonition config found for admonition type "${t}". Using Info as fallback.`),se.info)}(n),c=a??l.label,{iconComponent:s}=l,u=r??o.createElement(s,null);return o.createElement("div",{className:(0,i.Z)(d.k.common.admonition,d.k.common.admonitionType(e.type),"alert",`alert--${l.infimaClassName}`,re)},o.createElement("div",{className:le},o.createElement("span",{className:ce},u),c),o.createElement("div",{className:ie},t))},mermaid:n(1875).Z};function pe(e){let{children:t}=e;return o.createElement(a.Zo,{components:de},t)}},2244:(e,t,n)=>{"use strict";n.d(t,{Z:()=>l});var o=n(7294),a=n(6010),r=n(9960);function l(e){const{permalink:t,title:n,subLabel:l,isNext:c}=e;return o.createElement(r.Z,{className:(0,a.Z)("pagination-nav__link",c?"pagination-nav__link--next":"pagination-nav__link--prev"),to:t},l&&o.createElement("div",{className:"pagination-nav__sublabel"},l),o.createElement("div",{className:"pagination-nav__label"},n))}},6233:(e,t,n)=>{"use strict";n.d(t,{Z:()=>u});var o=n(7294),a=n(6010),r=n(5999),l=n(9960);const c={tag:"tag_zVej",tagRegular:"tagRegular_sFm0",tagWithCount:"tagWithCount_h2kH"};function i(e){let{permalink:t,label:n,count:r}=e;return o.createElement(l.Z,{href:t,className:(0,a.Z)(c.tag,r?c.tagWithCount:c.tagRegular)},n,r&&o.createElement("span",null,r))}const s={tags:"tags_jXut",tag:"tag_QGVx"};function u(e){let{tags:t}=e;return o.createElement(o.Fragment,null,o.createElement("b",null,o.createElement(r.Z,{id:"theme.tags.tagsListLabel",description:"The label alongside a tag list"},"Tags:")),o.createElement("ul",{className:(0,a.Z)(s.tags,"padding--none","margin-left--sm")},t.map((e=>{let{label:t,permalink:n}=e;return o.createElement("li",{key:n,className:s.tag},o.createElement(i,{label:t,permalink:n}))}))))}},7594:(e,t)=>{function n(e){let t,n=[];for(let o of e.split(",").map((e=>e.trim())))if(/^-?\d+$/.test(o))n.push(parseInt(o,10));else if(t=o.match(/^(-?\d+)(-|\.\.\.?|\u2025|\u2026|\u22EF)(-?\d+)$/)){let[e,o,a,r]=t;if(o&&r){o=parseInt(o),r=parseInt(r);const e=o<r?1:-1;"-"!==a&&".."!==a&&"\u2025"!==a||(r+=e);for(let t=o;t!==r;t+=e)n.push(t)}}return n}t.default=n,e.exports=n}}]); \ No newline at end of file diff --git a/assets/js/20a6a7d9.6326b398.js b/assets/js/20a6a7d9.6326b398.js new file mode 100644 index 000000000..cc9eafcf6 --- /dev/null +++ b/assets/js/20a6a7d9.6326b398.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[757],{5680:(e,t,r)=>{r.d(t,{xA:()=>d,yg:()=>b});var a=r(6540);function n(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,a)}return r}function o(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?i(Object(r),!0).forEach((function(t){n(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):i(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function l(e,t){if(null==e)return{};var r,a,n=function(e,t){if(null==e)return{};var r,a,n={},i=Object.keys(e);for(a=0;a<i.length;a++)r=i[a],t.indexOf(r)>=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a<i.length;a++)r=i[a],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var s=a.createContext({}),p=function(e){var t=a.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},d=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},c="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},g=a.forwardRef((function(e,t){var r=e.components,n=e.mdxType,i=e.originalType,s=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),c=p(r),g=n,b=c["".concat(s,".").concat(g)]||c[g]||m[g]||i;return r?a.createElement(b,o(o({ref:t},d),{},{components:r})):a.createElement(b,o({ref:t},d))}));function b(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var i=r.length,o=new Array(i);o[0]=g;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:n,o[1]=l;for(var p=2;p<i;p++)o[p]=r[p];return a.createElement.apply(null,o)}return a.createElement.apply(null,r)}g.displayName="MDXCreateElement"},6927:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>m,frontMatter:()=>i,metadata:()=>l,toc:()=>p});var a=r(8168),n=(r(6540),r(5680));const i={id:"guide",title:"Using Weaver"},o=void 0,l={unversionedId:"external/getting-started/guide",id:"external/getting-started/guide",title:"Using Weaver",description:"\x3c!--",source:"@site/docs/external/getting-started/guide.md",sourceDirName:"external/getting-started",slug:"/external/getting-started/guide",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/guide",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/getting-started/guide.md",tags:[],version:"current",frontMatter:{id:"guide",title:"Using Weaver"},sidebar:"Documentation",previous:{title:"Weaver Framework",permalink:"/weaver-dlt-interoperability/docs/external/introduction"},next:{title:"Component Overview",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/overview"}},s={},p=[],d={toc:p},c="wrapper";function m(e){let{components:t,...r}=e;return(0,n.yg)(c,(0,a.A)({},d,r,{components:t,mdxType:"MDXLayout"}),(0,n.yg)("p",null,"The easiest way to understand how Weaver works is to run it at a small scale:"),(0,n.yg)("ul",null,(0,n.yg)("li",{parentName:"ul"},"First, ",(0,n.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/overview"},"launch a set of basic test networks")," built on Fabric, Corda and Besu. These networks offer the most basic capabilities of their DLT platforms and run toy applications (contracts and Layer-2) that can easily be tracked and debugged. You can launch these networks in one of several different ways: building Weaver components and dependencies locally or importing pre-built ones from Github packages, running core components in the host or in Docker containers. The choice depends on whether you just want to get these networks up and running or if you wish to customize the setup by modifying source code and configurations."),(0,n.yg)("li",{parentName:"ul"},"Once the test networks are launched, you can test two distinct kinds of interoperation modes:",(0,n.yg)("ul",{parentName:"li"},(0,n.yg)("li",{parentName:"ul"},(0,n.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/data-sharing"},"Data sharing"),": all combinations of Fabric and Corda networks supported"),(0,n.yg)("li",{parentName:"ul"},(0,n.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview"},"Asset exchange"),": all pairs of network types from {Fabric, Corda, Besu} are supported"),(0,n.yg)("li",{parentName:"ul"},(0,n.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-transfer"},"Asset transfer"),": all combinations of Fabric and Corda networks supported"))),(0,n.yg)("li",{parentName:"ul"},'(To bring down the test networks, go back to the "Setup" pages and follow instructions in the respective "Teardown" sections.)'),(0,n.yg)("li",{parentName:"ul"},'After you run these tests and get a flavor of how the system and protocols work, you will be ready to move on to "real" networks, enhancing them with interoperation capabilities by incorporating Weaver into them. Check out the guidelines and templates for ',(0,n.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/fabric"},"Fabric"),", ",(0,n.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/corda"},"Corda"),", and ",(0,n.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/besu"},"Besu")," networks.")),(0,n.yg)("p",null,"If you wish to go further and understand Weaver specifics, dig into the code, or contribute to the open-source project, check out the ",(0,n.yg)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability"},"project repository"),". For specific information about individual Weaver components, see:"),(0,n.yg)("ul",null,(0,n.yg)("li",{parentName:"ul"},(0,n.yg)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/core/relay/README.md"},"Relay")," module"),(0,n.yg)("li",{parentName:"ul"},(0,n.yg)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/core/drivers/fabric-driver/readme.md"},"Fabric")," and ",(0,n.yg)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/core/drivers/corda-driver/README.md"},"Corda")," drivers"),(0,n.yg)("li",{parentName:"ul"},(0,n.yg)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/core/network/fabric-interop-cc/README.md"},"Fabric Interoperation Chaincode"),", ",(0,n.yg)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/core/network/corda-interop-app/README.md"},"Interoperation CorDapp"),", and ",(0,n.yg)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/core/network/besu/README.md"},"Besu Interoperation Contract")),(0,n.yg)("li",{parentName:"ul"},"Common ",(0,n.yg)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/common/protos"},"protobufs"),": compiled in ",(0,n.yg)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/common/protos-js/README.md"},"JavaScript"),", ",(0,n.yg)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/common/protos-go/README.md"},"Golang"),", ",(0,n.yg)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/common/protos-java-kt/README.md"},"Java"),", ",(0,n.yg)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/common/protos-rs/README.md"},"Rust")," and ",(0,n.yg)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/common/protos-sol/README.md"},"Solidity")),(0,n.yg)("li",{parentName:"ul"},"Fabric Interoperation SDKs in ",(0,n.yg)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/sdks/fabric/interoperation-node-sdk/README.md"},"Node.js")," and ",(0,n.yg)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/sdks/fabric/go-sdk/readme.md"},"Golang")),(0,n.yg)("li",{parentName:"ul"},"Corda Interoperation SDK in ",(0,n.yg)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/sdks/corda/README.md"},"Kotlin/Java")," "),(0,n.yg)("li",{parentName:"ul"},"Besu Interoperation SDK in ",(0,n.yg)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/sdks/besu/interoperation-node-sdk/README.md"},"Node.js")," "),(0,n.yg)("li",{parentName:"ul"},"Sample ",(0,n.yg)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/samples/fabric"},"Fabric")," and ",(0,n.yg)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/samples/corda"},"Corda")," applications for experimentation and testing"),(0,n.yg)("li",{parentName:"ul"},(0,n.yg)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/tests/network-setups/fabric/dev/README.md"},"Fabric"),", ",(0,n.yg)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/tests/network-setups/corda/README.md"},"Corda"),", and ",(0,n.yg)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/tests/network-setups/besu/README.md"},"Besu")," test network setups")),(0,n.yg)("p",null,"The Weaver ",(0,n.yg)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/rfcs/README.md"},"RFCs")," contain detailed specifications of the models, data structures, protocols, and message formats."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/20a6a7d9.70d2e06a.js b/assets/js/20a6a7d9.70d2e06a.js deleted file mode 100644 index ff88c4388..000000000 --- a/assets/js/20a6a7d9.70d2e06a.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[4330],{3905:(e,t,r)=>{r.d(t,{Zo:()=>d,kt:()=>u});var a=r(7294);function n(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,a)}return r}function o(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?i(Object(r),!0).forEach((function(t){n(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):i(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function l(e,t){if(null==e)return{};var r,a,n=function(e,t){if(null==e)return{};var r,a,n={},i=Object.keys(e);for(a=0;a<i.length;a++)r=i[a],t.indexOf(r)>=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a<i.length;a++)r=i[a],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var s=a.createContext({}),p=function(e){var t=a.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},d=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},c="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},b=a.forwardRef((function(e,t){var r=e.components,n=e.mdxType,i=e.originalType,s=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),c=p(r),b=n,u=c["".concat(s,".").concat(b)]||c[b]||m[b]||i;return r?a.createElement(u,o(o({ref:t},d),{},{components:r})):a.createElement(u,o({ref:t},d))}));function u(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var i=r.length,o=new Array(i);o[0]=b;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:n,o[1]=l;for(var p=2;p<i;p++)o[p]=r[p];return a.createElement.apply(null,o)}return a.createElement.apply(null,r)}b.displayName="MDXCreateElement"},2383:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>m,frontMatter:()=>i,metadata:()=>l,toc:()=>p});var a=r(7462),n=(r(7294),r(3905));const i={id:"guide",title:"Using Weaver"},o=void 0,l={unversionedId:"external/getting-started/guide",id:"external/getting-started/guide",title:"Using Weaver",description:"\x3c!--",source:"@site/docs/external/getting-started/guide.md",sourceDirName:"external/getting-started",slug:"/external/getting-started/guide",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/guide",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/getting-started/guide.md",tags:[],version:"current",frontMatter:{id:"guide",title:"Using Weaver"},sidebar:"Documentation",previous:{title:"Weaver Framework",permalink:"/weaver-dlt-interoperability/docs/external/introduction"},next:{title:"Component Overview",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/overview"}},s={},p=[],d={toc:p},c="wrapper";function m(e){let{components:t,...r}=e;return(0,n.kt)(c,(0,a.Z)({},d,r,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("p",null,"The easiest way to understand how Weaver works is to run it at a small scale:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"First, ",(0,n.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/overview"},"launch a set of basic test networks")," built on Fabric, Corda and Besu. These networks offer the most basic capabilities of their DLT platforms and run toy applications (contracts and Layer-2) that can easily be tracked and debugged. You can launch these networks in one of several different ways: building Weaver components and dependencies locally or importing pre-built ones from Github packages, running core components in the host or in Docker containers. The choice depends on whether you just want to get these networks up and running or if you wish to customize the setup by modifying source code and configurations."),(0,n.kt)("li",{parentName:"ul"},"Once the test networks are launched, you can test two distinct kinds of interoperation modes:",(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/data-sharing"},"Data sharing"),": all combinations of Fabric and Corda networks supported"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview"},"Asset exchange"),": all pairs of network types from {Fabric, Corda, Besu} are supported"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-transfer"},"Asset transfer"),": all combinations of Fabric and Corda networks supported"))),(0,n.kt)("li",{parentName:"ul"},'(To bring down the test networks, go back to the "Setup" pages and follow instructions in the respective "Teardown" sections.)'),(0,n.kt)("li",{parentName:"ul"},'After you run these tests and get a flavor of how the system and protocols work, you will be ready to move on to "real" networks, enhancing them with interoperation capabilities by incorporating Weaver into them. Check out the guidelines and templates for ',(0,n.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/fabric"},"Fabric"),", ",(0,n.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/corda"},"Corda"),", and ",(0,n.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/besu"},"Besu")," networks.")),(0,n.kt)("p",null,"If you wish to go further and understand Weaver specifics, dig into the code, or contribute to the open-source project, check out the ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability"},"project repository"),". For specific information about individual Weaver components, see:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/core/relay/README.md"},"Relay")," module"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/core/drivers/fabric-driver/readme.md"},"Fabric")," and ",(0,n.kt)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/core/drivers/corda-driver/README.md"},"Corda")," drivers"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/core/network/fabric-interop-cc/README.md"},"Fabric Interoperation Chaincode"),", ",(0,n.kt)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/core/network/corda-interop-app/README.md"},"Interoperation CorDapp"),", and ",(0,n.kt)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/core/network/besu/README.md"},"Besu Interoperation Contract")),(0,n.kt)("li",{parentName:"ul"},"Common ",(0,n.kt)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/common/protos"},"protobufs"),": compiled in ",(0,n.kt)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/common/protos-js/README.md"},"JavaScript"),", ",(0,n.kt)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/common/protos-go/README.md"},"Golang"),", ",(0,n.kt)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/common/protos-java-kt/README.md"},"Java"),", ",(0,n.kt)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/common/protos-rs/README.md"},"Rust")," and ",(0,n.kt)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/common/protos-sol/README.md"},"Solidity")),(0,n.kt)("li",{parentName:"ul"},"Fabric Interoperation SDKs in ",(0,n.kt)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/sdks/fabric/interoperation-node-sdk/README.md"},"Node.js")," and ",(0,n.kt)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/sdks/fabric/go-sdk/readme.md"},"Golang")),(0,n.kt)("li",{parentName:"ul"},"Corda Interoperation SDK in ",(0,n.kt)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/sdks/corda/README.md"},"Kotlin/Java")," "),(0,n.kt)("li",{parentName:"ul"},"Besu Interoperation SDK in ",(0,n.kt)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/sdks/besu/interoperation-node-sdk/README.md"},"Node.js")," "),(0,n.kt)("li",{parentName:"ul"},"Sample ",(0,n.kt)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/samples/fabric"},"Fabric")," and ",(0,n.kt)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/samples/corda"},"Corda")," applications for experimentation and testing"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/tests/network-setups/fabric/dev/README.md"},"Fabric"),", ",(0,n.kt)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/tests/network-setups/corda/README.md"},"Corda"),", and ",(0,n.kt)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/tests/network-setups/besu/README.md"},"Besu")," test network setups")),(0,n.kt)("p",null,"The Weaver ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/rfcs/README.md"},"RFCs")," contain detailed specifications of the models, data structures, protocols, and message formats."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/239a9e81.5c089920.js b/assets/js/239a9e81.675cb60f.js similarity index 84% rename from assets/js/239a9e81.5c089920.js rename to assets/js/239a9e81.675cb60f.js index 22221b977..7c0b2c5d7 100644 --- a/assets/js/239a9e81.5c089920.js +++ b/assets/js/239a9e81.675cb60f.js @@ -1 +1 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[7900],{3905:(e,t,r)=>{r.d(t,{Zo:()=>c,kt:()=>u});var n=r(7294);function i(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function o(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?a(Object(r),!0).forEach((function(t){i(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):a(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function l(e,t){if(null==e)return{};var r,n,i=function(e,t){if(null==e)return{};var r,n,i={},a=Object.keys(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||(i[r]=e[r]);return i}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(i[r]=e[r])}return i}var p=n.createContext({}),s=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},c=function(e){var t=s(e.components);return n.createElement(p.Provider,{value:t},e.children)},d="mdxType",g={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},v=n.forwardRef((function(e,t){var r=e.components,i=e.mdxType,a=e.originalType,p=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),d=s(r),v=i,u=d["".concat(p,".").concat(v)]||d[v]||g[v]||a;return r?n.createElement(u,o(o({ref:t},c),{},{components:r})):n.createElement(u,o({ref:t},c))}));function u(e,t){var r=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var a=r.length,o=new Array(a);o[0]=v;var l={};for(var p in t)hasOwnProperty.call(t,p)&&(l[p]=t[p]);l.originalType=e,l[d]="string"==typeof e?e:i,o[1]=l;for(var s=2;s<a;s++)o[s]=r[s];return n.createElement.apply(null,o)}return n.createElement.apply(null,r)}v.displayName="MDXCreateElement"},7827:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>p,contentTitle:()=>o,default:()=>g,frontMatter:()=>a,metadata:()=>l,toc:()=>s});var n=r(7462),i=(r(7294),r(3905));const a={id:"overview",title:"Testing Interoperation Modes Overview",sidebar_label:"Overview",pagination_label:"Testing Interoperation Modes",pagination_prev:"external/getting-started/test-network/ledger-initialization"},o=void 0,l={unversionedId:"external/getting-started/interop/overview",id:"external/getting-started/interop/overview",title:"Testing Interoperation Modes Overview",description:"\x3c!--",source:"@site/docs/external/getting-started/interop/overview.md",sourceDirName:"external/getting-started/interop",slug:"/external/getting-started/interop/overview",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/overview",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/getting-started/interop/overview.md",tags:[],version:"current",frontMatter:{id:"overview",title:"Testing Interoperation Modes Overview",sidebar_label:"Overview",pagination_label:"Testing Interoperation Modes",pagination_prev:"external/getting-started/test-network/ledger-initialization"},sidebar:"Documentation",previous:{title:"Ledger Initialization",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/ledger-initialization"},next:{title:"Data Sharing",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/data-sharing"}},p={},s=[],c={toc:s},d="wrapper";function g(e){let{components:t,...r}=e;return(0,i.kt)(d,(0,n.Z)({},c,r,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"To test any of the interoperability modes supported by Weaver in test networks that have already been launched and bootstrapped, follow the appropriate link below."),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/data-sharing"},"Data Sharing")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview"},"Asset Exchange")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-transfer"},"Asset Transfer"))))}g.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[3919],{5680:(e,t,r)=>{r.d(t,{xA:()=>c,yg:()=>u});var n=r(6540);function i(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function o(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?a(Object(r),!0).forEach((function(t){i(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):a(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function l(e,t){if(null==e)return{};var r,n,i=function(e,t){if(null==e)return{};var r,n,i={},a=Object.keys(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||(i[r]=e[r]);return i}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(i[r]=e[r])}return i}var p=n.createContext({}),s=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},c=function(e){var t=s(e.components);return n.createElement(p.Provider,{value:t},e.children)},d="mdxType",g={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},v=n.forwardRef((function(e,t){var r=e.components,i=e.mdxType,a=e.originalType,p=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),d=s(r),v=i,u=d["".concat(p,".").concat(v)]||d[v]||g[v]||a;return r?n.createElement(u,o(o({ref:t},c),{},{components:r})):n.createElement(u,o({ref:t},c))}));function u(e,t){var r=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var a=r.length,o=new Array(a);o[0]=v;var l={};for(var p in t)hasOwnProperty.call(t,p)&&(l[p]=t[p]);l.originalType=e,l[d]="string"==typeof e?e:i,o[1]=l;for(var s=2;s<a;s++)o[s]=r[s];return n.createElement.apply(null,o)}return n.createElement.apply(null,r)}v.displayName="MDXCreateElement"},9746:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>p,contentTitle:()=>o,default:()=>g,frontMatter:()=>a,metadata:()=>l,toc:()=>s});var n=r(8168),i=(r(6540),r(5680));const a={id:"overview",title:"Testing Interoperation Modes Overview",sidebar_label:"Overview",pagination_label:"Testing Interoperation Modes",pagination_prev:"external/getting-started/test-network/ledger-initialization"},o=void 0,l={unversionedId:"external/getting-started/interop/overview",id:"external/getting-started/interop/overview",title:"Testing Interoperation Modes Overview",description:"\x3c!--",source:"@site/docs/external/getting-started/interop/overview.md",sourceDirName:"external/getting-started/interop",slug:"/external/getting-started/interop/overview",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/overview",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/getting-started/interop/overview.md",tags:[],version:"current",frontMatter:{id:"overview",title:"Testing Interoperation Modes Overview",sidebar_label:"Overview",pagination_label:"Testing Interoperation Modes",pagination_prev:"external/getting-started/test-network/ledger-initialization"},sidebar:"Documentation",previous:{title:"Ledger Initialization",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/ledger-initialization"},next:{title:"Data Sharing",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/data-sharing"}},p={},s=[],c={toc:s},d="wrapper";function g(e){let{components:t,...r}=e;return(0,i.yg)(d,(0,n.A)({},c,r,{components:t,mdxType:"MDXLayout"}),(0,i.yg)("p",null,"To test any of the interoperability modes supported by Weaver in test networks that have already been launched and bootstrapped, follow the appropriate link below."),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/data-sharing"},"Data Sharing")),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview"},"Asset Exchange")),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-transfer"},"Asset Transfer"))))}g.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/2435.fd066790.js b/assets/js/2435.fd066790.js new file mode 100644 index 000000000..85f11f1f5 --- /dev/null +++ b/assets/js/2435.fd066790.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[2435],{6669:(e,t,a)=>{a.d(t,{A:()=>h});var l=a(6540),r=a(53),n=a(5713),o=a(4581),s=a(5489),i=a(1312);const m={sidebar:"sidebar_re4s",sidebarItemTitle:"sidebarItemTitle_pO2u",sidebarItemList:"sidebarItemList_Yudw",sidebarItem:"sidebarItem__DBe",sidebarItemLink:"sidebarItemLink_mo7H",sidebarItemLinkActive:"sidebarItemLinkActive_I1ZP"};function c(e){let{sidebar:t}=e;return l.createElement("aside",{className:"col col--3"},l.createElement("nav",{className:(0,r.A)(m.sidebar,"thin-scrollbar"),"aria-label":(0,i.T)({id:"theme.blog.sidebar.navAriaLabel",message:"Blog recent posts navigation",description:"The ARIA label for recent posts in the blog sidebar"})},l.createElement("div",{className:(0,r.A)(m.sidebarItemTitle,"margin-bottom--md")},t.title),l.createElement("ul",{className:(0,r.A)(m.sidebarItemList,"clean-list")},t.items.map((e=>l.createElement("li",{key:e.permalink,className:m.sidebarItem},l.createElement(s.A,{isNavLink:!0,to:e.permalink,className:m.sidebarItemLink,activeClassName:m.sidebarItemLinkActive},e.title)))))))}var u=a(5600);function d(e){let{sidebar:t}=e;return l.createElement("ul",{className:"menu__list"},t.items.map((e=>l.createElement("li",{key:e.permalink,className:"menu__list-item"},l.createElement(s.A,{isNavLink:!0,to:e.permalink,className:"menu__link",activeClassName:"menu__link--active"},e.title)))))}function g(e){return l.createElement(u.GX,{component:d,props:e})}function p(e){let{sidebar:t}=e;const a=(0,o.l)();return t?.items.length?"mobile"===a?l.createElement(g,{sidebar:t}):l.createElement(c,{sidebar:t}):null}function h(e){const{sidebar:t,toc:a,children:o,...s}=e,i=t&&t.items.length>0;return l.createElement(n.A,s,l.createElement("div",{className:"container margin-vert--lg"},l.createElement("div",{className:"row"},l.createElement(p,{sidebar:t}),l.createElement("main",{className:(0,r.A)("col",{"col--7":i,"col--9 col--offset-1":!i}),itemScope:!0,itemType:"http://schema.org/Blog"},o),a&&l.createElement("div",{className:"col col--2"},a))))}},5623:(e,t,a)=>{a.d(t,{A:()=>U});var l=a(6540),r=a(53),n=a(7131),o=a(6025);function s(e){let{children:t,className:a}=e;const{frontMatter:r,assets:s}=(0,n.e)(),{withBaseUrl:i}=(0,o.h)(),m=s.image??r.image;return l.createElement("article",{className:a,itemProp:"blogPost",itemScope:!0,itemType:"http://schema.org/BlogPosting"},m&&l.createElement("meta",{itemProp:"image",content:i(m,{absolute:!0})}),t)}var i=a(5489);const m={title:"title_f1Hy"};function c(e){let{className:t}=e;const{metadata:a,isBlogPostPage:o}=(0,n.e)(),{permalink:s,title:c}=a,u=o?"h1":"h2";return l.createElement(u,{className:(0,r.A)(m.title,t),itemProp:"headline"},o?c:l.createElement(i.A,{itemProp:"url",to:s},c))}var u=a(1312),d=a(4586);const g=["zero","one","two","few","many","other"];function p(e){return g.filter((t=>e.includes(t)))}const h={locale:"en",pluralForms:p(["one","other"]),select:e=>1===e?"one":"other"};function b(){const{i18n:{currentLocale:e}}=(0,d.A)();return(0,l.useMemo)((()=>{try{return function(e){const t=new Intl.PluralRules(e);return{locale:e,pluralForms:p(t.resolvedOptions().pluralCategories),select:e=>t.select(e)}}(e)}catch(t){return console.error(`Failed to use Intl.PluralRules for locale "${e}".\nDocusaurus will fallback to the default (English) implementation.\nError: ${t.message}\n`),h}}),[e])}function E(){const e=b();return{selectMessage:(t,a)=>function(e,t,a){const l=e.split("|");if(1===l.length)return l[0];l.length>a.pluralForms.length&&console.error(`For locale=${a.locale}, a maximum of ${a.pluralForms.length} plural forms are expected (${a.pluralForms.join(",")}), but the message contains ${l.length}: ${e}`);const r=a.select(t),n=a.pluralForms.indexOf(r);return l[Math.min(n,l.length-1)]}(a,t,e)}}const f={container:"container_mt6G"};function v(e){let{readingTime:t}=e;const a=function(){const{selectMessage:e}=E();return t=>{const a=Math.ceil(t);return e(a,(0,u.T)({id:"theme.blog.post.readingTime.plurals",description:'Pluralized label for "{readingTime} min read". Use as much plural forms (separated by "|") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)',message:"One min read|{readingTime} min read"},{readingTime:a}))}}();return l.createElement(l.Fragment,null,a(t))}function P(e){let{date:t,formattedDate:a}=e;return l.createElement("time",{dateTime:t,itemProp:"datePublished"},a)}function A(){return l.createElement(l.Fragment,null," \xb7 ")}function N(e){let{className:t}=e;const{metadata:a}=(0,n.e)(),{date:o,formattedDate:s,readingTime:i}=a;return l.createElement("div",{className:(0,r.A)(f.container,"margin-vert--md",t)},l.createElement(P,{date:o,formattedDate:s}),void 0!==i&&l.createElement(l.Fragment,null,l.createElement(A,null),l.createElement(v,{readingTime:i})))}function _(e){return e.href?l.createElement(i.A,e):l.createElement(l.Fragment,null,e.children)}function k(e){let{author:t,className:a}=e;const{name:n,title:o,url:s,imageURL:i,email:m}=t,c=s||m&&`mailto:${m}`||void 0;return l.createElement("div",{className:(0,r.A)("avatar margin-bottom--sm",a)},i&&l.createElement(_,{href:c,className:"avatar__photo-link"},l.createElement("img",{className:"avatar__photo",src:i,alt:n})),n&&l.createElement("div",{className:"avatar__intro",itemProp:"author",itemScope:!0,itemType:"https://schema.org/Person"},l.createElement("div",{className:"avatar__name"},l.createElement(_,{href:c,itemProp:"url"},l.createElement("span",{itemProp:"name"},n))),o&&l.createElement("small",{className:"avatar__subtitle",itemProp:"description"},o)))}const T={authorCol:"authorCol_Hf19",imageOnlyAuthorRow:"imageOnlyAuthorRow_pa_O",imageOnlyAuthorCol:"imageOnlyAuthorCol_G86a"};function w(e){let{className:t}=e;const{metadata:{authors:a},assets:o}=(0,n.e)();if(0===a.length)return null;const s=a.every((e=>{let{name:t}=e;return!t}));return l.createElement("div",{className:(0,r.A)("margin-top--md margin-bottom--sm",s?T.imageOnlyAuthorRow:"row",t)},a.map(((e,t)=>l.createElement("div",{className:(0,r.A)(!s&&"col col--6",s?T.imageOnlyAuthorCol:T.authorCol),key:t},l.createElement(k,{author:{...e,imageURL:o.authorsImageUrls[t]??e.imageURL}})))))}function I(){return l.createElement("header",null,l.createElement(c,null),l.createElement(N,null),l.createElement(w,null))}var y=a(440),F=a(9717);function L(e){let{children:t,className:a}=e;const{isBlogPostPage:o}=(0,n.e)();return l.createElement("div",{id:o?y.blogPostContainerID:void 0,className:(0,r.A)("markdown",a),itemProp:"articleBody"},l.createElement(F.A,null,t))}var B=a(1943),C=a(8046),M=a(8168);function R(){return l.createElement("b",null,l.createElement(u.A,{id:"theme.blog.post.readMore",description:"The label used in blog post item excerpts to link to full blog posts"},"Read More"))}function O(e){const{blogPostTitle:t,...a}=e;return l.createElement(i.A,(0,M.A)({"aria-label":(0,u.T)({message:"Read more about {title}",id:"theme.blog.post.readMoreLabel",description:"The ARIA label for the link to full blog posts from excerpts"},{title:t})},a),l.createElement(R,null))}const x={blogPostFooterDetailsFull:"blogPostFooterDetailsFull_mRVl"};function D(){const{metadata:e,isBlogPostPage:t}=(0,n.e)(),{tags:a,title:o,editUrl:s,hasTruncateMarker:i}=e,m=!t&&i,c=a.length>0;return c||m||s?l.createElement("footer",{className:(0,r.A)("row docusaurus-mt-lg",t&&x.blogPostFooterDetailsFull)},c&&l.createElement("div",{className:(0,r.A)("col",{"col--9":m})},l.createElement(C.A,{tags:a})),t&&s&&l.createElement("div",{className:"col margin-top--sm"},l.createElement(B.A,{editUrl:s})),m&&l.createElement("div",{className:(0,r.A)("col text--right",{"col--3":c})},l.createElement(O,{blogPostTitle:o,to:e.permalink}))):null}function U(e){let{children:t,className:a}=e;const o=function(){const{isBlogPostPage:e}=(0,n.e)();return e?void 0:"margin-bottom--xl"}();return l.createElement(s,{className:(0,r.A)(o,a)},l.createElement(I,null),l.createElement(L,null,t),l.createElement(D,null))}},7131:(e,t,a)=>{a.d(t,{e:()=>s,i:()=>o});var l=a(6540),r=a(9532);const n=l.createContext(null);function o(e){let{children:t,content:a,isBlogPostPage:r=!1}=e;const o=function(e){let{content:t,isBlogPostPage:a}=e;return(0,l.useMemo)((()=>({metadata:t.metadata,frontMatter:t.frontMatter,assets:t.assets,toc:t.toc,isBlogPostPage:a})),[t,a])}({content:a,isBlogPostPage:r});return l.createElement(n.Provider,{value:o},t)}function s(){const e=(0,l.useContext)(n);if(null===e)throw new r.dV("BlogPostProvider");return e}}}]); \ No newline at end of file diff --git a/assets/js/2565.60f9ac1e.js b/assets/js/2565.60f9ac1e.js new file mode 100644 index 000000000..78149c19f --- /dev/null +++ b/assets/js/2565.60f9ac1e.js @@ -0,0 +1 @@ +(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[2565],{5680:(e,t,n)=>{"use strict";n.d(t,{xA:()=>u,yg:()=>f});var o=n(6540);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function c(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?r(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):r(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,o,a=function(e,t){if(null==e)return{};var n,o,a={},r=Object.keys(e);for(o=0;o<r.length;o++)n=r[o],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(o=0;o<r.length;o++)n=r[o],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var i=o.createContext({}),s=function(e){var t=o.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):c(c({},t),e)),n},u=function(e){var t=s(e.components);return o.createElement(i.Provider,{value:t},e.children)},m="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},p=o.forwardRef((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,i=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),m=s(n),p=a,f=m["".concat(i,".").concat(p)]||m[p]||d[p]||r;return n?o.createElement(f,c(c({ref:t},u),{},{components:n})):o.createElement(f,c({ref:t},u))}));function f(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,c=new Array(r);c[0]=p;var l={};for(var i in t)hasOwnProperty.call(t,i)&&(l[i]=t[i]);l.originalType=e,l[m]="string"==typeof e?e:a,c[1]=l;for(var s=2;s<r;s++)c[s]=n[s];return o.createElement.apply(null,c)}return o.createElement.apply(null,n)}p.displayName="MDXCreateElement"},1943:(e,t,n)=>{"use strict";n.d(t,{A:()=>u});var o=n(6540),a=n(1312),r=n(7559),c=n(8168),l=n(53);const i={iconEdit:"iconEdit_Z9Sw"};function s(e){let{className:t,...n}=e;return o.createElement("svg",(0,c.A)({fill:"currentColor",height:"20",width:"20",viewBox:"0 0 40 40",className:(0,l.A)(i.iconEdit,t),"aria-hidden":"true"},n),o.createElement("g",null,o.createElement("path",{d:"m34.5 11.7l-3 3.1-6.3-6.3 3.1-3q0.5-0.5 1.2-0.5t1.1 0.5l3.9 3.9q0.5 0.4 0.5 1.1t-0.5 1.2z m-29.5 17.1l18.4-18.5 6.3 6.3-18.4 18.4h-6.3v-6.2z"})))}function u(e){let{editUrl:t}=e;return o.createElement("a",{href:t,target:"_blank",rel:"noreferrer noopener",className:r.G.common.editThisPage},o.createElement(s,null),o.createElement(a.A,{id:"theme.common.editThisPage",description:"The link label to edit the current page"},"Edit this page"))}},1107:(e,t,n)=>{"use strict";n.d(t,{A:()=>s});var o=n(8168),a=n(6540),r=n(53),c=n(1312),l=n(6342);const i={anchorWithStickyNavbar:"anchorWithStickyNavbar_LWe7",anchorWithHideOnScrollNavbar:"anchorWithHideOnScrollNavbar_WYt5"};function s(e){let{as:t,id:n,...s}=e;const{navbar:{hideOnScroll:u}}=(0,l.p)();return"h1"!==t&&n?a.createElement(t,(0,o.A)({},s,{className:(0,r.A)("anchor",u?i.anchorWithHideOnScrollNavbar:i.anchorWithStickyNavbar),id:n}),s.children,a.createElement("a",{className:"hash-link",href:`#${n}`,title:(0,c.T)({id:"theme.common.headingLinkTitle",message:"Direct link to heading",description:"Title for link to heading"})},"\u200b")):a.createElement(t,(0,o.A)({},s,{id:void 0}))}},9717:(e,t,n)=>{"use strict";n.d(t,{A:()=>pe});var o=n(6540),a=n(5680),r=n(8168),c=n(5260);var l=n(2303),i=n(53),s=n(5293),u=n(6342);function m(){const{prism:e}=(0,u.p)(),{colorMode:t}=(0,s.G)(),n=e.theme,o=e.darkTheme||n;return"dark"===t?o:n}var d=n(7559),p=n(8426),f=n.n(p);const g=/title=(?<quote>["'])(?<title>.*?)\1/,h=/\{(?<range>[\d,-]+)\}/,y={js:{start:"\\/\\/",end:""},jsBlock:{start:"\\/\\*",end:"\\*\\/"},jsx:{start:"\\{\\s*\\/\\*",end:"\\*\\/\\s*\\}"},bash:{start:"#",end:""},html:{start:"\x3c!--",end:"--\x3e"}};function b(e,t){const n=e.map((e=>{const{start:n,end:o}=y[e];return`(?:${n}\\s*(${t.flatMap((e=>[e.line,e.block?.start,e.block?.end].filter(Boolean))).join("|")})\\s*${o})`})).join("|");return new RegExp(`^\\s*(?:${n})\\s*$`)}function v(e,t){let n=e.replace(/\n$/,"");const{language:o,magicComments:a,metastring:r}=t;if(r&&h.test(r)){const e=r.match(h).groups.range;if(0===a.length)throw new Error(`A highlight range has been given in code block's metastring (\`\`\` ${r}), but no magic comment config is available. Docusaurus applies the first magic comment entry's className for metastring ranges.`);const t=a[0].className,o=f()(e).filter((e=>e>0)).map((e=>[e-1,[t]]));return{lineClassNames:Object.fromEntries(o),code:n}}if(void 0===o)return{lineClassNames:{},code:n};const c=function(e,t){switch(e){case"js":case"javascript":case"ts":case"typescript":return b(["js","jsBlock"],t);case"jsx":case"tsx":return b(["js","jsBlock","jsx"],t);case"html":return b(["js","jsBlock","html"],t);case"python":case"py":case"bash":return b(["bash"],t);case"markdown":case"md":return b(["html","jsx","bash"],t);default:return b(Object.keys(y),t)}}(o,a),l=n.split("\n"),i=Object.fromEntries(a.map((e=>[e.className,{start:0,range:""}]))),s=Object.fromEntries(a.filter((e=>e.line)).map((e=>{let{className:t,line:n}=e;return[n,t]}))),u=Object.fromEntries(a.filter((e=>e.block)).map((e=>{let{className:t,block:n}=e;return[n.start,t]}))),m=Object.fromEntries(a.filter((e=>e.block)).map((e=>{let{className:t,block:n}=e;return[n.end,t]})));for(let p=0;p<l.length;){const e=l[p].match(c);if(!e){p+=1;continue}const t=e.slice(1).find((e=>void 0!==e));s[t]?i[s[t]].range+=`${p},`:u[t]?i[u[t]].start=p:m[t]&&(i[m[t]].range+=`${i[m[t]].start}-${p-1},`),l.splice(p,1)}n=l.join("\n");const d={};return Object.entries(i).forEach((e=>{let[t,{range:n}]=e;f()(n).forEach((e=>{d[e]??=[],d[e].push(t)}))})),{lineClassNames:d,code:n}}const E={codeBlockContainer:"codeBlockContainer_Ckt0"};function k(e){let{as:t,...n}=e;const a=function(e){const t={color:"--prism-color",backgroundColor:"--prism-background-color"},n={};return Object.entries(e.plain).forEach((e=>{let[o,a]=e;const r=t[o];r&&"string"==typeof a&&(n[r]=a)})),n}(m());return o.createElement(t,(0,r.A)({},n,{style:a,className:(0,i.A)(n.className,E.codeBlockContainer,d.G.common.codeBlock)}))}const N={codeBlockContent:"codeBlockContent_biex",codeBlockTitle:"codeBlockTitle_Ktv7",codeBlock:"codeBlock_bY9V",codeBlockStandalone:"codeBlockStandalone_MEMb",codeBlockLines:"codeBlockLines_e6Vv",codeBlockLinesWithNumbering:"codeBlockLinesWithNumbering_o6Pm",buttonGroup:"buttonGroup__atx"};function A(e){let{children:t,className:n}=e;return o.createElement(k,{as:"pre",tabIndex:0,className:(0,i.A)(N.codeBlockStandalone,"thin-scrollbar",n)},o.createElement("code",{className:N.codeBlockLines},t))}var C=n(9532);const w={attributes:!0,characterData:!0,childList:!0,subtree:!0};function B(e,t){const[n,a]=(0,o.useState)(),r=(0,o.useCallback)((()=>{a(e.current?.closest("[role=tabpanel][hidden]"))}),[e,a]);(0,o.useEffect)((()=>{r()}),[r]),function(e,t,n){void 0===n&&(n=w);const a=(0,C._q)(t),r=(0,C.Be)(n);(0,o.useEffect)((()=>{const t=new MutationObserver(a);return e&&t.observe(e,r),()=>t.disconnect()}),[e,a,r])}(n,(e=>{e.forEach((e=>{"attributes"===e.type&&"hidden"===e.attributeName&&(t(),r())}))}),{attributes:!0,characterData:!1,childList:!1,subtree:!1})}const T={plain:{backgroundColor:"#2a2734",color:"#9a86fd"},styles:[{types:["comment","prolog","doctype","cdata","punctuation"],style:{color:"#6c6783"}},{types:["namespace"],style:{opacity:.7}},{types:["tag","operator","number"],style:{color:"#e09142"}},{types:["property","function"],style:{color:"#9a86fd"}},{types:["tag-id","selector","atrule-id"],style:{color:"#eeebff"}},{types:["attr-name"],style:{color:"#c4b9fe"}},{types:["boolean","string","entity","url","attr-value","keyword","control","directive","unit","statement","regex","atrule","placeholder","variable"],style:{color:"#ffcc99"}},{types:["deleted"],style:{textDecorationLine:"line-through"}},{types:["inserted"],style:{textDecorationLine:"underline"}},{types:["italic"],style:{fontStyle:"italic"}},{types:["important","bold"],style:{fontWeight:"bold"}},{types:["important"],style:{color:"#c4b9fe"}}]};var _={Prism:n(1258).A,theme:T};function L(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function j(){return j=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var o in n)Object.prototype.hasOwnProperty.call(n,o)&&(e[o]=n[o])}return e},j.apply(this,arguments)}var x=/\r\n|\r|\n/,O=function(e){0===e.length?e.push({types:["plain"],content:"\n",empty:!0}):1===e.length&&""===e[0].content&&(e[0].content="\n",e[0].empty=!0)},S=function(e,t){var n=e.length;return n>0&&e[n-1]===t?e:e.concat(t)};function P(e,t){var n={};for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&-1===t.indexOf(o)&&(n[o]=e[o]);return n}var z=function(e){function t(){for(var t=this,n=[],o=arguments.length;o--;)n[o]=arguments[o];e.apply(this,n),L(this,"getThemeDict",(function(e){if(void 0!==t.themeDict&&e.theme===t.prevTheme&&e.language===t.prevLanguage)return t.themeDict;t.prevTheme=e.theme,t.prevLanguage=e.language;var n=e.theme?function(e,t){var n=e.plain,o=Object.create(null),a=e.styles.reduce((function(e,n){var o=n.languages,a=n.style;return o&&!o.includes(t)||n.types.forEach((function(t){var n=j({},e[t],a);e[t]=n})),e}),o);return a.root=n,a.plain=j({},n,{backgroundColor:null}),a}(e.theme,e.language):void 0;return t.themeDict=n})),L(this,"getLineProps",(function(e){var n=e.key,o=e.className,a=e.style,r=j({},P(e,["key","className","style","line"]),{className:"token-line",style:void 0,key:void 0}),c=t.getThemeDict(t.props);return void 0!==c&&(r.style=c.plain),void 0!==a&&(r.style=void 0!==r.style?j({},r.style,a):a),void 0!==n&&(r.key=n),o&&(r.className+=" "+o),r})),L(this,"getStyleForToken",(function(e){var n=e.types,o=e.empty,a=n.length,r=t.getThemeDict(t.props);if(void 0!==r){if(1===a&&"plain"===n[0])return o?{display:"inline-block"}:void 0;if(1===a&&!o)return r[n[0]];var c=o?{display:"inline-block"}:{},l=n.map((function(e){return r[e]}));return Object.assign.apply(Object,[c].concat(l))}})),L(this,"getTokenProps",(function(e){var n=e.key,o=e.className,a=e.style,r=e.token,c=j({},P(e,["key","className","style","token"]),{className:"token "+r.types.join(" "),children:r.content,style:t.getStyleForToken(r),key:void 0});return void 0!==a&&(c.style=void 0!==c.style?j({},c.style,a):a),void 0!==n&&(c.key=n),o&&(c.className+=" "+o),c})),L(this,"tokenize",(function(e,t,n,o){var a={code:t,grammar:n,language:o,tokens:[]};e.hooks.run("before-tokenize",a);var r=a.tokens=e.tokenize(a.code,a.grammar,a.language);return e.hooks.run("after-tokenize",a),r}))}return e&&(t.__proto__=e),t.prototype=Object.create(e&&e.prototype),t.prototype.constructor=t,t.prototype.render=function(){var e=this.props,t=e.Prism,n=e.language,o=e.code,a=e.children,r=this.getThemeDict(this.props),c=t.languages[n];return a({tokens:function(e){for(var t=[[]],n=[e],o=[0],a=[e.length],r=0,c=0,l=[],i=[l];c>-1;){for(;(r=o[c]++)<a[c];){var s=void 0,u=t[c],m=n[c][r];if("string"==typeof m?(u=c>0?u:["plain"],s=m):(u=S(u,m.type),m.alias&&(u=S(u,m.alias)),s=m.content),"string"==typeof s){var d=s.split(x),p=d.length;l.push({types:u,content:d[0]});for(var f=1;f<p;f++)O(l),i.push(l=[]),l.push({types:u,content:d[f]})}else c++,t.push(u),n.push(s),o.push(0),a.push(s.length)}c--,t.pop(),n.pop(),o.pop(),a.pop()}return O(l),i}(void 0!==c?this.tokenize(t,o,c,n):[o]),className:"prism-code language-"+n,style:void 0!==r?r.root:{},getLineProps:this.getLineProps,getTokenProps:this.getTokenProps})},t}(o.Component);const W=z,M={codeLine:"codeLine_lJS_",codeLineNumber:"codeLineNumber_Tfdd",codeLineContent:"codeLineContent_feaV"};function H(e){let{line:t,classNames:n,showLineNumbers:a,getLineProps:c,getTokenProps:l}=e;1===t.length&&"\n"===t[0].content&&(t[0].content="");const s=c({line:t,className:(0,i.A)(n,a&&M.codeLine)}),u=t.map(((e,t)=>o.createElement("span",(0,r.A)({key:t},l({token:e,key:t})))));return o.createElement("span",s,a?o.createElement(o.Fragment,null,o.createElement("span",{className:M.codeLineNumber}),o.createElement("span",{className:M.codeLineContent},u)):u,o.createElement("br",null))}var D=n(1312);const I={copyButtonCopied:"copyButtonCopied_obH4",copyButtonIcons:"copyButtonIcons_eSgA",copyButtonIcon:"copyButtonIcon_y97N",copyButtonSuccessIcon:"copyButtonSuccessIcon_LjdS"};function R(e){let{code:t,className:n}=e;const[a,r]=(0,o.useState)(!1),c=(0,o.useRef)(void 0),l=(0,o.useCallback)((()=>{!function(e,t){let{target:n=document.body}=void 0===t?{}:t;if("string"!=typeof e)throw new TypeError(`Expected parameter \`text\` to be a \`string\`, got \`${typeof e}\`.`);const o=document.createElement("textarea"),a=document.activeElement;o.value=e,o.setAttribute("readonly",""),o.style.contain="strict",o.style.position="absolute",o.style.left="-9999px",o.style.fontSize="12pt";const r=document.getSelection(),c=r.rangeCount>0&&r.getRangeAt(0);n.append(o),o.select(),o.selectionStart=0,o.selectionEnd=e.length;let l=!1;try{l=document.execCommand("copy")}catch{}o.remove(),c&&(r.removeAllRanges(),r.addRange(c)),a&&a.focus()}(t),r(!0),c.current=window.setTimeout((()=>{r(!1)}),1e3)}),[t]);return(0,o.useEffect)((()=>()=>window.clearTimeout(c.current)),[]),o.createElement("button",{type:"button","aria-label":a?(0,D.T)({id:"theme.CodeBlock.copied",message:"Copied",description:"The copied button label on code blocks"}):(0,D.T)({id:"theme.CodeBlock.copyButtonAriaLabel",message:"Copy code to clipboard",description:"The ARIA label for copy code blocks button"}),title:(0,D.T)({id:"theme.CodeBlock.copy",message:"Copy",description:"The copy button label on code blocks"}),className:(0,i.A)("clean-btn",n,I.copyButton,a&&I.copyButtonCopied),onClick:l},o.createElement("span",{className:I.copyButtonIcons,"aria-hidden":"true"},o.createElement("svg",{className:I.copyButtonIcon,viewBox:"0 0 24 24"},o.createElement("path",{d:"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"})),o.createElement("svg",{className:I.copyButtonSuccessIcon,viewBox:"0 0 24 24"},o.createElement("path",{d:"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"}))))}const V={wordWrapButtonIcon:"wordWrapButtonIcon_Bwma",wordWrapButtonEnabled:"wordWrapButtonEnabled_EoeP"};function $(e){let{className:t,onClick:n,isEnabled:a}=e;const r=(0,D.T)({id:"theme.CodeBlock.wordWrapToggle",message:"Toggle word wrap",description:"The title attribute for toggle word wrapping button of code block lines"});return o.createElement("button",{type:"button",onClick:n,className:(0,i.A)("clean-btn",t,a&&V.wordWrapButtonEnabled),"aria-label":r,title:r},o.createElement("svg",{className:V.wordWrapButtonIcon,viewBox:"0 0 24 24","aria-hidden":"true"},o.createElement("path",{fill:"currentColor",d:"M4 19h6v-2H4v2zM20 5H4v2h16V5zm-3 6H4v2h13.25c1.1 0 2 .9 2 2s-.9 2-2 2H15v-2l-3 3l3 3v-2h2c2.21 0 4-1.79 4-4s-1.79-4-4-4z"})))}function G(e){let{children:t,className:n="",metastring:a,title:c,showLineNumbers:l,language:s}=e;const{prism:{defaultLanguage:d,magicComments:p}}=(0,u.p)(),f=s??function(e){const t=e.split(" ").find((e=>e.startsWith("language-")));return t?.replace(/language-/,"")}(n)??d,h=m(),y=function(){const[e,t]=(0,o.useState)(!1),[n,a]=(0,o.useState)(!1),r=(0,o.useRef)(null),c=(0,o.useCallback)((()=>{const n=r.current.querySelector("code");e?n.removeAttribute("style"):(n.style.whiteSpace="pre-wrap",n.style.overflowWrap="anywhere"),t((e=>!e))}),[r,e]),l=(0,o.useCallback)((()=>{const{scrollWidth:e,clientWidth:t}=r.current,n=e>t||r.current.querySelector("code").hasAttribute("style");a(n)}),[r]);return B(r,l),(0,o.useEffect)((()=>{l()}),[e,l]),(0,o.useEffect)((()=>(window.addEventListener("resize",l,{passive:!0}),()=>{window.removeEventListener("resize",l)})),[l]),{codeBlockRef:r,isEnabled:e,isCodeScrollable:n,toggle:c}}(),b=function(e){return e?.match(g)?.groups.title??""}(a)||c,{lineClassNames:E,code:A}=v(t,{metastring:a,language:f,magicComments:p}),C=l??function(e){return Boolean(e?.includes("showLineNumbers"))}(a);return o.createElement(k,{as:"div",className:(0,i.A)(n,f&&!n.includes(`language-${f}`)&&`language-${f}`)},b&&o.createElement("div",{className:N.codeBlockTitle},b),o.createElement("div",{className:N.codeBlockContent},o.createElement(W,(0,r.A)({},_,{theme:h,code:A,language:f??"text"}),(e=>{let{className:t,tokens:n,getLineProps:a,getTokenProps:r}=e;return o.createElement("pre",{tabIndex:0,ref:y.codeBlockRef,className:(0,i.A)(t,N.codeBlock,"thin-scrollbar")},o.createElement("code",{className:(0,i.A)(N.codeBlockLines,C&&N.codeBlockLinesWithNumbering)},n.map(((e,t)=>o.createElement(H,{key:t,line:e,getLineProps:a,getTokenProps:r,classNames:E[t],showLineNumbers:C})))))})),o.createElement("div",{className:N.buttonGroup},(y.isEnabled||y.isCodeScrollable)&&o.createElement($,{className:N.codeButton,onClick:()=>y.toggle(),isEnabled:y.isEnabled}),o.createElement(R,{className:N.codeButton,code:A}))))}function q(e){let{children:t,...n}=e;const a=(0,l.A)(),c=function(e){return o.Children.toArray(e).some((e=>(0,o.isValidElement)(e)))?e:Array.isArray(e)?e.join(""):e}(t),i="string"==typeof c?G:A;return o.createElement(i,(0,r.A)({key:String(a)},n),c)}var F=n(5489);var U=n(1422);const Y={details:"details_lb9f",isBrowser:"isBrowser_bmU9",collapsibleContent:"collapsibleContent_i85q"};function Z(e){return!!e&&("SUMMARY"===e.tagName||Z(e.parentElement))}function Q(e,t){return!!e&&(e===t||Q(e.parentElement,t))}function X(e){let{summary:t,children:n,...a}=e;const c=(0,l.A)(),s=(0,o.useRef)(null),{collapsed:u,setCollapsed:m}=(0,U.u)({initialState:!a.open}),[d,p]=(0,o.useState)(a.open);return o.createElement("details",(0,r.A)({},a,{ref:s,open:d,"data-collapsed":u,className:(0,i.A)(Y.details,c&&Y.isBrowser,a.className),onMouseDown:e=>{Z(e.target)&&e.detail>1&&e.preventDefault()},onClick:e=>{e.stopPropagation();const t=e.target;Z(t)&&Q(t,s.current)&&(e.preventDefault(),u?(m(!1),p(!0)):m(!0))}}),t??o.createElement("summary",null,"Details"),o.createElement(U.N,{lazy:!1,collapsed:u,disableSSRStyle:!0,onCollapseTransitionEnd:e=>{m(e),p(!e)}},o.createElement("div",{className:Y.collapsibleContent},n)))}const J={details:"details_b_Ee"},K="alert alert--info";function ee(e){let{...t}=e;return o.createElement(X,(0,r.A)({},t,{className:(0,i.A)(K,J.details,t.className)}))}var te=n(1107);function ne(e){return o.createElement(te.A,e)}const oe={containsTaskList:"containsTaskList_mC6p"};const ae={img:"img_ev3q"};const re="admonition_LlT9",ce="admonitionHeading_tbUL",le="admonitionIcon_kALy",ie="admonitionContent_S0QG";const se={note:{infimaClassName:"secondary",iconComponent:function(){return o.createElement("svg",{viewBox:"0 0 14 16"},o.createElement("path",{fillRule:"evenodd",d:"M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"}))},label:o.createElement(D.A,{id:"theme.admonition.note",description:"The default label used for the Note admonition (:::note)"},"note")},tip:{infimaClassName:"success",iconComponent:function(){return o.createElement("svg",{viewBox:"0 0 12 16"},o.createElement("path",{fillRule:"evenodd",d:"M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"}))},label:o.createElement(D.A,{id:"theme.admonition.tip",description:"The default label used for the Tip admonition (:::tip)"},"tip")},danger:{infimaClassName:"danger",iconComponent:function(){return o.createElement("svg",{viewBox:"0 0 12 16"},o.createElement("path",{fillRule:"evenodd",d:"M5.05.31c.81 2.17.41 3.38-.52 4.31C3.55 5.67 1.98 6.45.9 7.98c-1.45 2.05-1.7 6.53 3.53 7.7-2.2-1.16-2.67-4.52-.3-6.61-.61 2.03.53 3.33 1.94 2.86 1.39-.47 2.3.53 2.27 1.67-.02.78-.31 1.44-1.13 1.81 3.42-.59 4.78-3.42 4.78-5.56 0-2.84-2.53-3.22-1.25-5.61-1.52.13-2.03 1.13-1.89 2.75.09 1.08-1.02 1.8-1.86 1.33-.67-.41-.66-1.19-.06-1.78C8.18 5.31 8.68 2.45 5.05.32L5.03.3l.02.01z"}))},label:o.createElement(D.A,{id:"theme.admonition.danger",description:"The default label used for the Danger admonition (:::danger)"},"danger")},info:{infimaClassName:"info",iconComponent:function(){return o.createElement("svg",{viewBox:"0 0 14 16"},o.createElement("path",{fillRule:"evenodd",d:"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"}))},label:o.createElement(D.A,{id:"theme.admonition.info",description:"The default label used for the Info admonition (:::info)"},"info")},caution:{infimaClassName:"warning",iconComponent:function(){return o.createElement("svg",{viewBox:"0 0 16 16"},o.createElement("path",{fillRule:"evenodd",d:"M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"}))},label:o.createElement(D.A,{id:"theme.admonition.caution",description:"The default label used for the Caution admonition (:::caution)"},"caution")}},ue={secondary:"note",important:"info",success:"tip",warning:"danger"};function me(e){const{mdxAdmonitionTitle:t,rest:n}=function(e){const t=o.Children.toArray(e),n=t.find((e=>o.isValidElement(e)&&"mdxAdmonitionTitle"===e.props?.mdxType)),a=o.createElement(o.Fragment,null,t.filter((e=>e!==n)));return{mdxAdmonitionTitle:n,rest:a}}(e.children);return{...e,title:e.title??t,children:n}}const de={head:function(e){const t=o.Children.map(e.children,(e=>o.isValidElement(e)?function(e){if(e.props?.mdxType&&e.props.originalType){const{mdxType:t,originalType:n,...a}=e.props;return o.createElement(e.props.originalType,a)}return e}(e):e));return o.createElement(c.A,e,t)},code:function(e){const t=["a","abbr","b","br","button","cite","code","del","dfn","em","i","img","input","ins","kbd","label","object","output","q","ruby","s","small","span","strong","sub","sup","time","u","var","wbr"];return o.Children.toArray(e.children).every((e=>"string"==typeof e&&!e.includes("\n")||(0,o.isValidElement)(e)&&t.includes(e.props?.mdxType)))?o.createElement("code",e):o.createElement(q,e)},a:function(e){return o.createElement(F.A,e)},pre:function(e){return o.createElement(q,(0,o.isValidElement)(e.children)&&"code"===e.children.props?.originalType?e.children.props:{...e})},details:function(e){const t=o.Children.toArray(e.children),n=t.find((e=>o.isValidElement(e)&&"summary"===e.props?.mdxType)),a=o.createElement(o.Fragment,null,t.filter((e=>e!==n)));return o.createElement(ee,(0,r.A)({},e,{summary:n}),a)},ul:function(e){return o.createElement("ul",(0,r.A)({},e,{className:(t=e.className,(0,i.A)(t,t?.includes("contains-task-list")&&oe.containsTaskList))}));var t},img:function(e){return o.createElement("img",(0,r.A)({loading:"lazy"},e,{className:(t=e.className,(0,i.A)(t,ae.img))}));var t},h1:e=>o.createElement(ne,(0,r.A)({as:"h1"},e)),h2:e=>o.createElement(ne,(0,r.A)({as:"h2"},e)),h3:e=>o.createElement(ne,(0,r.A)({as:"h3"},e)),h4:e=>o.createElement(ne,(0,r.A)({as:"h4"},e)),h5:e=>o.createElement(ne,(0,r.A)({as:"h5"},e)),h6:e=>o.createElement(ne,(0,r.A)({as:"h6"},e)),admonition:function(e){const{children:t,type:n,title:a,icon:r}=me(e),c=function(e){const t=ue[e]??e,n=se[t];return n||(console.warn(`No admonition config found for admonition type "${t}". Using Info as fallback.`),se.info)}(n),l=a??c.label,{iconComponent:s}=c,u=r??o.createElement(s,null);return o.createElement("div",{className:(0,i.A)(d.G.common.admonition,d.G.common.admonitionType(e.type),"alert",`alert--${c.infimaClassName}`,re)},o.createElement("div",{className:ce},o.createElement("span",{className:le},u),l),o.createElement("div",{className:ie},t))},mermaid:n(418).A};function pe(e){let{children:t}=e;return o.createElement(a.xA,{components:de},t)}},9022:(e,t,n)=>{"use strict";n.d(t,{A:()=>c});var o=n(6540),a=n(53),r=n(5489);function c(e){const{permalink:t,title:n,subLabel:c,isNext:l}=e;return o.createElement(r.A,{className:(0,a.A)("pagination-nav__link",l?"pagination-nav__link--next":"pagination-nav__link--prev"),to:t},c&&o.createElement("div",{className:"pagination-nav__sublabel"},c),o.createElement("div",{className:"pagination-nav__label"},n))}},8046:(e,t,n)=>{"use strict";n.d(t,{A:()=>u});var o=n(6540),a=n(53),r=n(1312),c=n(5489);const l={tag:"tag_zVej",tagRegular:"tagRegular_sFm0",tagWithCount:"tagWithCount_h2kH"};function i(e){let{permalink:t,label:n,count:r}=e;return o.createElement(c.A,{href:t,className:(0,a.A)(l.tag,r?l.tagWithCount:l.tagRegular)},n,r&&o.createElement("span",null,r))}const s={tags:"tags_jXut",tag:"tag_QGVx"};function u(e){let{tags:t}=e;return o.createElement(o.Fragment,null,o.createElement("b",null,o.createElement(r.A,{id:"theme.tags.tagsListLabel",description:"The label alongside a tag list"},"Tags:")),o.createElement("ul",{className:(0,a.A)(s.tags,"padding--none","margin-left--sm")},t.map((e=>{let{label:t,permalink:n}=e;return o.createElement("li",{key:n,className:s.tag},o.createElement(i,{label:t,permalink:n}))}))))}},8426:(e,t)=>{function n(e){let t,n=[];for(let o of e.split(",").map((e=>e.trim())))if(/^-?\d+$/.test(o))n.push(parseInt(o,10));else if(t=o.match(/^(-?\d+)(-|\.\.\.?|\u2025|\u2026|\u22EF)(-?\d+)$/)){let[e,o,a,r]=t;if(o&&r){o=parseInt(o),r=parseInt(r);const e=o<r?1:-1;"-"!==a&&".."!==a&&"\u2025"!==a||(r+=e);for(let t=o;t!==r;t+=e)n.push(t)}}return n}t.default=n,e.exports=n}}]); \ No newline at end of file diff --git a/assets/js/25e7257c.57659e76.js b/assets/js/25e7257c.57659e76.js deleted file mode 100644 index 5592f751a..000000000 --- a/assets/js/25e7257c.57659e76.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[7376],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>k});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,a,r=function(e,t){if(null==e)return{};var n,a,r={},i=Object.keys(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=a.createContext({}),c=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=c(e.components);return a.createElement(s.Provider,{value:t},e.children)},d="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},b=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),d=c(n),b=r,k=d["".concat(s,".").concat(b)]||d[b]||m[b]||i;return n?a.createElement(k,o(o({ref:t},p),{},{components:n})):a.createElement(k,o({ref:t},p))}));function k(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,o=new Array(i);o[0]=b;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[d]="string"==typeof e?e:r,o[1]=l;for(var c=2;c<i;c++)o[c]=n[c];return a.createElement.apply(null,o)}return a.createElement.apply(null,n)}b.displayName="MDXCreateElement"},7532:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>m,frontMatter:()=>i,metadata:()=>l,toc:()=>c});var a=n(7462),r=(n(7294),n(3905));const i={id:"fabric-besu",title:"Asset Exchange: Fabric with Besu",sidebar_label:"Fabric with Besu",pagination_label:"Fabric with Besu",pagination_prev:"external/getting-started/interop/asset-exchange/overview"},o=void 0,l={unversionedId:"external/getting-started/interop/asset-exchange/fabric-besu",id:"external/getting-started/interop/asset-exchange/fabric-besu",title:"Asset Exchange: Fabric with Besu",description:"We will demonstrate asset exchange of a bond in Fabric network1 with 10 BobERC20 tokens on Besu network2.",source:"@site/docs/external/getting-started/interop/asset-exchange/fabric-besu.md",sourceDirName:"external/getting-started/interop/asset-exchange",slug:"/external/getting-started/interop/asset-exchange/fabric-besu",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-besu",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/getting-started/interop/asset-exchange/fabric-besu.md",tags:[],version:"current",frontMatter:{id:"fabric-besu",title:"Asset Exchange: Fabric with Besu",sidebar_label:"Fabric with Besu",pagination_label:"Fabric with Besu",pagination_prev:"external/getting-started/interop/asset-exchange/overview"},sidebar:"Documentation",previous:{title:"Asset Exchange",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview"},next:{title:"Corda with Corda",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/corda-corda"}},s={},c=[],p={toc:c},d="wrapper";function m(e){let{components:t,...n}=e;return(0,r.kt)(d,(0,a.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"We will demonstrate asset exchange of a bond in Fabric ",(0,r.kt)("inlineCode",{parentName:"p"},"network1")," with ",(0,r.kt)("inlineCode",{parentName:"p"},"10 BobERC20")," tokens on Besu ",(0,r.kt)("inlineCode",{parentName:"p"},"network2"),".\nFor Fabric commands, run from ",(0,r.kt)("inlineCode",{parentName:"p"},"samples/fabric/fabric-cli")," folder, and for Besu commands, run from ",(0,r.kt)("inlineCode",{parentName:"p"},"ssamples/besu/besu-cli")," folder. Here ",(0,r.kt)("inlineCode",{parentName:"p"},"Alice")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"Bob")," in Fabric ",(0,r.kt)("inlineCode",{parentName:"p"},"network1")," correspond to account ",(0,r.kt)("inlineCode",{parentName:"p"},"1")," and account ",(0,r.kt)("inlineCode",{parentName:"p"},"2")," in Besu ",(0,r.kt)("inlineCode",{parentName:"p"},"network2")," respectively. Following are the step-by-step asset exchange process:"),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:"left"},"The hash used in following steps can be replaced by any valid ",(0,r.kt)("inlineCode",{parentName:"td"},"SHA256")," hash.")))),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"From ",(0,r.kt)("inlineCode",{parentName:"li"},"fabric-cli"),", generate secret-hash pair using following command (prints hash in base64):",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},"./bin/fabric-cli hash --hash_fn=SHA256 secrettext\n"))),(0,r.kt)("li",{parentName:"ul"},"Run the following to verify the status of the bond assets owned by ",(0,r.kt)("inlineCode",{parentName:"li"},"alice")," and ",(0,r.kt)("inlineCode",{parentName:"li"},"bob")," in the Fabric network ",(0,r.kt)("inlineCode",{parentName:"li"},"network1")," from ",(0,r.kt)("inlineCode",{parentName:"li"},"samples/fabric/fabric-cli")," folder:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"./scripts/getAssetStatus.sh\n"))),(0,r.kt)("li",{parentName:"ul"},"Run the following in ",(0,r.kt)("inlineCode",{parentName:"li"},"besu-cli"),", to verify the status of the assets owned by ",(0,r.kt)("inlineCode",{parentName:"li"},"Alice")," and ",(0,r.kt)("inlineCode",{parentName:"li"},"Bob")," in the Besu network ",(0,r.kt)("inlineCode",{parentName:"li"},"network2"),":",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset get-balance --network=network2 --account=1\n./bin/besu-cli asset get-balance --network=network2 --account=2\n"))),(0,r.kt)("li",{parentName:"ul"},"Run the following to trigger ",(0,r.kt)("inlineCode",{parentName:"li"},"alice")," locking ",(0,r.kt)("inlineCode",{parentName:"li"},"bond01:a03")," for ",(0,r.kt)("inlineCode",{parentName:"li"},"bob")," in ",(0,r.kt)("inlineCode",{parentName:"li"},"network1")," for 60 mins:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset exchange lock --timeout-duration=3600 --locker=alice --recipient=bob --hashBase64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs= --target-network=network1 --param=bond01:a03\n"))),(0,r.kt)("li",{parentName:"ul"},"Run the following to verify ",(0,r.kt)("inlineCode",{parentName:"li"},"alice"),"'s lock:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset exchange is-locked --locker=alice --recipient=bob --target-network=network1 --param=bond01:a03\n"))),(0,r.kt)("li",{parentName:"ul"},"Run the following to trigger ",(0,r.kt)("inlineCode",{parentName:"li"},"bob")," locking ",(0,r.kt)("inlineCode",{parentName:"li"},"10")," units of ",(0,r.kt)("inlineCode",{parentName:"li"},"BobERC20")," tokens for ",(0,r.kt)("inlineCode",{parentName:"li"},"alice")," in ",(0,r.kt)("inlineCode",{parentName:"li"},"network2")," for 30 mins:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset lock --network=network2 --sender_account=2 --recipient_account=1 --amount=10 --timeout=1800 --hash_base64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs=\n")),"Note the ",(0,r.kt)("inlineCode",{parentName:"li"},"contract-id")," printed as output in above command. The output line containing ",(0,r.kt)("inlineCode",{parentName:"li"},"contract-id")," (text in base64 after ",(0,r.kt)("inlineCode",{parentName:"li"},"Lock contract ID:"),") would like this:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"Lock contract ID: 48f59da2ac632117bf79b4aa986f5ece8a2439dc143d576965c17bc8275b0925\n")),"Let's refer it ",(0,r.kt)("inlineCode",{parentName:"li"},"<contract-id-2>")," for this demonstration."),(0,r.kt)("li",{parentName:"ul"},"Run the following to verify ",(0,r.kt)("inlineCode",{parentName:"li"},"bob"),"'s lock:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset is-locked --network=network2 --lock_contract_id=<contract-id-2>\n"))),(0,r.kt)("li",{parentName:"ul"},"Run the following to trigger ",(0,r.kt)("inlineCode",{parentName:"li"},"alice"),"'s claim for ",(0,r.kt)("inlineCode",{parentName:"li"},"10")," units of ",(0,r.kt)("inlineCode",{parentName:"li"},"BobERC20")," tokens locked by ",(0,r.kt)("inlineCode",{parentName:"li"},"bob")," in ",(0,r.kt)("inlineCode",{parentName:"li"},"network2"),":",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset claim --network=network2 --recipient_account=1 --preimage=secrettext --lock_contract_id=<contract-id-2>\n"))),(0,r.kt)("li",{parentName:"ul"},"Run the following to trigger ",(0,r.kt)("inlineCode",{parentName:"li"},"bob"),"'s claim for ",(0,r.kt)("inlineCode",{parentName:"li"},"bond01:a03")," locked by ",(0,r.kt)("inlineCode",{parentName:"li"},"alice")," in ",(0,r.kt)("inlineCode",{parentName:"li"},"network1"),":",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset exchange claim --recipient=bob --locker=alice --target-network=network1 --param=bond01:a03 --secret=secrettext\n"))),(0,r.kt)("li",{parentName:"ul"},"Run the following to verify the status of the bond assets owned by ",(0,r.kt)("inlineCode",{parentName:"li"},"alice")," and ",(0,r.kt)("inlineCode",{parentName:"li"},"bob")," in the Fabric network ",(0,r.kt)("inlineCode",{parentName:"li"},"network1")," from ",(0,r.kt)("inlineCode",{parentName:"li"},"samples/fabric/fabric-cli")," folder:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"./scripts/getAssetStatus.sh\n"))),(0,r.kt)("li",{parentName:"ul"},"Run the following in ",(0,r.kt)("inlineCode",{parentName:"li"},"besu-cli"),", to verify the status of the assets owned by ",(0,r.kt)("inlineCode",{parentName:"li"},"Alice")," and ",(0,r.kt)("inlineCode",{parentName:"li"},"Bob")," in the Besu network ",(0,r.kt)("inlineCode",{parentName:"li"},"network2"),":",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset get-balance --network=network2 --account=1\n./bin/besu-cli asset get-balance --network=network2 --account=2\n")))),(0,r.kt)("p",null,"The above steps complete a successful asset exchange between Fabric and Corda networks.\nIn addition to the above commands, following commands can be run if specified timeout has expired and the locked asset remains unclaimed."),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"If ",(0,r.kt)("inlineCode",{parentName:"li"},"alice")," wants to unlock the bond asset, run the following to trigger ",(0,r.kt)("inlineCode",{parentName:"li"},"alice"),"'s re-claim for ",(0,r.kt)("inlineCode",{parentName:"li"},"bond01:a03")," locked in ",(0,r.kt)("inlineCode",{parentName:"li"},"network1"),":",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset exchange unlock --locker=alice --recipient=bob --target-network=network1 --param=bond01:a03\n"))),(0,r.kt)("li",{parentName:"ul"},"If ",(0,r.kt)("inlineCode",{parentName:"li"},"bob")," wants to unlock the token asset, run the following to trigger ",(0,r.kt)("inlineCode",{parentName:"li"},"bob"),"'s re-claim for ",(0,r.kt)("inlineCode",{parentName:"li"},"50 BobERC20")," tokens locked in ",(0,r.kt)("inlineCode",{parentName:"li"},"network2"),":",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset unlock --network=network2 --lock_contract_id=<contract-id-2> --sender_account=2\n")))))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/25e7257c.5dcf7b40.js b/assets/js/25e7257c.5dcf7b40.js new file mode 100644 index 000000000..2ec3c4c21 --- /dev/null +++ b/assets/js/25e7257c.5dcf7b40.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[3433],{5680:(e,n,a)=>{a.d(n,{xA:()=>p,yg:()=>b});var t=a(6540);function r(e,n,a){return n in e?Object.defineProperty(e,n,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[n]=a,e}function i(e,n){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var t=Object.getOwnPropertySymbols(e);n&&(t=t.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),a.push.apply(a,t)}return a}function o(e){for(var n=1;n<arguments.length;n++){var a=null!=arguments[n]?arguments[n]:{};n%2?i(Object(a),!0).forEach((function(n){r(e,n,a[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(a)):i(Object(a)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(a,n))}))}return e}function l(e,n){if(null==e)return{};var a,t,r=function(e,n){if(null==e)return{};var a,t,r={},i=Object.keys(e);for(t=0;t<i.length;t++)a=i[t],n.indexOf(a)>=0||(r[a]=e[a]);return r}(e,n);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(t=0;t<i.length;t++)a=i[t],n.indexOf(a)>=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var s=t.createContext({}),c=function(e){var n=t.useContext(s),a=n;return e&&(a="function"==typeof e?e(n):o(o({},n),e)),a},p=function(e){var n=c(e.components);return t.createElement(s.Provider,{value:n},e.children)},g="mdxType",d={inlineCode:"code",wrapper:function(e){var n=e.children;return t.createElement(t.Fragment,{},n)}},m=t.forwardRef((function(e,n){var a=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),g=c(a),m=r,b=g["".concat(s,".").concat(m)]||g[m]||d[m]||i;return a?t.createElement(b,o(o({ref:n},p),{},{components:a})):t.createElement(b,o({ref:n},p))}));function b(e,n){var a=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var i=a.length,o=new Array(i);o[0]=m;var l={};for(var s in n)hasOwnProperty.call(n,s)&&(l[s]=n[s]);l.originalType=e,l[g]="string"==typeof e?e:r,o[1]=l;for(var c=2;c<i;c++)o[c]=a[c];return t.createElement.apply(null,o)}return t.createElement.apply(null,a)}m.displayName="MDXCreateElement"},7717:(e,n,a)=>{a.r(n),a.d(n,{assets:()=>s,contentTitle:()=>o,default:()=>d,frontMatter:()=>i,metadata:()=>l,toc:()=>c});var t=a(8168),r=(a(6540),a(5680));const i={id:"fabric-besu",title:"Asset Exchange: Fabric with Besu",sidebar_label:"Fabric with Besu",pagination_label:"Fabric with Besu",pagination_prev:"external/getting-started/interop/asset-exchange/overview"},o=void 0,l={unversionedId:"external/getting-started/interop/asset-exchange/fabric-besu",id:"external/getting-started/interop/asset-exchange/fabric-besu",title:"Asset Exchange: Fabric with Besu",description:"We will demonstrate asset exchange of a bond in Fabric network1 with 10 BobERC20 tokens on Besu network2.",source:"@site/docs/external/getting-started/interop/asset-exchange/fabric-besu.md",sourceDirName:"external/getting-started/interop/asset-exchange",slug:"/external/getting-started/interop/asset-exchange/fabric-besu",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-besu",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/getting-started/interop/asset-exchange/fabric-besu.md",tags:[],version:"current",frontMatter:{id:"fabric-besu",title:"Asset Exchange: Fabric with Besu",sidebar_label:"Fabric with Besu",pagination_label:"Fabric with Besu",pagination_prev:"external/getting-started/interop/asset-exchange/overview"},sidebar:"Documentation",previous:{title:"Asset Exchange",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview"},next:{title:"Corda with Corda",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/corda-corda"}},s={},c=[],p={toc:c},g="wrapper";function d(e){let{components:n,...a}=e;return(0,r.yg)(g,(0,t.A)({},p,a,{components:n,mdxType:"MDXLayout"}),(0,r.yg)("p",null,"We will demonstrate asset exchange of a bond in Fabric ",(0,r.yg)("inlineCode",{parentName:"p"},"network1")," with ",(0,r.yg)("inlineCode",{parentName:"p"},"10 BobERC20")," tokens on Besu ",(0,r.yg)("inlineCode",{parentName:"p"},"network2"),".\nFor Fabric commands, run from ",(0,r.yg)("inlineCode",{parentName:"p"},"samples/fabric/fabric-cli")," folder, and for Besu commands, run from ",(0,r.yg)("inlineCode",{parentName:"p"},"samples/besu/besu-cli")," folder, in your clone of the Weaver repository. Here ",(0,r.yg)("inlineCode",{parentName:"p"},"Alice")," and ",(0,r.yg)("inlineCode",{parentName:"p"},"Bob")," in Fabric ",(0,r.yg)("inlineCode",{parentName:"p"},"network1")," correspond to account ",(0,r.yg)("inlineCode",{parentName:"p"},"1")," and account ",(0,r.yg)("inlineCode",{parentName:"p"},"2")," in Besu ",(0,r.yg)("inlineCode",{parentName:"p"},"network2")," respectively. Following are the step-by-step asset exchange process:"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:"left"},"The hash used in following steps can be replaced by any valid ",(0,r.yg)("inlineCode",{parentName:"td"},"SHA256")," hash.")))),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"From ",(0,r.yg)("inlineCode",{parentName:"li"},"fabric-cli"),", generate secret-hash pair using following command (prints hash in base64):",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre"},"./bin/fabric-cli hash --hash_fn=SHA256 secrettext\n"))),(0,r.yg)("li",{parentName:"ul"},"Run the following to verify the status of the bond assets owned by ",(0,r.yg)("inlineCode",{parentName:"li"},"alice")," and ",(0,r.yg)("inlineCode",{parentName:"li"},"bob")," in the Fabric network ",(0,r.yg)("inlineCode",{parentName:"li"},"network1")," from ",(0,r.yg)("inlineCode",{parentName:"li"},"samples/fabric/fabric-cli")," folder:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"./scripts/getAssetStatus.sh\n"))),(0,r.yg)("li",{parentName:"ul"},"Run the following in ",(0,r.yg)("inlineCode",{parentName:"li"},"besu-cli"),", to verify the status of the assets owned by ",(0,r.yg)("inlineCode",{parentName:"li"},"Alice")," and ",(0,r.yg)("inlineCode",{parentName:"li"},"Bob")," in the Besu network ",(0,r.yg)("inlineCode",{parentName:"li"},"network2"),":",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset get-balance --network=network2 --account=1\n./bin/besu-cli asset get-balance --network=network2 --account=2\n"))),(0,r.yg)("li",{parentName:"ul"},"Run the following to trigger ",(0,r.yg)("inlineCode",{parentName:"li"},"alice")," locking ",(0,r.yg)("inlineCode",{parentName:"li"},"bond01:a03")," for ",(0,r.yg)("inlineCode",{parentName:"li"},"bob")," in ",(0,r.yg)("inlineCode",{parentName:"li"},"network1")," for 60 mins:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset exchange lock --timeout-duration=3600 --locker=alice --recipient=bob --hashBase64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs= --target-network=network1 --param=bond01:a03\n"))),(0,r.yg)("li",{parentName:"ul"},"Run the following to verify ",(0,r.yg)("inlineCode",{parentName:"li"},"alice"),"'s lock:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset exchange is-locked --locker=alice --recipient=bob --target-network=network1 --param=bond01:a03\n"))),(0,r.yg)("li",{parentName:"ul"},"Run the following to trigger ",(0,r.yg)("inlineCode",{parentName:"li"},"bob")," locking ",(0,r.yg)("inlineCode",{parentName:"li"},"10")," units of ",(0,r.yg)("inlineCode",{parentName:"li"},"BobERC20")," tokens for ",(0,r.yg)("inlineCode",{parentName:"li"},"alice")," in ",(0,r.yg)("inlineCode",{parentName:"li"},"network2")," for 30 mins:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset lock --network=network2 --sender_account=2 --recipient_account=1 --amount=10 --timeout=1800 --hash_base64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs=\n")),"Note the ",(0,r.yg)("inlineCode",{parentName:"li"},"contract-id")," printed as output in above command. The output line containing ",(0,r.yg)("inlineCode",{parentName:"li"},"contract-id")," (text in base64 after ",(0,r.yg)("inlineCode",{parentName:"li"},"Lock contract ID:"),") would like this:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"Lock contract ID: 48f59da2ac632117bf79b4aa986f5ece8a2439dc143d576965c17bc8275b0925\n")),"Let's refer it ",(0,r.yg)("inlineCode",{parentName:"li"},"<contract-id-2>")," for this demonstration."),(0,r.yg)("li",{parentName:"ul"},"Run the following to verify ",(0,r.yg)("inlineCode",{parentName:"li"},"bob"),"'s lock:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset is-locked --network=network2 --lock_contract_id=<contract-id-2>\n"))),(0,r.yg)("li",{parentName:"ul"},"Run the following to trigger ",(0,r.yg)("inlineCode",{parentName:"li"},"alice"),"'s claim for ",(0,r.yg)("inlineCode",{parentName:"li"},"10")," units of ",(0,r.yg)("inlineCode",{parentName:"li"},"BobERC20")," tokens locked by ",(0,r.yg)("inlineCode",{parentName:"li"},"bob")," in ",(0,r.yg)("inlineCode",{parentName:"li"},"network2"),":",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset claim --network=network2 --recipient_account=1 --preimage=secrettext --lock_contract_id=<contract-id-2>\n"))),(0,r.yg)("li",{parentName:"ul"},"Run the following to trigger ",(0,r.yg)("inlineCode",{parentName:"li"},"bob"),"'s claim for ",(0,r.yg)("inlineCode",{parentName:"li"},"bond01:a03")," locked by ",(0,r.yg)("inlineCode",{parentName:"li"},"alice")," in ",(0,r.yg)("inlineCode",{parentName:"li"},"network1"),":",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset exchange claim --recipient=bob --locker=alice --target-network=network1 --param=bond01:a03 --secret=secrettext\n"))),(0,r.yg)("li",{parentName:"ul"},"Run the following to verify the status of the bond assets owned by ",(0,r.yg)("inlineCode",{parentName:"li"},"alice")," and ",(0,r.yg)("inlineCode",{parentName:"li"},"bob")," in the Fabric network ",(0,r.yg)("inlineCode",{parentName:"li"},"network1")," from ",(0,r.yg)("inlineCode",{parentName:"li"},"samples/fabric/fabric-cli")," folder:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"./scripts/getAssetStatus.sh\n"))),(0,r.yg)("li",{parentName:"ul"},"Run the following in ",(0,r.yg)("inlineCode",{parentName:"li"},"besu-cli"),", to verify the status of the assets owned by ",(0,r.yg)("inlineCode",{parentName:"li"},"Alice")," and ",(0,r.yg)("inlineCode",{parentName:"li"},"Bob")," in the Besu network ",(0,r.yg)("inlineCode",{parentName:"li"},"network2"),":",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset get-balance --network=network2 --account=1\n./bin/besu-cli asset get-balance --network=network2 --account=2\n")))),(0,r.yg)("p",null,"The above steps complete a successful asset exchange between Fabric and Corda networks.\nIn addition to the above commands, following commands can be run if specified timeout has expired and the locked asset remains unclaimed."),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"If ",(0,r.yg)("inlineCode",{parentName:"li"},"alice")," wants to unlock the bond asset, run the following to trigger ",(0,r.yg)("inlineCode",{parentName:"li"},"alice"),"'s re-claim for ",(0,r.yg)("inlineCode",{parentName:"li"},"bond01:a03")," locked in ",(0,r.yg)("inlineCode",{parentName:"li"},"network1"),":",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset exchange unlock --locker=alice --recipient=bob --target-network=network1 --param=bond01:a03\n"))),(0,r.yg)("li",{parentName:"ul"},"If ",(0,r.yg)("inlineCode",{parentName:"li"},"bob")," wants to unlock the token asset, run the following to trigger ",(0,r.yg)("inlineCode",{parentName:"li"},"bob"),"'s re-claim for ",(0,r.yg)("inlineCode",{parentName:"li"},"50 BobERC20")," tokens locked in ",(0,r.yg)("inlineCode",{parentName:"li"},"network2"),":",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset unlock --network=network2 --lock_contract_id=<contract-id-2> --sender_account=2\n")))))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/27ea52af.7c2fc5f7.js b/assets/js/27ea52af.f35ea651.js similarity index 58% rename from assets/js/27ea52af.7c2fc5f7.js rename to assets/js/27ea52af.f35ea651.js index d71cf65a5..a1ad5724c 100644 --- a/assets/js/27ea52af.7c2fc5f7.js +++ b/assets/js/27ea52af.f35ea651.js @@ -1 +1 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[3807],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>b});var r=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?a(Object(n),!0).forEach((function(t){i(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):a(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,r,i=function(e,t){if(null==e)return{};var n,r,i={},a=Object.keys(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var l=r.createContext({}),p=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},d=function(e){var t=p(e.components);return r.createElement(l.Provider,{value:t},e.children)},c="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},g=r.forwardRef((function(e,t){var n=e.components,i=e.mdxType,a=e.originalType,l=e.parentName,d=s(e,["components","mdxType","originalType","parentName"]),c=p(n),g=i,b=c["".concat(l,".").concat(g)]||c[g]||u[g]||a;return n?r.createElement(b,o(o({ref:t},d),{},{components:n})):r.createElement(b,o({ref:t},d))}));function b(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var a=n.length,o=new Array(a);o[0]=g;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[c]="string"==typeof e?e:i,o[1]=s;for(var p=2;p<a;p++)o[p]=n[p];return r.createElement.apply(null,o)}return r.createElement.apply(null,n)}g.displayName="MDXCreateElement"},4884:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>o,default:()=>u,frontMatter:()=>a,metadata:()=>s,toc:()=>p});var r=n(7462),i=(n(7294),n(3905));const a={id:"integration-patterns",title:"Integration Patterns"},o=void 0,s={unversionedId:"external/what-is-interoperability/integration-patterns",id:"external/what-is-interoperability/integration-patterns",title:"Integration Patterns",description:"\x3c!--",source:"@site/docs/external/what-is-interoperability/integration-patterns.md",sourceDirName:"external/what-is-interoperability",slug:"/external/what-is-interoperability/integration-patterns",permalink:"/weaver-dlt-interoperability/docs/external/what-is-interoperability/integration-patterns",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/what-is-interoperability/integration-patterns.md",tags:[],version:"current",frontMatter:{id:"integration-patterns",title:"Integration Patterns"},sidebar:"Documentation",previous:{title:"Levels of Interoperability",permalink:"/weaver-dlt-interoperability/docs/external/what-is-interoperability/levels-of-interoperability"},next:{title:"Interoperability Modes",permalink:"/weaver-dlt-interoperability/docs/external/interoperability-modes"}},l={},p=[{value:"Distributed Ledger Integration Patterns",id:"distributed-ledger-integration-patterns",level:2},{value:"Consensus-based integration between ledgers",id:"consensus-based-integration-between-ledgers",level:3},{value:"Standard API integration between applications",id:"standard-api-integration-between-applications",level:3},{value:"Single enterprise participating in multiple neworks",id:"single-enterprise-participating-in-multiple-neworks",level:3},{value:"Single network deployed on multiple heterogenous infrastructure",id:"single-network-deployed-on-multiple-heterogenous-infrastructure",level:3}],d={toc:p},c="wrapper";function u(e){let{components:t,...a}=e;return(0,i.kt)(c,(0,r.Z)({},d,a,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"Integration patterns are well-known reusable solutions for integrating systems together. A number of patterns exist for addressing various types integration problems. The specific pattern applied in practice depends on the nature of the integration problem, the overall objective of the integration task, trade-offs in alternate approaches, and potential risks."),(0,i.kt)("h2",{id:"distributed-ledger-integration-patterns"},"Distributed Ledger Integration Patterns"),(0,i.kt)("p",null,"Here we present common patterns for integrating distributed ledgers. Not all problems are equal, some approaches to itegrating ledgers are preferred over others depending on the use case, the purpose of the itegration and the risks involved."),(0,i.kt)("h3",{id:"consensus-based-integration-between-ledgers"},"Consensus-based integration between ledgers"),(0,i.kt)("p",null,"Consensus-based integration aims to communicate the consensus view of one network to another. The consensus view is a representation of state on the ledger that is collectively agreed by the members of the network. This form of integration provides the highest assurance on the validity of state. The Weaver framework is designed to address consensus-based integration between ledgers built on different distributed ledger protocols."),(0,i.kt)("p",null,(0,i.kt)("img",{src:n(1034).Z,width:"1138",height:"517"})),(0,i.kt)("h3",{id:"standard-api-integration-between-applications"},"Standard API integration between applications"),(0,i.kt)("p",null,"A standard API integration relies on a single party exposing an endpoint for state exchange. The validity of state relies entirely on the trust placed on the party exposing the endpoint."),(0,i.kt)("p",null,(0,i.kt)("img",{src:n(4333).Z,width:"1138",height:"514"})),(0,i.kt)("h3",{id:"single-enterprise-participating-in-multiple-neworks"},"Single enterprise participating in multiple neworks"),(0,i.kt)("p",null,"A single enterprise participating in multiple networks can integrate state and contract logic across these networks using off-chain workflows. Unlike the previous pattern, this pattern relies on the enterprise having valid membership credentials on multiple networks. Significant trust must be placed on the organization coordianting the exchange of state across these networks."),(0,i.kt)("p",null,(0,i.kt)("img",{src:n(346).Z,width:"1138",height:"517"})),(0,i.kt)("h3",{id:"single-network-deployed-on-multiple-heterogenous-infrastructure"},"Single network deployed on multiple heterogenous infrastructure"),(0,i.kt)("p",null,"Although not an integration pattern, this pattern demonstrates interoperability at the infrastructure layer. The ability to run nodes on multiple cloud providers, as well as on-prem infrastructure, ensures networks are resilient to failures or censorship by infrastructure providers."),(0,i.kt)("p",null,(0,i.kt)("img",{src:n(4975).Z,width:"1137",height:"516"})))}u.isMDXComponent=!0},1034:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/integration-pattern-consensus-driven-63ad28eb160267a0584ba64abbc6fa0e.jpg"},346:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/integration-pattern-single-enterprise-multiple-networks-527009d72634b73ebda371b465340455.jpg"},4975:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/integration-pattern-single-network-multiple-cloud-cf5c86bedcefc81c781aa02bb89b2128.jpg"},4333:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/integration-pattern-single-party-api-828f5c42b687e693cc9b5cf4e914e85a.jpg"}}]); \ No newline at end of file +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[3292],{5680:(e,t,n)=>{n.d(t,{xA:()=>g,yg:()=>b});var r=n(6540);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?a(Object(n),!0).forEach((function(t){i(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):a(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,r,i=function(e,t){if(null==e)return{};var n,r,i={},a=Object.keys(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var l=r.createContext({}),p=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},g=function(e){var t=p(e.components);return r.createElement(l.Provider,{value:t},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},u=r.forwardRef((function(e,t){var n=e.components,i=e.mdxType,a=e.originalType,l=e.parentName,g=s(e,["components","mdxType","originalType","parentName"]),d=p(n),u=i,b=d["".concat(l,".").concat(u)]||d[u]||c[u]||a;return n?r.createElement(b,o(o({ref:t},g),{},{components:n})):r.createElement(b,o({ref:t},g))}));function b(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var a=n.length,o=new Array(a);o[0]=u;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[d]="string"==typeof e?e:i,o[1]=s;for(var p=2;p<a;p++)o[p]=n[p];return r.createElement.apply(null,o)}return r.createElement.apply(null,n)}u.displayName="MDXCreateElement"},9871:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>o,default:()=>c,frontMatter:()=>a,metadata:()=>s,toc:()=>p});var r=n(8168),i=(n(6540),n(5680));const a={id:"integration-patterns",title:"Integration Patterns"},o=void 0,s={unversionedId:"external/what-is-interoperability/integration-patterns",id:"external/what-is-interoperability/integration-patterns",title:"Integration Patterns",description:"\x3c!--",source:"@site/docs/external/what-is-interoperability/integration-patterns.md",sourceDirName:"external/what-is-interoperability",slug:"/external/what-is-interoperability/integration-patterns",permalink:"/weaver-dlt-interoperability/docs/external/what-is-interoperability/integration-patterns",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/what-is-interoperability/integration-patterns.md",tags:[],version:"current",frontMatter:{id:"integration-patterns",title:"Integration Patterns"},sidebar:"Documentation",previous:{title:"Levels of Interoperability",permalink:"/weaver-dlt-interoperability/docs/external/what-is-interoperability/levels-of-interoperability"},next:{title:"Interoperability Modes",permalink:"/weaver-dlt-interoperability/docs/external/interoperability-modes"}},l={},p=[{value:"Distributed Ledger Integration Patterns",id:"distributed-ledger-integration-patterns",level:2},{value:"Consensus-based integration between ledgers",id:"consensus-based-integration-between-ledgers",level:3},{value:"Standard API integration between applications",id:"standard-api-integration-between-applications",level:3},{value:"Single enterprise participating in multiple neworks",id:"single-enterprise-participating-in-multiple-neworks",level:3},{value:"Single network deployed on multiple heterogenous infrastructure",id:"single-network-deployed-on-multiple-heterogenous-infrastructure",level:3}],g={toc:p},d="wrapper";function c(e){let{components:t,...a}=e;return(0,i.yg)(d,(0,r.A)({},g,a,{components:t,mdxType:"MDXLayout"}),(0,i.yg)("p",null,"Integration patterns are well-known reusable solutions for integrating systems together. A number of patterns exist for addressing various types integration problems. The specific pattern applied in practice depends on the nature of the integration problem, the overall objective of the integration task, trade-offs in alternate approaches, and potential risks."),(0,i.yg)("h2",{id:"distributed-ledger-integration-patterns"},"Distributed Ledger Integration Patterns"),(0,i.yg)("p",null,"Here we present common patterns for integrating distributed ledgers. Not all problems are equal, some approaches to itegrating ledgers are preferred over others depending on the use case, the purpose of the itegration and the risks involved."),(0,i.yg)("h3",{id:"consensus-based-integration-between-ledgers"},"Consensus-based integration between ledgers"),(0,i.yg)("p",null,"Consensus-based integration aims to communicate the consensus view of one network to another. The consensus view is a representation of state on the ledger that is collectively agreed by the members of the network. This form of integration provides the highest assurance on the validity of state. The Weaver framework is designed to address consensus-based integration between ledgers built on different distributed ledger protocols."),(0,i.yg)("p",null,(0,i.yg)("img",{src:n(223).A,width:"1138",height:"517"})),(0,i.yg)("h3",{id:"standard-api-integration-between-applications"},"Standard API integration between applications"),(0,i.yg)("p",null,"A standard API integration relies on a single party exposing an endpoint for state exchange. The validity of state relies entirely on the trust placed on the party exposing the endpoint."),(0,i.yg)("p",null,(0,i.yg)("img",{src:n(8559).A,width:"1138",height:"514"})),(0,i.yg)("h3",{id:"single-enterprise-participating-in-multiple-neworks"},"Single enterprise participating in multiple neworks"),(0,i.yg)("p",null,"A single enterprise participating in multiple networks can integrate state and contract logic across these networks using off-chain workflows. Unlike the previous pattern, this pattern relies on the enterprise having valid membership credentials on multiple networks. Significant trust must be placed on the organization coordianting the exchange of state across these networks."),(0,i.yg)("p",null,(0,i.yg)("img",{src:n(9024).A,width:"1138",height:"517"})),(0,i.yg)("h3",{id:"single-network-deployed-on-multiple-heterogenous-infrastructure"},"Single network deployed on multiple heterogenous infrastructure"),(0,i.yg)("p",null,"Although not an integration pattern, this pattern demonstrates interoperability at the infrastructure layer. The ability to run nodes on multiple cloud providers, as well as on-prem infrastructure, ensures networks are resilient to failures or censorship by infrastructure providers."),(0,i.yg)("p",null,(0,i.yg)("img",{src:n(7473).A,width:"1137",height:"516"})))}c.isMDXComponent=!0},223:(e,t,n)=>{n.d(t,{A:()=>r});const r=n.p+"assets/images/integration-pattern-consensus-driven-63ad28eb160267a0584ba64abbc6fa0e.jpg"},9024:(e,t,n)=>{n.d(t,{A:()=>r});const r=n.p+"assets/images/integration-pattern-single-enterprise-multiple-networks-527009d72634b73ebda371b465340455.jpg"},7473:(e,t,n)=>{n.d(t,{A:()=>r});const r=n.p+"assets/images/integration-pattern-single-network-multiple-cloud-cf5c86bedcefc81c781aa02bb89b2128.jpg"},8559:(e,t,n)=>{n.d(t,{A:()=>r});const r=n.p+"assets/images/integration-pattern-single-party-api-828f5c42b687e693cc9b5cf4e914e85a.jpg"}}]); \ No newline at end of file diff --git a/assets/js/2b962623.d12dec53.js b/assets/js/2b962623.b8b3bd6c.js similarity index 79% rename from assets/js/2b962623.d12dec53.js rename to assets/js/2b962623.b8b3bd6c.js index 100251c18..817865499 100644 --- a/assets/js/2b962623.d12dec53.js +++ b/assets/js/2b962623.b8b3bd6c.js @@ -1 +1 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[9822],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>h});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function o(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?i(Object(r),!0).forEach((function(t){a(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):i(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function s(e,t){if(null==e)return{};var r,n,a=function(e,t){if(null==e)return{};var r,n,a={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var l=n.createContext({}),c=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},p=function(e){var t=c(e.components);return n.createElement(l.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,i=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=c(r),m=a,h=d["".concat(l,".").concat(m)]||d[m]||u[m]||i;return r?n.createElement(h,o(o({ref:t},p),{},{components:r})):n.createElement(h,o({ref:t},p))}));function h(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=r.length,o=new Array(i);o[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[d]="string"==typeof e?e:a,o[1]=s;for(var c=2;c<i;c++)o[c]=r[c];return n.createElement.apply(null,o)}return n.createElement.apply(null,r)}m.displayName="MDXCreateElement"},3539:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>o,default:()=>u,frontMatter:()=>i,metadata:()=>s,toc:()=>c});var n=r(7462),a=(r(7294),r(3905));const i={id:"overview",title:"Overview"},o=void 0,s={unversionedId:"external/user-stories/overview",id:"external/user-stories/overview",title:"Overview",description:"\x3c!--",source:"@site/docs/external/user-stories/overview.md",sourceDirName:"external/user-stories",slug:"/external/user-stories/overview",permalink:"/weaver-dlt-interoperability/docs/external/user-stories/overview",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/user-stories/overview.md",tags:[],version:"current",frontMatter:{id:"overview",title:"Overview"},sidebar:"Documentation",previous:{title:"Design Principles",permalink:"/weaver-dlt-interoperability/docs/external/design-principles"},next:{title:"Global Trade",permalink:"/weaver-dlt-interoperability/docs/external/user-stories/global-trade"}},l={},c=[{value:"Application Domains",id:"application-domains",level:2},{value:"Global Trade",id:"global-trade",level:3},{value:"Financial Markets",id:"financial-markets",level:3},{value:"Other Scenarios",id:"other-scenarios",level:3}],p={toc:c},d="wrapper";function u(e){let{components:t,...r}=e;return(0,a.kt)(d,(0,n.Z)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"In the ",(0,a.kt)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/external/interoperability-modes"},"introduction"),", we listed various modes (or patterns) of interoperation like asset transfers, asset exchanges, and data sharing. In IT parlance, we can think of this as a ",(0,a.kt)("em",{parentName:"p"},"horizontal")," classification of use cases for interoperability. In this section of the documentation, we will discuss the ",(0,a.kt)("em",{parentName:"p"},"verticals"),", or application domains, that exemplify the use and necessity of interoperation mechanisms."),(0,a.kt)("h2",{id:"application-domains"},"Application Domains"),(0,a.kt)("p",null,"Distributed ledger technology has been applied gainfully to several areas where legacy processes were inefficient, cumbersome, and error-prone. With the enablement of interoperation among these networks, they have the potential to take the next step toward a truly decentralized yet trustworthy internet. We call out two prominent focus areas."),(0,a.kt)("h3",{id:"global-trade"},"Global Trade"),(0,a.kt)("p",null,"Trade when seen from a global and international perspective is highly complex. In the absence of central coordinating and law-enforcing authorities at the world level, various ad hoc processes have been created and refined over centuries by merchants, financiers, and regulators, to manage complex supply-chain logistics and cross-border financing that underpin global trade. These processes exist to ensure that parties can hedge their risks, mitigate possibilities for non-compliance, and ship goods from one location to another while complying with regulatory guidelines."),(0,a.kt)("p",null,"Multiple networks have emerged to handle trade processes limited in scope. There exist networks to handle trade logistics (like TradeLens, built on Hyperledger Fabric), food tracking (IBM Food Trust, built on Hyperledger Fabric), trade finance (like We.Trade, built on Hyperledger Fabric, and Marco Polo, built on R3 Corda), cross-border payments, and ",(0,a.kt)("em",{parentName:"p"},"know-your-customer"),", or KYC, processes. An end-to-end trade scenario, involving shipment of goods, financing commitments, documentation, shipping, tracking, and payments, will rely on many or all of these networks. Interoperation will help us overcome this fragmentation and lack of visibility of one network into another, and enable trustworthy and efficient trades at global scale using blockchain technology. See ",(0,a.kt)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/external/user-stories/global-trade"},"Global Trade")," for a concrete example."),(0,a.kt)("h3",{id:"financial-markets"},"Financial Markets"),(0,a.kt)("p",null,"Securities trading is a common and lucrative transaction in financial markets. As with any form of exchange, when a security is sold in exchange for money, the party that gives up its asset first faces a ",(0,a.kt)("em",{parentName:"p"},"non-compliance risk"),"; i.e., the other party may renege on the deal after it receives an asset. With the advent of blockchain-backed digital currencies maintained by countries' central banks, opportunities now exist to carry out security trades safely and efficiently. But this requires interoperation between networks managing digital currency on behalf of central banks (like private versions of Bitcoin networks with faster commitment times) and networks managing tracking securities and their ownerships. See ",(0,a.kt)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/external/user-stories/financial-markets"},"DvP in Financial Markets")," for a concrete example."),(0,a.kt)("h3",{id:"other-scenarios"},"Other Scenarios"),(0,a.kt)("p",null,"There are other domains or ",(0,a.kt)("em",{parentName:"p"},"verticals")," we can think of that would benefit from interoperation. Healthcare is one, where different networks may exist: citizens' identity records, employer network, healthcare provider network, insurance companies' network, etc. For efficiency of operation (with privacy preservation guarantees) and to ensure that service and payments occur promptly and accurately, these networks may seek to interoperate. Similarly, interoperation between networks that manage users' academic and professional credentials may help employers and job seekers."))}u.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[8159],{5680:(e,t,r)=>{r.d(t,{xA:()=>p,yg:()=>y});var n=r(6540);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function o(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?i(Object(r),!0).forEach((function(t){a(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):i(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function s(e,t){if(null==e)return{};var r,n,a=function(e,t){if(null==e)return{};var r,n,a={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var l=n.createContext({}),c=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},p=function(e){var t=c(e.components);return n.createElement(l.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,i=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=c(r),m=a,y=d["".concat(l,".").concat(m)]||d[m]||u[m]||i;return r?n.createElement(y,o(o({ref:t},p),{},{components:r})):n.createElement(y,o({ref:t},p))}));function y(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=r.length,o=new Array(i);o[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[d]="string"==typeof e?e:a,o[1]=s;for(var c=2;c<i;c++)o[c]=r[c];return n.createElement.apply(null,o)}return n.createElement.apply(null,r)}m.displayName="MDXCreateElement"},4435:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>o,default:()=>u,frontMatter:()=>i,metadata:()=>s,toc:()=>c});var n=r(8168),a=(r(6540),r(5680));const i={id:"overview",title:"Overview"},o=void 0,s={unversionedId:"external/user-stories/overview",id:"external/user-stories/overview",title:"Overview",description:"\x3c!--",source:"@site/docs/external/user-stories/overview.md",sourceDirName:"external/user-stories",slug:"/external/user-stories/overview",permalink:"/weaver-dlt-interoperability/docs/external/user-stories/overview",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/user-stories/overview.md",tags:[],version:"current",frontMatter:{id:"overview",title:"Overview"},sidebar:"Documentation",previous:{title:"Design Principles",permalink:"/weaver-dlt-interoperability/docs/external/design-principles"},next:{title:"Global Trade",permalink:"/weaver-dlt-interoperability/docs/external/user-stories/global-trade"}},l={},c=[{value:"Application Domains",id:"application-domains",level:2},{value:"Global Trade",id:"global-trade",level:3},{value:"Financial Markets",id:"financial-markets",level:3},{value:"Other Scenarios",id:"other-scenarios",level:3}],p={toc:c},d="wrapper";function u(e){let{components:t,...r}=e;return(0,a.yg)(d,(0,n.A)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,a.yg)("p",null,"In the ",(0,a.yg)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/external/interoperability-modes"},"introduction"),", we listed various modes (or patterns) of interoperation like asset transfers, asset exchanges, and data sharing. In IT parlance, we can think of this as a ",(0,a.yg)("em",{parentName:"p"},"horizontal")," classification of use cases for interoperability. In this section of the documentation, we will discuss the ",(0,a.yg)("em",{parentName:"p"},"verticals"),", or application domains, that exemplify the use and necessity of interoperation mechanisms."),(0,a.yg)("h2",{id:"application-domains"},"Application Domains"),(0,a.yg)("p",null,"Distributed ledger technology has been applied gainfully to several areas where legacy processes were inefficient, cumbersome, and error-prone. With the enablement of interoperation among these networks, they have the potential to take the next step toward a truly decentralized yet trustworthy internet. We call out two prominent focus areas."),(0,a.yg)("h3",{id:"global-trade"},"Global Trade"),(0,a.yg)("p",null,"Trade when seen from a global and international perspective is highly complex. In the absence of central coordinating and law-enforcing authorities at the world level, various ad hoc processes have been created and refined over centuries by merchants, financiers, and regulators, to manage complex supply-chain logistics and cross-border financing that underpin global trade. These processes exist to ensure that parties can hedge their risks, mitigate possibilities for non-compliance, and ship goods from one location to another while complying with regulatory guidelines."),(0,a.yg)("p",null,"Multiple networks have emerged to handle trade processes limited in scope. There exist networks to handle trade logistics (like TradeLens, built on Hyperledger Fabric), food tracking (IBM Food Trust, built on Hyperledger Fabric), trade finance (like We.Trade, built on Hyperledger Fabric, and Marco Polo, built on R3 Corda), cross-border payments, and ",(0,a.yg)("em",{parentName:"p"},"know-your-customer"),", or KYC, processes. An end-to-end trade scenario, involving shipment of goods, financing commitments, documentation, shipping, tracking, and payments, will rely on many or all of these networks. Interoperation will help us overcome this fragmentation and lack of visibility of one network into another, and enable trustworthy and efficient trades at global scale using blockchain technology. See ",(0,a.yg)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/external/user-stories/global-trade"},"Global Trade")," for a concrete example."),(0,a.yg)("h3",{id:"financial-markets"},"Financial Markets"),(0,a.yg)("p",null,"Securities trading is a common and lucrative transaction in financial markets. As with any form of exchange, when a security is sold in exchange for money, the party that gives up its asset first faces a ",(0,a.yg)("em",{parentName:"p"},"non-compliance risk"),"; i.e., the other party may renege on the deal after it receives an asset. With the advent of blockchain-backed digital currencies maintained by countries' central banks, opportunities now exist to carry out security trades safely and efficiently. But this requires interoperation between networks managing digital currency on behalf of central banks (like private versions of Bitcoin networks with faster commitment times) and networks managing tracking securities and their ownerships. See ",(0,a.yg)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/external/user-stories/financial-markets"},"DvP in Financial Markets")," for a concrete example."),(0,a.yg)("h3",{id:"other-scenarios"},"Other Scenarios"),(0,a.yg)("p",null,"There are other domains or ",(0,a.yg)("em",{parentName:"p"},"verticals")," we can think of that would benefit from interoperation. Healthcare is one, where different networks may exist: citizens' identity records, employer network, healthcare provider network, insurance companies' network, etc. For efficiency of operation (with privacy preservation guarantees) and to ensure that service and payments occur promptly and accurately, these networks may seek to interoperate. Similarly, interoperation between networks that manage users' academic and professional credentials may help employers and job seekers."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/2e5dd55e.0edaba25.js b/assets/js/2e5dd55e.0edaba25.js new file mode 100644 index 000000000..3b3ce8252 --- /dev/null +++ b/assets/js/2e5dd55e.0edaba25.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[3108],{5680:(e,n,a)=>{a.d(n,{xA:()=>d,yg:()=>y});var t=a(6540);function i(e,n,a){return n in e?Object.defineProperty(e,n,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[n]=a,e}function r(e,n){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var t=Object.getOwnPropertySymbols(e);n&&(t=t.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),a.push.apply(a,t)}return a}function l(e){for(var n=1;n<arguments.length;n++){var a=null!=arguments[n]?arguments[n]:{};n%2?r(Object(a),!0).forEach((function(n){i(e,n,a[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(a)):r(Object(a)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(a,n))}))}return e}function o(e,n){if(null==e)return{};var a,t,i=function(e,n){if(null==e)return{};var a,t,i={},r=Object.keys(e);for(t=0;t<r.length;t++)a=r[t],n.indexOf(a)>=0||(i[a]=e[a]);return i}(e,n);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(t=0;t<r.length;t++)a=r[t],n.indexOf(a)>=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(i[a]=e[a])}return i}var s=t.createContext({}),p=function(e){var n=t.useContext(s),a=n;return e&&(a="function"==typeof e?e(n):l(l({},n),e)),a},d=function(e){var n=p(e.components);return t.createElement(s.Provider,{value:n},e.children)},g="mdxType",c={inlineCode:"code",wrapper:function(e){var n=e.children;return t.createElement(t.Fragment,{},n)}},m=t.forwardRef((function(e,n){var a=e.components,i=e.mdxType,r=e.originalType,s=e.parentName,d=o(e,["components","mdxType","originalType","parentName"]),g=p(a),m=i,y=g["".concat(s,".").concat(m)]||g[m]||c[m]||r;return a?t.createElement(y,l(l({ref:n},d),{},{components:a})):t.createElement(y,l({ref:n},d))}));function y(e,n){var a=arguments,i=n&&n.mdxType;if("string"==typeof e||i){var r=a.length,l=new Array(r);l[0]=m;var o={};for(var s in n)hasOwnProperty.call(n,s)&&(o[s]=n[s]);o.originalType=e,o[g]="string"==typeof e?e:i,l[1]=o;for(var p=2;p<r;p++)l[p]=a[p];return t.createElement.apply(null,l)}return t.createElement.apply(null,a)}m.displayName="MDXCreateElement"},2453:(e,n,a)=>{a.r(n),a.d(n,{assets:()=>s,contentTitle:()=>l,default:()=>c,frontMatter:()=>r,metadata:()=>o,toc:()=>p});var t=a(8168),i=(a(6540),a(5680));const r={id:"asset-transfer",title:"Asset Transfer",pagination_prev:"external/getting-started/interop/overview",pagination_next:"external/getting-started/enabling-weaver-network/overview"},l=void 0,o={unversionedId:"external/getting-started/interop/asset-transfer",id:"external/getting-started/interop/asset-transfer",title:"Asset Transfer",description:"\x3c!--",source:"@site/docs/external/getting-started/interop/asset-transfer.md",sourceDirName:"external/getting-started/interop",slug:"/external/getting-started/interop/asset-transfer",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-transfer",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/getting-started/interop/asset-transfer.md",tags:[],version:"current",frontMatter:{id:"asset-transfer",title:"Asset Transfer",pagination_prev:"external/getting-started/interop/overview",pagination_next:"external/getting-started/enabling-weaver-network/overview"},sidebar:"Documentation",previous:{title:"Testing Interoperation Modes",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/overview"},next:{title:"Enabling Weaver in Existing DLT Applications",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/overview"}},s={},p=[{value:"1. Fabric with Fabric",id:"1-fabric-with-fabric",level:2},{value:"Transfer or recover a bond (non-fungible) asset",id:"transfer-or-recover-a-bond-non-fungible-asset",level:3},{value:"Transfer or recover token (fungible) assets",id:"transfer-or-recover-token-fungible-assets",level:3},{value:"2. Corda with Corda",id:"2-corda-with-corda",level:2},{value:"Transfer or recover token (fungible) assets",id:"transfer-or-recover-token-fungible-assets-1",level:3},{value:"Transfer or recover bond (non-fungible) assets",id:"transfer-or-recover-bond-non-fungible-assets",level:3},{value:"3. Fabric with Corda",id:"3-fabric-with-corda",level:2},{value:"Transfer or recover token (fungible) assets",id:"transfer-or-recover-token-fungible-assets-2",level:3},{value:"4. Corda with Fabric",id:"4-corda-with-fabric",level:2},{value:"Transfer or recover token (fungible) assets",id:"transfer-or-recover-token-fungible-assets-3",level:3}],d={toc:p},g="wrapper";function c(e){let{components:n,...a}=e;return(0,i.yg)(g,(0,t.A)({},d,a,{components:n,mdxType:"MDXLayout"}),(0,i.yg)("p",null,"This document lists sample ways in which you can exercise the asset-transfer interoperation protocol on the test network ",(0,i.yg)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/overview"},"launched earlier"),"."),(0,i.yg)("p",null,"Once the networks, relays, and drivers have been launched, and the ledgers bootstrapped, you can trigger the following interoperation flows corresponding to distinct asset-sharing combinations ",(0,i.yg)("em",{parentName:"p"},"other combinations of DLTs will be supported soon"),"):"),(0,i.yg)("h2",{id:"1-fabric-with-fabric"},"1. Fabric with Fabric"),(0,i.yg)("p",null,"One Fabric network transfers either a bond or some tokens owned by Alice to Bob in the other network"),(0,i.yg)("p",null,"Assuming that the ",(0,i.yg)("inlineCode",{parentName:"p"},"simpleassettransfer")," chaincode has been deployed in both networks, run the following steps by navigating to the ",(0,i.yg)("inlineCode",{parentName:"p"},"samples/fabric/fabric-cli")," folder (",(0,i.yg)("em",{parentName:"p"},"the Go CLI doesn't support asset transfer yet"),")."),(0,i.yg)("h3",{id:"transfer-or-recover-a-bond-non-fungible-asset"},"Transfer or recover a bond (non-fungible) asset"),(0,i.yg)("ol",null,(0,i.yg)("li",{parentName:"ol"},"Verify that ",(0,i.yg)("inlineCode",{parentName:"li"},"alice")," owns bonds with ids ",(0,i.yg)("inlineCode",{parentName:"li"},"a03")," and ",(0,i.yg)("inlineCode",{parentName:"li"},"a04")," as follows:",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},'./bin/fabric-cli chaincode query --user=alice mychannel simpleassettransfer ReadAsset \'["bond01","a03"]\' --local-network=network1\n./bin/fabric-cli chaincode query --user=alice mychannel simpleassettransfer ReadAsset \'["bond01","a04"]\' --local-network=network1\n')),"You should see a JSON structure corresponding to the bond being logged on the console in each case."),(0,i.yg)("li",{parentName:"ol"},"Get ",(0,i.yg)("inlineCode",{parentName:"li"},"alice")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"network1")," to pledge bond ",(0,i.yg)("inlineCode",{parentName:"li"},"a03")," to ",(0,i.yg)("inlineCode",{parentName:"li"},"bob")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"network2")," as follows (with a 1 hour timeout):",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset transfer pledge --source-network=network1 --dest-network=network2 --recipient=bob --expiry-secs=3600 --type=bond --ref=a03 --data-file=src/data/assetsForTransfer.json\n")),"You should see a message containing the unique ID of this pledge on the console as ",(0,i.yg)("inlineCode",{parentName:"li"},"Asset pledged with ID <pledge-id>")," (",(0,i.yg)("inlineCode",{parentName:"li"},"<pledge-id>")," is a hexadecimal string)."),(0,i.yg)("li",{parentName:"ol"},"Get ",(0,i.yg)("inlineCode",{parentName:"li"},"bob")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"network2")," to claim this bond asset as follows:",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset transfer claim --source-network=network1 --dest-network=network2 --user=bob --owner=alice --type='bond.fabric' --pledge-id=<pledge-id> --param=bond01:a03\n"))),(0,i.yg)("li",{parentName:"ol"},"Verify that ",(0,i.yg)("inlineCode",{parentName:"li"},"alice")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"network1")," does not own this asset as follows:",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},'./bin/fabric-cli chaincode query --user=alice mychannel simpleassettransfer ReadAsset \'["bond01","a03"]\' --local-network=network1\n')),"You should see an error message like ",(0,i.yg)("inlineCode",{parentName:"li"},"Error: the asset a03 does not exist"),"."),(0,i.yg)("li",{parentName:"ol"},"Verify that ",(0,i.yg)("inlineCode",{parentName:"li"},"bob")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"network2")," now owns this asset as follows:",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},'./bin/fabric-cli chaincode query --user=bob mychannel simpleassettransfer ReadAsset \'["bond01","a03"]\' --local-network=network2\n'))),(0,i.yg)("li",{parentName:"ol"},"Now get ",(0,i.yg)("inlineCode",{parentName:"li"},"alice")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"network1")," to pledge bond ",(0,i.yg)("inlineCode",{parentName:"li"},"a04")," to ",(0,i.yg)("inlineCode",{parentName:"li"},"bob")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"network2")," as follows (with a 1 minute timeout):",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset transfer pledge --source-network=network1 --dest-network=network2 --recipient=bob --expiry-secs=60 --type=bond --ref=a04 --data-file=src/data/assetsForTransfer.json\n")),"Wait for a minute as follows:",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"sleep 60\n")),"You should see a message containing the unique ID of this pledge on the console as ",(0,i.yg)("inlineCode",{parentName:"li"},"Asset pledged with ID <pledge-id>")," (",(0,i.yg)("inlineCode",{parentName:"li"},"<pledge-id>")," is a hexadecimal string)."),(0,i.yg)("li",{parentName:"ol"},"Now get ",(0,i.yg)("inlineCode",{parentName:"li"},"bob")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"network2")," to claim this bond asset as follows:",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset transfer claim --source-network=network1 --dest-network=network2 --user=bob --owner=alice --type='bond.fabric' --pledge-id=<pledge-id> --param=bond01:a04\n")),"This should fail as the pledge has already expired."),(0,i.yg)("li",{parentName:"ol"},"Now get ",(0,i.yg)("inlineCode",{parentName:"li"},"alice")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"network1")," to reclaim the asset as follows:",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset transfer reclaim --source-network=network1 --user=alice --type='bond.fabric' --pledge-id=<pledge-id> --param=bond01:a04\n"))),(0,i.yg)("li",{parentName:"ol"},"Verify that ",(0,i.yg)("inlineCode",{parentName:"li"},"alice")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"network1")," owns this asset as follows:",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},'./bin/fabric-cli chaincode query --user=alice mychannel simpleassettransfer ReadAsset \'["bond01","a04"]\' --local-network=network1\n'))),(0,i.yg)("li",{parentName:"ol"},"Verify that ",(0,i.yg)("inlineCode",{parentName:"li"},"bob")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"network2")," does not own this asset as follows:",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},'./bin/fabric-cli chaincode query --user=bob mychannel simpleassettransfer ReadAsset \'["bond01","a04"]\' --local-network=network2\n')),"You should see an error message like ",(0,i.yg)("inlineCode",{parentName:"li"},"Error: the asset a04 does not exist"),".")),(0,i.yg)("h3",{id:"transfer-or-recover-token-fungible-assets"},"Transfer or recover token (fungible) assets"),(0,i.yg)("ol",null,(0,i.yg)("li",{parentName:"ol"},"Verify that ",(0,i.yg)("inlineCode",{parentName:"li"},"alice")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"network1")," owns ",(0,i.yg)("inlineCode",{parentName:"li"},"10000")," tokens as follows:",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./scripts/getTokenBalance.sh network1 alice\n"))),(0,i.yg)("li",{parentName:"ol"},"Verify that ",(0,i.yg)("inlineCode",{parentName:"li"},"bob")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"network2")," owns no tokens as follows:",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./scripts/getTokenBalance.sh network2 bob\n")),"You should see an error message like ",(0,i.yg)("inlineCode",{parentName:"li"},"Error: owner does not have a wallet"),"."),(0,i.yg)("li",{parentName:"ol"},"Get ",(0,i.yg)("inlineCode",{parentName:"li"},"alice")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"network1")," to pledge 50 tokens to ",(0,i.yg)("inlineCode",{parentName:"li"},"bob")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"network2")," as follows (with a 1 hour timeout):",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset transfer pledge --source-network=network1 --dest-network=network2 --recipient=bob --expiry-secs=3600 --type=token --units=50 --owner=alice --data-file=src/data/tokensForTransfer.json\n")),"You should see a message containing the unique ID of this pledge on the console as ",(0,i.yg)("inlineCode",{parentName:"li"},"Asset pledged with ID <pledge-id>")," (",(0,i.yg)("inlineCode",{parentName:"li"},"<pledge-id>")," is a hexadecimal string)."),(0,i.yg)("li",{parentName:"ol"},"Get ",(0,i.yg)("inlineCode",{parentName:"li"},"bob")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"network2")," to claim these tokens as follows (replace ",(0,i.yg)("inlineCode",{parentName:"li"},"<pledge-id>")," with the above hexadecimal value):",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset transfer claim --source-network=network1 --dest-network=network2 --user=bob --owner=alice --type='token.fabric' --pledge-id=<pledge-id> --param=token1:50\n"))),(0,i.yg)("li",{parentName:"ol"},"Verify that ",(0,i.yg)("inlineCode",{parentName:"li"},"alice")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"network1")," owns ",(0,i.yg)("inlineCode",{parentName:"li"},"9950")," tokens (after losing ",(0,i.yg)("inlineCode",{parentName:"li"},"50"),") as follows:",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./scripts/getTokenBalance.sh network1 alice\n"))),(0,i.yg)("li",{parentName:"ol"},"Verify that ",(0,i.yg)("inlineCode",{parentName:"li"},"bob")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"network2")," now owns ",(0,i.yg)("inlineCode",{parentName:"li"},"50")," tokens as follows:",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./scripts/getTokenBalance.sh network2 bob\n"))),(0,i.yg)("li",{parentName:"ol"},"Now get ",(0,i.yg)("inlineCode",{parentName:"li"},"alice")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"network1")," to pledge 100 tokens to ",(0,i.yg)("inlineCode",{parentName:"li"},"bob")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"network2")," as follows (with a 1 minute timeout):",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset transfer pledge --source-network=network1 --dest-network=network2 --recipient=bob --expiry-secs=60 --type=token --units=100 --owner=alice --data-file=src/data/tokensForTransfer.json\n")),"Wait for a minute as follows:",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"sleep 60\n")),"You should see a message containing the unique ID of this pledge on the console as ",(0,i.yg)("inlineCode",{parentName:"li"},"Asset pledged with ID <pledge-id>")," (",(0,i.yg)("inlineCode",{parentName:"li"},"<pledge-id>")," is a hexadecimal string)."),(0,i.yg)("li",{parentName:"ol"},"Now get ",(0,i.yg)("inlineCode",{parentName:"li"},"bob")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"network2")," to claim these tokens as follows (replace ",(0,i.yg)("inlineCode",{parentName:"li"},"<pledge-id>")," with the above hexadecimal value):",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset transfer claim --source-network=network1 --dest-network=network2 --user=bob --owner=alice --type='token.fabric' --pledge-id=<pledge-id> --param=token1:100\n")),"This should fail as the pledge has already expired."),(0,i.yg)("li",{parentName:"ol"},"Now get ",(0,i.yg)("inlineCode",{parentName:"li"},"alice")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"network1")," to reclaim these tokens as follows:",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset transfer reclaim --source-network=network1 --user=alice --type='token.fabric' --pledge-id=<pledge-id> --param=token1:100\n"))),(0,i.yg)("li",{parentName:"ol"},"Verify that ",(0,i.yg)("inlineCode",{parentName:"li"},"alice")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"network1")," still owns ",(0,i.yg)("inlineCode",{parentName:"li"},"9950")," tokens (after losing ",(0,i.yg)("inlineCode",{parentName:"li"},"50"),") as follows:",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./scripts/getTokenBalance.sh network1 alice\n"))),(0,i.yg)("li",{parentName:"ol"},"Verify that ",(0,i.yg)("inlineCode",{parentName:"li"},"bob")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"network2")," still owns only ",(0,i.yg)("inlineCode",{parentName:"li"},"50")," tokens as follows:",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./scripts/getTokenBalance.sh network2 bob\n")))),(0,i.yg)("h2",{id:"2-corda-with-corda"},"2. Corda with Corda"),(0,i.yg)("p",null,"One Corda network transfers either a bond or some tokens owned by the party ",(0,i.yg)("inlineCode",{parentName:"p"},"PartyA")," (",(0,i.yg)("inlineCode",{parentName:"p"},"CORDA_PORT=10006"),") to the party ",(0,i.yg)("inlineCode",{parentName:"p"},"PartyA")," (",(0,i.yg)("inlineCode",{parentName:"p"},"CORDA_PORT=30006"),") in the other network."),(0,i.yg)("h3",{id:"transfer-or-recover-token-fungible-assets-1"},"Transfer or recover token (fungible) assets"),(0,i.yg)("p",null,"Assume that the CorDapp ",(0,i.yg)("inlineCode",{parentName:"p"},"cordaSimpleApplication")," has been deployed in both networks."),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},"Navigate to the ",(0,i.yg)("inlineCode",{parentName:"li"},"samples/corda/corda-simple-application")," folder in your clone of the Weaver repository."),(0,i.yg)("li",{parentName:"ul"},"Add ",(0,i.yg)("inlineCode",{parentName:"li"},"5")," tokens of type ",(0,i.yg)("inlineCode",{parentName:"li"},"t1")," to ",(0,i.yg)("inlineCode",{parentName:"li"},"PartyA")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"Corda_Network"),":",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"NETWORK_NAME='Corda_Network' CORDA_PORT=10006 ./clients/build/install/clients/bin/clients issue-asset-state 5 t1\n")),"(check token balance for ",(0,i.yg)("inlineCode",{parentName:"li"},"PartyA")," by running the command ",(0,i.yg)("inlineCode",{parentName:"li"},"CORDA_PORT=10006 ./clients/build/install/clients/bin/clients get-asset-states-by-type t1"),")"),(0,i.yg)("li",{parentName:"ul"},"Let ",(0,i.yg)("inlineCode",{parentName:"li"},"PartyA")," pledge these tokens in ",(0,i.yg)("inlineCode",{parentName:"li"},"Corda_Network")," to be transferred to ",(0,i.yg)("inlineCode",{parentName:"li"},"PartyA")," of ",(0,i.yg)("inlineCode",{parentName:"li"},"Corda_Network2")," (pledge burns the tokens in the source/exporting network):",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"NETWORK_NAME='Corda_Network' CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer pledge-asset --fungible --timeout=\"3600\" --import-network-id='Corda_Network2' --recipient='O=PartyA, L=London, C=GB' --param='t1:5'\n")),"Note the ",(0,i.yg)("inlineCode",{parentName:"li"},"pledge-id")," displayed after successful execution of the command, which will be used in next steps. Let's denote it ",(0,i.yg)("inlineCode",{parentName:"li"},"<pledge-id>")," which is a hexadecimal string (pledge details can be cross checked using the commands ",(0,i.yg)("inlineCode",{parentName:"li"},"CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer is-asset-pledged -pid <pledge-id>")," and ",(0,i.yg)("inlineCode",{parentName:"li"},"CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer get-pledge-state -pid <pledge-id>"),")."),(0,i.yg)("li",{parentName:"ul"},"Check the token asset balance for ",(0,i.yg)("inlineCode",{parentName:"li"},"PartyA")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"Corda_Network")," by running the below command, and the output should not include the asset ",(0,i.yg)("inlineCode",{parentName:"li"},"t1:5")," issued earlier.",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"CORDA_PORT=10006 ./clients/build/install/clients/bin/clients get-asset-states-by-type t1\n"))),(0,i.yg)("li",{parentName:"ul"},"Let ",(0,i.yg)("inlineCode",{parentName:"li"},"PartyA")," claim in ",(0,i.yg)("inlineCode",{parentName:"li"},"Corda_Network2")," the tokens which are pledged in the Corda network ",(0,i.yg)("inlineCode",{parentName:"li"},"Corda_Network")," by replacing ",(0,i.yg)("inlineCode",{parentName:"li"},"<pledge-id>")," with the above hexadecimal value (claim issues the tokens in the destination/importing network):",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"NETWORK_NAME='Corda_Network2' CORDA_PORT=30006 ./clients/build/install/clients/bin/clients transfer claim-remote-asset --pledge-id='<pledge-id>' --locker='O=PartyA, L=London, C=GB' --transfer-category='token.corda' --export-network-id='Corda_Network' --param='t1:5' --import-relay-address='localhost:9082'\n")),"(the ",(0,i.yg)("inlineCode",{parentName:"li"},"linear-id"),", which is displayed after successful execution of the above command, can be used to check the newly issued tokens for ",(0,i.yg)("inlineCode",{parentName:"li"},"PartyA")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"Corda_Network2")," by running ",(0,i.yg)("inlineCode",{parentName:"li"},"CORDA_PORT=30006 ./clients/build/install/clients/bin/clients get-state-using-linear-id <linear-id>"),"; or simply check the token balance for ",(0,i.yg)("inlineCode",{parentName:"li"},"PartyA")," by running the command ",(0,i.yg)("inlineCode",{parentName:"li"},"CORDA_PORT=30006 ./clients/build/install/clients/bin/clients get-asset-states-by-type t1")," which should output ",(0,i.yg)("inlineCode",{parentName:"li"},"5")," tokens of type ",(0,i.yg)("inlineCode",{parentName:"li"},"t1"),")")),(0,i.yg)("p",null,"The above steps complete a successful asset transfer from the Corda network ",(0,i.yg)("inlineCode",{parentName:"p"},"Corda_Network")," to the Corda network ",(0,i.yg)("inlineCode",{parentName:"p"},"Corda_Network2"),". In addition to the above commands, following is an extra option."),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},"Let ",(0,i.yg)("inlineCode",{parentName:"li"},"PartyA")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"Corda_Network")," try re-claim the token ",(0,i.yg)("inlineCode",{parentName:"li"},"t1:5")," asset, which will succeed only if the asset was not claimed by ",(0,i.yg)("inlineCode",{parentName:"li"},"PartyA")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"Corda_Network2")," and the pledge has expired:",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer reclaim-pledged-asset --pledge-id=<pledge-id> --export-relay-address='localhost:9081' --transfer-category='token.corda' --import-network-id='Corda_Network2' --param='t1:5'\n")))),(0,i.yg)("h3",{id:"transfer-or-recover-bond-non-fungible-assets"},"Transfer or recover bond (non-fungible) assets"),(0,i.yg)("p",null,"Assume that the CorDapp ",(0,i.yg)("inlineCode",{parentName:"p"},"cordaSimpleApplication")," has been deployed in both networks."),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},"Navigate to the ",(0,i.yg)("inlineCode",{parentName:"li"},"samples/corda/corda-simple-application")," folder in your clone of the Weaver repository."),(0,i.yg)("li",{parentName:"ul"},"Add a bond asset with id ",(0,i.yg)("inlineCode",{parentName:"li"},"a10")," and type ",(0,i.yg)("inlineCode",{parentName:"li"},"bond01")," to ",(0,i.yg)("inlineCode",{parentName:"li"},"PartyA")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"Corda_Network"),":",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients bond issue-asset 'a10' 'bond01'\n")),"(check token balance for ",(0,i.yg)("inlineCode",{parentName:"li"},"PartyA")," by running the command ",(0,i.yg)("inlineCode",{parentName:"li"},"CORDA_PORT=10006 ./clients/build/install/clients/bin/clients bond get-assets-by-type 'bond01'"),")"),(0,i.yg)("li",{parentName:"ul"},"Let ",(0,i.yg)("inlineCode",{parentName:"li"},"PartyA")," pledge these tokens in ",(0,i.yg)("inlineCode",{parentName:"li"},"Corda_Network")," to be transferred to ",(0,i.yg)("inlineCode",{parentName:"li"},"PartyA")," of ",(0,i.yg)("inlineCode",{parentName:"li"},"Corda_Network2")," (pledge burns the tokens in the source/exporting network):",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer pledge-asset --timeout=\"3600\" --import-network-id='Corda_Network2' --recipient='O=PartyA, L=London, C=GB' --param='bond01:a10'\n")),"Note the ",(0,i.yg)("inlineCode",{parentName:"li"},"pledge-id")," displayed after successful execution of the command, which will be used in next steps. Let's denote it ",(0,i.yg)("inlineCode",{parentName:"li"},"<pledge-id>")," which is a hexadecimal string (pledge details can be cross checked using the commands ",(0,i.yg)("inlineCode",{parentName:"li"},"CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer is-asset-pledged -pid <pledge-id>")," and ",(0,i.yg)("inlineCode",{parentName:"li"},"CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer get-pledge-state -pid <pledge-id>"),")."),(0,i.yg)("li",{parentName:"ul"},"Check the bond asset balance for ",(0,i.yg)("inlineCode",{parentName:"li"},"PartyA")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"Corda_Network")," by running the below command, and the output should not include the asset ",(0,i.yg)("inlineCode",{parentName:"li"},"bond01:a10")," issued earlier.",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"CORDA_PORT=10006 ./clients/build/install/clients/bin/clients bond get-assets-by-type 'bond01'`\n"))),(0,i.yg)("li",{parentName:"ul"},"Let ",(0,i.yg)("inlineCode",{parentName:"li"},"PartyA")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"Corda_Network2")," claim the bond asset which is pledged in the Corda network ",(0,i.yg)("inlineCode",{parentName:"li"},"Corda_Network")," by replacing ",(0,i.yg)("inlineCode",{parentName:"li"},"<pledge-id>")," with the above hexadecimal value (claim issues the bond asset in the destination/importing network):",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"NETWORK_NAME=Corda_Network2 CORDA_PORT=30006 ./clients/build/install/clients/bin/clients transfer claim-remote-asset --pledge-id='<pledge-id>' --locker='O=PartyA, L=London, C=GB' --transfer-category='bond.corda' --export-network-id='Corda_Network' --param='bond01:a10' --import-relay-address='localhost:9082'\n")),"(the ",(0,i.yg)("inlineCode",{parentName:"li"},"linear-id"),", which is displayed after successful execution of the above command, can be used to check the newly issued bond asset for ",(0,i.yg)("inlineCode",{parentName:"li"},"PartyA")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"Corda_Network2")," by running ",(0,i.yg)("inlineCode",{parentName:"li"},"CORDA_PORT=30006 ./clients/build/install/clients/bin/clients bond get-asset-by-linear-id <linear-id>"),"; or simply check the bond asset balance for ",(0,i.yg)("inlineCode",{parentName:"li"},"PartyA")," by running the command ",(0,i.yg)("inlineCode",{parentName:"li"},"CORDA_PORT=30006 ./clients/build/install/clients/bin/clients bond get-assets-by-type 'bond01'")," which should output asset with id ",(0,i.yg)("inlineCode",{parentName:"li"},"a10")," and type ",(0,i.yg)("inlineCode",{parentName:"li"},"bond01"),")")),(0,i.yg)("p",null,"The above steps complete a successful asset transfer from the Corda network ",(0,i.yg)("inlineCode",{parentName:"p"},"Corda_Network")," to the Corda network ",(0,i.yg)("inlineCode",{parentName:"p"},"Corda_Network2"),". In addition to the above commands, following is an extra option."),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},"Let ",(0,i.yg)("inlineCode",{parentName:"li"},"PartyA")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"Corda_Network")," try re-claim the bond asset ",(0,i.yg)("inlineCode",{parentName:"li"},"bond01:a10"),", which will succeed only if the asset was not claimed by ",(0,i.yg)("inlineCode",{parentName:"li"},"PartyA")," and the pledge has expired:",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer reclaim-pledged-asset --pledge-id=<pledge-id> --export-relay-address='localhost:9081' --transfer-category='bond.corda' --import-network-id='Corda_Network2' --param='bond01:a10'\n")))),(0,i.yg)("h2",{id:"3-fabric-with-corda"},"3. Fabric with Corda"),(0,i.yg)("p",null,"A Fabric network transfers some tokens owned by ",(0,i.yg)("inlineCode",{parentName:"p"},"Alice")," to ",(0,i.yg)("inlineCode",{parentName:"p"},"PartyA")," (",(0,i.yg)("inlineCode",{parentName:"p"},"CORDA_PORT=10006"),") in a Corda network."),(0,i.yg)("h3",{id:"transfer-or-recover-token-fungible-assets-2"},"Transfer or recover token (fungible) assets"),(0,i.yg)("p",null,"Assuming that the ",(0,i.yg)("inlineCode",{parentName:"p"},"simpleassettransfer")," chaincode has been deployed in Fabric network ",(0,i.yg)("inlineCode",{parentName:"p"},"network1"),", run the following steps related to Fabric by navigating to the ",(0,i.yg)("inlineCode",{parentName:"p"},"samples/fabric/fabric-cli")," folder (",(0,i.yg)("em",{parentName:"p"},"the Go CLI doesn't support asset transfer yet"),")."),(0,i.yg)("p",null,"Similarly, assuming that the CorDapp ",(0,i.yg)("inlineCode",{parentName:"p"},"cordaSimpleApplication")," has been deployed in the Corda network ",(0,i.yg)("inlineCode",{parentName:"p"},"Corda_Network"),", run the following steps related to Corda by navigating to the ",(0,i.yg)("inlineCode",{parentName:"p"},"samples/corda/corda-simple-application")," folder."),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("p",{parentName:"li"},"Verify that ",(0,i.yg)("inlineCode",{parentName:"p"},"alice")," in ",(0,i.yg)("inlineCode",{parentName:"p"},"network1")," owns ",(0,i.yg)("inlineCode",{parentName:"p"},"10000")," tokens as follows:"),(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./scripts/getTokenBalance.sh network1 alice\n"))),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("p",{parentName:"li"},"Get ",(0,i.yg)("inlineCode",{parentName:"p"},"alice")," in ",(0,i.yg)("inlineCode",{parentName:"p"},"network1")," to pledge 50 tokens to ",(0,i.yg)("inlineCode",{parentName:"p"},"PartyA")," in ",(0,i.yg)("inlineCode",{parentName:"p"},"Corda_Network")," as follows (with a 1 hour timeout):"),(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset transfer pledge --source-network='network1' --dest-network='Corda_Network' --recipient='O=PartyA, L=London, C=GB' --expiry-secs=3600 --type='token' --units=50 --owner=alice --data-file=src/data/tokensForTransfer.json\n")),(0,i.yg)("p",{parentName:"li"}," You should see a message containing the unique ID of this pledge on the console as ",(0,i.yg)("inlineCode",{parentName:"p"},"Asset pledged with ID <pledge-id>")," (",(0,i.yg)("inlineCode",{parentName:"p"},"<pledge-id>")," is a hexadecimal string).")),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("p",{parentName:"li"},"Verify that ",(0,i.yg)("inlineCode",{parentName:"p"},"alice")," in ",(0,i.yg)("inlineCode",{parentName:"p"},"network1")," owns ",(0,i.yg)("inlineCode",{parentName:"p"},"9950")," tokens (after losing ",(0,i.yg)("inlineCode",{parentName:"p"},"50"),") as follows:"),(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./scripts/getTokenBalance.sh network1 alice\n"))),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("p",{parentName:"li"},"Let ",(0,i.yg)("inlineCode",{parentName:"p"},"PartyA")," claim in ",(0,i.yg)("inlineCode",{parentName:"p"},"Corda_Network")," the tokens which are pledged in the Fabric network ",(0,i.yg)("inlineCode",{parentName:"p"},"network1")," by replacing ",(0,i.yg)("inlineCode",{parentName:"p"},"<pledge-id>")," with the above hexadecimal value (claim issues the tokens in the destination/importing network):"),(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer claim-remote-asset --pledge-id='<pledge-id>' --locker='alice' --transfer-category='token.fabric' --export-network-id='network1' --param='token1:50' --import-relay-address='localhost:9081'\n")),(0,i.yg)("p",{parentName:"li"},"(the ",(0,i.yg)("inlineCode",{parentName:"p"},"linear-id"),", which is displayed after successful execution of the above command, can be used to check the newly issued tokens for ",(0,i.yg)("inlineCode",{parentName:"p"},"PartyA")," in ",(0,i.yg)("inlineCode",{parentName:"p"},"Corda_Network")," by running ",(0,i.yg)("inlineCode",{parentName:"p"},"CORDA_PORT=10006 ./clients/build/install/clients/bin/clients get-state-using-linear-id <linear-id>"),"; or simply check the token balance for ",(0,i.yg)("inlineCode",{parentName:"p"},"PartyA")," by running the command ",(0,i.yg)("inlineCode",{parentName:"p"},"CORDA_PORT=10006 ./clients/build/install/clients/bin/clients get-asset-states-by-type token1")," which should output ",(0,i.yg)("inlineCode",{parentName:"p"},"50")," tokens of type ",(0,i.yg)("inlineCode",{parentName:"p"},"token1"),")"))),(0,i.yg)("p",null,"The above steps complete a successful asset transfer from the Fabric network ",(0,i.yg)("inlineCode",{parentName:"p"},"network1")," to the Corda network ",(0,i.yg)("inlineCode",{parentName:"p"},"Corda_Network"),". Below demostrates re-claim of the tokens pledged in the Fabric network after the pledge expiry."),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("p",{parentName:"li"},"Now get ",(0,i.yg)("inlineCode",{parentName:"p"},"alice")," in ",(0,i.yg)("inlineCode",{parentName:"p"},"network1")," to pledge 100 tokens to ",(0,i.yg)("inlineCode",{parentName:"p"},"PartyA")," in ",(0,i.yg)("inlineCode",{parentName:"p"},"Corda_Network")," as follows (with a 1 minute timeout):"),(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset transfer pledge --source-network='network1' --dest-network='Corda_Network' --recipient='O=PartyA, L=London, C=GB' --expiry-secs=60 --type=token --units=100 --owner=alice --data-file=src/data/tokensForTransfer.json\n")),(0,i.yg)("p",{parentName:"li"}," You should see a message containing the unique ID of this pledge on the console as ",(0,i.yg)("inlineCode",{parentName:"p"},"Asset pledged with ID <pledge-id>")," (",(0,i.yg)("inlineCode",{parentName:"p"},"<pledge-id>")," is a hexadecimal string)."),(0,i.yg)("p",{parentName:"li"}," Wait for a minute as follows:"),(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"sleep 60\n"))),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("p",{parentName:"li"},"Let ",(0,i.yg)("inlineCode",{parentName:"p"},"PartyA")," in ",(0,i.yg)("inlineCode",{parentName:"p"},"Corda_Network")," claim the tokens which are pledged in the Fabric network ",(0,i.yg)("inlineCode",{parentName:"p"},"network1")," by replacing ",(0,i.yg)("inlineCode",{parentName:"p"},"<pledge-id>")," with the above hexadecimal value (claim issues the tokens in the destination/importing network):"),(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer claim-remote-asset --pledge-id='<pledge-id>' --locker='alice' --transfer-category='token.fabric' --export-network-id='network1' --param='token1:100' --import-relay-address='localhost:9080'\n")),(0,i.yg)("p",{parentName:"li"}," This should fail as the pledge has already expired."),(0,i.yg)("p",{parentName:"li"}," (check the token balance for ",(0,i.yg)("inlineCode",{parentName:"p"},"PartyA")," by running the command ",(0,i.yg)("inlineCode",{parentName:"p"},"CORDA_PORT=10006 ./clients/build/install/clients/bin/clients get-asset-states-by-type token1")," which should still show ",(0,i.yg)("inlineCode",{parentName:"p"},"50")," tokens of type ",(0,i.yg)("inlineCode",{parentName:"p"},"token1")," but not ",(0,i.yg)("inlineCode",{parentName:"p"},"150"),")")),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("p",{parentName:"li"},"Now get ",(0,i.yg)("inlineCode",{parentName:"p"},"alice")," in ",(0,i.yg)("inlineCode",{parentName:"p"},"network1")," to reclaim these tokens as follows:"),(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset transfer reclaim --source-network='network1' --user='alice' --type='token.corda' --pledge-id=<pledge-id> --param=token1:100\n"))),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("p",{parentName:"li"},"Verify that ",(0,i.yg)("inlineCode",{parentName:"p"},"alice")," in ",(0,i.yg)("inlineCode",{parentName:"p"},"network1")," still owns ",(0,i.yg)("inlineCode",{parentName:"p"},"9950")," tokens (after losing ",(0,i.yg)("inlineCode",{parentName:"p"},"50"),") as follows:"),(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./scripts/getTokenBalance.sh network1 alice\n")))),(0,i.yg)("h2",{id:"4-corda-with-fabric"},"4. Corda with Fabric"),(0,i.yg)("p",null,"A Corda network transfers some tokens owned by ",(0,i.yg)("inlineCode",{parentName:"p"},"PartyA")," (",(0,i.yg)("inlineCode",{parentName:"p"},"CORDA_PORT=10006"),") to ",(0,i.yg)("inlineCode",{parentName:"p"},"Alice")," in a Fabric network."),(0,i.yg)("h3",{id:"transfer-or-recover-token-fungible-assets-3"},"Transfer or recover token (fungible) assets"),(0,i.yg)("p",null,"Assuming that the CorDapp ",(0,i.yg)("inlineCode",{parentName:"p"},"cordaSimpleApplication")," has been deployed in the Corda network ",(0,i.yg)("inlineCode",{parentName:"p"},"Corda_Network"),", run the following steps related to Corda by navigating to the ",(0,i.yg)("inlineCode",{parentName:"p"},"samples/corda/corda-simple-application")," folder."),(0,i.yg)("p",null,"Similarly, assume that the ",(0,i.yg)("inlineCode",{parentName:"p"},"simpleassettransfer")," chaincode has been deployed in Fabric network ",(0,i.yg)("inlineCode",{parentName:"p"},"network1"),", run the following steps related to Fabric by navigating to the ",(0,i.yg)("inlineCode",{parentName:"p"},"samples/fabric/fabric-cli")," folder (",(0,i.yg)("em",{parentName:"p"},"the Go CLI doesn't support asset transfer yet"),")."),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},"Add ",(0,i.yg)("inlineCode",{parentName:"li"},"5")," tokens of type ",(0,i.yg)("inlineCode",{parentName:"li"},"token1")," to ",(0,i.yg)("inlineCode",{parentName:"li"},"PartyA")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"Corda_Network"),":",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"CORDA_PORT=10006 ./clients/build/install/clients/bin/clients issue-asset-state 5 token1\n")),"(check token balance for ",(0,i.yg)("inlineCode",{parentName:"li"},"PartyA")," by running the command ",(0,i.yg)("inlineCode",{parentName:"li"},"CORDA_PORT=10006 ./clients/build/install/clients/bin/clients get-asset-states-by-type token1"),")"),(0,i.yg)("li",{parentName:"ul"},"Let ",(0,i.yg)("inlineCode",{parentName:"li"},"PartyA")," pledge (with a 1 hour timeout) these tokens in ",(0,i.yg)("inlineCode",{parentName:"li"},"Corda_Network")," to be transferred to ",(0,i.yg)("inlineCode",{parentName:"li"},"Alice")," of Fabric network ",(0,i.yg)("inlineCode",{parentName:"li"},"network1")," (pledge burns the tokens in the source/exporting network):",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer pledge-asset --fungible --timeout=\"3600\" --import-network-id='network1' --recipient='alice' --param='token1:5'\n")),"Note the ",(0,i.yg)("inlineCode",{parentName:"li"},"pledge-id")," displayed after successful execution of the command, which will be used in next steps. Let's denote it ",(0,i.yg)("inlineCode",{parentName:"li"},"<pledge-id>")," which is a hexadecimal string (pledge details can be cross checked using the commands ",(0,i.yg)("inlineCode",{parentName:"li"},"CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer is-asset-pledged -pid <pledge-id>")," and ",(0,i.yg)("inlineCode",{parentName:"li"},"CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer get-pledge-state -pid <pledge-id>"),")."),(0,i.yg)("li",{parentName:"ul"},"Check the token asset balance for ",(0,i.yg)("inlineCode",{parentName:"li"},"PartyA")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"Corda_Network")," by running the below command, and the output should not include the asset ",(0,i.yg)("inlineCode",{parentName:"li"},"token1:5")," issued earlier.",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre"},"CORDA_PORT=10006 ./clients/build/install/clients/bin/clients get-asset-states-by-type token1`\n"))),(0,i.yg)("li",{parentName:"ul"},"Verify that ",(0,i.yg)("inlineCode",{parentName:"li"},"alice")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"network1")," owns ",(0,i.yg)("inlineCode",{parentName:"li"},"10000")," tokens as follows:",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./scripts/getTokenBalance.sh network1 alice\n"))),(0,i.yg)("li",{parentName:"ul"},"Get ",(0,i.yg)("inlineCode",{parentName:"li"},"alice")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"network")," to claim these tokens as follows (replace ",(0,i.yg)("inlineCode",{parentName:"li"},"<pledge-id>")," with the above hexadecimal value):",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset transfer claim --source-network='Corda_Network' --dest-network=network1 --user='alice' --owner='O=PartyA, L=London, C=GB' --type='token.corda' --pledge-id=<pledge-id> --param=token1:5\n"))),(0,i.yg)("li",{parentName:"ul"},"Verify that ",(0,i.yg)("inlineCode",{parentName:"li"},"alice")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"network")," now owns ",(0,i.yg)("inlineCode",{parentName:"li"},"1050")," tokens as follows:",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./scripts/getTokenBalance.sh network1 alice\n")))),(0,i.yg)("p",null,"The above steps complete a successful asset transfer from the Corda network ",(0,i.yg)("inlineCode",{parentName:"p"},"Corda_Network")," to the Fabric network ",(0,i.yg)("inlineCode",{parentName:"p"},"network1"),". In addition to the above commands, following is an extra option."),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},"Let ",(0,i.yg)("inlineCode",{parentName:"li"},"PartyA")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"Corda_Network")," try re-claim the token ",(0,i.yg)("inlineCode",{parentName:"li"},"token1:5")," asset, which will succeed only if the asset was not claimed by ",(0,i.yg)("inlineCode",{parentName:"li"},"alice")," in Fabric network and the pledge has expired (replace ",(0,i.yg)("inlineCode",{parentName:"li"},"<pledge-id>")," with the above hexadecimal value):",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer reclaim-pledged-asset --pledge-id=<pledge-id> --export-relay-address='localhost:9081' --transfer-category='token.fabric' --import-network-id='network1' --param='token1:5'\n")))))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/2e5dd55e.71fe4275.js b/assets/js/2e5dd55e.71fe4275.js deleted file mode 100644 index d8b42219d..000000000 --- a/assets/js/2e5dd55e.71fe4275.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[4010],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>N});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function l(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?r(Object(n),!0).forEach((function(t){i(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):r(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function o(e,t){if(null==e)return{};var n,a,i=function(e,t){if(null==e)return{};var n,a,i={},r=Object.keys(e);for(a=0;a<r.length;a++)n=r[a],t.indexOf(n)>=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a<r.length;a++)n=r[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=a.createContext({}),p=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},d=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},k="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,r=e.originalType,s=e.parentName,d=o(e,["components","mdxType","originalType","parentName"]),k=p(n),m=i,N=k["".concat(s,".").concat(m)]||k[m]||c[m]||r;return n?a.createElement(N,l(l({ref:t},d),{},{components:n})):a.createElement(N,l({ref:t},d))}));function N(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=n.length,l=new Array(r);l[0]=m;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[k]="string"==typeof e?e:i,l[1]=o;for(var p=2;p<r;p++)l[p]=n[p];return a.createElement.apply(null,l)}return a.createElement.apply(null,n)}m.displayName="MDXCreateElement"},8854:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>c,frontMatter:()=>r,metadata:()=>o,toc:()=>p});var a=n(7462),i=(n(7294),n(3905));const r={id:"asset-transfer",title:"Asset Transfer",pagination_prev:"external/getting-started/interop/overview",pagination_next:"external/getting-started/enabling-weaver-network/overview"},l=void 0,o={unversionedId:"external/getting-started/interop/asset-transfer",id:"external/getting-started/interop/asset-transfer",title:"Asset Transfer",description:"\x3c!--",source:"@site/docs/external/getting-started/interop/asset-transfer.md",sourceDirName:"external/getting-started/interop",slug:"/external/getting-started/interop/asset-transfer",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-transfer",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/getting-started/interop/asset-transfer.md",tags:[],version:"current",frontMatter:{id:"asset-transfer",title:"Asset Transfer",pagination_prev:"external/getting-started/interop/overview",pagination_next:"external/getting-started/enabling-weaver-network/overview"},sidebar:"Documentation",previous:{title:"Testing Interoperation Modes",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/overview"},next:{title:"Enabling Weaver in Existing DLT Applications",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/overview"}},s={},p=[{value:"1. Fabric with Fabric",id:"1-fabric-with-fabric",level:2},{value:"Transfer or recover a bond (non-fungible) asset",id:"transfer-or-recover-a-bond-non-fungible-asset",level:3},{value:"Transfer or recover token (fungible) assets",id:"transfer-or-recover-token-fungible-assets",level:3},{value:"2. Corda with Corda",id:"2-corda-with-corda",level:2},{value:"Transfer or recover token (fungible) assets",id:"transfer-or-recover-token-fungible-assets-1",level:3},{value:"Transfer or recover bond (non-fungible) assets",id:"transfer-or-recover-bond-non-fungible-assets",level:3},{value:"3. Fabric with Corda",id:"3-fabric-with-corda",level:2},{value:"Transfer or recover token (fungible) assets",id:"transfer-or-recover-token-fungible-assets-2",level:3},{value:"4. Corda with Fabric",id:"4-corda-with-fabric",level:2},{value:"Transfer or recover token (fungible) assets",id:"transfer-or-recover-token-fungible-assets-3",level:3}],d={toc:p},k="wrapper";function c(e){let{components:t,...n}=e;return(0,i.kt)(k,(0,a.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"This document lists sample ways in which you can exercise the asset-transfer interoperation protocol on the test network ",(0,i.kt)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/overview"},"launched earlier"),"."),(0,i.kt)("p",null,"Once the networks, relays, and drivers have been launched, and the ledgers bootstrapped, you can trigger the following interoperation flows corresponding to distinct asset-sharing combinations ",(0,i.kt)("em",{parentName:"p"},"other combinations of DLTs will be supported soon"),"):"),(0,i.kt)("h2",{id:"1-fabric-with-fabric"},"1. Fabric with Fabric"),(0,i.kt)("p",null,"One Fabric network transfers either a bond or some tokens owned by Alice to Bob in the other network"),(0,i.kt)("p",null,"Assuming that the ",(0,i.kt)("inlineCode",{parentName:"p"},"simpleassettransfer")," chaincode has been deployed in both networks, run the following steps by navigating to the ",(0,i.kt)("inlineCode",{parentName:"p"},"samples/fabric/fabric-cli")," folder (",(0,i.kt)("em",{parentName:"p"},"the Go CLI doesn't support asset transfer yet"),")."),(0,i.kt)("h3",{id:"transfer-or-recover-a-bond-non-fungible-asset"},"Transfer or recover a bond (non-fungible) asset"),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},"Verify that ",(0,i.kt)("inlineCode",{parentName:"li"},"alice")," owns bonds with ids ",(0,i.kt)("inlineCode",{parentName:"li"},"a03")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"a04")," as follows:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},'./bin/fabric-cli chaincode query --user=alice mychannel simpleassettransfer ReadAsset \'["bond01","a03"]\' --local-network=network1\n./bin/fabric-cli chaincode query --user=alice mychannel simpleassettransfer ReadAsset \'["bond01","a04"]\' --local-network=network1\n')),"You should see a JSON structure corresponding to the bond being logged on the console in each case."),(0,i.kt)("li",{parentName:"ol"},"Get ",(0,i.kt)("inlineCode",{parentName:"li"},"alice")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"network1")," to pledge bond ",(0,i.kt)("inlineCode",{parentName:"li"},"a03")," to ",(0,i.kt)("inlineCode",{parentName:"li"},"bob")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"network2")," as follows (with a 1 hour timeout):",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset transfer pledge --source-network=network1 --dest-network=network2 --recipient=bob --expiry-secs=3600 --type=bond --ref=a03 --data-file=src/data/assetsForTransfer.json\n")),"You should see a message containing the unique ID of this pledge on the console as ",(0,i.kt)("inlineCode",{parentName:"li"},"Asset pledged with ID <pledge-id>")," (",(0,i.kt)("inlineCode",{parentName:"li"},"<pledge-id>")," is a hexadecimal string)."),(0,i.kt)("li",{parentName:"ol"},"Get ",(0,i.kt)("inlineCode",{parentName:"li"},"bob")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"network2")," to claim this bond asset as follows:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset transfer claim --source-network=network1 --dest-network=network2 --user=bob --owner=alice --type='bond.fabric' --pledge-id=<pledge-id> --param=bond01:a03\n"))),(0,i.kt)("li",{parentName:"ol"},"Verify that ",(0,i.kt)("inlineCode",{parentName:"li"},"alice")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"network1")," does not own this asset as follows:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},'./bin/fabric-cli chaincode query --user=alice mychannel simpleassettransfer ReadAsset \'["bond01","a03"]\' --local-network=network1\n')),"You should see an error message like ",(0,i.kt)("inlineCode",{parentName:"li"},"Error: the asset a03 does not exist"),"."),(0,i.kt)("li",{parentName:"ol"},"Verify that ",(0,i.kt)("inlineCode",{parentName:"li"},"bob")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"network2")," now owns this asset as follows:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},'./bin/fabric-cli chaincode query --user=bob mychannel simpleassettransfer ReadAsset \'["bond01","a03"]\' --local-network=network2\n'))),(0,i.kt)("li",{parentName:"ol"},"Now get ",(0,i.kt)("inlineCode",{parentName:"li"},"alice")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"network1")," to pledge bond ",(0,i.kt)("inlineCode",{parentName:"li"},"a04")," to ",(0,i.kt)("inlineCode",{parentName:"li"},"bob")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"network2")," as follows (with a 1 minute timeout):",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset transfer pledge --source-network=network1 --dest-network=network2 --recipient=bob --expiry-secs=60 --type=bond --ref=a04 --data-file=src/data/assetsForTransfer.json\n")),"Wait for a minute as follows:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"sleep 60\n")),"You should see a message containing the unique ID of this pledge on the console as ",(0,i.kt)("inlineCode",{parentName:"li"},"Asset pledged with ID <pledge-id>")," (",(0,i.kt)("inlineCode",{parentName:"li"},"<pledge-id>")," is a hexadecimal string)."),(0,i.kt)("li",{parentName:"ol"},"Now get ",(0,i.kt)("inlineCode",{parentName:"li"},"bob")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"network2")," to claim this bond asset as follows:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset transfer claim --source-network=network1 --dest-network=network2 --user=bob --owner=alice --type='bond.fabric' --pledge-id=<pledge-id> --param=bond01:a04\n")),"This should fail as the pledge has already expired."),(0,i.kt)("li",{parentName:"ol"},"Now get ",(0,i.kt)("inlineCode",{parentName:"li"},"alice")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"network1")," to reclaim the asset as follows:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset transfer reclaim --source-network=network1 --user=alice --type='bond.fabric' --pledge-id=<pledge-id> --param=bond01:a04\n"))),(0,i.kt)("li",{parentName:"ol"},"Verify that ",(0,i.kt)("inlineCode",{parentName:"li"},"alice")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"network1")," owns this asset as follows:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},'./bin/fabric-cli chaincode query --user=alice mychannel simpleassettransfer ReadAsset \'["bond01","a04"]\' --local-network=network1\n'))),(0,i.kt)("li",{parentName:"ol"},"Verify that ",(0,i.kt)("inlineCode",{parentName:"li"},"bob")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"network2")," does not own this asset as follows:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},'./bin/fabric-cli chaincode query --user=bob mychannel simpleassettransfer ReadAsset \'["bond01","a04"]\' --local-network=network2\n')),"You should see an error message like ",(0,i.kt)("inlineCode",{parentName:"li"},"Error: the asset a04 does not exist"),".")),(0,i.kt)("h3",{id:"transfer-or-recover-token-fungible-assets"},"Transfer or recover token (fungible) assets"),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},"Verify that ",(0,i.kt)("inlineCode",{parentName:"li"},"alice")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"network1")," owns ",(0,i.kt)("inlineCode",{parentName:"li"},"10000")," tokens as follows:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./scripts/getTokenBalance.sh network1 alice\n"))),(0,i.kt)("li",{parentName:"ol"},"Verify that ",(0,i.kt)("inlineCode",{parentName:"li"},"bob")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"network2")," owns no tokens as follows:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./scripts/getTokenBalance.sh network2 bob\n")),"You should see an error message like ",(0,i.kt)("inlineCode",{parentName:"li"},"Error: owner does not have a wallet"),"."),(0,i.kt)("li",{parentName:"ol"},"Get ",(0,i.kt)("inlineCode",{parentName:"li"},"alice")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"network1")," to pledge 50 tokens to ",(0,i.kt)("inlineCode",{parentName:"li"},"bob")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"network2")," as follows (with a 1 hour timeout):",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset transfer pledge --source-network=network1 --dest-network=network2 --recipient=bob --expiry-secs=3600 --type=token --units=50 --owner=alice --data-file=src/data/tokensForTransfer.json\n")),"You should see a message containing the unique ID of this pledge on the console as ",(0,i.kt)("inlineCode",{parentName:"li"},"Asset pledged with ID <pledge-id>")," (",(0,i.kt)("inlineCode",{parentName:"li"},"<pledge-id>")," is a hexadecimal string)."),(0,i.kt)("li",{parentName:"ol"},"Get ",(0,i.kt)("inlineCode",{parentName:"li"},"bob")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"network2")," to claim these tokens as follows (replace ",(0,i.kt)("inlineCode",{parentName:"li"},"<pledge-id>")," with the above hexadecimal value):",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset transfer claim --source-network=network1 --dest-network=network2 --user=bob --owner=alice --type='token.fabric' --pledge-id=<pledge-id> --param=token1:50\n"))),(0,i.kt)("li",{parentName:"ol"},"Verify that ",(0,i.kt)("inlineCode",{parentName:"li"},"alice")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"network1")," owns ",(0,i.kt)("inlineCode",{parentName:"li"},"9950")," tokens (after losing ",(0,i.kt)("inlineCode",{parentName:"li"},"50"),") as follows:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./scripts/getTokenBalance.sh network1 alice\n"))),(0,i.kt)("li",{parentName:"ol"},"Verify that ",(0,i.kt)("inlineCode",{parentName:"li"},"bob")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"network2")," now owns ",(0,i.kt)("inlineCode",{parentName:"li"},"50")," tokens as follows:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./scripts/getTokenBalance.sh network2 bob\n"))),(0,i.kt)("li",{parentName:"ol"},"Now get ",(0,i.kt)("inlineCode",{parentName:"li"},"alice")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"network1")," to pledge 100 tokens to ",(0,i.kt)("inlineCode",{parentName:"li"},"bob")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"network2")," as follows (with a 1 minute timeout):",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset transfer pledge --source-network=network1 --dest-network=network2 --recipient=bob --expiry-secs=60 --type=token --units=100 --owner=alice --data-file=src/data/tokensForTransfer.json\n")),"Wait for a minute as follows:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"sleep 60\n")),"You should see a message containing the unique ID of this pledge on the console as ",(0,i.kt)("inlineCode",{parentName:"li"},"Asset pledged with ID <pledge-id>")," (",(0,i.kt)("inlineCode",{parentName:"li"},"<pledge-id>")," is a hexadecimal string)."),(0,i.kt)("li",{parentName:"ol"},"Now get ",(0,i.kt)("inlineCode",{parentName:"li"},"bob")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"network2")," to claim these tokens as follows (replace ",(0,i.kt)("inlineCode",{parentName:"li"},"<pledge-id>")," with the above hexadecimal value):",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset transfer claim --source-network=network1 --dest-network=network2 --user=bob --owner=alice --type='token.fabric' --pledge-id=<pledge-id> --param=token1:100\n")),"This should fail as the pledge has already expired."),(0,i.kt)("li",{parentName:"ol"},"Now get ",(0,i.kt)("inlineCode",{parentName:"li"},"alice")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"network1")," to reclaim these tokens as follows:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset transfer reclaim --source-network=network1 --user=alice --type='token.fabric' --pledge-id=<pledge-id> --param=token1:100\n"))),(0,i.kt)("li",{parentName:"ol"},"Verify that ",(0,i.kt)("inlineCode",{parentName:"li"},"alice")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"network1")," still owns ",(0,i.kt)("inlineCode",{parentName:"li"},"9950")," tokens (after losing ",(0,i.kt)("inlineCode",{parentName:"li"},"50"),") as follows:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./scripts/getTokenBalance.sh network1 alice\n"))),(0,i.kt)("li",{parentName:"ol"},"Verify that ",(0,i.kt)("inlineCode",{parentName:"li"},"bob")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"network2")," still owns only ",(0,i.kt)("inlineCode",{parentName:"li"},"50")," tokens as follows:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./scripts/getTokenBalance.sh network2 bob\n")))),(0,i.kt)("h2",{id:"2-corda-with-corda"},"2. Corda with Corda"),(0,i.kt)("p",null,"One Corda network transfers either a bond or some tokens owned by the party ",(0,i.kt)("inlineCode",{parentName:"p"},"PartyA")," (",(0,i.kt)("inlineCode",{parentName:"p"},"CORDA_PORT=10006"),") to the party ",(0,i.kt)("inlineCode",{parentName:"p"},"PartyA")," (",(0,i.kt)("inlineCode",{parentName:"p"},"CORDA_PORT=30006"),") in the other network."),(0,i.kt)("h3",{id:"transfer-or-recover-token-fungible-assets-1"},"Transfer or recover token (fungible) assets"),(0,i.kt)("p",null,"Assume that the CorDapp ",(0,i.kt)("inlineCode",{parentName:"p"},"cordaSimpleApplication")," has been deployed in both networks."),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Navigate to ",(0,i.kt)("inlineCode",{parentName:"li"},"samples/corda/corda-simple-application")," folder."),(0,i.kt)("li",{parentName:"ul"},"Add ",(0,i.kt)("inlineCode",{parentName:"li"},"5")," tokens of type ",(0,i.kt)("inlineCode",{parentName:"li"},"t1")," to ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyA")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network"),":",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"NETWORK_NAME='Corda_Network' CORDA_PORT=10006 ./clients/build/install/clients/bin/clients issue-asset-state 5 t1\n")),"(check token balance for ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyA")," by running the command ",(0,i.kt)("inlineCode",{parentName:"li"},"CORDA_PORT=10006 ./clients/build/install/clients/bin/clients get-asset-states-by-type t1"),")"),(0,i.kt)("li",{parentName:"ul"},"Let ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyA")," pledge these tokens in ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network")," to be transferred to ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyA")," of ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network2")," (pledge burns the tokens in the source/exporting network):",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"NETWORK_NAME='Corda_Network' CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer pledge-asset --fungible --timeout=\"3600\" --import-network-id='Corda_Network2' --recipient='O=PartyA, L=London, C=GB' --param='t1:5'\n")),"Note the ",(0,i.kt)("inlineCode",{parentName:"li"},"pledge-id")," displayed after successful execution of the command, which will be used in next steps. Let's denote it ",(0,i.kt)("inlineCode",{parentName:"li"},"<pledge-id>")," which is a hexadecimal string (pledge details can be cross checked using the commands ",(0,i.kt)("inlineCode",{parentName:"li"},"CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer is-asset-pledged -pid <pledge-id>")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer get-pledge-state -pid <pledge-id>"),")."),(0,i.kt)("li",{parentName:"ul"},"Check the token asset balance for ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyA")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network")," by running the below command, and the output should not include the asset ",(0,i.kt)("inlineCode",{parentName:"li"},"t1:5")," issued earlier.",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"CORDA_PORT=10006 ./clients/build/install/clients/bin/clients get-asset-states-by-type t1\n"))),(0,i.kt)("li",{parentName:"ul"},"Let ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyA")," claim in ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network2")," the tokens which are pledged in the Corda network ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network")," by replacing ",(0,i.kt)("inlineCode",{parentName:"li"},"<pledge-id>")," with the above hexadecimal value (claim issues the tokens in the destination/importing network):",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"NETWORK_NAME='Corda_Network2' CORDA_PORT=30006 ./clients/build/install/clients/bin/clients transfer claim-remote-asset --pledge-id='<pledge-id>' --locker='O=PartyA, L=London, C=GB' --transfer-category='token.corda' --export-network-id='Corda_Network' --param='t1:5' --import-relay-address='localhost:9082'\n")),"(the ",(0,i.kt)("inlineCode",{parentName:"li"},"linear-id"),", which is displayed after successful execution of the above command, can be used to check the newly issued tokens for ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyA")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network2")," by running ",(0,i.kt)("inlineCode",{parentName:"li"},"CORDA_PORT=30006 ./clients/build/install/clients/bin/clients get-state-using-linear-id <linear-id>"),"; or simply check the token balance for ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyA")," by running the command ",(0,i.kt)("inlineCode",{parentName:"li"},"CORDA_PORT=30006 ./clients/build/install/clients/bin/clients get-asset-states-by-type t1")," which should output ",(0,i.kt)("inlineCode",{parentName:"li"},"5")," tokens of type ",(0,i.kt)("inlineCode",{parentName:"li"},"t1"),")")),(0,i.kt)("p",null,"The above steps complete a successful asset transfer from the Corda network ",(0,i.kt)("inlineCode",{parentName:"p"},"Corda_Network")," to the Corda network ",(0,i.kt)("inlineCode",{parentName:"p"},"Corda_Network2"),". In addition to the above commands, following is an extra option."),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Let ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyA")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network")," try re-claim the token ",(0,i.kt)("inlineCode",{parentName:"li"},"t1:5")," asset, which will succeed only if the asset was not claimed by ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyA")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network2")," and the pledge has expired:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer reclaim-pledged-asset --pledge-id=<pledge-id> --export-relay-address='localhost:9081' --transfer-category='token.corda' --import-network-id='Corda_Network2' --param='t1:5'\n")))),(0,i.kt)("h3",{id:"transfer-or-recover-bond-non-fungible-assets"},"Transfer or recover bond (non-fungible) assets"),(0,i.kt)("p",null,"Assume that the CorDapp ",(0,i.kt)("inlineCode",{parentName:"p"},"cordaSimpleApplication")," has been deployed in both networks."),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Navigate to ",(0,i.kt)("inlineCode",{parentName:"li"},"samples/corda/corda-simple-application")," folder."),(0,i.kt)("li",{parentName:"ul"},"Add a bond asset with id ",(0,i.kt)("inlineCode",{parentName:"li"},"a10")," and type ",(0,i.kt)("inlineCode",{parentName:"li"},"bond01")," to ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyA")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network"),":",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients bond issue-asset 'a10' 'bond01'\n")),"(check token balance for ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyA")," by running the command ",(0,i.kt)("inlineCode",{parentName:"li"},"CORDA_PORT=10006 ./clients/build/install/clients/bin/clients bond get-assets-by-type 'bond01'"),")"),(0,i.kt)("li",{parentName:"ul"},"Let ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyA")," pledge these tokens in ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network")," to be transferred to ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyA")," of ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network2")," (pledge burns the tokens in the source/exporting network):",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer pledge-asset --timeout=\"3600\" --import-network-id='Corda_Network2' --recipient='O=PartyA, L=London, C=GB' --param='bond01:a10'\n")),"Note the ",(0,i.kt)("inlineCode",{parentName:"li"},"pledge-id")," displayed after successful execution of the command, which will be used in next steps. Let's denote it ",(0,i.kt)("inlineCode",{parentName:"li"},"<pledge-id>")," which is a hexadecimal string (pledge details can be cross checked using the commands ",(0,i.kt)("inlineCode",{parentName:"li"},"CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer is-asset-pledged -pid <pledge-id>")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer get-pledge-state -pid <pledge-id>"),")."),(0,i.kt)("li",{parentName:"ul"},"Check the bond asset balance for ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyA")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network")," by running the below command, and the output should not include the asset ",(0,i.kt)("inlineCode",{parentName:"li"},"bond01:a10")," issued earlier.",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"CORDA_PORT=10006 ./clients/build/install/clients/bin/clients bond get-assets-by-type 'bond01'`\n"))),(0,i.kt)("li",{parentName:"ul"},"Let ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyA")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network2")," claim the bond asset which is pledged in the Corda network ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network")," by replacing ",(0,i.kt)("inlineCode",{parentName:"li"},"<pledge-id>")," with the above hexadecimal value (claim issues the bond asset in the destination/importing network):",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"NETWORK_NAME=Corda_Network2 CORDA_PORT=30006 ./clients/build/install/clients/bin/clients transfer claim-remote-asset --pledge-id='<pledge-id>' --locker='O=PartyA, L=London, C=GB' --transfer-category='bond.corda' --export-network-id='Corda_Network' --param='bond01:a10' --import-relay-address='localhost:9082'\n")),"(the ",(0,i.kt)("inlineCode",{parentName:"li"},"linear-id"),", which is displayed after successful execution of the above command, can be used to check the newly issued bond asset for ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyA")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network2")," by running ",(0,i.kt)("inlineCode",{parentName:"li"},"CORDA_PORT=30006 ./clients/build/install/clients/bin/clients bond get-asset-by-linear-id <linear-id>"),"; or simply check the bond asset balance for ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyA")," by running the command ",(0,i.kt)("inlineCode",{parentName:"li"},"CORDA_PORT=30006 ./clients/build/install/clients/bin/clients bond get-assets-by-type 'bond01'")," which should output asset with id ",(0,i.kt)("inlineCode",{parentName:"li"},"a10")," and type ",(0,i.kt)("inlineCode",{parentName:"li"},"bond01"),")")),(0,i.kt)("p",null,"The above steps complete a successful asset transfer from the Corda network ",(0,i.kt)("inlineCode",{parentName:"p"},"Corda_Network")," to the Corda network ",(0,i.kt)("inlineCode",{parentName:"p"},"Corda_Network2"),". In addition to the above commands, following is an extra option."),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Let ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyA")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network")," try re-claim the bond asset ",(0,i.kt)("inlineCode",{parentName:"li"},"bond01:a10"),", which will succeed only if the asset was not claimed by ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyA")," and the pledge has expired:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer reclaim-pledged-asset --pledge-id=<pledge-id> --export-relay-address='localhost:9081' --transfer-category='bond.corda' --import-network-id='Corda_Network2' --param='bond01:a10'\n")))),(0,i.kt)("h2",{id:"3-fabric-with-corda"},"3. Fabric with Corda"),(0,i.kt)("p",null,"A Fabric network transfers some tokens owned by ",(0,i.kt)("inlineCode",{parentName:"p"},"Alice")," to ",(0,i.kt)("inlineCode",{parentName:"p"},"PartyA")," (",(0,i.kt)("inlineCode",{parentName:"p"},"CORDA_PORT=10006"),") in a Corda network."),(0,i.kt)("h3",{id:"transfer-or-recover-token-fungible-assets-2"},"Transfer or recover token (fungible) assets"),(0,i.kt)("p",null,"Assuming that the ",(0,i.kt)("inlineCode",{parentName:"p"},"simpleassettransfer")," chaincode has been deployed in Fabric network ",(0,i.kt)("inlineCode",{parentName:"p"},"network1"),", run the following steps related to Fabric by navigating to the ",(0,i.kt)("inlineCode",{parentName:"p"},"samples/fabric/fabric-cli")," folder (",(0,i.kt)("em",{parentName:"p"},"the Go CLI doesn't support asset transfer yet"),")."),(0,i.kt)("p",null,"Similarly, assuming that the CorDapp ",(0,i.kt)("inlineCode",{parentName:"p"},"cordaSimpleApplication")," has been deployed in the Corda network ",(0,i.kt)("inlineCode",{parentName:"p"},"Corda_Network"),", run the following steps related to Corda by navigating to the ",(0,i.kt)("inlineCode",{parentName:"p"},"samples/corda/corda-simple-application")," folder."),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},"Verify that ",(0,i.kt)("inlineCode",{parentName:"p"},"alice")," in ",(0,i.kt)("inlineCode",{parentName:"p"},"network1")," owns ",(0,i.kt)("inlineCode",{parentName:"p"},"10000")," tokens as follows:"),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./scripts/getTokenBalance.sh network1 alice\n"))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},"Get ",(0,i.kt)("inlineCode",{parentName:"p"},"alice")," in ",(0,i.kt)("inlineCode",{parentName:"p"},"network1")," to pledge 50 tokens to ",(0,i.kt)("inlineCode",{parentName:"p"},"PartyA")," in ",(0,i.kt)("inlineCode",{parentName:"p"},"Corda_Network")," as follows (with a 1 hour timeout):"),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset transfer pledge --source-network='network1' --dest-network='Corda_Network' --recipient='O=PartyA, L=London, C=GB' --expiry-secs=3600 --type='token' --units=50 --owner=alice --data-file=src/data/tokensForTransfer.json\n")),(0,i.kt)("p",{parentName:"li"}," You should see a message containing the unique ID of this pledge on the console as ",(0,i.kt)("inlineCode",{parentName:"p"},"Asset pledged with ID <pledge-id>")," (",(0,i.kt)("inlineCode",{parentName:"p"},"<pledge-id>")," is a hexadecimal string).")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},"Verify that ",(0,i.kt)("inlineCode",{parentName:"p"},"alice")," in ",(0,i.kt)("inlineCode",{parentName:"p"},"network1")," owns ",(0,i.kt)("inlineCode",{parentName:"p"},"9950")," tokens (after losing ",(0,i.kt)("inlineCode",{parentName:"p"},"50"),") as follows:"),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./scripts/getTokenBalance.sh network1 alice\n"))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},"Let ",(0,i.kt)("inlineCode",{parentName:"p"},"PartyA")," claim in ",(0,i.kt)("inlineCode",{parentName:"p"},"Corda_Network")," the tokens which are pledged in the Fabric network ",(0,i.kt)("inlineCode",{parentName:"p"},"network1")," by replacing ",(0,i.kt)("inlineCode",{parentName:"p"},"<pledge-id>")," with the above hexadecimal value (claim issues the tokens in the destination/importing network):"),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer claim-remote-asset --pledge-id='<pledge-id>' --locker='alice' --transfer-category='token.fabric' --export-network-id='network1' --param='token1:50' --import-relay-address='localhost:9081'\n")),(0,i.kt)("p",{parentName:"li"},"(the ",(0,i.kt)("inlineCode",{parentName:"p"},"linear-id"),", which is displayed after successful execution of the above command, can be used to check the newly issued tokens for ",(0,i.kt)("inlineCode",{parentName:"p"},"PartyA")," in ",(0,i.kt)("inlineCode",{parentName:"p"},"Corda_Network")," by running ",(0,i.kt)("inlineCode",{parentName:"p"},"CORDA_PORT=10006 ./clients/build/install/clients/bin/clients get-state-using-linear-id <linear-id>"),"; or simply check the token balance for ",(0,i.kt)("inlineCode",{parentName:"p"},"PartyA")," by running the command ",(0,i.kt)("inlineCode",{parentName:"p"},"CORDA_PORT=10006 ./clients/build/install/clients/bin/clients get-asset-states-by-type token1")," which should output ",(0,i.kt)("inlineCode",{parentName:"p"},"50")," tokens of type ",(0,i.kt)("inlineCode",{parentName:"p"},"token1"),")"))),(0,i.kt)("p",null,"The above steps complete a successful asset transfer from the Fabric network ",(0,i.kt)("inlineCode",{parentName:"p"},"network1")," to the Corda network ",(0,i.kt)("inlineCode",{parentName:"p"},"Corda_Network"),". Below demostrates re-claim of the tokens pledged in the Fabric network after the pledge expiry."),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},"Now get ",(0,i.kt)("inlineCode",{parentName:"p"},"alice")," in ",(0,i.kt)("inlineCode",{parentName:"p"},"network1")," to pledge 100 tokens to ",(0,i.kt)("inlineCode",{parentName:"p"},"PartyA")," in ",(0,i.kt)("inlineCode",{parentName:"p"},"Corda_Network")," as follows (with a 1 minute timeout):"),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset transfer pledge --source-network='network1' --dest-network='Corda_Network' --recipient='O=PartyA, L=London, C=GB' --expiry-secs=60 --type=token --units=100 --owner=alice --data-file=src/data/tokensForTransfer.json\n")),(0,i.kt)("p",{parentName:"li"}," You should see a message containing the unique ID of this pledge on the console as ",(0,i.kt)("inlineCode",{parentName:"p"},"Asset pledged with ID <pledge-id>")," (",(0,i.kt)("inlineCode",{parentName:"p"},"<pledge-id>")," is a hexadecimal string)."),(0,i.kt)("p",{parentName:"li"}," Wait for a minute as follows:"),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"sleep 60\n"))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},"Let ",(0,i.kt)("inlineCode",{parentName:"p"},"PartyA")," in ",(0,i.kt)("inlineCode",{parentName:"p"},"Corda_Network")," claim the tokens which are pledged in the Fabric network ",(0,i.kt)("inlineCode",{parentName:"p"},"network1")," by replacing ",(0,i.kt)("inlineCode",{parentName:"p"},"<pledge-id>")," with the above hexadecimal value (claim issues the tokens in the destination/importing network):"),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer claim-remote-asset --pledge-id='<pledge-id>' --locker='alice' --transfer-category='token.fabric' --export-network-id='network1' --param='token1:100' --import-relay-address='localhost:9080'\n")),(0,i.kt)("p",{parentName:"li"}," This should fail as the pledge has already expired."),(0,i.kt)("p",{parentName:"li"}," (check the token balance for ",(0,i.kt)("inlineCode",{parentName:"p"},"PartyA")," by running the command ",(0,i.kt)("inlineCode",{parentName:"p"},"CORDA_PORT=10006 ./clients/build/install/clients/bin/clients get-asset-states-by-type token1")," which should still show ",(0,i.kt)("inlineCode",{parentName:"p"},"50")," tokens of type ",(0,i.kt)("inlineCode",{parentName:"p"},"token1")," but not ",(0,i.kt)("inlineCode",{parentName:"p"},"150"),")")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},"Now get ",(0,i.kt)("inlineCode",{parentName:"p"},"alice")," in ",(0,i.kt)("inlineCode",{parentName:"p"},"network1")," to reclaim these tokens as follows:"),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset transfer reclaim --source-network='network1' --user='alice' --type='token.corda' --pledge-id=<pledge-id> --param=token1:100\n"))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},"Verify that ",(0,i.kt)("inlineCode",{parentName:"p"},"alice")," in ",(0,i.kt)("inlineCode",{parentName:"p"},"network1")," still owns ",(0,i.kt)("inlineCode",{parentName:"p"},"9950")," tokens (after losing ",(0,i.kt)("inlineCode",{parentName:"p"},"50"),") as follows:"),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./scripts/getTokenBalance.sh network1 alice\n")))),(0,i.kt)("h2",{id:"4-corda-with-fabric"},"4. Corda with Fabric"),(0,i.kt)("p",null,"A Corda network transfers some tokens owned by ",(0,i.kt)("inlineCode",{parentName:"p"},"PartyA")," (",(0,i.kt)("inlineCode",{parentName:"p"},"CORDA_PORT=10006"),") to ",(0,i.kt)("inlineCode",{parentName:"p"},"Alice")," in a Fabric network."),(0,i.kt)("h3",{id:"transfer-or-recover-token-fungible-assets-3"},"Transfer or recover token (fungible) assets"),(0,i.kt)("p",null,"Assuming that the CorDapp ",(0,i.kt)("inlineCode",{parentName:"p"},"cordaSimpleApplication")," has been deployed in the Corda network ",(0,i.kt)("inlineCode",{parentName:"p"},"Corda_Network"),", run the following steps related to Corda by navigating to the ",(0,i.kt)("inlineCode",{parentName:"p"},"samples/corda/corda-simple-application")," folder."),(0,i.kt)("p",null,"Similarly, assume that the ",(0,i.kt)("inlineCode",{parentName:"p"},"simpleassettransfer")," chaincode has been deployed in Fabric network ",(0,i.kt)("inlineCode",{parentName:"p"},"network1"),", run the following steps related to Fabric by navigating to the ",(0,i.kt)("inlineCode",{parentName:"p"},"samples/fabric/fabric-cli")," folder (",(0,i.kt)("em",{parentName:"p"},"the Go CLI doesn't support asset transfer yet"),")."),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Add ",(0,i.kt)("inlineCode",{parentName:"li"},"5")," tokens of type ",(0,i.kt)("inlineCode",{parentName:"li"},"token1")," to ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyA")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network"),":",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"CORDA_PORT=10006 ./clients/build/install/clients/bin/clients issue-asset-state 5 token1\n")),"(check token balance for ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyA")," by running the command ",(0,i.kt)("inlineCode",{parentName:"li"},"CORDA_PORT=10006 ./clients/build/install/clients/bin/clients get-asset-states-by-type token1"),")"),(0,i.kt)("li",{parentName:"ul"},"Let ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyA")," pledge (with a 1 hour timeout) these tokens in ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network")," to be transferred to ",(0,i.kt)("inlineCode",{parentName:"li"},"Alice")," of Fabric network ",(0,i.kt)("inlineCode",{parentName:"li"},"network1")," (pledge burns the tokens in the source/exporting network):",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer pledge-asset --fungible --timeout=\"3600\" --import-network-id='network1' --recipient='alice' --param='token1:5'\n")),"Note the ",(0,i.kt)("inlineCode",{parentName:"li"},"pledge-id")," displayed after successful execution of the command, which will be used in next steps. Let's denote it ",(0,i.kt)("inlineCode",{parentName:"li"},"<pledge-id>")," which is a hexadecimal string (pledge details can be cross checked using the commands ",(0,i.kt)("inlineCode",{parentName:"li"},"CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer is-asset-pledged -pid <pledge-id>")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer get-pledge-state -pid <pledge-id>"),")."),(0,i.kt)("li",{parentName:"ul"},"Check the token asset balance for ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyA")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network")," by running the below command, and the output should not include the asset ",(0,i.kt)("inlineCode",{parentName:"li"},"token1:5")," issued earlier.",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre"},"CORDA_PORT=10006 ./clients/build/install/clients/bin/clients get-asset-states-by-type token1`\n"))),(0,i.kt)("li",{parentName:"ul"},"Verify that ",(0,i.kt)("inlineCode",{parentName:"li"},"alice")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"network1")," owns ",(0,i.kt)("inlineCode",{parentName:"li"},"10000")," tokens as follows:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./scripts/getTokenBalance.sh network1 alice\n"))),(0,i.kt)("li",{parentName:"ul"},"Get ",(0,i.kt)("inlineCode",{parentName:"li"},"alice")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"network")," to claim these tokens as follows (replace ",(0,i.kt)("inlineCode",{parentName:"li"},"<pledge-id>")," with the above hexadecimal value):",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset transfer claim --source-network='Corda_Network' --dest-network=network1 --user='alice' --owner='O=PartyA, L=London, C=GB' --type='token.corda' --pledge-id=<pledge-id> --param=token1:5\n"))),(0,i.kt)("li",{parentName:"ul"},"Verify that ",(0,i.kt)("inlineCode",{parentName:"li"},"alice")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"network")," now owns ",(0,i.kt)("inlineCode",{parentName:"li"},"1050")," tokens as follows:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./scripts/getTokenBalance.sh network1 alice\n")))),(0,i.kt)("p",null,"The above steps complete a successful asset transfer from the Corda network ",(0,i.kt)("inlineCode",{parentName:"p"},"Corda_Network")," to the Fabric network ",(0,i.kt)("inlineCode",{parentName:"p"},"network1"),". In addition to the above commands, following is an extra option."),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Let ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyA")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network")," try re-claim the token ",(0,i.kt)("inlineCode",{parentName:"li"},"token1:5")," asset, which will succeed only if the asset was not claimed by ",(0,i.kt)("inlineCode",{parentName:"li"},"alice")," in Fabric network and the pledge has expired (replace ",(0,i.kt)("inlineCode",{parentName:"li"},"<pledge-id>")," with the above hexadecimal value):",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer reclaim-pledged-asset --pledge-id=<pledge-id> --export-relay-address='localhost:9081' --transfer-category='token.fabric' --import-network-id='network1' --param='token1:5'\n")))))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/2e5ddf1e.ab6b10ea.js b/assets/js/2e5ddf1e.ab6b10ea.js deleted file mode 100644 index 1651171ef..000000000 --- a/assets/js/2e5ddf1e.ab6b10ea.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[2187],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>d});var n=r(7294);function i(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function o(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?a(Object(r),!0).forEach((function(t){i(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):a(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function l(e,t){if(null==e)return{};var r,n,i=function(e,t){if(null==e)return{};var r,n,i={},a=Object.keys(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||(i[r]=e[r]);return i}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(i[r]=e[r])}return i}var c=n.createContext({}),p=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},u=function(e){var t=p(e.components);return n.createElement(c.Provider,{value:t},e.children)},s="mdxType",y={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},f=n.forwardRef((function(e,t){var r=e.components,i=e.mdxType,a=e.originalType,c=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),s=p(r),f=i,d=s["".concat(c,".").concat(f)]||s[f]||y[f]||a;return r?n.createElement(d,o(o({ref:t},u),{},{components:r})):n.createElement(d,o({ref:t},u))}));function d(e,t){var r=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var a=r.length,o=new Array(a);o[0]=f;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l[s]="string"==typeof e?e:i,o[1]=l;for(var p=2;p<a;p++)o[p]=r[p];return n.createElement.apply(null,o)}return n.createElement.apply(null,r)}f.displayName="MDXCreateElement"},2931:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>y,frontMatter:()=>a,metadata:()=>l,toc:()=>p});var n=r(7462),i=(r(7294),r(3905));const a={},o=void 0,l={unversionedId:"internal/activity-plan",id:"internal/activity-plan",title:"activity-plan",description:"\x3c!--",source:"@site/docs/internal/activity-plan.md",sourceDirName:"internal",slug:"/internal/activity-plan",permalink:"/weaver-dlt-interoperability/docs/internal/activity-plan",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/internal/activity-plan.md",tags:[],version:"current",frontMatter:{}},c={},p=[],u={toc:p},s="wrapper";function y(e){let{components:t,...r}=e;return(0,i.kt)(s,(0,n.Z)({},u,r,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("hr",null),(0,i.kt)("p",null,"id: activity-plan\ntitle: Activity Plan"),(0,i.kt)("hr",null),(0,i.kt)("h1",{id:"milestones-and-activities"},"Milestones and Activities"))}y.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/2ec21c4a.12b71632.js b/assets/js/2ec21c4a.12b71632.js new file mode 100644 index 000000000..71c3e7d6a --- /dev/null +++ b/assets/js/2ec21c4a.12b71632.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[5302],{5680:(e,n,t)=>{t.d(n,{xA:()=>s,yg:()=>u});var a=t(6540);function i(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function r(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function o(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?r(Object(t),!0).forEach((function(n){i(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):r(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function l(e,n){if(null==e)return{};var t,a,i=function(e,n){if(null==e)return{};var t,a,i={},r=Object.keys(e);for(a=0;a<r.length;a++)t=r[a],n.indexOf(t)>=0||(i[t]=e[t]);return i}(e,n);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a<r.length;a++)t=r[a],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(i[t]=e[t])}return i}var p=a.createContext({}),d=function(e){var n=a.useContext(p),t=n;return e&&(t="function"==typeof e?e(n):o(o({},n),e)),t},s=function(e){var n=d(e.components);return a.createElement(p.Provider,{value:n},e.children)},c="mdxType",y={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},g=a.forwardRef((function(e,n){var t=e.components,i=e.mdxType,r=e.originalType,p=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),c=d(t),g=i,u=c["".concat(p,".").concat(g)]||c[g]||y[g]||r;return t?a.createElement(u,o(o({ref:n},s),{},{components:t})):a.createElement(u,o({ref:n},s))}));function u(e,n){var t=arguments,i=n&&n.mdxType;if("string"==typeof e||i){var r=t.length,o=new Array(r);o[0]=g;var l={};for(var p in n)hasOwnProperty.call(n,p)&&(l[p]=n[p]);l.originalType=e,l[c]="string"==typeof e?e:i,o[1]=l;for(var d=2;d<r;d++)o[d]=t[d];return a.createElement.apply(null,o)}return a.createElement.apply(null,t)}g.displayName="MDXCreateElement"},4002:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>p,contentTitle:()=>o,default:()=>y,frontMatter:()=>r,metadata:()=>l,toc:()=>d});var a=t(8168),i=(t(6540),t(5680));const r={id:"advanced-configuration",title:"Advanced Configuration"},o=void 0,l={unversionedId:"external/getting-started/test-network/advanced-configuration",id:"external/getting-started/test-network/advanced-configuration",title:"Advanced Configuration",description:"\x3c!--",source:"@site/docs/external/getting-started/test-network/advanced-configuration.md",sourceDirName:"external/getting-started/test-network",slug:"/external/getting-started/test-network/advanced-configuration",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/advanced-configuration",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/getting-started/test-network/advanced-configuration.md",tags:[],version:"current",frontMatter:{id:"advanced-configuration",title:"Advanced Configuration"},sidebar:"Documentation",previous:{title:"Ledger Initialization",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/ledger-initialization"},next:{title:"Testing Interoperation Modes",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/overview"}},p={},d=[{value:"Corda",id:"corda",level:2},{value:"Relay",id:"relay",level:3},{value:"Driver",id:"driver",level:3},{value:"Network",id:"network",level:3},{value:"Client Application",id:"client-application",level:3},{value:"Fabric",id:"fabric",level:2},{value:"Relay",id:"relay-1",level:3},{value:"Driver",id:"driver-1",level:3},{value:"Fabric CLI",id:"fabric-cli",level:3}],s={toc:d},c="wrapper";function y(e){let{components:n,...t}=e;return(0,i.yg)(c,(0,a.A)({},s,t,{components:n,mdxType:"MDXLayout"}),(0,i.yg)("p",null,"You can configure the different components of the test network to use non-default parameter values for various settings (such as host names or port numbers). Here is a list of configurations you can tweak, classified by the DLT type."),(0,i.yg)("h2",{id:"corda"},"Corda"),(0,i.yg)("h3",{id:"relay"},"Relay"),(0,i.yg)("p",null,"To run the relay on a different port from the default (",(0,i.yg)("inlineCode",{parentName:"p"},"9081"),"), do the following:"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},"Navigate to the ",(0,i.yg)("inlineCode",{parentName:"li"},"core/relay")," folder in your clone of the Weaver repository."),(0,i.yg)("li",{parentName:"ul"},"Update the ",(0,i.yg)("inlineCode",{parentName:"li"},"port")," field in ",(0,i.yg)("inlineCode",{parentName:"li"},"config/Corda_Relay.toml"),"."),(0,i.yg)("li",{parentName:"ul"},"To ensure that the relay of ",(0,i.yg)("inlineCode",{parentName:"li"},"network1")," can communicate with this relay, update the ",(0,i.yg)("inlineCode",{parentName:"li"},"port")," field in the ",(0,i.yg)("inlineCode",{parentName:"li"},"relays.Corda_Relay")," section in ",(0,i.yg)("inlineCode",{parentName:"li"},"config/Fabric_Relay.toml")," with the same value."),(0,i.yg)("li",{parentName:"ul"},"To ensure that the relay of ",(0,i.yg)("inlineCode",{parentName:"li"},"network2")," can communicate with this relay, update the ",(0,i.yg)("inlineCode",{parentName:"li"},"port")," field in the ",(0,i.yg)("inlineCode",{parentName:"li"},"relays.Corda_Relay")," section in ",(0,i.yg)("inlineCode",{parentName:"li"},"config/Fabric_Relay2.toml")," with the same value."),(0,i.yg)("li",{parentName:"ul"},"(You can update host names in similar locations, by adjusting the ",(0,i.yg)("inlineCode",{parentName:"li"},"hostname")," field.)"),(0,i.yg)("li",{parentName:"ul"},"When you attempt a Fabric to Corda interoperation flow, use the new host name or port (instead of ",(0,i.yg)("inlineCode",{parentName:"li"},"localhost:9081"),").")),(0,i.yg)("h3",{id:"driver"},"Driver"),(0,i.yg)("p",null,"To run the driver on a different port from the default (",(0,i.yg)("inlineCode",{parentName:"p"},"9099"),"), do the following:"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},"Navigate to the ",(0,i.yg)("inlineCode",{parentName:"li"},"core/drivers/corda-driver")," folder in your clone of the Weaver repository."),(0,i.yg)("li",{parentName:"ul"},"Set the environment variable ",(0,i.yg)("inlineCode",{parentName:"li"},"DRIVER_PORT")," appropriately while running the executable as follows:",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"DRIVER_PORT=<port> ./build/install/corda-driver/bin/corda-driver\n")))),(0,i.yg)("p",null,"To ensure that the relay can connect to this driver:"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},"Navigate to the ",(0,i.yg)("inlineCode",{parentName:"li"},"core/relay")," folder in your clone of the Weaver repository."),(0,i.yg)("li",{parentName:"ul"},"Update the ",(0,i.yg)("inlineCode",{parentName:"li"},"port")," field in the ",(0,i.yg)("inlineCode",{parentName:"li"},"drivers.Corda")," section in ",(0,i.yg)("inlineCode",{parentName:"li"},"config/Corda_Relay.toml")," with the same value.")),(0,i.yg)("h3",{id:"network"},"Network"),(0,i.yg)("table",null,(0,i.yg)("thead",{parentName:"table"},(0,i.yg)("tr",{parentName:"thead"},(0,i.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,i.yg)("tbody",{parentName:"table"},(0,i.yg)("tr",{parentName:"tbody"},(0,i.yg)("td",{parentName:"tr",align:"left"},"In our sample setup, all the Corda nodes must be running on the same machine (",(0,i.yg)("inlineCode",{parentName:"td"},"localhost")," or some other) for seamless communication.")))),(0,i.yg)("p",null,"To change the ports the Corda nodes are listening on, do the following:"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},"Navigate to the ",(0,i.yg)("inlineCode",{parentName:"li"},"tests/network-setups/corda")," folder in your clone of the Weaver repository."),(0,i.yg)("li",{parentName:"ul"},"Update the exposed ports in ",(0,i.yg)("inlineCode",{parentName:"li"},"docker-compose.yml")," (defaults are ",(0,i.yg)("inlineCode",{parentName:"li"},"10003")," for the ",(0,i.yg)("inlineCode",{parentName:"li"},"notary")," container and ",(0,i.yg)("inlineCode",{parentName:"li"},"10006")," for the ",(0,i.yg)("inlineCode",{parentName:"li"},"partya")," container)."),(0,i.yg)("li",{parentName:"ul"},"Navigate to the ",(0,i.yg)("inlineCode",{parentName:"li"},"samples/corda/corda-simple-application")," folder in your clone of the Weaver repository."),(0,i.yg)("li",{parentName:"ul"},"Update the ",(0,i.yg)("inlineCode",{parentName:"li"},"CORDA_HOST")," (default is ",(0,i.yg)("inlineCode",{parentName:"li"},"localhost"),") and ",(0,i.yg)("inlineCode",{parentName:"li"},"CORDA_PORT")," (default is ",(0,i.yg)("inlineCode",{parentName:"li"},"10006"),") environment variables on your host machine to reflect the above update, or run the client bootstrapping script as follows:",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"CORDA_HOST=<hostname> CORDA_PORT=<port> make initialise-vault\n"))),(0,i.yg)("li",{parentName:"ul"},"When you attempt a Fabric to Corda interoperation flow, use the new host name and port values as in the following example (",(0,i.yg)("inlineCode",{parentName:"li"},"network1")," requesting ",(0,i.yg)("inlineCode",{parentName:"li"},"Corda_Network"),"):",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli interop --local-network=network1 --requesting-org=org1.network1.com localhost:9081/Corda_Network/<CORDA_HOST>:<CORDA_PORT>#com.cordaSimpleApplication.flow.GetStateByKey:H`\n")))),(0,i.yg)("h3",{id:"client-application"},"Client Application"),(0,i.yg)("p",null,"The config files used to initialise the network's verification policies, access control policies, and security group info, contain the address (host name and port) of the Corda node.\nTo update the address of the Corda node, do the following:"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},"Navigate to the ",(0,i.yg)("inlineCode",{parentName:"li"},"samples/corda/corda-simple-application")," folder in your clone of the Weaver repository."),(0,i.yg)("li",{parentName:"ul"},"Edit the ",(0,i.yg)("inlineCode",{parentName:"li"},"rules --\x3e resource")," field in line 7 in ",(0,i.yg)("inlineCode",{parentName:"li"},"clients/src/main/resources/config/FabricNetworkAccessControlPolicy.json")," by replacing ",(0,i.yg)("inlineCode",{parentName:"li"},"localhost:10006")," with ",(0,i.yg)("inlineCode",{parentName:"li"},"<CORDA_HOST>:<CORDA_PORT>")," as specified in the previous section.")),(0,i.yg)("h2",{id:"fabric"},"Fabric"),(0,i.yg)("h3",{id:"relay-1"},"Relay"),(0,i.yg)("p",null,"To run the relay on a different port from the default (",(0,i.yg)("inlineCode",{parentName:"p"},"9080")," for ",(0,i.yg)("inlineCode",{parentName:"p"},"network1")," and ",(0,i.yg)("inlineCode",{parentName:"p"},"9083")," for ",(0,i.yg)("inlineCode",{parentName:"p"},"network2"),"), do the following:"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},"Navigate to the ",(0,i.yg)("inlineCode",{parentName:"li"},"core/relay")," folder in your clone of the Weaver repository."),(0,i.yg)("li",{parentName:"ul"},"Update the ",(0,i.yg)("inlineCode",{parentName:"li"},"port")," field in ",(0,i.yg)("inlineCode",{parentName:"li"},"config/Fabric_Relay.toml")," (for ",(0,i.yg)("inlineCode",{parentName:"li"},"network1"),") or ",(0,i.yg)("inlineCode",{parentName:"li"},"config/Fabric_Relay2.toml")," (for ",(0,i.yg)("inlineCode",{parentName:"li"},"network2"),")."),(0,i.yg)("li",{parentName:"ul"},"To ensure Fabric-Fabric relay communication, update the foreign relay port in the ",(0,i.yg)("inlineCode",{parentName:"li"},"port")," field in the ",(0,i.yg)("inlineCode",{parentName:"li"},"relays.Fabric_Relay")," section in either of the above files."),(0,i.yg)("li",{parentName:"ul"},"To ensure that the Corda network's relay can communicate with this relay, update the ",(0,i.yg)("inlineCode",{parentName:"li"},"port")," field in the ",(0,i.yg)("inlineCode",{parentName:"li"},"relays.Fabric_Relay")," section in ",(0,i.yg)("inlineCode",{parentName:"li"},"config/Corda_Relay.toml"),"."),(0,i.yg)("li",{parentName:"ul"},"(You can update host names in similar locations, by adjusting the ",(0,i.yg)("inlineCode",{parentName:"li"},"hostname")," field.)"),(0,i.yg)("li",{parentName:"ul"},"When you attempt a Fabric to Fabric or Corda to Fabric interoperation flow, use the new host name or port (instead of ",(0,i.yg)("inlineCode",{parentName:"li"},"localhost:9081")," or ",(0,i.yg)("inlineCode",{parentName:"li"},"localhost:9083"),")."),(0,i.yg)("li",{parentName:"ul"},"Navigate to the ",(0,i.yg)("inlineCode",{parentName:"li"},"core/drivers/fabric-driver")," folder in your clone of the Weaver repository."),(0,i.yg)("li",{parentName:"ul"},"Update the ",(0,i.yg)("inlineCode",{parentName:"li"},"RELAY_ENDPOINT")," variable in ",(0,i.yg)("inlineCode",{parentName:"li"},".env")," or specify ",(0,i.yg)("inlineCode",{parentName:"li"},"RELAY_ENDPOINT=<hostname>:<port>")," in the command line while running the driver using ",(0,i.yg)("inlineCode",{parentName:"li"},"npm run dev"),"."),(0,i.yg)("li",{parentName:"ul"},"Navigate to the ",(0,i.yg)("inlineCode",{parentName:"li"},"samples/fabric/fabric-cli")," folder in your clone of the Weaver repository."),(0,i.yg)("li",{parentName:"ul"},"Update the ",(0,i.yg)("inlineCode",{parentName:"li"},"relayEndpoint")," variables appropriately.")),(0,i.yg)("h3",{id:"driver-1"},"Driver"),(0,i.yg)("p",null,"The ",(0,i.yg)("inlineCode",{parentName:"p"},"fabric-driver")," configuration can be controlled by environment variables either set in ",(0,i.yg)("inlineCode",{parentName:"p"},".env")," in the ",(0,i.yg)("inlineCode",{parentName:"p"},"core/drivers/fabric-driver")," folder (or a copy if you created one) in your clone of the Weaver repository or passed in the command line when you run ",(0,i.yg)("inlineCode",{parentName:"p"},"npm run dev")," to start the driver. The relevant variables you can control when you make any change to the setup are:"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("inlineCode",{parentName:"li"},"CONNECTION_PROFILE"),": this is the path to the connection profile. If you make changes to the network or use a different one, create a new connection profile and point to it using this variable."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("inlineCode",{parentName:"li"},"RELAY_ENDPOINT"),": this is the endpoint of the relay (hostname and port), and you can adjust it as described in the previous section; this is where the relay will be listening for incoming requests and from where the relay will channel foreign requests as well."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("inlineCode",{parentName:"li"},"DRIVER_ENDPOINT"),": this is the hostname and port the driver itself will bind to, and you can change it from the default (",(0,i.yg)("inlineCode",{parentName:"li"},"localhost:9090")," for ",(0,i.yg)("inlineCode",{parentName:"li"},"network1")," and ",(0,i.yg)("inlineCode",{parentName:"li"},"localhost:9095")," for ",(0,i.yg)("inlineCode",{parentName:"li"},"network2"),") as per your need")),(0,i.yg)("h3",{id:"fabric-cli"},"Fabric CLI"),(0,i.yg)("p",null,"You can adjust settings for ",(0,i.yg)("inlineCode",{parentName:"p"},"fabric-cli")," in the ",(0,i.yg)("inlineCode",{parentName:"p"},".env")," and ",(0,i.yg)("inlineCode",{parentName:"p"},"config.json")," (in the ",(0,i.yg)("inlineCode",{parentName:"p"},"samples/fabric/fabric-cli")," folder in your clone of the Weaver repository) as described earlier."),(0,i.yg)("p",null,"Important environment variables (in ",(0,i.yg)("inlineCode",{parentName:"p"},".env"),") are:"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("inlineCode",{parentName:"li"},"DEFAULT_CHANNEL"),": this is the name of the channel the CLI will interact with. If you build a new channel or network, update the channel name here."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("inlineCode",{parentName:"li"},"DEFAULT_CHAINCODE"),": this is the name of the interoperaton chaincode the CLI will submit transactions and queries to for policy and security group bootstrapping. If you wish to test with a modified interoperation chaincode with a different name, update this value."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("inlineCode",{parentName:"li"},"MEMBER_CREDENTIAL_FOLDER"),": as described earlier, this is an absolute path that points to policies and security group info associated with foreign networks. You can adjust this info for the existing three networks or add credentials for another network you wish to test interoperation flows with."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("inlineCode",{parentName:"li"},"LOCAL"),": this is a boolean, indicating whether the network to connect to is running on (and as) ",(0,i.yg)("inlineCode",{parentName:"li"},"localhost")),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("inlineCode",{parentName:"li"},"DEFAULT_APPLICATION_CHAINCODE"),": this is the name of the application chaincode which maintains information that can be shared (with proof) with other networks upon request using interoperation. You may write and deploy your own chaincode and use its name here instead of the default ",(0,i.yg)("inlineCode",{parentName:"li"},"simplestate"),"."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("inlineCode",{parentName:"li"},"CONFIG_PATH"),": this points to the JSON file containing the configurations of all the Fabric networks that need to be configured using the ",(0,i.yg)("inlineCode",{parentName:"li"},"fabric-cli"),".")),(0,i.yg)("p",null,"The ",(0,i.yg)("inlineCode",{parentName:"p"},"config.json")," (which can have a different name as long as you add the right reference to ",(0,i.yg)("inlineCode",{parentName:"p"},".env")," and configure ",(0,i.yg)("inlineCode",{parentName:"p"},"fabric-cli")," suitably) has the following structure (it can have any number of networks specified):"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre"},'{\n "network1": {\n "connProfilePath": "",\n "relayEndpoint": ""\n },\n "network2": {\n "connProfilePath": "",\n "relayEndpoint": ""\n }\n}\n\n')),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("inlineCode",{parentName:"li"},"connProfilePath"),": absolute path of the network's connection profile"),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("inlineCode",{parentName:"li"},"relayEndpoint"),": hostname and port of the particular network's relay (make sure you sync this with any changes made to that relay's configuration)")))}y.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/2ec21c4a.75cb851a.js b/assets/js/2ec21c4a.75cb851a.js deleted file mode 100644 index 4230ee255..000000000 --- a/assets/js/2ec21c4a.75cb851a.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[3299],{3905:(e,t,n)=>{n.d(t,{Zo:()=>s,kt:()=>h});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?r(Object(n),!0).forEach((function(t){i(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):r(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,a,i=function(e,t){if(null==e)return{};var n,a,i={},r=Object.keys(e);for(a=0;a<r.length;a++)n=r[a],t.indexOf(n)>=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a<r.length;a++)n=r[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var d=a.createContext({}),p=function(e){var t=a.useContext(d),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},s=function(e){var t=p(e.components);return a.createElement(d.Provider,{value:t},e.children)},c="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},u=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,r=e.originalType,d=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),c=p(n),u=i,h=c["".concat(d,".").concat(u)]||c[u]||m[u]||r;return n?a.createElement(h,o(o({ref:t},s),{},{components:n})):a.createElement(h,o({ref:t},s))}));function h(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=n.length,o=new Array(r);o[0]=u;var l={};for(var d in t)hasOwnProperty.call(t,d)&&(l[d]=t[d]);l.originalType=e,l[c]="string"==typeof e?e:i,o[1]=l;for(var p=2;p<r;p++)o[p]=n[p];return a.createElement.apply(null,o)}return a.createElement.apply(null,n)}u.displayName="MDXCreateElement"},7219:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>d,contentTitle:()=>o,default:()=>m,frontMatter:()=>r,metadata:()=>l,toc:()=>p});var a=n(7462),i=(n(7294),n(3905));const r={id:"advanced-configuration",title:"Advanced Configuration"},o=void 0,l={unversionedId:"external/getting-started/test-network/advanced-configuration",id:"external/getting-started/test-network/advanced-configuration",title:"Advanced Configuration",description:"\x3c!--",source:"@site/docs/external/getting-started/test-network/advanced-configuration.md",sourceDirName:"external/getting-started/test-network",slug:"/external/getting-started/test-network/advanced-configuration",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/advanced-configuration",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/getting-started/test-network/advanced-configuration.md",tags:[],version:"current",frontMatter:{id:"advanced-configuration",title:"Advanced Configuration"},sidebar:"Documentation",previous:{title:"Ledger Initialization",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/ledger-initialization"},next:{title:"Testing Interoperation Modes",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/overview"}},d={},p=[{value:"Corda",id:"corda",level:2},{value:"Relay",id:"relay",level:3},{value:"Driver",id:"driver",level:3},{value:"Network",id:"network",level:3},{value:"Client Application",id:"client-application",level:3},{value:"Fabric",id:"fabric",level:2},{value:"Relay",id:"relay-1",level:3},{value:"Driver",id:"driver-1",level:3},{value:"Fabric CLI",id:"fabric-cli",level:3}],s={toc:p},c="wrapper";function m(e){let{components:t,...n}=e;return(0,i.kt)(c,(0,a.Z)({},s,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"You can configure the different components of the test network to use non-default parameter values for various settings (such as host names or port numbers). Here is a list of configurations you can tweak, classified by the DLT type."),(0,i.kt)("h2",{id:"corda"},"Corda"),(0,i.kt)("h3",{id:"relay"},"Relay"),(0,i.kt)("p",null,"To run the relay on a different port from the default (",(0,i.kt)("inlineCode",{parentName:"p"},"9081"),"), do the following:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Navigate to the ",(0,i.kt)("inlineCode",{parentName:"li"},"core/relay")," folder."),(0,i.kt)("li",{parentName:"ul"},"Update the ",(0,i.kt)("inlineCode",{parentName:"li"},"port")," field in ",(0,i.kt)("inlineCode",{parentName:"li"},"config/Corda_Relay.toml"),"."),(0,i.kt)("li",{parentName:"ul"},"To ensure that the relay of ",(0,i.kt)("inlineCode",{parentName:"li"},"network1")," can communicate with this relay, update the ",(0,i.kt)("inlineCode",{parentName:"li"},"port")," field in the ",(0,i.kt)("inlineCode",{parentName:"li"},"relays.Corda_Relay")," section in ",(0,i.kt)("inlineCode",{parentName:"li"},"config/Fabric_Relay.toml")," with the same value."),(0,i.kt)("li",{parentName:"ul"},"To ensure that the relay of ",(0,i.kt)("inlineCode",{parentName:"li"},"network2")," can communicate with this relay, update the ",(0,i.kt)("inlineCode",{parentName:"li"},"port")," field in the ",(0,i.kt)("inlineCode",{parentName:"li"},"relays.Corda_Relay")," section in ",(0,i.kt)("inlineCode",{parentName:"li"},"config/Fabric_Relay2.toml")," with the same value."),(0,i.kt)("li",{parentName:"ul"},"(You can update host names in similar locations, by adjusting the ",(0,i.kt)("inlineCode",{parentName:"li"},"hostname")," field.)"),(0,i.kt)("li",{parentName:"ul"},"When you attempt a Fabric to Corda interoperation flow, use the new host name or port (instead of ",(0,i.kt)("inlineCode",{parentName:"li"},"localhost:9081"),").")),(0,i.kt)("h3",{id:"driver"},"Driver"),(0,i.kt)("p",null,"To run the driver on a different port from the default (",(0,i.kt)("inlineCode",{parentName:"p"},"9099"),"), do the following:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Navigate to the ",(0,i.kt)("inlineCode",{parentName:"li"},"core/drivers/corda-driver")," folder."),(0,i.kt)("li",{parentName:"ul"},"Set the environment variable ",(0,i.kt)("inlineCode",{parentName:"li"},"DRIVER_PORT")," appropriately while running the executable as follows:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"DRIVER_PORT=<port> ./build/install/corda-driver/bin/corda-driver\n")))),(0,i.kt)("p",null,"To ensure that the relay can connect to this driver:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Navigate to the ",(0,i.kt)("inlineCode",{parentName:"li"},"core/relay")," folder."),(0,i.kt)("li",{parentName:"ul"},"Update the ",(0,i.kt)("inlineCode",{parentName:"li"},"port")," field in the ",(0,i.kt)("inlineCode",{parentName:"li"},"drivers.Corda")," section in ",(0,i.kt)("inlineCode",{parentName:"li"},"config/Corda_Relay.toml")," with the same value.")),(0,i.kt)("h3",{id:"network"},"Network"),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"left"},"In our sample setup, all the Corda nodes must be running on the same machine (",(0,i.kt)("inlineCode",{parentName:"td"},"localhost")," or some other) for seamless communication.")))),(0,i.kt)("p",null,"To change the ports the Corda nodes are listening on, do the following:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Navigate to the ",(0,i.kt)("inlineCode",{parentName:"li"},"tests/network-setups/corda")," folder."),(0,i.kt)("li",{parentName:"ul"},"Update the exposed ports in ",(0,i.kt)("inlineCode",{parentName:"li"},"docker-compose.yml")," (defaults are ",(0,i.kt)("inlineCode",{parentName:"li"},"10003")," for the ",(0,i.kt)("inlineCode",{parentName:"li"},"notary")," container and ",(0,i.kt)("inlineCode",{parentName:"li"},"10006")," for the ",(0,i.kt)("inlineCode",{parentName:"li"},"partya")," container)."),(0,i.kt)("li",{parentName:"ul"},"Navigate to the ",(0,i.kt)("inlineCode",{parentName:"li"},"samples/corda/corda-simple-application")," folder."),(0,i.kt)("li",{parentName:"ul"},"Update the ",(0,i.kt)("inlineCode",{parentName:"li"},"CORDA_HOST")," (default is ",(0,i.kt)("inlineCode",{parentName:"li"},"localhost"),") and ",(0,i.kt)("inlineCode",{parentName:"li"},"CORDA_PORT")," (default is ",(0,i.kt)("inlineCode",{parentName:"li"},"10006"),") environment variables on your host machine to reflect the above update, or run the client bootstrapping script as follows:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"CORDA_HOST=<hostname> CORDA_PORT=<port> make initialise-vault\n"))),(0,i.kt)("li",{parentName:"ul"},"When you attempt a Fabric to Corda interoperation flow, use the new host name and port values as in the following example (",(0,i.kt)("inlineCode",{parentName:"li"},"network1")," requesting ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network"),"):",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli interop --local-network=network1 --requesting-org=org1.network1.com localhost:9081/Corda_Network/<CORDA_HOST>:<CORDA_PORT>#com.cordaSimpleApplication.flow.GetStateByKey:H`\n")))),(0,i.kt)("h3",{id:"client-application"},"Client Application"),(0,i.kt)("p",null,"The config files used to initialise the network's verification policies, access control policies, and security group info, contain the address (host name and port) of the Corda node.\nTo update the address of the Corda node, do the following:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Navigate to the ",(0,i.kt)("inlineCode",{parentName:"li"},"samples/corda/corda-simple-application")," folder."),(0,i.kt)("li",{parentName:"ul"},"Edit the ",(0,i.kt)("inlineCode",{parentName:"li"},"rules --\x3e resource")," field in line 7 in ",(0,i.kt)("inlineCode",{parentName:"li"},"clients/src/main/resources/config/FabricNetworkAccessControlPolicy.json")," by replacing ",(0,i.kt)("inlineCode",{parentName:"li"},"localhost:10006")," with ",(0,i.kt)("inlineCode",{parentName:"li"},"<CORDA_HOST>:<CORDA_PORT>")," as specified in the previous section.")),(0,i.kt)("h2",{id:"fabric"},"Fabric"),(0,i.kt)("h3",{id:"relay-1"},"Relay"),(0,i.kt)("p",null,"To run the relay on a different port from the default (",(0,i.kt)("inlineCode",{parentName:"p"},"9080")," for ",(0,i.kt)("inlineCode",{parentName:"p"},"network1")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"9083")," for ",(0,i.kt)("inlineCode",{parentName:"p"},"network2"),"), do the following:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Navigate to the ",(0,i.kt)("inlineCode",{parentName:"li"},"core/relay")," folder."),(0,i.kt)("li",{parentName:"ul"},"Update the ",(0,i.kt)("inlineCode",{parentName:"li"},"port")," field in ",(0,i.kt)("inlineCode",{parentName:"li"},"config/Fabric_Relay.toml")," (for ",(0,i.kt)("inlineCode",{parentName:"li"},"network1"),") or ",(0,i.kt)("inlineCode",{parentName:"li"},"config/Fabric_Relay2.toml")," (for ",(0,i.kt)("inlineCode",{parentName:"li"},"network2"),")."),(0,i.kt)("li",{parentName:"ul"},"To ensure Fabric-Fabric relay communication, update the foreign relay port in the ",(0,i.kt)("inlineCode",{parentName:"li"},"port")," field in the ",(0,i.kt)("inlineCode",{parentName:"li"},"relays.Fabric_Relay")," section in either of the above files."),(0,i.kt)("li",{parentName:"ul"},"To ensure that the Corda network's relay can communicate with this relay, update the ",(0,i.kt)("inlineCode",{parentName:"li"},"port")," field in the ",(0,i.kt)("inlineCode",{parentName:"li"},"relays.Fabric_Relay")," section in ",(0,i.kt)("inlineCode",{parentName:"li"},"config/Corda_Relay.toml"),"."),(0,i.kt)("li",{parentName:"ul"},"(You can update host names in similar locations, by adjusting the ",(0,i.kt)("inlineCode",{parentName:"li"},"hostname")," field.)"),(0,i.kt)("li",{parentName:"ul"},"When you attempt a Fabric to Fabric or Corda to Fabric interoperation flow, use the new host name or port (instead of ",(0,i.kt)("inlineCode",{parentName:"li"},"localhost:9081")," or ",(0,i.kt)("inlineCode",{parentName:"li"},"localhost:9083"),")."),(0,i.kt)("li",{parentName:"ul"},"Navigate to the ",(0,i.kt)("inlineCode",{parentName:"li"},"core/drivers/fabric-driver")," folder."),(0,i.kt)("li",{parentName:"ul"},"Update the ",(0,i.kt)("inlineCode",{parentName:"li"},"RELAY_ENDPOINT")," variable in ",(0,i.kt)("inlineCode",{parentName:"li"},".env")," or specify ",(0,i.kt)("inlineCode",{parentName:"li"},"RELAY_ENDPOINT=<hostname>:<port>")," in the command line while running the driver using ",(0,i.kt)("inlineCode",{parentName:"li"},"npm run dev"),"."),(0,i.kt)("li",{parentName:"ul"},"Navigate to the ",(0,i.kt)("inlineCode",{parentName:"li"},"samples/fabric/fabric-cli")," folder."),(0,i.kt)("li",{parentName:"ul"},"Update the ",(0,i.kt)("inlineCode",{parentName:"li"},"relayEndpoint")," variables appropriately.")),(0,i.kt)("h3",{id:"driver-1"},"Driver"),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"fabric-driver")," configuration can be controlled by environment variables either set in ",(0,i.kt)("inlineCode",{parentName:"p"},".env")," in the ",(0,i.kt)("inlineCode",{parentName:"p"},"core/drivers/fabric-driver")," folder (or a copy if you created one) or passed in the command line when you run ",(0,i.kt)("inlineCode",{parentName:"p"},"npm run dev")," to start the driver. The relevant variables you can control when you make any change to the setup are:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"CONNECTION_PROFILE"),": this is the path to the connection profile. If you make changes to the network or use a different one, create a new connection profile and point to it using this variable."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"RELAY_ENDPOINT"),": this is the endpoint of the relay (hostname and port), and you can adjust it as described in the previous section; this is where the relay will be listening for incoming requests and from where the relay will channel foreign requests as well."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"DRIVER_ENDPOINT"),": this is the hostname and port the driver itself will bind to, and you can change it from the default (",(0,i.kt)("inlineCode",{parentName:"li"},"localhost:9090")," for ",(0,i.kt)("inlineCode",{parentName:"li"},"network1")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"localhost:9095")," for ",(0,i.kt)("inlineCode",{parentName:"li"},"network2"),") as per your need")),(0,i.kt)("h3",{id:"fabric-cli"},"Fabric CLI"),(0,i.kt)("p",null,"You can adjust settings for ",(0,i.kt)("inlineCode",{parentName:"p"},"fabric-cli")," in the ",(0,i.kt)("inlineCode",{parentName:"p"},".env")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"config.json")," (in the ",(0,i.kt)("inlineCode",{parentName:"p"},"samples/fabric/fabric-cli")," folder) as described earlier."),(0,i.kt)("p",null,"Important environment variables (in ",(0,i.kt)("inlineCode",{parentName:"p"},".env"),") are:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"DEFAULT_CHANNEL"),": this is the name of the channel the CLI will interact with. If you build a new channel or network, update the channel name here."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"DEFAULT_CHAINCODE"),": this is the name of the interoperaton chaincode the CLI will submit transactions and queries to for policy and security group bootstrapping. If you wish to test with a modified interoperation chaincode with a different name, update this value."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"MEMBER_CREDENTIAL_FOLDER"),": as described earlier, this is an absolute path that points to policies and security group info associated with foreign networks. You can adjust this info for the existing three networks or add credentials for another network you wish to test interoperation flows with."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"LOCAL"),": this is a boolean, indicating whether the network to connect to is running on (and as) ",(0,i.kt)("inlineCode",{parentName:"li"},"localhost")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"DEFAULT_APPLICATION_CHAINCODE"),": this is the name of the application chaincode which maintains information that can be shared (with proof) with other networks upon request using interoperation. You may write and deploy your own chaincode and use its name here instead of the default ",(0,i.kt)("inlineCode",{parentName:"li"},"simplestate"),"."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"CONFIG_PATH"),": this points to the JSON file containing the configurations of all the Fabric networks that need to be configured using the ",(0,i.kt)("inlineCode",{parentName:"li"},"fabric-cli"),".")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"config.json")," (which can have a different name as long as you add the right reference to ",(0,i.kt)("inlineCode",{parentName:"p"},".env")," and configure ",(0,i.kt)("inlineCode",{parentName:"p"},"fabric-cli")," suitably) has the following structure (it can have any number of networks specified):"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'{\n "network1": {\n "connProfilePath": "",\n "relayEndpoint": ""\n },\n "network2": {\n "connProfilePath": "",\n "relayEndpoint": ""\n }\n}\n\n')),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"connProfilePath"),": absolute path of the network's connection profile"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"relayEndpoint"),": hostname and port of the particular network's relay (make sure you sync this with any changes made to that relay's configuration)")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/36367655.51cefe07.js b/assets/js/36367655.51cefe07.js new file mode 100644 index 000000000..07ab392fd --- /dev/null +++ b/assets/js/36367655.51cefe07.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[3966],{5680:(e,a,n)=>{n.d(a,{xA:()=>g,yg:()=>u});var t=n(6540);function r(e,a,n){return a in e?Object.defineProperty(e,a,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[a]=n,e}function i(e,a){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var t=Object.getOwnPropertySymbols(e);a&&(t=t.filter((function(a){return Object.getOwnPropertyDescriptor(e,a).enumerable}))),n.push.apply(n,t)}return n}function l(e){for(var a=1;a<arguments.length;a++){var n=null!=arguments[a]?arguments[a]:{};a%2?i(Object(n),!0).forEach((function(a){r(e,a,n[a])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(a){Object.defineProperty(e,a,Object.getOwnPropertyDescriptor(n,a))}))}return e}function o(e,a){if(null==e)return{};var n,t,r=function(e,a){if(null==e)return{};var n,t,r={},i=Object.keys(e);for(t=0;t<i.length;t++)n=i[t],a.indexOf(n)>=0||(r[n]=e[n]);return r}(e,a);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(t=0;t<i.length;t++)n=i[t],a.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=t.createContext({}),p=function(e){var a=t.useContext(s),n=a;return e&&(n="function"==typeof e?e(a):l(l({},a),e)),n},g=function(e){var a=p(e.components);return t.createElement(s.Provider,{value:a},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var a=e.children;return t.createElement(t.Fragment,{},a)}},y=t.forwardRef((function(e,a){var n=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,g=o(e,["components","mdxType","originalType","parentName"]),d=p(n),y=r,u=d["".concat(s,".").concat(y)]||d[y]||c[y]||i;return n?t.createElement(u,l(l({ref:a},g),{},{components:n})):t.createElement(u,l({ref:a},g))}));function u(e,a){var n=arguments,r=a&&a.mdxType;if("string"==typeof e||r){var i=n.length,l=new Array(i);l[0]=y;var o={};for(var s in a)hasOwnProperty.call(a,s)&&(o[s]=a[s]);o.originalType=e,o[d]="string"==typeof e?e:r,l[1]=o;for(var p=2;p<i;p++)l[p]=n[p];return t.createElement.apply(null,l)}return t.createElement.apply(null,n)}y.displayName="MDXCreateElement"},3196:(e,a,n)=>{n.r(a),n.d(a,{assets:()=>s,contentTitle:()=>l,default:()=>c,frontMatter:()=>i,metadata:()=>o,toc:()=>p});var t=n(8168),r=(n(6540),n(5680));const i={id:"setup-local",title:"Setup with Locally Built Weaver Components",pagination_prev:"external/getting-started/test-network/overview",pagination_next:"external/getting-started/test-network/ledger-initialization"},l=void 0,o={unversionedId:"external/getting-started/test-network/setup-local",id:"external/getting-started/test-network/setup-local",title:"Setup with Locally Built Weaver Components",description:"\x3c!--",source:"@site/docs/external/getting-started/test-network/setup-local.md",sourceDirName:"external/getting-started/test-network",slug:"/external/getting-started/test-network/setup-local",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-local",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/getting-started/test-network/setup-local.md",tags:[],version:"current",frontMatter:{id:"setup-local",title:"Setup with Locally Built Weaver Components",pagination_prev:"external/getting-started/test-network/overview",pagination_next:"external/getting-started/test-network/ledger-initialization"},sidebar:"Documentation",previous:{title:"Component Overview",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/overview"},next:{title:"Ledger Initialization",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/ledger-initialization"}},s={},p=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Software",id:"software",level:3},{value:"Credentials",id:"credentials",level:3},{value:"Getting the Code and Documentation",id:"getting-the-code-and-documentation",level:2},{value:"Common Structures",id:"common-structures",level:2},{value:"Securing Components",id:"securing-components",level:2},{value:"Hyperledger Fabric Components",id:"hyperledger-fabric-components",level:2},{value:"Fabric Interoperation Node SDK",id:"fabric-interoperation-node-sdk",level:3},{value:"Fabric Network",id:"fabric-network",level:3},{value:"Fabric Client (fabric-cli)",id:"fabric-client-fabric-cli",level:3},{value:"Prerequisites",id:"prerequisites-1",level:4},{value:"Installation",id:"installation",level:4},{value:"Fabric Relay",id:"fabric-relay",level:3},{value:"Building",id:"building",level:4},{value:"Deployment",id:"deployment",level:4},{value:"Fabric Driver",id:"fabric-driver",level:3},{value:"Configuring",id:"configuring",level:4},{value:"Building",id:"building-1",level:4},{value:"Running",id:"running",level:4},{value:"Fabric IIN Agent",id:"fabric-iin-agent",level:3},{value:"Building",id:"building-2",level:4},{value:"Configuration",id:"configuration",level:4},{value:"Security Domain Configuration",id:"security-domain-configuration",level:4},{value:"DNS Configuration",id:"dns-configuration",level:4},{value:"Environment Variables",id:"environment-variables",level:4},{value:"Deployment",id:"deployment-1",level:4},{value:"Corda Components",id:"corda-components",level:2},{value:"Interoperation CorDapp",id:"interoperation-cordapp",level:3},{value:"Corda Interoperation SDK",id:"corda-interoperation-sdk",level:3},{value:"Corda Simple Application and Client (Application)",id:"corda-simple-application-and-client-application",level:3},{value:"Corda Network",id:"corda-network",level:3},{value:"Corda Relay",id:"corda-relay",level:3},{value:"Corda Driver",id:"corda-driver",level:3},{value:"Building Corda Driver",id:"building-corda-driver",level:4},{value:"Configuring",id:"configuring-1",level:4},{value:"Running",id:"running-1",level:4},{value:"Hyperledger Besu Components",id:"hyperledger-besu-components",level:2},{value:"Prerequisites",id:"prerequisites-2",level:3},{value:"Besu Interoperation Node SDK",id:"besu-interoperation-node-sdk",level:3},{value:"Besu Network",id:"besu-network",level:3},{value:"Contracts",id:"contracts",level:3},{value:"Besu Client (besu-cli)",id:"besu-client-besu-cli",level:3},{value:"Prerequisites",id:"prerequisites-3",level:4},{value:"Installation",id:"installation-1",level:4},{value:"Tear Down the Setup",id:"tear-down-the-setup",level:2}],g={toc:p},d="wrapper";function c(e){let{components:a,...n}=e;return(0,r.yg)(d,(0,t.A)({},g,n,{components:a,mdxType:"MDXLayout"}),(0,r.yg)("p",null,"In this document, we detail the steps using which you can bring up networks using the default configuration settings and by building Weaver interoperation modules, SDK libraries, and relay drivers locally from your Weaver clone. To customize these settings (e.g., hostnames, ports), refer to the ",(0,r.yg)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/advanced-configuration"},"Advanced Configuration page"),"."),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:"left"},"The default configuration is for a development setup, therefore all components are run on ",(0,r.yg)("inlineCode",{parentName:"td"},"localhost"),", many within Docker containers.")))),(0,r.yg)("p",null,"Follow the instructions below to build and run components followed by interoperation flows. These instructions have been tested on Ubuntu Linux (bash shell) and Mac OS. In general, they should work on any system and shell as long as the various dependenices have been installed and configured."),(0,r.yg)("h2",{id:"prerequisites"},"Prerequisites"),(0,r.yg)("h3",{id:"software"},"Software"),(0,r.yg)("p",null,"Before starting, make sure you have the following software installed on your host machine:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},"OpenSSL: ",(0,r.yg)("em",{parentName:"p"},"install using package manager, like ",(0,r.yg)("inlineCode",{parentName:"em"},"apt")," on Debian/Ubuntu Linux (specifically packages ",(0,r.yg)("inlineCode",{parentName:"em"},"openssl")," and ",(0,r.yg)("inlineCode",{parentName:"em"},"libssl-dev"),")"))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},"Curl: ",(0,r.yg)("em",{parentName:"p"},"install using package manager, like ",(0,r.yg)("inlineCode",{parentName:"em"},"apt")," on Debian/Ubuntu Linux"))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},"Git: ",(0,r.yg)("a",{parentName:"p",href:"https://git-scm.com/book/en/v2/Getting-Started-Installing-Git"},"sample instructions"))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},"Docker: ",(0,r.yg)("a",{parentName:"p",href:"https://docs.docker.com/engine/install/"},"sample instructions")," (Latest version)")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},"Docker-Compose: ",(0,r.yg)("a",{parentName:"p",href:"https://docs.docker.com/compose/install/"},"sample instructions")," (Version 1.28.2 or higher, but lower than version V2)")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},"Golang: ",(0,r.yg)("a",{parentName:"p",href:"https://golang.org/dl/"},"sample instructions")," (Version 1.16 or higher)")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},"Java (JDK and JRE): ",(0,r.yg)("a",{parentName:"p",href:"https://openjdk.java.net/install/"},"sample instructions")," (Version 8)")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},"Node.js and NPM: ",(0,r.yg)("a",{parentName:"p",href:"https://nodejs.org/en/download/package-manager/"},"sample instructions")," (Version 16 Supported)")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},"Yarn: ",(0,r.yg)("a",{parentName:"p",href:"https://classic.yarnpkg.com/en/docs/install/"},"sample instructions"))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},"Rust: ",(0,r.yg)("a",{parentName:"p",href:"https://www.rust-lang.org/tools/install"},"sample instructions"))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},"Protoc (Protobuf compiler): ",(0,r.yg)("em",{parentName:"p"},"Golang should already be installed and configured.")),(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},"Default method: Run the following with ",(0,r.yg)("inlineCode",{parentName:"p"},"sudo")," if necessary. This will install both the protobuf compiler and the Go code generator plugins."),(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre"},"apt-get install protobuf-compiler\ngo install google.golang.org/protobuf/cmd/protoc-gen-go\ngo install google.golang.org/grpc/cmd/protoc-gen-go-grpc\n"))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},"If the above method installs an older version of ",(0,r.yg)("inlineCode",{parentName:"p"},"protoc")," (check using ",(0,r.yg)("inlineCode",{parentName:"p"},"protoc --version"),"), say below 3.12.x, you should download pre-compiled binaries instead. (With an older version, you may see errors while attempting to launch and setup the Fabric networks)."),(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre"},'sudo apt-get remove protobuf-compiler\ncurl -LO https://github.com/protocolbuffers/protobuf/releases/download/v3.15.6/protoc-3.15.6-linux-x86_64.zip\nsudo apt-get install unzip\nunzip protoc-3.15.6-linux-x86_64.zip -d <some-folder-path>\nexport PATH="$PATH:<some-folder-path>/bin"\ngo install google.golang.org/protobuf/cmd/protoc-gen-go\ngo install google.golang.org/grpc/cmd/protoc-gen-go-grpc\n')),(0,r.yg)("table",{parentName:"li"},(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:"left"},"The latest version at present is ",(0,r.yg)("inlineCode",{parentName:"td"},"3.15.6"),", but you should check the above link to find the most current version before running the above steps.")))))))),(0,r.yg)("h3",{id:"credentials"},"Credentials"),(0,r.yg)("p",null,"Make sure you have an SSH or GPG key registered in ",(0,r.yg)("a",{parentName:"p",href:"https://github.com"},"https://github.com")," to allow seamless cloning of repositories (at present, various setup scripts clone repositories using the ",(0,r.yg)("inlineCode",{parentName:"p"},"https://")," prefix but this may change to ",(0,r.yg)("inlineCode",{parentName:"p"},"git@")," in the future)."),(0,r.yg)("h2",{id:"getting-the-code-and-documentation"},"Getting the Code and Documentation"),(0,r.yg)("p",null,"Clone the ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability"},"weaver-dlt-interoperability")," repository. The code to get a basic test network up and running and test data-sharing interoperation flows lies in the subfolder ",(0,r.yg)("inlineCode",{parentName:"p"},"tests/network-setups"),", which should be your starting point, though the setups will rely on other parts of the repository, as you will find out in the instructions given on this page."),(0,r.yg)("h2",{id:"common-structures"},"Common Structures"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"common/protos")," folder contains structure definitions in the protobuf format that are used by all the different components. The various ",(0,r.yg)("inlineCode",{parentName:"p"},"common/protos-*")," folders are meant to contain compiled protobufs (in different languages)."),(0,r.yg)("p",null,"To compile the protobufs for JavaScript, do the following:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"common/protos-js")," folder."),(0,r.yg)("li",{parentName:"ul"},"Run the following command:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make build\n")))),(0,r.yg)("p",null,"To compile the protobufs for Golang, do the following:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"common/protos-go")," folder."),(0,r.yg)("li",{parentName:"ul"},"Run the following command:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make build\n")))),(0,r.yg)("p",null,"To compile the protobufs for Java, do the following:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"common/protos-java-kt")," folder."),(0,r.yg)("li",{parentName:"ul"},"Run the following command:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make build\n")))),(0,r.yg)("p",null,"To compile the protobufs for Solidity, do the following:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"common/protos-sol")," folder."),(0,r.yg)("li",{parentName:"ul"},"Run the following command:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make build\n")))),(0,r.yg)("p",null,"To compile the protobufs for Rust, do the following:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"common/protos-rs")," folder."),(0,r.yg)("li",{parentName:"ul"},"Run the following command:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make build\n")))),(0,r.yg)("h2",{id:"securing-components"},"Securing Components"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:"left"},"The relays and drivers corresponding to the different test networks you will encounter below can be run with or without TLS enabled. But the default files used in the demonstrations assume that either all relays and drivers are TLS-enabled or none are. Therefore, you should determine at the outset whether or not you wish to run the entire set of components in TLS-enabled mode, and select appropriate commands in the provided instructions.")))),(0,r.yg)("h2",{id:"hyperledger-fabric-components"},"Hyperledger Fabric Components"),(0,r.yg)("p",null,"Using the sequence of instructions below, you can start two separate Fabric networks, each with a single channel and application contract (chaincode). You can also start an interoperation contract, a relay, and a ",(0,r.yg)("em",{parentName:"p"},"driver")," acting on behalf of each network. You can build a Fabric CLI tool with which you can initialize both networks' ledgers with access control policies, foreign networks' security groups (i.e., membership providers' certificate chains), and some sample key-value pairs that can be shared during subsequent interoperation flows."),(0,r.yg)("h3",{id:"fabric-interoperation-node-sdk"},"Fabric Interoperation Node SDK"),(0,r.yg)("p",null,"A client-layer library (companion to ",(0,r.yg)("inlineCode",{parentName:"p"},"hyperledger/fabric-sdk-node"),") is defined in the ",(0,r.yg)("inlineCode",{parentName:"p"},"sdks/fabric/interoperation-node-sdk")," folder. This contains functions for Fabric Gateway-based applications to exercise interoperation capabilities via relays and also several utility/helper functions. The Fabric-CLI tool, which we will use later, depends on this library."),(0,r.yg)("p",null,"To build the library, do the following:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"sdks/fabric/interoperation-node-sdk")," folder."),(0,r.yg)("li",{parentName:"ul"},"Run the following command:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make build-local\n")))),(0,r.yg)("h3",{id:"fabric-network"},"Fabric Network"),(0,r.yg)("p",null,"The code for this lies in the ",(0,r.yg)("inlineCode",{parentName:"p"},"tests/network-setups")," folder."),(0,r.yg)("p",null,"This folder contains code to create and launch networks ",(0,r.yg)("inlineCode",{parentName:"p"},"network1")," and ",(0,r.yg)("inlineCode",{parentName:"p"},"network2")," of identical specifications:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Network: 1 peer, 1 peer CA, 1 ordering service node, 1 ordering service CA"),(0,r.yg)("li",{parentName:"ul"},"Single channel named ",(0,r.yg)("inlineCode",{parentName:"li"},"mychannel")),(0,r.yg)("li",{parentName:"ul"},"One of the following contracts deployed on ",(0,r.yg)("inlineCode",{parentName:"li"},"mychannel"),", the choice depending on the ",(0,r.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/interoperability-modes"},"interoperability mode")," you wish to test:",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"simplestate")," (",(0,r.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/data-sharing"},"Data Sharing"),"): supports simple transactions (",(0,r.yg)("inlineCode",{parentName:"li"},"Create"),", ",(0,r.yg)("inlineCode",{parentName:"li"},"Read"),", ",(0,r.yg)("inlineCode",{parentName:"li"},"Update"),", ",(0,r.yg)("inlineCode",{parentName:"li"},"Delete"),") involving storage and lookup of <key, value> pairs."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"simplestatewithacl")," (",(0,r.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/data-sharing"},"Data Sharing"),"): identical to ",(0,r.yg)("inlineCode",{parentName:"li"},"simplestate")," but with extra security features to ensure that the Weaver infrastructure cannot be bypassed by a malicious client of the network."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"simpleasset")," (",(0,r.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview"},"Asset Exchange"),"): supports creation, modification, transfer, and deletion, as well as locking, unlocking, and claiming, of simple bonds and tokens (examples of non-fungible and fungible assets respectively)."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"simpleassetandinterop")," (",(0,r.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview"},"Asset Exchange"),"): identical to ",(0,r.yg)("inlineCode",{parentName:"li"},"simpleasset")," but where the locking, unlocking, and claiming logic is imported as a library in the chaincode rather than available in the common Fabric Interoperation Chaincode (a Weaver component)."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"simpleassettransfer")," (",(0,r.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview"},"Asset Exchange")," or ",(0,r.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-transfer"},"Asset Transfer"),"): augmentation of ",(0,r.yg)("inlineCode",{parentName:"li"},"simpleasset")," with asset pledging, claiming, and reclaiming features for cross-network transfers.")))),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:"left"},"For new users, we recommend testing the Data Sharing feature first with the ",(0,r.yg)("inlineCode",{parentName:"td"},"simplestate")," contract. To test the other modes, you can simply ",(0,r.yg)("a",{parentName:"td",href:"#tear-down-the-setup"},"tear down")," the Fabric networks and restart them with the appropriate chaincodes installed.")))),(0,r.yg)("p",null,"Follow the instructions below to build and launch the networks:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"tests/network-setups/fabric/dev")," folder."),(0,r.yg)("li",{parentName:"ul"},"To spin up both network1 and network2 with the interoperation chaincode and the default ",(0,r.yg)("inlineCode",{parentName:"li"},"simplestate")," chaincode installed, run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make start-interop-local\n"))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("em",{parentName:"li"},"To launch the networks with a different application chaincode from the above list, run"),":",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make start-interop-local CHAINCODE_NAME=<chaincode-name>\n"))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("em",{parentName:"li"},"To launch the networks with 2 organizations, each with a peer (this will enable more variation and experimentation, which you can attempt after testing interoperation protocols across basic network configurations), run"),":",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},'make start-interop-local PROFILE="2-nodes"\n')))),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:"left"},"If you do not wish to test Fabric-Fabric interoperation, you can choose to launch only one of the two networks along with its interoperation chaincode. For ",(0,r.yg)("inlineCode",{parentName:"td"},"network1"),", run ",(0,r.yg)("inlineCode",{parentName:"td"},"make start-interop-network1-local"),", and for ",(0,r.yg)("inlineCode",{parentName:"td"},"network2"),", run ",(0,r.yg)("inlineCode",{parentName:"td"},"make start-interop-network2-local"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:"left"},"If you wish to enable end-to-end confidentiality by default in the interoperation modules that are deployed during network launch, set the environment variable ",(0,r.yg)("inlineCode",{parentName:"td"},"E2E_CONFIDENTIALITY")," to ",(0,r.yg)("inlineCode",{parentName:"td"},"true")," in the command line as follows: ",(0,r.yg)("inlineCode",{parentName:"td"},"E2E_CONFIDENTIALITY=true make start-interop-local"))))),(0,r.yg)("p",null,"For more information, refer to the associated ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/tests/network-setups/fabric/dev"},"README"),"."),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},"Troubleshooting Tips"),":"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"If you see any errors during the launches, re-check the prerequisites (software installations and credentials). Ensure your network connection is working. As a safe bet, you can retry after cleanup: kill and remove all Docker containers and associated volumes."),(0,r.yg)("li",{parentName:"ul"},"If ",(0,r.yg)("inlineCode",{parentName:"li"},"protoc")," or ",(0,r.yg)("inlineCode",{parentName:"li"},"protoc-gen-go")," throws an error, reinstall ",(0,r.yg)("inlineCode",{parentName:"li"},"protoc")," and ",(0,r.yg)("inlineCode",{parentName:"li"},"protoc-gen-go")," using suggestions made in the Prerequisites section above.")),(0,r.yg)("h3",{id:"fabric-client-fabric-cli"},"Fabric Client (fabric-cli)"),(0,r.yg)("p",null,"The CLI is used to interact with a Fabric network, configure it and run chaincode transactions to record data on the channel ledger or query data. It is also used to interact with remote networks through the relay to trigger an interoperation flow for data request and acceptance."),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"fabric-cli")," Node.js source code is located in the ",(0,r.yg)("inlineCode",{parentName:"p"},"samples/fabric/fabric-cli")," folder and the Golang source code in the ",(0,r.yg)("inlineCode",{parentName:"p"},"samples/fabric/go-cli")," folder."),(0,r.yg)("h4",{id:"prerequisites-1"},"Prerequisites"),(0,r.yg)("p",null,"If you are using a Linux system, make sure that lib64 is installed."),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:"left"},"For the Node.js version of the ",(0,r.yg)("inlineCode",{parentName:"td"},"fabric-cli"),", the setup and running instructions below were tested with all Node.js versions from v11.14.0 to v14.17.3.")))),(0,r.yg)("h4",{id:"installation"},"Installation"),(0,r.yg)("p",null,"You can install ",(0,r.yg)("inlineCode",{parentName:"p"},"fabric-cli")," as follows (for both the Node.js and Golang versions):"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"samples/fabric/fabric-cli")," folder (for the Node.js version) or the ",(0,r.yg)("inlineCode",{parentName:"li"},"samples/fabric/go-cli")," folder (for the Golang version)."),(0,r.yg)("li",{parentName:"ul"},"Run the following to install dependencies (for the Node.js version) or the executable (for the Golang version):",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make build-local\n"))),(0,r.yg)("li",{parentName:"ul"},"Use the ",(0,r.yg)("inlineCode",{parentName:"li"},"fabric-cli")," executable in the ",(0,r.yg)("inlineCode",{parentName:"li"},"bin")," folder for ",(0,r.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/ledger-initialization"},"subsequent actions"),".")),(0,r.yg)("h3",{id:"fabric-relay"},"Fabric Relay"),(0,r.yg)("p",null,"The relay is a module acting on behalf of a network, enabling interoperation flows with other networks by communicating with their relays.\nThe code for this lies in the ",(0,r.yg)("inlineCode",{parentName:"p"},"core/relay")," folder."),(0,r.yg)("h4",{id:"building"},"Building"),(0,r.yg)("p",null,(0,r.yg)("em",{parentName:"p"},"Prerequisite"),": make sure Rust is already installed and that the ",(0,r.yg)("inlineCode",{parentName:"p"},"cargo")," executable is in your system path (after installation of Rust, this should be available in ",(0,r.yg)("inlineCode",{parentName:"p"},"$HOME/.cargo/bin"),"); you can also ensure this by running ",(0,r.yg)("inlineCode",{parentName:"p"},'source "$HOME/.cargo/env"'),"."),(0,r.yg)("p",null,"Build the generic (i.e., common to all DLTs) relay module as follows:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"core/relay")," folder."),(0,r.yg)("li",{parentName:"ul"},"Run the following:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make\n"))),(0,r.yg)("li",{parentName:"ul"},"If you observe errors during the above compilation, update certain packages (on which the Weaver Relay is dependent) to their latest versions and recompile as follows:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make update-pkgs\nmake\n")))),(0,r.yg)("h4",{id:"deployment"},"Deployment"),(0,r.yg)("p",null,"An instance or a relay can be run using a suitable configuration file. Samples are available in the ",(0,r.yg)("inlineCode",{parentName:"p"},"core/relay/config")," folder."),(0,r.yg)("p",null,"Run a relay for ",(0,r.yg)("inlineCode",{parentName:"p"},"network1")," as follows:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"core/relay")," folder."),(0,r.yg)("li",{parentName:"ul"},"To launch the server without TLS, leave the configuration file ",(0,r.yg)("inlineCode",{parentName:"li"},"config/Fabric_Relay.toml")," in its default state. Otherwise, edit it to set TLS flags for this relay and the other relays and drivers it will connect to in this demonstration as follows:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-toml"},'.\n.\ncert_path="credentials/fabric_cert.pem"\nkey_path="credentials/fabric_key"\ntls=true\n.\n.\n[relays]\n[relays.Corda_Relay]\nhostname="localhost"\nport="9081"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n[relays.Corda_Relay2]\nhostname="localhost"\nport="9082"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n[relays.Fabric_Relay2]\nhostname="localhost"\nport="9083"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n.\n.\n[drivers]\n[drivers.Fabric]\nhostname="localhost"\nport="9090"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n.\n.\n'))),(0,r.yg)("li",{parentName:"ul"},"To launch the server, simply run the following:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"RELAY_CONFIG=config/Fabric_Relay.toml cargo run --bin server\n")))),(0,r.yg)("p",null,"Run a relay for ",(0,r.yg)("inlineCode",{parentName:"p"},"network2")," as follows (",(0,r.yg)("em",{parentName:"p"},"do this only if you have launched both Fabric networks ",(0,r.yg)("inlineCode",{parentName:"em"},"network1")," and ",(0,r.yg)("inlineCode",{parentName:"em"},"network2")," and wish to test interoperation between them"),")"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"core/relay")," folder."),(0,r.yg)("li",{parentName:"ul"},"To launch the server without TLS, leave the configuration file ",(0,r.yg)("inlineCode",{parentName:"li"},"config/Fabric_Relay2.toml")," in its default state. Otherwise, edit it to set TLS flags for this relay and the other relays and drivers it will connect to in this demonstration as follows:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-toml"},'.\n.\ncert_path="credentials/fabric_cert.pem"\nkey_path="credentials/fabric_key"\ntls=true\n.\n.\n[relays]\n[relays.Corda_Relay]\nhostname="localhost"\nport="9081"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n[relays.Corda_Relay2]\nhostname="localhost"\nport="9082"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n[relays.Fabric_Relay]\nhostname="localhost"\nport="9080"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n.\n.\n[drivers]\n[drivers.Fabric]\nhostname="localhost"\nport="9095"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n.\n.\n'))),(0,r.yg)("li",{parentName:"ul"},"To launch the server, simply run the following:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"RELAY_CONFIG=config/Fabric_Relay2.toml cargo run --bin server\n")))),(0,r.yg)("p",null,"For more information, see the ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/core/relay"},"relay README"),"."),(0,r.yg)("h3",{id:"fabric-driver"},"Fabric Driver"),(0,r.yg)("p",null,"A driver is a DLT-specific plugin invoked by the relay while conveying external data queries to the local peer network and collecting a response with proofs. The Fabric driver is built as a Fabric client application on the ",(0,r.yg)("inlineCode",{parentName:"p"},"fabric-network")," NPM package.\nThe code for this lies in the ",(0,r.yg)("inlineCode",{parentName:"p"},"core/drivers/fabric-driver")," folder."),(0,r.yg)("h4",{id:"configuring"},"Configuring"),(0,r.yg)("p",null,"In the ",(0,r.yg)("inlineCode",{parentName:"p"},"core/drivers/fabric-driver")," folder, copy ",(0,r.yg)("inlineCode",{parentName:"p"},".env.template")," to ",(0,r.yg)("inlineCode",{parentName:"p"},".env")," and update ",(0,r.yg)("inlineCode",{parentName:"p"},"CONNECTION_PROFILE")," to point to the connection profile of the Fabric network (e.g. ",(0,r.yg)("inlineCode",{parentName:"p"},"<PATH-TO-WEAVER>/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json"),")"),(0,r.yg)("p",null,"Configure ",(0,r.yg)("inlineCode",{parentName:"p"},"fabric-driver")," for ",(0,r.yg)("inlineCode",{parentName:"p"},"network1")," as follows:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"core/drivers/fabric-driver")," folder."),(0,r.yg)("li",{parentName:"ul"},"Create a ",(0,r.yg)("inlineCode",{parentName:"li"},".env")," file by copying ",(0,r.yg)("inlineCode",{parentName:"li"},".env.template")," and setting suitable parameter values:",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},"The ",(0,r.yg)("inlineCode",{parentName:"li"},"CONNECTION_PROFILE")," should point to the absolute path of the connection profile for ",(0,r.yg)("inlineCode",{parentName:"li"},"network1"),".",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},"For this exercise, specify the path ",(0,r.yg)("inlineCode",{parentName:"li"},"<PATH-TO-WEAVER>/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json")," (",(0,r.yg)("em",{parentName:"li"},"you must specify the full absolute path here"),")."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"<PATH-TO-WEAVER>")," here is the absolute path of the ",(0,r.yg)("inlineCode",{parentName:"li"},"weaver-dlt-interoperability")," clone folder."))),(0,r.yg)("li",{parentName:"ul"},"If you wish to start the driver without TLS, set the following parameter values:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre"},"RELAY_TLS=false\nRELAY_TLSCA_CERT_PATH=\nDRIVER_TLS=false\nDRIVER_TLS_CERT_PATH=\nDRIVER_TLS_KEY_PATH=\n")),"Otherwise, if you wish to start the driver with TLS enabled, set the following parameter values (replace ",(0,r.yg)("inlineCode",{parentName:"li"},"<PATH-TO-WEAVER>")," with the absolute path of the ",(0,r.yg)("inlineCode",{parentName:"li"},"weaver-dlt-interoperability")," clone folder):",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre"},"RELAY_TLS=true\nRELAY_TLSCA_CERT_PATH=<PATH-TO-WEAVER>/core/relay/credentials/fabric_ca_cert.pem\nDRIVER_TLS=true\nDRIVER_TLS_CERT_PATH=<PATH-TO-WEAVER>/core/relay/credentials/fabric_cert.pem\nDRIVER_TLS_KEY_PATH=<PATH-TO-WEAVER>/core/relay/credentials/fabric_key\n"))),(0,r.yg)("li",{parentName:"ul"},"Leave the default values unchanged for the other parameters. The relay and driver endpoints as well as the network name are already specified in the template.")))),(0,r.yg)("h4",{id:"building-1"},"Building"),(0,r.yg)("p",null,"Build the Fabric driver module as follows:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"core/drivers/fabric-driver")," folder."),(0,r.yg)("li",{parentName:"ul"},"Run the following:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make build-local\n")))),(0,r.yg)("h4",{id:"running"},"Running"),(0,r.yg)("p",null,"Run a Fabric driver for ",(0,r.yg)("inlineCode",{parentName:"p"},"network1")," as follows:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"core/drivers/fabric-driver")," folder."),(0,r.yg)("li",{parentName:"ul"},"Run the following:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"npm run dev\n")))),(0,r.yg)("p",null,"Run a Fabric driver for ",(0,r.yg)("inlineCode",{parentName:"p"},"network2")," as follows (",(0,r.yg)("em",{parentName:"p"},"do this only if you wish to test interoperation between the two Fabric networks ",(0,r.yg)("inlineCode",{parentName:"em"},"network1")," and ",(0,r.yg)("inlineCode",{parentName:"em"},"network2")),")"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"core/drivers/fabric-driver")," folder."),(0,r.yg)("li",{parentName:"ul"},"Run the following (replace ",(0,r.yg)("inlineCode",{parentName:"li"},"<PATH-TO-WEAVER>")," with the absolute path of the ",(0,r.yg)("inlineCode",{parentName:"li"},"weaver-dlt-interoperability")," clone folder):",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"CONNECTION_PROFILE=<PATH-TO-WEAVER>/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/connection-org1.json NETWORK_NAME=network2 RELAY_ENDPOINT=localhost:9083 DRIVER_ENDPOINT=localhost:9095 npm run dev\n")))),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:"left"},"The variables we specified earlier in the ",(0,r.yg)("inlineCode",{parentName:"td"},".env")," for ",(0,r.yg)("inlineCode",{parentName:"td"},"network1")," are now passed in the command line. Alternatively, you can make a copy of the ",(0,r.yg)("inlineCode",{parentName:"td"},"fabric-driver")," folder with a different name and create a separate ",(0,r.yg)("inlineCode",{parentName:"td"},".env")," file within it that contains links to the connection profile, relay, and driver for ",(0,r.yg)("inlineCode",{parentName:"td"},"network2"),".")))),(0,r.yg)("h3",{id:"fabric-iin-agent"},"Fabric IIN Agent"),(0,r.yg)("p",null,"IIN Agent is a client of a member of a DLT network or security domain with special permissions to update security domain identities and configurations on the ledger via the network's interoperation module. The code for this lies in the ",(0,r.yg)("inlineCode",{parentName:"p"},"core/identity-management/iin-agent")," folder. Navigate to the ",(0,r.yg)("inlineCode",{parentName:"p"},"core/identity-management/iin-agent")," folder."),(0,r.yg)("h4",{id:"building-2"},"Building"),(0,r.yg)("p",null,"To build the IIN Agent, run:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make build-local\n")),(0,r.yg)("h4",{id:"configuration"},"Configuration"),(0,r.yg)("p",null,"Ledger config file specifies ledger specific IIN Agent details such as identity and which network and organization to connect to."),(0,r.yg)("ol",null,(0,r.yg)("li",{parentName:"ol"},(0,r.yg)("p",{parentName:"li"},"To create config file for ",(0,r.yg)("inlineCode",{parentName:"p"},"Org1MSP"),"'s Fabric IIN Agent of ",(0,r.yg)("inlineCode",{parentName:"p"},"network1"),", follow the steps:"),(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},"Create copy of template config file for Fabric IIN Agent: ",(0,r.yg)("inlineCode",{parentName:"li"},"src/fabric-ledger/config.json.template"),", say to location ",(0,r.yg)("inlineCode",{parentName:"li"},"src/fabric-ledger/config-n1-org1.json"),"."),(0,r.yg)("li",{parentName:"ul"},"Replace ",(0,r.yg)("inlineCode",{parentName:"li"},"<path-to-connection-profile>")," with ",(0,r.yg)("inlineCode",{parentName:"li"},"<PATH-TO-WEAVER>/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json"),", where ",(0,r.yg)("inlineCode",{parentName:"li"},"<PATH-TO-WEAVER>")," should be substituted with the absolute path location of your clone of Weaver."),(0,r.yg)("li",{parentName:"ul"},"Set ",(0,r.yg)("inlineCode",{parentName:"li"},"mspId")," as ",(0,r.yg)("inlineCode",{parentName:"li"},"Org1MSP"),"."),(0,r.yg)("li",{parentName:"ul"},"Set ",(0,r.yg)("inlineCode",{parentName:"li"},"agent.affiliation")," as ",(0,r.yg)("inlineCode",{parentName:"li"},"org1.department1"),"."))),(0,r.yg)("li",{parentName:"ol"},(0,r.yg)("p",{parentName:"li"},"To create config file for ",(0,r.yg)("inlineCode",{parentName:"p"},"Org2MSP"),"'s Fabric IIN Agent of ",(0,r.yg)("inlineCode",{parentName:"p"},"network1"),", repeat ",(0,r.yg)("inlineCode",{parentName:"p"},"Step 1")," with different name for config file, say ",(0,r.yg)("inlineCode",{parentName:"p"},"src/fabric-ledger/config-n1-org2.json"),", and replace ",(0,r.yg)("inlineCode",{parentName:"p"},"org1")," with ",(0,r.yg)("inlineCode",{parentName:"p"},"org2")," and ",(0,r.yg)("inlineCode",{parentName:"p"},"Org1MSP")," with ",(0,r.yg)("inlineCode",{parentName:"p"},"Org2MSP"),".")),(0,r.yg)("li",{parentName:"ol"},(0,r.yg)("p",{parentName:"li"},"To create config file for ",(0,r.yg)("inlineCode",{parentName:"p"},"Org1MSP"),"'s Fabric IIN Agent of ",(0,r.yg)("inlineCode",{parentName:"p"},"network2"),", repeat ",(0,r.yg)("inlineCode",{parentName:"p"},"Step 1")," with different name for config file, say ",(0,r.yg)("inlineCode",{parentName:"p"},"src/fabric-ledger/config-n2-org1.json"),", and replace ",(0,r.yg)("inlineCode",{parentName:"p"},"network1")," with ",(0,r.yg)("inlineCode",{parentName:"p"},"network2"),".")),(0,r.yg)("li",{parentName:"ol"},(0,r.yg)("p",{parentName:"li"},"To create config file for ",(0,r.yg)("inlineCode",{parentName:"p"},"Org2MSP"),"'s Fabric IIN Agent of ",(0,r.yg)("inlineCode",{parentName:"p"},"network2"),", repeat ",(0,r.yg)("inlineCode",{parentName:"p"},"Step 1")," with different name for config file, say ",(0,r.yg)("inlineCode",{parentName:"p"},"src/fabric-ledger/config-n2-org2.json"),", and replace ",(0,r.yg)("inlineCode",{parentName:"p"},"network1")," with ",(0,r.yg)("inlineCode",{parentName:"p"},"network2"),", ",(0,r.yg)("inlineCode",{parentName:"p"},"org1")," with ",(0,r.yg)("inlineCode",{parentName:"p"},"org2")," and ",(0,r.yg)("inlineCode",{parentName:"p"},"Org1MSP")," with ",(0,r.yg)("inlineCode",{parentName:"p"},"Org2MSP"),"."))),(0,r.yg)("h4",{id:"security-domain-configuration"},"Security Domain Configuration"),(0,r.yg)("p",null,"Security Domain config file specifies the scope of security domain, which can be a channel in Fabric networks or list of nodes. File ",(0,r.yg)("inlineCode",{parentName:"p"},"docker-testnet/configs/security-domain-config.json")," can be used for Weaver testnets."),(0,r.yg)("h4",{id:"dns-configuration"},"DNS Configuration"),(0,r.yg)("p",null,"To allow an IIN Agent's to be able to discover other IIN Agents, a config file for DNS is required. Create one ",(0,r.yg)("inlineCode",{parentName:"p"},"dnsconfig.json")," by creating a copy of template ",(0,r.yg)("inlineCode",{parentName:"p"},"dnsconfig.json.template"),", and replace the values with:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"If Fabric networks are started with 1 org, and IIN Agent are to be started without TLS, use following values:")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-json"},'{\n "network1": {\n "Org1MSP": {\n "endpoint": "localhost:9500",\n "tls": false,\n "tlsCACertPath": ""\n }\n },\n "network2": {\n "Org1MSP": {\n "endpoint": "localhost:9501",\n "tls": false,\n "tlsCACertPath": ""\n }\n }\n}\n')),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"If Fabric networks are started with 1 org, and IIN Agent are to be started with TLS, use following values:")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-json"},'{\n "network1": {\n "Org1MSP": {\n "endpoint": "localhost:9500",\n "tls": true,\n "tlsCACertPath": "../../relay/credentials/fabric_ca_cert.pem"\n }\n },\n "network2": {\n "Org1MSP": {\n "endpoint": "localhost:9501",\n "tls": true,\n "tlsCACertPath": "../../relay/credentials/fabric_ca_cert.pem"\n }\n }\n}\n')),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"If Fabric networks are started with 2 orgs, and IIN Agent are to be started without TLS, use following values:")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-json"},'{\n "network1": {\n "Org1MSP": {\n "endpoint": "localhost:9500",\n "tls": false,\n "tlsCACertPath": ""\n },\n "Org2MSP": {\n "endpoint": "localhost:9510",\n "tls": false,\n "tlsCACertPath": ""\n }\n },\n "network2": {\n "Org1MSP": {\n "endpoint": "localhost:9501",\n "tls": false,\n "tlsCACertPath": ""\n },\n "Org2MSP": {\n "endpoint": "localhost:9511",\n "tls": false,\n "tlsCACertPath": ""\n }\n }\n}\n')),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"If Fabric networks are started with 2 orgs, and IIN Agent are to be started with TLS, use following values:")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-json"},'{\n "network1": {\n "Org1MSP": {\n "endpoint": "localhost:9500",\n "tls": true,\n "tlsCACertPath": "../../relay/credentials/fabric_ca_cert.pem"\n },\n "Org2MSP": {\n "endpoint": "localhost:9510",\n "tls": true,\n "tlsCACertPath": "../../relay/credentials/fabric_ca_cert.pem"\n }\n },\n "network2": {\n "Org1MSP": {\n "endpoint": "localhost:9501",\n "tls": true,\n "tlsCACertPath": "../../relay/credentials/fabric_ca_cert.pem"\n },\n "Org2MSP": {\n "endpoint": "localhost:9511",\n "tls": true,\n "tlsCACertPath": "../../relay/credentials/fabric_ca_cert.pem"\n }\n }\n}\n')),(0,r.yg)("h4",{id:"environment-variables"},"Environment Variables"),(0,r.yg)("p",null,"To configure environment variables for ",(0,r.yg)("inlineCode",{parentName:"p"},"Org1MSP"),"'s Fabric IIN Agent of ",(0,r.yg)("inlineCode",{parentName:"p"},"network1"),", follow the steps:"),(0,r.yg)("ol",null,(0,r.yg)("li",{parentName:"ol"},"Create a copy of ",(0,r.yg)("inlineCode",{parentName:"li"},".env.template")," as ",(0,r.yg)("inlineCode",{parentName:"li"},".env"),", and update following values based on previous configuration file paths:")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre"},"IIN_AGENT_ENDPOINT=localhost:9500\nMEMBER_ID=Org1MSP\nSECURITY_DOMAIN=network1\nDLT_TYPE=fabric\nCONFIG_PATH=./src/fabric-ledger/config-n1-org1.json\nDNS_CONFIG_PATH=./dnsconfig.json\nSECURITY_DOMAIN_CONFIG_PATH=./docker-testnet/configs/security-domain-config.json\nWEAVER_CONTRACT_ID=interop\nAUTO_SYNC=true\n")),(0,r.yg)("ol",{start:2},(0,r.yg)("li",{parentName:"ol"},"If IIN Agent has to be started with TLS enabled, also update following values:")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre"},"IIN_AGENT_TLS=true\nIIN_AGENT_TLS_CERT_PATH=../../relay/credentials/fabric_cert.pem\nIIN_AGENT_TLS_KEY_PATH=../../relay/credentials/fabric_key\n")),(0,r.yg)("h4",{id:"deployment-1"},"Deployment"),(0,r.yg)("p",null,"Use the following steps to run Fabric IIN Agents in host machine:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"To start IIN Agent for ",(0,r.yg)("inlineCode",{parentName:"li"},"Org1MSP")," of ",(0,r.yg)("inlineCode",{parentName:"li"},"network1"),", run:")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"npm run dev\n")),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"To start IIN Agent for ",(0,r.yg)("inlineCode",{parentName:"li"},"Org2MSP")," of ",(0,r.yg)("inlineCode",{parentName:"li"},"network1")," (",(0,r.yg)("em",{parentName:"li"},"only required if Fabric network was started with 2 orgs"),"), run:")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"IIN_AGENT_ENDPOINT=localhost:9510 MEMBER_ID=Org2MSP CONFIG_PATH=./src/fabric-ledger/config-n1-org2.json npm run dev\n")),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"To start IIN Agent for ",(0,r.yg)("inlineCode",{parentName:"li"},"Org1MSP")," of ",(0,r.yg)("inlineCode",{parentName:"li"},"network2"),", run:")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"IIN_AGENT_ENDPOINT=localhost:9501 SECURITY_DOMAIN=network2 CONFIG_PATH=./src/fabric-ledger/config-n2-org1.json npm run dev\n")),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"To start IIN Agent for ",(0,r.yg)("inlineCode",{parentName:"li"},"Org2MSP")," of ",(0,r.yg)("inlineCode",{parentName:"li"},"network2")," (",(0,r.yg)("em",{parentName:"li"},"only required if Fabric network was started with 2 orgs"),"), run:")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"IIN_AGENT_ENDPOINT=localhost:9511 MEMBER_ID=Org2MSP SECURITY_DOMAIN=network2 CONFIG_PATH=./src/fabric-ledger/config-n2-org2.json npm run dev\n")),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:"left"},"The variables we specified earlier in the ",(0,r.yg)("inlineCode",{parentName:"td"},".env")," for ",(0,r.yg)("inlineCode",{parentName:"td"},"network1")," are now passed in the command line. Alternatively, you can make a copy of the ",(0,r.yg)("inlineCode",{parentName:"td"},"fabric-driver")," folder with a different name and create a separate ",(0,r.yg)("inlineCode",{parentName:"td"},".env")," file within it that contains links to the connection profile, relay, and driver for ",(0,r.yg)("inlineCode",{parentName:"td"},"network2"),".")))),(0,r.yg)("h2",{id:"corda-components"},"Corda Components"),(0,r.yg)("p",null,"Using the sequence of instructions below, you can start a Corda network and run an application CorDapp on it. You can also run an interoperation CorDapp, a relay and a ",(0,r.yg)("em",{parentName:"p"},"driver")," acting on behalf of the network. You can initialize the network's vault with access control policies, foreign networks' security groups (i.e., membership providers' certificate chains), and some sample state values that can be shared during subsequent interoperation flows."),(0,r.yg)("h3",{id:"interoperation-cordapp"},"Interoperation CorDapp"),(0,r.yg)("p",null,"The interoperation CorDapp is deployed to run as part of any Corda application flow that involves cross-network interoperation."),(0,r.yg)("p",null,"Build the interoperation CorDapp as follows:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"core/network/corda-interop-app")," folder."),(0,r.yg)("li",{parentName:"ul"},"Run the following to create the JAR files on which other Corda network components will depend on:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make build-local\n")))),(0,r.yg)("h3",{id:"corda-interoperation-sdk"},"Corda Interoperation SDK"),(0,r.yg)("p",null,"A client-layer library is defined in the ",(0,r.yg)("inlineCode",{parentName:"p"},"sdks/corda")," folder. This contains functions for Corda based client applications to exercise interoperation capabilities via relays and also several utility/helper functions. The Corda Client tool, which we will use later, depends on this library."),(0,r.yg)("p",null,"To build the library, do the following:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"sdks/corda")," folder."),(0,r.yg)("li",{parentName:"ul"},"Run the following command (",(0,r.yg)("em",{parentName:"li"},"make sure there is no github.properties file present in the directory"),"):",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make build\n")))),(0,r.yg)("h3",{id:"corda-simple-application-and-client-application"},"Corda Simple Application and Client (Application)"),(0,r.yg)("p",null,"This is a simple CorDapp that maintains a state of type ",(0,r.yg)("inlineCode",{parentName:"p"},"SimpleState"),", which is a set of key-value pairs (of strings).\nThe code for this lies in the ",(0,r.yg)("inlineCode",{parentName:"p"},"samples/corda/corda-simple-application")," folder."),(0,r.yg)("p",null,"Build the ",(0,r.yg)("inlineCode",{parentName:"p"},"corda-simple-application")," CorDapp as follows:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"samples/corda/corda-simple-application")," folder."),(0,r.yg)("li",{parentName:"ul"},"Run the following:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make build-local\n")))),(0,r.yg)("h3",{id:"corda-network"},"Corda Network"),(0,r.yg)("p",null,"The Corda networks' code lies in the ",(0,r.yg)("inlineCode",{parentName:"p"},"tests/network-setups/corda")," folder. You can launch two separate Corda networks, namely ",(0,r.yg)("inlineCode",{parentName:"p"},"Corda_Network")," and ",(0,r.yg)("inlineCode",{parentName:"p"},"Corda_Network2"),". Each network runs the ",(0,r.yg)("inlineCode",{parentName:"p"},"samples/corda/corda-simple-application")," CorDapp by default, which maintains a state named ",(0,r.yg)("inlineCode",{parentName:"p"},"SimpleState")," containing a set of key-value pairs (of strings)."),(0,r.yg)("p",null,"Follow the instructions below to build and launch both networks:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"tests/network-setups/corda")," folder."),(0,r.yg)("li",{parentName:"ul"},"To spin up the Corda networks with the Interoperation CorDapps:",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},"Each consisting of 1 node and a notary (for data-transfer), run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make start-local\n"))),(0,r.yg)("li",{parentName:"ul"},"Each consisting of 2 nodes and a notary (for asset-exchange/transfer), run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},'make start-local PROFILE="2-nodes"\n'))),(0,r.yg)("li",{parentName:"ul"},"Each consisting of 3 nodes and a notary (for asset-exchange/transfer), run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},'make start-local PROFILE="3-nodes"\n')))))),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:"left"},"If you do not wish to test Corda-Corda interoperation, you can choose to launch only one of the two networks along with its interoperation CorDapp. For ",(0,r.yg)("inlineCode",{parentName:"td"},"Corda_Network"),", run ",(0,r.yg)("inlineCode",{parentName:"td"},"make start-network1-local"),", and for ",(0,r.yg)("inlineCode",{parentName:"td"},"Corda_Network2"),", run ",(0,r.yg)("inlineCode",{parentName:"td"},"make start-network2-local"),".")))),(0,r.yg)("p",null,"You should see the following message in the terminal:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre"},"Waiting for network node services to start\n")),(0,r.yg)("p",null,"The Corda nodes and notary may take a while (several minutes on memory-constrained systems) to start. If they start up successfully, you should something like the following for each network, though the number of node entries will depend on the profile you used to start the network with (replace ",(0,r.yg)("inlineCode",{parentName:"p"},"<network-name>")," with ",(0,r.yg)("inlineCode",{parentName:"p"},"Corda_Network")," or ",(0,r.yg)("inlineCode",{parentName:"p"},"Corda_Network2"),"):"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"PartyA node services started for network <network-name>\nPartyB node services started for network <network-name>\nPartyC node services started for network <network-name>\nNotary node services started for network <network-name>\n")),(0,r.yg)("h3",{id:"corda-relay"},"Corda Relay"),(0,r.yg)("p",null,"The relay was built earlier, so you just need to use a different configuration file to start a relay for the Corda network."),(0,r.yg)("p",null,"Run a relay for ",(0,r.yg)("inlineCode",{parentName:"p"},"Corda_Network")," as follows:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"p"},"core/relay")," folder.")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},"(Make sure you've already built the relay by running ",(0,r.yg)("inlineCode",{parentName:"p"},"make"),".)")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},"To launch the server without TLS, leave the configuration file ",(0,r.yg)("inlineCode",{parentName:"p"},"config/Corda_Relay.toml")," in its default state. Otherwise, edit it to set TLS flags for this relay and the other relays and drivers it will connect to in this demonstration as follows:"),(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-toml"},'.\n.\ncert_path="credentials/fabric_cert.pem"\nkey_path="credentials/fabric_key"\ntls=true\n.\n.\n[relays]\n[relays.Fabric_Relay]\nhostname="localhost"\nport="9080"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n[relays.Fabric_Relay2]\nhostname="localhost"\nport="9083"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n[relays.Corda_Relay2]\nhostname="localhost"\nport="9082"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n.\n.\n[drivers]\n[drivers.Corda]\nhostname="localhost"\nport="9099"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n.\n.\n'))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},"To launch the server, simply run the following:"),(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"RELAY_CONFIG=config/Corda_Relay.toml cargo run --bin server\n")),(0,r.yg)("p",{parentName:"li"},"If the relay starts up successfully, the following will be logged on your terminal:"),(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre"},'Relay Name: "Corda_Relay"\nRelayServer listening on [::1]:9081\n')))),(0,r.yg)("p",null,"Run a relay for ",(0,r.yg)("inlineCode",{parentName:"p"},"Corda_Network2")," as follows (",(0,r.yg)("em",{parentName:"p"},"do this only if you have launched both Corda networks ",(0,r.yg)("inlineCode",{parentName:"em"},"Corda_Network")," and ",(0,r.yg)("inlineCode",{parentName:"em"},"Corda_Network2")," and wish to test interoperation between them"),")"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"p"},"core/relay")," folder.")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},"To launch the server without TLS, leave the configuration file ",(0,r.yg)("inlineCode",{parentName:"p"},"config/Corda_Relay2.toml")," in its default state. Otherwise, edit it to set TLS flags for this relay and the other relays and drivers it will connect to in this demonstration as follows:"),(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-toml"},'.\n.\ncert_path="credentials/fabric_cert.pem"\nkey_path="credentials/fabric_key"\ntls=true\n.\n.\n[relays]\n[relays.Fabric_Relay]\nhostname="localhost"\nport="9080"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n[relays.Fabric_Relay2]\nhostname="localhost"\nport="9083"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n[relays.Corda_Relay]\nhostname="localhost"\nport="9081"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n.\n.\n[drivers]\n[drivers.Corda]\nhostname="localhost"\nport="9098"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n.\n.\n'))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},"To launch the server, simply run the following:"),(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"RELAY_CONFIG=config/Corda_Relay2.toml cargo run --bin server\n")),(0,r.yg)("p",{parentName:"li"},"If the relay starts up successfully, the following will be logged on your terminal:"),(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre"},'Relay Name: "Corda2_Relay"\nRelayServer listening on [::1]:9082\n')))),(0,r.yg)("h3",{id:"corda-driver"},"Corda Driver"),(0,r.yg)("p",null,"The code for this lies in the ",(0,r.yg)("inlineCode",{parentName:"p"},"core/drivers/corda-driver")," folder."),(0,r.yg)("h4",{id:"building-corda-driver"},"Building Corda Driver"),(0,r.yg)("p",null,"Build the Corda driver module as follows:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"core/drivers/corda-driver")," folder."),(0,r.yg)("li",{parentName:"ul"},"Run the following:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make build-local\n")))),(0,r.yg)("h4",{id:"configuring-1"},"Configuring"),(0,r.yg)("p",null,"Configure the drivers as follows (you can skip this if you wish to run the drivers without TLS):"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"core/drivers/corda-driver")," folder and create a ",(0,r.yg)("inlineCode",{parentName:"li"},".env")," file."),(0,r.yg)("li",{parentName:"ul"},"To run the drivers without TLS, set the following default values:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre"},"RELAY_TLS=false\nRELAY_TLSCA_TRUST_STORE=\nRELAY_TLSCA_TRUST_STORE_PASSWORD=\nRELAY_TLSCA_CERT_PATHS=\n"))),(0,r.yg)("li",{parentName:"ul"},"To run the drivers with TLS, set the following values (replace ",(0,r.yg)("inlineCode",{parentName:"li"},"<PATH-TO-WEAVER>")," with the absolute path of the ",(0,r.yg)("inlineCode",{parentName:"li"},"weaver-dlt-interoperability")," clone folder):",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre"},"RELAY_TLS=true\nRELAY_TLSCA_TRUST_STORE=<PATH-TO-WEAVER>/core/relay/credentials/fabric_trust_store.jks\nRELAY_TLSCA_TRUST_STORE_PASSWORD=trelay\nRELAY_TLSCA_CERT_PATHS=<PATH-TO-WEAVER>/core/relay/credentials/fabric_ca_cert.pem\n")))),(0,r.yg)("h4",{id:"running-1"},"Running"),(0,r.yg)("p",null,"Run a Corda driver as follows:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"core/drivers/corda-driver")," folder."),(0,r.yg)("li",{parentName:"ul"},"Run the following to start Corda driver for ",(0,r.yg)("inlineCode",{parentName:"li"},"Corda_Network"),":",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"./build/install/corda-driver/bin/corda-driver\n")),"If the driver starts successfully, it should log the following message on your terminal:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre"},"Corda driver gRPC server started. Listening on port 9099\n"))),(0,r.yg)("li",{parentName:"ul"},"Run the following to start Corda driver for ",(0,r.yg)("inlineCode",{parentName:"li"},"Corda_Network2"),":",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"DRIVER_PORT=9098 ./build/install/corda-driver/bin/corda-driver\n")),"If the driver starts successfully, it should log the following message on your terminal:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre"},"Corda driver gRPC server started. Listening on port 9098\n")))),(0,r.yg)("h2",{id:"hyperledger-besu-components"},"Hyperledger Besu Components"),(0,r.yg)("p",null,"Using the sequence of instructions below, you can start two separate Besu networks, each with 4 validator nodes, and EthSigner and application contract. You can also install an interoperation contract in the network. You can build a Besu CLI tool with which you can initialize both networks' ledgers."),(0,r.yg)("h3",{id:"prerequisites-2"},"Prerequisites"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Java (JDK and JRE): ",(0,r.yg)("a",{parentName:"li",href:"https://openjdk.java.net/install/"},"sample instructions")," (Version 11)\nYou need to run Besu instructions in a separate environment (separate terminal or machine) than Corda, as Corda requires Java 8. You can also use ",(0,r.yg)("inlineCode",{parentName:"li"},"update-alternatives")," to switch between java versions."),(0,r.yg)("li",{parentName:"ul"},"tmux: ",(0,r.yg)("inlineCode",{parentName:"li"},"sudo apt install tmux")),(0,r.yg)("li",{parentName:"ul"},"Besu: ",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},"Download and unpack the latest ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/hyperledger/besu/releases/latest"},"https://github.com/hyperledger/besu/releases/latest"),". You will find it in the link of the form: ",(0,r.yg)("a",{parentName:"li",href:"https://hyperledger.jfrog.io/artifactory/besu-binaries/besu/x.y.z/besu-x.y.z.zip"},"https://hyperledger.jfrog.io/artifactory/besu-binaries/besu/x.y.z/besu-x.y.z.zip")," with x.y.z replaced with the version number. For instance, run the following command after updating version number accordingly.",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre"},"wget https://hyperledger.jfrog.io/artifactory/besu-binaries/besu/21.7.0/besu-21.7.0.zip\n"))),(0,r.yg)("li",{parentName:"ul"},"Add the path to ",(0,r.yg)("inlineCode",{parentName:"li"},"besu-x.y.z/bin")," to your system PATH"))),(0,r.yg)("li",{parentName:"ul"},"EthSigner: ",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},"Download and unpack the latest from ",(0,r.yg)("a",{parentName:"li",href:"https://cloudsmith.io/~consensys/repos/ethsigner/packages/?q=tag%3Alatest"},"https://cloudsmith.io/~consensys/repos/ethsigner/packages/?q=tag%3Alatest")," (Requires Java 11 or later)"),(0,r.yg)("li",{parentName:"ul"},"Add the path to ",(0,r.yg)("inlineCode",{parentName:"li"},"ethsigner-x.y.z/bin")," to your system PATH")))),(0,r.yg)("h3",{id:"besu-interoperation-node-sdk"},"Besu Interoperation Node SDK"),(0,r.yg)("p",null,"A client-layer library is defined in the ",(0,r.yg)("inlineCode",{parentName:"p"},"sdks/besu/interoperation-node-sdk")," folder. This contains functions for Besu web3JS based applications to exercise interoperation capabilities via several utility/helper functions. The Besu-CLI tool, which we will use later, depends on this library."),(0,r.yg)("p",null,"To build the library, do the following:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"sdks/besu/interoperation-node-sdk")," folder."),(0,r.yg)("li",{parentName:"ul"},"Run the following command:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make build-local\n")))),(0,r.yg)("h3",{id:"besu-network"},"Besu Network"),(0,r.yg)("p",null,"The code for this lies in the ",(0,r.yg)("inlineCode",{parentName:"p"},"tests/network-setups/besu")," folder."),(0,r.yg)("p",null,"This folder contains code to create and launch networks ",(0,r.yg)("inlineCode",{parentName:"p"},"Network1")," and ",(0,r.yg)("inlineCode",{parentName:"p"},"Network2")," of identical specifications:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Network: 4 validator nodes, 1 EthSigner node."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"Network1")," uses ",(0,r.yg)("inlineCode",{parentName:"li"},"8545")," port for EthSigner while ",(0,r.yg)("inlineCode",{parentName:"li"},"Network2")," uses ",(0,r.yg)("inlineCode",{parentName:"li"},"9544")," port for EthSigner.")),(0,r.yg)("p",null,"Follow the instructions below to build and launch the networks:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"tests/network-setups/besu")," folder."),(0,r.yg)("li",{parentName:"ul"},"To spin up both Network1 and Network2, run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make start\n")))),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:"left"},"If you do not wish to test Besu-Besu interoperation, you can choose to launch only one of the two networks. For ",(0,r.yg)("inlineCode",{parentName:"td"},"Network1"),", run ",(0,r.yg)("inlineCode",{parentName:"td"},"make start-network1"),", and for ",(0,r.yg)("inlineCode",{parentName:"td"},"Network2"),", run ",(0,r.yg)("inlineCode",{parentName:"td"},"make start-network2"))))),(0,r.yg)("p",null,"For more information, refer to the associated ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/tests/network-setups/besu"},"README"),"."),(0,r.yg)("h3",{id:"contracts"},"Contracts"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"AssetExchangeContract")," must be deployed which is present in ",(0,r.yg)("inlineCode",{parentName:"li"},"core/network/besu/contracts/interop/manageAssetAny.sol"),". This contract is deployed along with application contract."),(0,r.yg)("li",{parentName:"ul"},"Application contract ",(0,r.yg)("inlineCode",{parentName:"li"},"simpleasset"),", located in ",(0,r.yg)("inlineCode",{parentName:"li"},"samples/besu/simpleasset")," directory (for ",(0,r.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview"},"Asset Exchange"),"), which supports creation, modification, transfer, and deletion, as well as locking, unlocking, and claiming, of simple ",(0,r.yg)("inlineCode",{parentName:"li"},"AliceERC20")," and ",(0,r.yg)("inlineCode",{parentName:"li"},"BobERC20")," tokens (examples of fungible assets), or ",(0,r.yg)("inlineCode",{parentName:"li"},"AliceERC721")," and ",(0,r.yg)("inlineCode",{parentName:"li"},"BobERC721")," tokens (example of non-fungible assets), or ",(0,r.yg)("inlineCode",{parentName:"li"},"AliceERC1155")," and ",(0,r.yg)("inlineCode",{parentName:"li"},"BobERC1155")," tokens (example of hybrid assets).")),(0,r.yg)("p",null,"To deploy ",(0,r.yg)("inlineCode",{parentName:"p"},"simpleasset")," with ",(0,r.yg)("inlineCode",{parentName:"p"},"AssetExchangeContract")," on both Besu networks, navigate to ",(0,r.yg)("inlineCode",{parentName:"p"},"samples/besu/simpleasset")," folder, and run:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make deploy-contracts\n")),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:"left"},"If you chose to launch only one of the two networks, then for ",(0,r.yg)("inlineCode",{parentName:"td"},"Network1"),", run ",(0,r.yg)("inlineCode",{parentName:"td"},"make deploy-contract-network1"),", and for ",(0,r.yg)("inlineCode",{parentName:"td"},"Network2"),", run ",(0,r.yg)("inlineCode",{parentName:"td"},"deploy-contract-network2"))))),(0,r.yg)("h3",{id:"besu-client-besu-cli"},"Besu Client (besu-cli)"),(0,r.yg)("p",null,"The CLI is used to interact with a Besu network, configure it and run contract transactions to record data on the ledger or query data."),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"besu-cli")," Node.js source code is located in the ",(0,r.yg)("inlineCode",{parentName:"p"},"samples/besu/besu-cli")," folder."),(0,r.yg)("h4",{id:"prerequisites-3"},"Prerequisites"),(0,r.yg)("p",null,"If you are using a Linux system, make sure that lib64 is installed."),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:"left"},"For the Node.js version of the ",(0,r.yg)("inlineCode",{parentName:"td"},"besu-cli"),", the setup and running instructions below were tested with all Node.js versions from v11.14.0 to v14.17.3.")))),(0,r.yg)("h4",{id:"installation-1"},"Installation"),(0,r.yg)("p",null,"You can install ",(0,r.yg)("inlineCode",{parentName:"p"},"besu-cli")," as follows:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"samples/besu/besu-cli")," folder."),(0,r.yg)("li",{parentName:"ul"},"Run the following to install dependencies:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make build-local\n"))),(0,r.yg)("li",{parentName:"ul"},"Use the ",(0,r.yg)("inlineCode",{parentName:"li"},"besu-cli")," executable in the ",(0,r.yg)("inlineCode",{parentName:"li"},"bin")," folder for ",(0,r.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/ledger-initialization"},"subsequent actions"),".")),(0,r.yg)("h2",{id:"tear-down-the-setup"},"Tear Down the Setup"),(0,r.yg)("p",null,"Bring down the test network's components as follows:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Simply terminate the various relays and drivers, which are running in the foreground in different terminals"),(0,r.yg)("li",{parentName:"ul"},"To bring down the running Corda network:",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"tests/network-setups/corda")," folder."),(0,r.yg)("li",{parentName:"ul"},"Run the following:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make clean\n"))))),(0,r.yg)("li",{parentName:"ul"},"To bring down all the running Fabric networks:",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"tests/network-setups/fabric/dev")," folder."),(0,r.yg)("li",{parentName:"ul"},"Run the following:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make clean\n"))))),(0,r.yg)("li",{parentName:"ul"},"To bring down all the running Besu networks:",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"tests/network-setups/besu")," folder."),(0,r.yg)("li",{parentName:"ul"},"Run the following:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make clean\n")))))))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/36367655.972f50cd.js b/assets/js/36367655.972f50cd.js deleted file mode 100644 index 25fb7f47e..000000000 --- a/assets/js/36367655.972f50cd.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[7736],{3905:(e,t,a)=>{a.d(t,{Zo:()=>d,kt:()=>k});var n=a(7294);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function i(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function l(e){for(var t=1;t<arguments.length;t++){var a=null!=arguments[t]?arguments[t]:{};t%2?i(Object(a),!0).forEach((function(t){r(e,t,a[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(a)):i(Object(a)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(a,t))}))}return e}function o(e,t){if(null==e)return{};var a,n,r=function(e,t){if(null==e)return{};var a,n,r={},i=Object.keys(e);for(n=0;n<i.length;n++)a=i[n],t.indexOf(a)>=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)a=i[n],t.indexOf(a)>=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var s=n.createContext({}),p=function(e){var t=n.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):l(l({},t),e)),a},d=function(e){var t=p(e.components);return n.createElement(s.Provider,{value:t},e.children)},c="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,d=o(e,["components","mdxType","originalType","parentName"]),c=p(a),m=r,k=c["".concat(s,".").concat(m)]||c[m]||u[m]||i;return a?n.createElement(k,l(l({ref:t},d),{},{components:a})):n.createElement(k,l({ref:t},d))}));function k(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=a.length,l=new Array(i);l[0]=m;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[c]="string"==typeof e?e:r,l[1]=o;for(var p=2;p<i;p++)l[p]=a[p];return n.createElement.apply(null,l)}return n.createElement.apply(null,a)}m.displayName="MDXCreateElement"},3059:(e,t,a)=>{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>u,frontMatter:()=>i,metadata:()=>o,toc:()=>p});var n=a(7462),r=(a(7294),a(3905));const i={id:"setup-local",title:"Setup with Locally Built Weaver Components",pagination_prev:"external/getting-started/test-network/overview",pagination_next:"external/getting-started/test-network/ledger-initialization"},l=void 0,o={unversionedId:"external/getting-started/test-network/setup-local",id:"external/getting-started/test-network/setup-local",title:"Setup with Locally Built Weaver Components",description:"\x3c!--",source:"@site/docs/external/getting-started/test-network/setup-local.md",sourceDirName:"external/getting-started/test-network",slug:"/external/getting-started/test-network/setup-local",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-local",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/getting-started/test-network/setup-local.md",tags:[],version:"current",frontMatter:{id:"setup-local",title:"Setup with Locally Built Weaver Components",pagination_prev:"external/getting-started/test-network/overview",pagination_next:"external/getting-started/test-network/ledger-initialization"},sidebar:"Documentation",previous:{title:"Component Overview",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/overview"},next:{title:"Ledger Initialization",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/ledger-initialization"}},s={},p=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Software",id:"software",level:3},{value:"Credentials",id:"credentials",level:3},{value:"Getting the Code and Documentation",id:"getting-the-code-and-documentation",level:2},{value:"Common Structures",id:"common-structures",level:2},{value:"Securing Components",id:"securing-components",level:2},{value:"Hyperledger Fabric Components",id:"hyperledger-fabric-components",level:2},{value:"Fabric Interoperation Node SDK",id:"fabric-interoperation-node-sdk",level:3},{value:"Fabric Network",id:"fabric-network",level:3},{value:"Fabric Client (fabric-cli)",id:"fabric-client-fabric-cli",level:3},{value:"Prerequisites",id:"prerequisites-1",level:4},{value:"Installation",id:"installation",level:4},{value:"Fabric Relay",id:"fabric-relay",level:3},{value:"Building",id:"building",level:4},{value:"Deployment",id:"deployment",level:4},{value:"Fabric Driver",id:"fabric-driver",level:3},{value:"Configuring",id:"configuring",level:4},{value:"Building",id:"building-1",level:4},{value:"Running",id:"running",level:4},{value:"Fabric IIN Agent",id:"fabric-iin-agent",level:3},{value:"Building",id:"building-2",level:4},{value:"Configuration",id:"configuration",level:4},{value:"Security Domain Configuration",id:"security-domain-configuration",level:4},{value:"DNS Configuration",id:"dns-configuration",level:4},{value:"Environment Variables",id:"environment-variables",level:4},{value:"Deployment",id:"deployment-1",level:4},{value:"Corda Components",id:"corda-components",level:2},{value:"Interoperation CorDapp",id:"interoperation-cordapp",level:3},{value:"Corda Interoperation SDK",id:"corda-interoperation-sdk",level:3},{value:"Corda Simple Application and Client (Application)",id:"corda-simple-application-and-client-application",level:3},{value:"Corda Network",id:"corda-network",level:3},{value:"Corda Relay",id:"corda-relay",level:3},{value:"Corda Driver",id:"corda-driver",level:3},{value:"Building Corda Driver",id:"building-corda-driver",level:4},{value:"Configuring",id:"configuring-1",level:4},{value:"Running",id:"running-1",level:4},{value:"Hyperledger Besu Components",id:"hyperledger-besu-components",level:2},{value:"Prerequisites",id:"prerequisites-2",level:3},{value:"Besu Interoperation Node SDK",id:"besu-interoperation-node-sdk",level:3},{value:"Besu Network",id:"besu-network",level:3},{value:"Contracts",id:"contracts",level:3},{value:"Besu Client (besu-cli)",id:"besu-client-besu-cli",level:3},{value:"Prerequisites",id:"prerequisites-3",level:4},{value:"Installation",id:"installation-1",level:4},{value:"Tear Down the Setup",id:"tear-down-the-setup",level:2}],d={toc:p},c="wrapper";function u(e){let{components:t,...a}=e;return(0,r.kt)(c,(0,n.Z)({},d,a,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"In this document, we detail the steps using which you can bring up networks using the default configuration settings and by building Weaver interoperation modules, SDK libraries, and relay drivers locally from your Weaver clone. To customize these settings (e.g., hostnames, ports), refer to the ",(0,r.kt)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/advanced-configuration"},"Advanced Configuration page"),"."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:"left"},"The default configuration is for a development setup, therefore all components are run on ",(0,r.kt)("inlineCode",{parentName:"td"},"localhost"),", many within Docker containers.")))),(0,r.kt)("p",null,"Follow the instructions below to build and run components followed by interoperation flows. These instructions have been tested on Ubuntu Linux (bash shell) and Mac OS. In general, they should work on any system and shell as long as the various dependenices have been installed and configured."),(0,r.kt)("h2",{id:"prerequisites"},"Prerequisites"),(0,r.kt)("h3",{id:"software"},"Software"),(0,r.kt)("p",null,"Before starting, make sure you have the following software installed on your host machine:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Curl: ",(0,r.kt)("em",{parentName:"li"},"install using package manager, like ",(0,r.kt)("inlineCode",{parentName:"em"},"apt")," on Debian/Ubuntu Linux")),(0,r.kt)("li",{parentName:"ul"},"Git: ",(0,r.kt)("a",{parentName:"li",href:"https://git-scm.com/book/en/v2/Getting-Started-Installing-Git"},"sample instructions")),(0,r.kt)("li",{parentName:"ul"},"Docker: ",(0,r.kt)("a",{parentName:"li",href:"https://docs.docker.com/engine/install/"},"sample instructions")," (Latest version)"),(0,r.kt)("li",{parentName:"ul"},"Docker-Compose: ",(0,r.kt)("a",{parentName:"li",href:"https://docs.docker.com/compose/install/"},"sample instructions")," (Version 1.28.2 or higher, but lower than version V2)"),(0,r.kt)("li",{parentName:"ul"},"Golang: ",(0,r.kt)("a",{parentName:"li",href:"https://golang.org/dl/"},"sample instructions")," (Version 1.16 or higher)"),(0,r.kt)("li",{parentName:"ul"},"Java (JDK and JRE): ",(0,r.kt)("a",{parentName:"li",href:"https://openjdk.java.net/install/"},"sample instructions")," (Version 8)"),(0,r.kt)("li",{parentName:"ul"},"Node.js and NPM: ",(0,r.kt)("a",{parentName:"li",href:"https://nodejs.org/en/download/package-manager/"},"sample instructions")," (Version 16 Supported)"),(0,r.kt)("li",{parentName:"ul"},"Yarn: ",(0,r.kt)("a",{parentName:"li",href:"https://classic.yarnpkg.com/en/docs/install/"},"sample instructions")),(0,r.kt)("li",{parentName:"ul"},"Rust: ",(0,r.kt)("a",{parentName:"li",href:"https://www.rust-lang.org/tools/install"},"sample instructions")),(0,r.kt)("li",{parentName:"ul"},"Protoc (Protobuf compiler): ",(0,r.kt)("em",{parentName:"li"},"Golang should already be installed and configured."),(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"Default method: Run the following with ",(0,r.kt)("inlineCode",{parentName:"li"},"sudo")," if necessary. This will install both the protobuf compiler and the Go code generator plugins.",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},"apt-get install protobuf-compiler\ngo install google.golang.org/protobuf/cmd/protoc-gen-go\ngo install google.golang.org/grpc/cmd/protoc-gen-go-grpc\n"))),(0,r.kt)("li",{parentName:"ul"},"If the above method installs an older version of ",(0,r.kt)("inlineCode",{parentName:"li"},"protoc")," (check using ",(0,r.kt)("inlineCode",{parentName:"li"},"protoc --version"),"), say below 3.12.x, you should download pre-compiled binaries instead. (With an older version, you may see errors while attempting to launch and setup the Fabric networks).",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},'sudo apt-get remove protobuf-compiler\ncurl -LO https://github.com/protocolbuffers/protobuf/releases/download/v3.15.6/protoc-3.15.6-linux-x86_64.zip\nsudo apt-get install unzip\nunzip protoc-3.15.6-linux-x86_64.zip -d <some-folder-path>\nexport PATH="$PATH:<some-folder-path>/bin"\ngo install google.golang.org/protobuf/cmd/protoc-gen-go\ngo install google.golang.org/grpc/cmd/protoc-gen-go-grpc\n')),(0,r.kt)("table",{parentName:"li"},(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:"left"},"The latest version at present is ",(0,r.kt)("inlineCode",{parentName:"td"},"3.15.6"),", but you should check the above link to find the most current version before running the above steps.")))))))),(0,r.kt)("h3",{id:"credentials"},"Credentials"),(0,r.kt)("p",null,"Make sure you have an SSH or GPG key registered in ",(0,r.kt)("a",{parentName:"p",href:"https://github.com"},"https://github.com")," to allow seamless cloning of repositories (at present, various setup scripts clone repositories using the ",(0,r.kt)("inlineCode",{parentName:"p"},"https://")," prefix but this may change to ",(0,r.kt)("inlineCode",{parentName:"p"},"git@")," in the future)."),(0,r.kt)("h2",{id:"getting-the-code-and-documentation"},"Getting the Code and Documentation"),(0,r.kt)("p",null,"Clone the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability"},"weaver-dlt-interoperability")," repository. The code to get a basic test network up and running and test data-sharing interoperation flows lies in the subfolder ",(0,r.kt)("inlineCode",{parentName:"p"},"tests/network-setups"),", which should be your starting point, though the setups will rely on other parts of the repository, as you will find out in the instructions given on this page."),(0,r.kt)("h2",{id:"common-structures"},"Common Structures"),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"common/protos")," folder contains structure definitions in the protobuf format that are used by all the different components. The various ",(0,r.kt)("inlineCode",{parentName:"p"},"common/protos-*")," folders are meant to contain compiled protobufs (in different languages)."),(0,r.kt)("p",null,"To compile the protobufs for JavaScript, do the following:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"common/protos-js")," folder."),(0,r.kt)("li",{parentName:"ul"},"Run the following command:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make build\n")))),(0,r.kt)("p",null,"To compile the protobufs for Golang, do the following:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"common/protos-go")," folder."),(0,r.kt)("li",{parentName:"ul"},"Run the following command:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make build\n")))),(0,r.kt)("p",null,"To compile the protobufs for Java, do the following:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"common/protos-java-kt")," folder."),(0,r.kt)("li",{parentName:"ul"},"Run the following command:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make build\n")))),(0,r.kt)("p",null,"To compile the protobufs for Solidity, do the following:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"common/protos-sol")," folder."),(0,r.kt)("li",{parentName:"ul"},"Run the following command:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make build\n")))),(0,r.kt)("h2",{id:"securing-components"},"Securing Components"),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:"left"},"The relays and drivers corresponding to the different test networks you will encounter below can be run with or without TLS enabled. But the default files used in the demonstrations assume that either all relays and drivers are TLS-enabled or none are. Therefore, you should determine at the outset whether or not you wish to run the entire set of components in TLS-enabled mode, and select appropriate commands in the provided instructions.")))),(0,r.kt)("h2",{id:"hyperledger-fabric-components"},"Hyperledger Fabric Components"),(0,r.kt)("p",null,"Using the sequence of instructions below, you can start two separate Fabric networks, each with a single channel and application contract (chaincode). You can also start an interoperation contract, a relay, and a ",(0,r.kt)("em",{parentName:"p"},"driver")," acting on behalf of each network. You can build a Fabric CLI tool with which you can initialize both networks' ledgers with access control policies, foreign networks' security groups (i.e., membership providers' certificate chains), and some sample key-value pairs that can be shared during subsequent interoperation flows."),(0,r.kt)("h3",{id:"fabric-interoperation-node-sdk"},"Fabric Interoperation Node SDK"),(0,r.kt)("p",null,"A client-layer library (companion to ",(0,r.kt)("inlineCode",{parentName:"p"},"hyperledger/fabric-sdk-node"),") is defined in the ",(0,r.kt)("inlineCode",{parentName:"p"},"sdks/fabric/interoperation-node-sdk")," folder. This contains functions for Fabric Gateway-based applications to exercise interoperation capabilities via relays and also several utility/helper functions. The Fabric-CLI tool, which we will use later, depends on this library."),(0,r.kt)("p",null,"To build the library, do the following:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"sdks/fabric/interoperation-node-sdk")," folder."),(0,r.kt)("li",{parentName:"ul"},"Run the following command:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make build-local\n")))),(0,r.kt)("h3",{id:"fabric-network"},"Fabric Network"),(0,r.kt)("p",null,"The code for this lies in the ",(0,r.kt)("inlineCode",{parentName:"p"},"tests/network-setups")," folder."),(0,r.kt)("p",null,"This folder contains code to create and launch networks ",(0,r.kt)("inlineCode",{parentName:"p"},"network1")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"network2")," of identical specifications:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Network: 1 peer, 1 peer CA, 1 ordering service node, 1 ordering service CA"),(0,r.kt)("li",{parentName:"ul"},"Single channel named ",(0,r.kt)("inlineCode",{parentName:"li"},"mychannel")),(0,r.kt)("li",{parentName:"ul"},"One of the following contracts deployed on ",(0,r.kt)("inlineCode",{parentName:"li"},"mychannel"),", the choice depending on the ",(0,r.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/interoperability-modes"},"interoperability mode")," you wish to test:",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"simplestate")," (",(0,r.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/data-sharing"},"Data Sharing"),"): supports simple transactions (",(0,r.kt)("inlineCode",{parentName:"li"},"Create"),", ",(0,r.kt)("inlineCode",{parentName:"li"},"Read"),", ",(0,r.kt)("inlineCode",{parentName:"li"},"Update"),", ",(0,r.kt)("inlineCode",{parentName:"li"},"Delete"),") involving storage and lookup of <key, value> pairs."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"simplestatewithacl")," (",(0,r.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/data-sharing"},"Data Sharing"),"): identical to ",(0,r.kt)("inlineCode",{parentName:"li"},"simplestate")," but with extra security features to ensure that the Weaver infrastructure cannot be bypassed by a malicious client of the network."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"simpleasset")," (",(0,r.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview"},"Asset Exchange"),"): supports creation, modification, transfer, and deletion, as well as locking, unlocking, and claiming, of simple bonds and tokens (examples of non-fungible and fungible assets respectively)."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"simpleassetandinterop")," (",(0,r.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview"},"Asset Exchange"),"): identical to ",(0,r.kt)("inlineCode",{parentName:"li"},"simpleasset")," but where the locking, unlocking, and claiming logic is imported as a library in the chaincode rather than available in the common Fabric Interoperation Chaincode (a Weaver component)."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"simpleassettransfer")," (",(0,r.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview"},"Asset Exchange")," or ",(0,r.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-transfer"},"Asset Transfer"),"): augmentation of ",(0,r.kt)("inlineCode",{parentName:"li"},"simpleasset")," with asset pledging, claiming, and reclaiming features for cross-network transfers.")))),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:"left"},"For new users, we recommend testing the Data Sharing feature first with the ",(0,r.kt)("inlineCode",{parentName:"td"},"simplestate")," contract. To test the other modes, you can simply ",(0,r.kt)("a",{parentName:"td",href:"#tear-down-the-setup"},"tear down")," the Fabric networks and restart them with the appropriate chaincodes installed.")))),(0,r.kt)("p",null,"Follow the instructions below to build and launch the networks:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"tests/network-setups/fabric/dev")," folder."),(0,r.kt)("li",{parentName:"ul"},"To spin up both network1 and network2 with the interoperation chaincode and the default ",(0,r.kt)("inlineCode",{parentName:"li"},"simplestate")," chaincode installed, run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make start-interop-local\n"))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("em",{parentName:"li"},"To launch the networks with a different application chaincode from the above list, run"),":",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make start-interop-local CHAINCODE_NAME=<chaincode-name>\n"))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("em",{parentName:"li"},"To launch the networks with 2 organizations, each with a peer (this will enable more variation and experimentation, which you can attempt after testing interoperation protocols across basic network configurations), run"),":",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'make start-interop-local PROFILE="2-nodes"\n')))),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:"left"},"If you do not wish to test Fabric-Fabric interoperation, you can choose to launch only one of the two networks along with its interoperation chaincode. For ",(0,r.kt)("inlineCode",{parentName:"td"},"network1"),", run ",(0,r.kt)("inlineCode",{parentName:"td"},"make start-interop-network1-local"),", and for ",(0,r.kt)("inlineCode",{parentName:"td"},"network2"),", run ",(0,r.kt)("inlineCode",{parentName:"td"},"make start-interop-network2-local"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:"left"},"If you wish to enable end-to-end confidentiality by default in the interoperation modules that are deployed during network launch, set the environment variable ",(0,r.kt)("inlineCode",{parentName:"td"},"E2E_CONFIDENTIALITY")," to ",(0,r.kt)("inlineCode",{parentName:"td"},"true")," in the command line as follows: ",(0,r.kt)("inlineCode",{parentName:"td"},"E2E_CONFIDENTIALITY=true make start-interop-local"))))),(0,r.kt)("p",null,"For more information, refer to the associated ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/tests/network-setups/fabric/dev"},"README"),"."),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Troubleshooting Tips"),":"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"If you see any errors during the launches, re-check the prerequisites (software installations and credentials). Ensure your network connection is working. As a safe bet, you can retry after cleanup: kill and remove all Docker containers and associated volumes."),(0,r.kt)("li",{parentName:"ul"},"If ",(0,r.kt)("inlineCode",{parentName:"li"},"protoc")," or ",(0,r.kt)("inlineCode",{parentName:"li"},"protoc-gen-go")," throws an error, reinstall ",(0,r.kt)("inlineCode",{parentName:"li"},"protoc")," and ",(0,r.kt)("inlineCode",{parentName:"li"},"protoc-gen-go")," using suggestions made in the Prerequisites section above.")),(0,r.kt)("h3",{id:"fabric-client-fabric-cli"},"Fabric Client (fabric-cli)"),(0,r.kt)("p",null,"The CLI is used to interact with a Fabric network, configure it and run chaincode transactions to record data on the channel ledger or query data. It is also used to interact with remote networks through the relay to trigger an interoperation flow for data request and acceptance."),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"fabric-cli")," Node.js source code is located in the ",(0,r.kt)("inlineCode",{parentName:"p"},"samples/fabric/fabric-cli")," folder and the Golang source code in the ",(0,r.kt)("inlineCode",{parentName:"p"},"samples/fabric/go-cli")," folder."),(0,r.kt)("h4",{id:"prerequisites-1"},"Prerequisites"),(0,r.kt)("p",null,"If you are using a Linux system, make sure that lib64 is installed."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:"left"},"For the Node.js version of the ",(0,r.kt)("inlineCode",{parentName:"td"},"fabric-cli"),", the setup and running instructions below were tested with all Node.js versions from v11.14.0 to v14.17.3.")))),(0,r.kt)("h4",{id:"installation"},"Installation"),(0,r.kt)("p",null,"You can install ",(0,r.kt)("inlineCode",{parentName:"p"},"fabric-cli")," as follows (for both the Node.js and Golang versions):"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"samples/fabric/fabric-cli")," folder or the ",(0,r.kt)("inlineCode",{parentName:"li"},"samples/fabric/go-cli")," folder."),(0,r.kt)("li",{parentName:"ul"},"Run the following to install dependencies (for the Node.js version) or the executable (for the Golang version):",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make build-local\n"))),(0,r.kt)("li",{parentName:"ul"},"Use the ",(0,r.kt)("inlineCode",{parentName:"li"},"fabric-cli")," executable in the ",(0,r.kt)("inlineCode",{parentName:"li"},"bin")," folder for ",(0,r.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/ledger-initialization"},"subsequent actions"),".")),(0,r.kt)("h3",{id:"fabric-relay"},"Fabric Relay"),(0,r.kt)("p",null,"The relay is a module acting on behalf of a network, enabling interoperation flows with other networks by communicating with their relays.\nThe code for this lies in the ",(0,r.kt)("inlineCode",{parentName:"p"},"core/relay")," folder."),(0,r.kt)("h4",{id:"building"},"Building"),(0,r.kt)("p",null,(0,r.kt)("em",{parentName:"p"},"Prerequisite"),": make sure Rust is already installed and that the ",(0,r.kt)("inlineCode",{parentName:"p"},"cargo")," executable is in your system path (after installation of Rust, this should be available in ",(0,r.kt)("inlineCode",{parentName:"p"},"$HOME/.cargo/bin"),"); you can also ensure this by running ",(0,r.kt)("inlineCode",{parentName:"p"},'source "$HOME/.cargo/env"'),"."),(0,r.kt)("p",null,"Build the generic (i.e., common to all DLTs) relay module as follows:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"core/relay")," folder."),(0,r.kt)("li",{parentName:"ul"},"Run the following:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make\n"))),(0,r.kt)("li",{parentName:"ul"},"To avoid errors during Weaver Relay compilation, update certain packages (on which the Weaver Relay is dependent) to their latest versions as follows:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make update-pkgs\n")))),(0,r.kt)("h4",{id:"deployment"},"Deployment"),(0,r.kt)("p",null,"An instance or a relay can be run using a suitable configuration file. Samples are available in the ",(0,r.kt)("inlineCode",{parentName:"p"},"core/relay/config")," folder."),(0,r.kt)("p",null,"Run a relay for ",(0,r.kt)("inlineCode",{parentName:"p"},"network1")," as follows:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"core/relay")," folder."),(0,r.kt)("li",{parentName:"ul"},"To launch the server without TLS, leave the configuration file ",(0,r.kt)("inlineCode",{parentName:"li"},"config/Fabric_Relay.toml")," in its default state. Otherwise, edit it to set TLS flags for this relay and the other relays and drivers it will connect to in this demonstration as follows:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-toml"},'.\n.\ncert_path="credentials/fabric_cert.pem"\nkey_path="credentials/fabric_key"\ntls=true\n.\n.\n[relays]\n[relays.Corda_Relay]\nhostname="localhost"\nport="9081"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n[relays.Corda_Relay2]\nhostname="localhost"\nport="9082"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n[relays.Fabric_Relay2]\nhostname="localhost"\nport="9083"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n.\n.\n[drivers]\n[drivers.Fabric]\nhostname="localhost"\nport="9090"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n.\n.\n'))),(0,r.kt)("li",{parentName:"ul"},"To launch the server, simply run the following:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"RELAY_CONFIG=config/Fabric_Relay.toml cargo run --bin server\n")))),(0,r.kt)("p",null,"Run a relay for ",(0,r.kt)("inlineCode",{parentName:"p"},"network2")," as follows (",(0,r.kt)("em",{parentName:"p"},"do this only if you have launched both Fabric networks ",(0,r.kt)("inlineCode",{parentName:"em"},"network1")," and ",(0,r.kt)("inlineCode",{parentName:"em"},"network2")," and wish to test interoperation between them"),")"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"core/relay")," folder."),(0,r.kt)("li",{parentName:"ul"},"To launch the server without TLS, leave the configuration file ",(0,r.kt)("inlineCode",{parentName:"li"},"config/Fabric_Relay2.toml")," in its default state. Otherwise, edit it to set TLS flags for this relay and the other relays and drivers it will connect to in this demonstration as follows:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-toml"},'.\n.\ncert_path="credentials/fabric_cert.pem"\nkey_path="credentials/fabric_key"\ntls=true\n.\n.\n[relays]\n[relays.Corda_Relay]\nhostname="localhost"\nport="9081"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n[relays.Corda_Relay2]\nhostname="localhost"\nport="9082"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n[relays.Fabric_Relay]\nhostname="localhost"\nport="9080"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n.\n.\n[drivers]\n[drivers.Fabric]\nhostname="localhost"\nport="9095"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n.\n.\n'))),(0,r.kt)("li",{parentName:"ul"},"To launch the server, simply run the following:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"RELAY_CONFIG=config/Fabric_Relay2.toml cargo run --bin server\n")))),(0,r.kt)("p",null,"For more information, see the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/core/relay"},"relay README"),"."),(0,r.kt)("h3",{id:"fabric-driver"},"Fabric Driver"),(0,r.kt)("p",null,"A driver is a DLT-specific plugin invoked by the relay while conveying external data queries to the local peer network and collecting a response with proofs. The Fabric driver is built as a Fabric client application on the ",(0,r.kt)("inlineCode",{parentName:"p"},"fabric-network")," NPM package.\nThe code for this lies in the ",(0,r.kt)("inlineCode",{parentName:"p"},"core/drivers/fabric-driver")," folder."),(0,r.kt)("h4",{id:"configuring"},"Configuring"),(0,r.kt)("p",null,"In the ",(0,r.kt)("inlineCode",{parentName:"p"},"core/drivers/fabric-driver")," folder, copy ",(0,r.kt)("inlineCode",{parentName:"p"},".env.template")," to ",(0,r.kt)("inlineCode",{parentName:"p"},".env")," and update ",(0,r.kt)("inlineCode",{parentName:"p"},"CONNECTION_PROFILE")," to point to the connection profile of the Fabric network (e.g. ",(0,r.kt)("inlineCode",{parentName:"p"},"<PATH-TO-WEAVER>/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json"),")"),(0,r.kt)("p",null,"Configure ",(0,r.kt)("inlineCode",{parentName:"p"},"fabric-driver")," for ",(0,r.kt)("inlineCode",{parentName:"p"},"network1")," as follows:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"core/drivers/fabric-driver")," folder."),(0,r.kt)("li",{parentName:"ul"},"Create a ",(0,r.kt)("inlineCode",{parentName:"li"},".env")," file by copying ",(0,r.kt)("inlineCode",{parentName:"li"},".env.template")," and setting suitable parameter values:",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"The ",(0,r.kt)("inlineCode",{parentName:"li"},"CONNECTION_PROFILE")," should point to the absolute path of the connection profile for ",(0,r.kt)("inlineCode",{parentName:"li"},"network1"),".",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"For this exercise, specify the path ",(0,r.kt)("inlineCode",{parentName:"li"},"<PATH-TO-WEAVER>/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json")," (",(0,r.kt)("em",{parentName:"li"},"you must specify the full absolute path here"),")."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"<PATH-TO-WEAVER>")," here is the absolute path of the ",(0,r.kt)("inlineCode",{parentName:"li"},"weaver-dlt-interoperability")," clone folder."))),(0,r.kt)("li",{parentName:"ul"},"If you wish to start the driver without TLS, set the following parameter values:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},"RELAY_TLS=false\nRELAY_TLSCA_CERT_PATH=\nDRIVER_TLS=false\nDRIVER_TLS_CERT_PATH=\nDRIVER_TLS_KEY_PATH=\n")),"Otherwise, if you wish to start the driver with TLS enabled, set the following parameter values (replace ",(0,r.kt)("inlineCode",{parentName:"li"},"<PATH-TO-WEAVER>")," with the absolute path of the ",(0,r.kt)("inlineCode",{parentName:"li"},"weaver-dlt-interoperability")," clone folder):",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},"RELAY_TLS=true\nRELAY_TLSCA_CERT_PATH=<PATH-TO-WEAVER>/core/relay/credentials/fabric_ca_cert.pem\nDRIVER_TLS=true\nDRIVER_TLS_CERT_PATH=<PATH-TO-WEAVER>/core/relay/credentials/fabric_cert.pem\nDRIVER_TLS_KEY_PATH=<PATH-TO-WEAVER>/core/relay/credentials/fabric_key\n"))),(0,r.kt)("li",{parentName:"ul"},"Leave the default values unchanged for the other parameters. The relay and driver endpoints as well as the network name are already specified in the template.")))),(0,r.kt)("h4",{id:"building-1"},"Building"),(0,r.kt)("p",null,"Build the Fabric driver module as follows:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"core/drivers/fabric-driver")," folder."),(0,r.kt)("li",{parentName:"ul"},"Run the following:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make build-local\n")))),(0,r.kt)("h4",{id:"running"},"Running"),(0,r.kt)("p",null,"Run a Fabric driver for ",(0,r.kt)("inlineCode",{parentName:"p"},"network1")," as follows:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"core/drivers/fabric-driver")," folder."),(0,r.kt)("li",{parentName:"ul"},"Run the following:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"npm run dev\n")))),(0,r.kt)("p",null,"Run a Fabric driver for ",(0,r.kt)("inlineCode",{parentName:"p"},"network2")," as follows (",(0,r.kt)("em",{parentName:"p"},"do this only if you wish to test interoperation between the two Fabric networks ",(0,r.kt)("inlineCode",{parentName:"em"},"network1")," and ",(0,r.kt)("inlineCode",{parentName:"em"},"network2")),")"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"core/drivers/fabric-driver")," folder."),(0,r.kt)("li",{parentName:"ul"},"Run the following:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"CONNECTION_PROFILE=<PATH-TO-WEAVER>/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/connection-org1.json NETWORK_NAME=network2 RELAY_ENDPOINT=localhost:9083 DRIVER_ENDPOINT=localhost:9095 npm run dev\n")))),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:"left"},"The variables we specified earlier in the ",(0,r.kt)("inlineCode",{parentName:"td"},".env")," for ",(0,r.kt)("inlineCode",{parentName:"td"},"network1")," are now passed in the command line. Alternatively, you can make a copy of the ",(0,r.kt)("inlineCode",{parentName:"td"},"fabric-driver")," folder with a different name and create a separate ",(0,r.kt)("inlineCode",{parentName:"td"},".env")," file within it that contains links to the connection profile, relay, and driver for ",(0,r.kt)("inlineCode",{parentName:"td"},"network2"),".")))),(0,r.kt)("h3",{id:"fabric-iin-agent"},"Fabric IIN Agent"),(0,r.kt)("p",null,"IIN Agent is a client of a member of a DLT network or security domain with special permissions to update security domain identities and configurations on the ledger via the network's interoperation module. The code for this lies in the ",(0,r.kt)("inlineCode",{parentName:"p"},"core/identity-management/iin-agent")," folder. Navigate to the ",(0,r.kt)("inlineCode",{parentName:"p"},"core/identity-management/iin-agent")," folder."),(0,r.kt)("h4",{id:"building-2"},"Building"),(0,r.kt)("p",null,"To build the IIN Agent, run:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make build-local\n")),(0,r.kt)("h4",{id:"configuration"},"Configuration"),(0,r.kt)("p",null,"Ledger config file specifies ledger specific IIN Agent details such as identity and which network and organization to connect to."),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"To create config file for ",(0,r.kt)("inlineCode",{parentName:"p"},"Org1MSP"),"'s Fabric IIN Agent of ",(0,r.kt)("inlineCode",{parentName:"p"},"network1"),", follow the steps:"),(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"Create copy of template config file for Fabric IIN Agent: ",(0,r.kt)("inlineCode",{parentName:"li"},"src/fabric-ledger/config.json.template"),", say to location ",(0,r.kt)("inlineCode",{parentName:"li"},"src/fabric-ledger/config-n1-org1.json"),"."),(0,r.kt)("li",{parentName:"ul"},"Replace ",(0,r.kt)("inlineCode",{parentName:"li"},"<path-to-connection-profile>")," with ",(0,r.kt)("inlineCode",{parentName:"li"},"<PATH-TO-WEAVER>/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json"),", where replace ",(0,r.kt)("inlineCode",{parentName:"li"},"<PATH-TO-WEAVER>")," with the location of your clone of Weaver."),(0,r.kt)("li",{parentName:"ul"},"Set ",(0,r.kt)("inlineCode",{parentName:"li"},"mspId")," as ",(0,r.kt)("inlineCode",{parentName:"li"},"Org1MSP"),"."),(0,r.kt)("li",{parentName:"ul"},"Set ",(0,r.kt)("inlineCode",{parentName:"li"},"agent.affiliation")," as ",(0,r.kt)("inlineCode",{parentName:"li"},"org1.department1"),"."))),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"To create config file for ",(0,r.kt)("inlineCode",{parentName:"p"},"Org2MSP"),"'s Fabric IIN Agent of ",(0,r.kt)("inlineCode",{parentName:"p"},"network1"),", repeat ",(0,r.kt)("inlineCode",{parentName:"p"},"Step 1")," with different name for config file, say ",(0,r.kt)("inlineCode",{parentName:"p"},"src/fabric-ledger/config-n1-org2.json"),", and replace ",(0,r.kt)("inlineCode",{parentName:"p"},"org1")," with ",(0,r.kt)("inlineCode",{parentName:"p"},"org2")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"Org1MSP")," with ",(0,r.kt)("inlineCode",{parentName:"p"},"Org2MSP"),".")),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"To create config file for ",(0,r.kt)("inlineCode",{parentName:"p"},"Org1MSP"),"'s Fabric IIN Agent of ",(0,r.kt)("inlineCode",{parentName:"p"},"network2"),", repeat ",(0,r.kt)("inlineCode",{parentName:"p"},"Step 1")," with different name for config file, say ",(0,r.kt)("inlineCode",{parentName:"p"},"src/fabric-ledger/config-n2-org1.json"),", and replace ",(0,r.kt)("inlineCode",{parentName:"p"},"network1")," with ",(0,r.kt)("inlineCode",{parentName:"p"},"network2"),".")),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"To create config file for ",(0,r.kt)("inlineCode",{parentName:"p"},"Org2MSP"),"'s Fabric IIN Agent of ",(0,r.kt)("inlineCode",{parentName:"p"},"network2"),", repeat ",(0,r.kt)("inlineCode",{parentName:"p"},"Step 1")," with different name for config file, say ",(0,r.kt)("inlineCode",{parentName:"p"},"src/fabric-ledger/config-n2-org2.json"),", and replace ",(0,r.kt)("inlineCode",{parentName:"p"},"network1")," with ",(0,r.kt)("inlineCode",{parentName:"p"},"network2"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"org1")," with ",(0,r.kt)("inlineCode",{parentName:"p"},"org2")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"Org1MSP")," with ",(0,r.kt)("inlineCode",{parentName:"p"},"Org2MSP"),"."))),(0,r.kt)("h4",{id:"security-domain-configuration"},"Security Domain Configuration"),(0,r.kt)("p",null,"Security Domain config file specifies the scope of security domain, which can be a channel in Fabric networks or list of nodes. File ",(0,r.kt)("inlineCode",{parentName:"p"},"docker-testnet/configs/security-domain-config.json")," can be used for Weaver testnets."),(0,r.kt)("h4",{id:"dns-configuration"},"DNS Configuration"),(0,r.kt)("p",null,"To allow an IIN Agent's to be able to discover other IIN Agents, a config file for DNS is required. Create one ",(0,r.kt)("inlineCode",{parentName:"p"},"dnsconfig.json")," by creating a copy of template ",(0,r.kt)("inlineCode",{parentName:"p"},"dnsconfig.json.template"),", and replace the values with:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"If Fabric networks are started with 1 org, and IIN Agent are to be started without TLS, use following values:")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json"},'{\n "network1": {\n "Org1MSP": {\n "endpoint": "localhost:9500",\n "tls": false,\n "tlsCACertPath": ""\n }\n },\n "network2": {\n "Org1MSP": {\n "endpoint": "localhost:9501",\n "tls": false,\n "tlsCACertPath": ""\n }\n }\n}\n')),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"If Fabric networks are started with 1 org, and IIN Agent are to be started with TLS, use following values:")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json"},'{\n "network1": {\n "Org1MSP": {\n "endpoint": "localhost:9500",\n "tls": true,\n "tlsCACertPath": "../../relay/credentials/fabric_ca_cert.pem"\n }\n },\n "network2": {\n "Org1MSP": {\n "endpoint": "localhost:9501",\n "tls": true,\n "tlsCACertPath": "../../relay/credentials/fabric_ca_cert.pem"\n }\n }\n}\n')),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"If Fabric networks are started with 2 orgs, and IIN Agent are to be started without TLS, use following values:")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json"},'{\n "network1": {\n "Org1MSP": {\n "endpoint": "localhost:9500",\n "tls": false,\n "tlsCACertPath": ""\n },\n "Org2MSP": {\n "endpoint": "localhost:9510",\n "tls": false,\n "tlsCACertPath": ""\n }\n },\n "network2": {\n "Org1MSP": {\n "endpoint": "localhost:9501",\n "tls": false,\n "tlsCACertPath": ""\n },\n "Org2MSP": {\n "endpoint": "localhost:9511",\n "tls": false,\n "tlsCACertPath": ""\n }\n }\n}\n')),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"If Fabric networks are started with 2 orgs, and IIN Agent are to be started with TLS, use following values:")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json"},'{\n "network1": {\n "Org1MSP": {\n "endpoint": "localhost:9500",\n "tls": true,\n "tlsCACertPath": "../../relay/credentials/fabric_ca_cert.pem"\n },\n "Org2MSP": {\n "endpoint": "localhost:9510",\n "tls": true,\n "tlsCACertPath": "../../relay/credentials/fabric_ca_cert.pem"\n }\n },\n "network2": {\n "Org1MSP": {\n "endpoint": "localhost:9501",\n "tls": true,\n "tlsCACertPath": "../../relay/credentials/fabric_ca_cert.pem"\n },\n "Org2MSP": {\n "endpoint": "localhost:9511",\n "tls": true,\n "tlsCACertPath": "../../relay/credentials/fabric_ca_cert.pem"\n }\n }\n}\n')),(0,r.kt)("h4",{id:"environment-variables"},"Environment Variables"),(0,r.kt)("p",null,"To configure environment variables for ",(0,r.kt)("inlineCode",{parentName:"p"},"Org1MSP"),"'s Fabric IIN Agent of ",(0,r.kt)("inlineCode",{parentName:"p"},"network1"),", follow the steps:"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},"Create a copy of ",(0,r.kt)("inlineCode",{parentName:"li"},".env.template")," as ",(0,r.kt)("inlineCode",{parentName:"li"},".env"),", and update following values based on previous configuration file paths:")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"IIN_AGENT_ENDPOINT=localhost:9500\nMEMBER_ID=Org1MSP\nSECURITY_DOMAIN=network1\nDLT_TYPE=fabric\nCONFIG_PATH=./src/fabric-ledger/config-n1-org1.json\nDNS_CONFIG_PATH=./dnsconfig.json\nSECURITY_DOMAIN_CONFIG_PATH=./docker-testnet/configs/security-domain-config.json\nWEAVER_CONTRACT_ID=interop\nAUTO_SYNC=true\n")),(0,r.kt)("ol",{start:2},(0,r.kt)("li",{parentName:"ol"},"If IIN Agent has to be started with TLS enabled, also update following values:")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"IIN_AGENT_TLS=false\nIIN_AGENT_TLS_CERT_PATH=../../relay/credentials/fabric_cert.pem\nIIN_AGENT_TLS_KEY_PATH=../../relay/credentials/fabric_key\n")),(0,r.kt)("h4",{id:"deployment-1"},"Deployment"),(0,r.kt)("p",null,"Use the following steps to run Fabric IIN Agents in host machine:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"To start IIN Agent for ",(0,r.kt)("inlineCode",{parentName:"li"},"Org1MSP")," of ",(0,r.kt)("inlineCode",{parentName:"li"},"network1"),", run:")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"npm run dev\n")),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"To start IIN Agent for ",(0,r.kt)("inlineCode",{parentName:"li"},"Org2MSP")," of ",(0,r.kt)("inlineCode",{parentName:"li"},"network1")," (",(0,r.kt)("em",{parentName:"li"},"only required if Fabric network was started with 2 orgs"),"), run:")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"IIN_AGENT_ENDPOINT=localhost:9510 MEMBER_ID=Org2MSP CONFIG_PATH=./src/fabric-ledger/config-n1-org2.json npm run dev\n")),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"To start IIN Agent for ",(0,r.kt)("inlineCode",{parentName:"li"},"Org1MSP")," of ",(0,r.kt)("inlineCode",{parentName:"li"},"network2"),", run:")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"IIN_AGENT_ENDPOINT=localhost:9501 SECURITY_DOMAIN=network2 CONFIG_PATH=./src/fabric-ledger/config-n2-org1.json npm run dev\n")),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"To start IIN Agent for ",(0,r.kt)("inlineCode",{parentName:"li"},"Org2MSP")," of ",(0,r.kt)("inlineCode",{parentName:"li"},"network2")," (",(0,r.kt)("em",{parentName:"li"},"only required if Fabric network was started with 2 orgs"),"), run:")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"IIN_AGENT_ENDPOINT=localhost:9511 MEMBER_ID=Org2MSP SECURITY_DOMAIN=network2 CONFIG_PATH=./src/fabric-ledger/config-n2-org2.json npm run dev\n")),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:"left"},"The variables we specified earlier in the ",(0,r.kt)("inlineCode",{parentName:"td"},".env")," for ",(0,r.kt)("inlineCode",{parentName:"td"},"network1")," are now passed in the command line. Alternatively, you can make a copy of the ",(0,r.kt)("inlineCode",{parentName:"td"},"fabric-driver")," folder with a different name and create a separate ",(0,r.kt)("inlineCode",{parentName:"td"},".env")," file within it that contains links to the connection profile, relay, and driver for ",(0,r.kt)("inlineCode",{parentName:"td"},"network2"),".")))),(0,r.kt)("h2",{id:"corda-components"},"Corda Components"),(0,r.kt)("p",null,"Using the sequence of instructions below, you can start a Corda network and run an application CorDapp on it. You can also run an interoperation CorDapp, a relay and a ",(0,r.kt)("em",{parentName:"p"},"driver")," acting on behalf of the network. You can initialize the network's vault with access control policies, foreign networks' security groups (i.e., membership providers' certificate chains), and some sample state values that can be shared during subsequent interoperation flows."),(0,r.kt)("h3",{id:"interoperation-cordapp"},"Interoperation CorDapp"),(0,r.kt)("p",null,"The interoperation CorDapp is deployed to run as part of any Corda application flow that involves cross-network interoperation."),(0,r.kt)("p",null,"Build the interoperation CorDapp as follows:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"core/network/corda-interop-app")," folder."),(0,r.kt)("li",{parentName:"ul"},"Run the following to create the JAR files on which other Corda network components will depend on:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make build-local\n")))),(0,r.kt)("h3",{id:"corda-interoperation-sdk"},"Corda Interoperation SDK"),(0,r.kt)("p",null,"A client-layer library is defined in the ",(0,r.kt)("inlineCode",{parentName:"p"},"sdks/corda")," folder. This contains functions for Corda based client applications to exercise interoperation capabilities via relays and also several utility/helper functions. The Corda Client tool, which we will use later, depends on this library."),(0,r.kt)("p",null,"To build the library, do the following:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"sdks/corda")," folder."),(0,r.kt)("li",{parentName:"ul"},"Run the following command (",(0,r.kt)("em",{parentName:"li"},"make sure there is no github.properties file present in the directory"),"):",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make build\n")))),(0,r.kt)("h3",{id:"corda-simple-application-and-client-application"},"Corda Simple Application and Client (Application)"),(0,r.kt)("p",null,"This is a simple CorDapp that maintains a state of type ",(0,r.kt)("inlineCode",{parentName:"p"},"SimpleState"),", which is a set of key-value pairs (of strings).\nThe code for this lies in the ",(0,r.kt)("inlineCode",{parentName:"p"},"samples/corda/corda-simple-application")," folder."),(0,r.kt)("p",null,"Build the ",(0,r.kt)("inlineCode",{parentName:"p"},"corda-simple-application")," CorDapp as follows:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"samples/corda/corda-simple-application")," folder."),(0,r.kt)("li",{parentName:"ul"},"Run the following:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make build-local\n")))),(0,r.kt)("h3",{id:"corda-network"},"Corda Network"),(0,r.kt)("p",null,"The Corda networks' code lies in the ",(0,r.kt)("inlineCode",{parentName:"p"},"tests/network-setups/corda")," folder. You can launch two separate Corda networks, namely ",(0,r.kt)("inlineCode",{parentName:"p"},"Corda_Network")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"Corda_Network2"),". Each network runs the ",(0,r.kt)("inlineCode",{parentName:"p"},"samples/corda/corda-simple-application")," CorDapp by default, which maintains a state named ",(0,r.kt)("inlineCode",{parentName:"p"},"SimpleState")," containing a set of key-value pairs (of strings)."),(0,r.kt)("p",null,"Follow the instructions below to build and launch both networks:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"tests/network-setups/corda")," folder."),(0,r.kt)("li",{parentName:"ul"},"To spin up the Corda networks with the Interoperation CorDapps:",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"Each consisting of 1 node and a notary (for data-transfer), run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make start-local\n"))),(0,r.kt)("li",{parentName:"ul"},"Each consisting of 2 nodes and a notary (for asset-exchange/transfer), run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'make start-local PROFILE="2-nodes"\n'))),(0,r.kt)("li",{parentName:"ul"},"Each consisting of 3 nodes and a notary (for asset-exchange/transfer), run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'make start-local PROFILE="3-nodes"\n')))))),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:"left"},"If you do not wish to test Corda-Corda interoperation, you can choose to launch only one of the two networks along with its interoperation CorDapp. For ",(0,r.kt)("inlineCode",{parentName:"td"},"Corda_Network"),", run ",(0,r.kt)("inlineCode",{parentName:"td"},"make start-network1-local"),", and for ",(0,r.kt)("inlineCode",{parentName:"td"},"Corda_Network2"),", run ",(0,r.kt)("inlineCode",{parentName:"td"},"make start-network2-local"),".")))),(0,r.kt)("p",null,"You should see the following message in the terminal:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"Waiting for network node services to start\n")),(0,r.kt)("p",null,"The Corda nodes and notary may take a while (several minutes on memory-constrained systems) to start. If they start up successfully, you should something like the following for each network, though the number of node entries will depend on the profile you used to start the network with (replace ",(0,r.kt)("inlineCode",{parentName:"p"},"<network-name>")," with ",(0,r.kt)("inlineCode",{parentName:"p"},"Corda_Network")," or ",(0,r.kt)("inlineCode",{parentName:"p"},"Corda_Network2"),"):"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"PartyA node services started for network <network-name>\nPartyB node services started for network <network-name>\nPartyC node services started for network <network-name>\nNotary node services started for network <network-name>\n")),(0,r.kt)("h3",{id:"corda-relay"},"Corda Relay"),(0,r.kt)("p",null,"The relay was built earlier, so you just need to use a different configuration file to start a relay for the Corda network."),(0,r.kt)("p",null,"Run a relay for ",(0,r.kt)("inlineCode",{parentName:"p"},"Corda_Network")," as follows:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"p"},"core/relay")," folder.")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"(Make sure you've already built the relay by running ",(0,r.kt)("inlineCode",{parentName:"p"},"make"),".)")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"To launch the server without TLS, leave the configuration file ",(0,r.kt)("inlineCode",{parentName:"p"},"config/Corda_Relay.toml")," in its default state. Otherwise, edit it to set TLS flags for this relay and the other relays and drivers it will connect to in this demonstration as follows:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-toml"},'.\n.\ncert_path="credentials/fabric_cert.pem"\nkey_path="credentials/fabric_key"\ntls=true\n.\n.\n[relays]\n[relays.Fabric_Relay]\nhostname="localhost"\nport="9080"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n[relays.Fabric_Relay2]\nhostname="localhost"\nport="9083"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n[relays.Corda_Relay2]\nhostname="localhost"\nport="9082"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n.\n.\n[drivers]\n[drivers.Corda]\nhostname="localhost"\nport="9099"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n.\n.\n'))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"To launch the server, simply run the following:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"RELAY_CONFIG=config/Corda_Relay.toml cargo run --bin server\n")),(0,r.kt)("p",{parentName:"li"},"If the relay starts up successfully, the following will be logged on your terminal:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},'Relay Name: "Corda_Relay"\nRelayServer listening on [::1]:9081\n')))),(0,r.kt)("p",null,"Run a relay for ",(0,r.kt)("inlineCode",{parentName:"p"},"Corda_Network2")," as follows (",(0,r.kt)("em",{parentName:"p"},"do this only if you have launched both Corda networks ",(0,r.kt)("inlineCode",{parentName:"em"},"Corda_Network")," and ",(0,r.kt)("inlineCode",{parentName:"em"},"Corda_Network2")," and wish to test interoperation between them"),")"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"p"},"core/relay")," folder.")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"To launch the server without TLS, leave the configuration file ",(0,r.kt)("inlineCode",{parentName:"p"},"config/Corda_Relay2.toml")," in its default state. Otherwise, edit it to set TLS flags for this relay and the other relays and drivers it will connect to in this demonstration as follows:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-toml"},'.\n.\ncert_path="credentials/fabric_cert.pem"\nkey_path="credentials/fabric_key"\ntls=true\n.\n.\n[relays]\n[relays.Fabric_Relay]\nhostname="localhost"\nport="9080"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n[relays.Fabric_Relay2]\nhostname="localhost"\nport="9083"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n[relays.Corda_Relay]\nhostname="localhost"\nport="9081"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n.\n.\n[drivers]\n[drivers.Corda]\nhostname="localhost"\nport="9098"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n.\n.\n'))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"To launch the server, simply run the following:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"RELAY_CONFIG=config/Corda_Relay2.toml cargo run --bin server\n")),(0,r.kt)("p",{parentName:"li"},"If the relay starts up successfully, the following will be logged on your terminal:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},'Relay Name: "Corda2_Relay"\nRelayServer listening on [::1]:9082\n')))),(0,r.kt)("h3",{id:"corda-driver"},"Corda Driver"),(0,r.kt)("p",null,"The code for this lies in the ",(0,r.kt)("inlineCode",{parentName:"p"},"core/drivers/corda-driver")," folder."),(0,r.kt)("h4",{id:"building-corda-driver"},"Building Corda Driver"),(0,r.kt)("p",null,"Build the Corda driver module as follows:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"core/drivers/corda-driver")," folder."),(0,r.kt)("li",{parentName:"ul"},"Run the following:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make build-local\n")))),(0,r.kt)("h4",{id:"configuring-1"},"Configuring"),(0,r.kt)("p",null,"Configure the drivers as follows (you can skip this if you wish to run the drivers without TLS):"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"core/drivers/corda-driver")," folder and create a ",(0,r.kt)("inlineCode",{parentName:"li"},".env")," file."),(0,r.kt)("li",{parentName:"ul"},"To run the drivers without TLS, set the following default values:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},"RELAY_TLS=false\nRELAY_TLSCA_TRUST_STORE=\nRELAY_TLSCA_TRUST_STORE_PASSWORD=\nRELAY_TLSCA_CERT_PATHS=\n"))),(0,r.kt)("li",{parentName:"ul"},"To run the drivers with TLS, set the following values (replace ",(0,r.kt)("inlineCode",{parentName:"li"},"<PATH-TO-WEAVER>")," with the absolute path of the ",(0,r.kt)("inlineCode",{parentName:"li"},"weaver-dlt-interoperability")," clone folder):",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},"RELAY_TLS=true\nRELAY_TLSCA_TRUST_STORE=<PATH-TO-WEAVER>/core/relay/credentials/fabric_trust_store.jks\nRELAY_TLSCA_TRUST_STORE_PASSWORD=trelay\nRELAY_TLSCA_CERT_PATHS=<PATH-TO-WEAVER>/core/relay/credentials/fabric_ca_cert.pem\n")))),(0,r.kt)("h4",{id:"running-1"},"Running"),(0,r.kt)("p",null,"Run a Corda driver as follows:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"core/drivers/corda-driver")," folder."),(0,r.kt)("li",{parentName:"ul"},"Run the following to start Corda driver for ",(0,r.kt)("inlineCode",{parentName:"li"},"Corda_Network"),":",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"./build/install/corda-driver/bin/corda-driver\n")),"If the driver starts successfully, it should log the following message on your terminal:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},"Corda driver gRPC server started. Listening on port 9099\n"))),(0,r.kt)("li",{parentName:"ul"},"Run the following to start Corda driver for ",(0,r.kt)("inlineCode",{parentName:"li"},"Corda_Network2"),":",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"DRIVER_PORT=9098 ./build/install/corda-driver/bin/corda-driver\n")),"If the driver starts successfully, it should log the following message on your terminal:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},"Corda driver gRPC server started. Listening on port 9098\n")))),(0,r.kt)("h2",{id:"hyperledger-besu-components"},"Hyperledger Besu Components"),(0,r.kt)("p",null,"Using the sequence of instructions below, you can start two separate Besu networks, each with 4 validator nodes, and EthSigner and application contract. You can also install an interoperation contract in the network. You can build a Besu CLI tool with which you can initialize both networks' ledgers."),(0,r.kt)("h3",{id:"prerequisites-2"},"Prerequisites"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Java (JDK and JRE): ",(0,r.kt)("a",{parentName:"li",href:"https://openjdk.java.net/install/"},"sample instructions")," (Version 11)\nYou need to run Besu instructions in a separate environment (separate terminal or machine) than Corda, as Corda requires Java 8. You can also use ",(0,r.kt)("inlineCode",{parentName:"li"},"update-alternatives")," to switch between java versions."),(0,r.kt)("li",{parentName:"ul"},"tmux: ",(0,r.kt)("inlineCode",{parentName:"li"},"sudo apt install tmux")),(0,r.kt)("li",{parentName:"ul"},"Besu: ",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"Download and unpack the latest ",(0,r.kt)("a",{parentName:"li",href:"https://github.com/hyperledger/besu/releases/latest"},"https://github.com/hyperledger/besu/releases/latest"),". You will find it in the link of the form: ",(0,r.kt)("a",{parentName:"li",href:"https://hyperledger.jfrog.io/artifactory/besu-binaries/besu/x.y.z/besu-x.y.z.zip"},"https://hyperledger.jfrog.io/artifactory/besu-binaries/besu/x.y.z/besu-x.y.z.zip")," with x.y.z replaced with the version number. For instance, run the following command after updating version number accordingly.",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},"wget https://hyperledger.jfrog.io/artifactory/besu-binaries/besu/21.7.0/besu-21.7.0.zip\n"))),(0,r.kt)("li",{parentName:"ul"},"Add the path to ",(0,r.kt)("inlineCode",{parentName:"li"},"besu-x.y.z/bin")," to your system PATH"))),(0,r.kt)("li",{parentName:"ul"},"EthSigner: ",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"Download and unpack the latest from ",(0,r.kt)("a",{parentName:"li",href:"https://cloudsmith.io/~consensys/repos/ethsigner/packages/?q=tag%3Alatest"},"https://cloudsmith.io/~consensys/repos/ethsigner/packages/?q=tag%3Alatest")," (Requires Java 11 or later)"),(0,r.kt)("li",{parentName:"ul"},"Add the path to ",(0,r.kt)("inlineCode",{parentName:"li"},"ethsigner-x.y.z/bin")," to your system PATH")))),(0,r.kt)("h3",{id:"besu-interoperation-node-sdk"},"Besu Interoperation Node SDK"),(0,r.kt)("p",null,"A client-layer library is defined in the ",(0,r.kt)("inlineCode",{parentName:"p"},"sdks/besu/interoperation-node-sdk")," folder. This contains functions for Besu web3JS based applications to exercise interoperation capabilities via several utility/helper functions. The Besu-CLI tool, which we will use later, depends on this library."),(0,r.kt)("p",null,"To build the library, do the following:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"sdks/besu/interoperation-node-sdk")," folder."),(0,r.kt)("li",{parentName:"ul"},"Run the following command:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make build-local\n")))),(0,r.kt)("h3",{id:"besu-network"},"Besu Network"),(0,r.kt)("p",null,"The code for this lies in the ",(0,r.kt)("inlineCode",{parentName:"p"},"tests/network-setups/besu")," folder."),(0,r.kt)("p",null,"This folder contains code to create and launch networks ",(0,r.kt)("inlineCode",{parentName:"p"},"Network1")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"Network2")," of identical specifications:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Network: 4 validator nodes, 1 EthSigner node."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"Network1")," uses ",(0,r.kt)("inlineCode",{parentName:"li"},"8545")," port for EthSigner while ",(0,r.kt)("inlineCode",{parentName:"li"},"Network2")," uses ",(0,r.kt)("inlineCode",{parentName:"li"},"9544")," port for EthSigner.")),(0,r.kt)("p",null,"Follow the instructions below to build and launch the networks:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"tests/network-setups/besu")," folder."),(0,r.kt)("li",{parentName:"ul"},"To spin up both Network1 and Network2, run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make start\n")))),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:"left"},"If you do not wish to test Besu-Besu interoperation, you can choose to launch only one of the two networks. For ",(0,r.kt)("inlineCode",{parentName:"td"},"Network1"),", run ",(0,r.kt)("inlineCode",{parentName:"td"},"make start-network1"),", and for ",(0,r.kt)("inlineCode",{parentName:"td"},"Network2"),", run ",(0,r.kt)("inlineCode",{parentName:"td"},"make start-network2"))))),(0,r.kt)("p",null,"For more information, refer to the associated ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/tests/network-setups/besu"},"README"),"."),(0,r.kt)("h3",{id:"contracts"},"Contracts"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"AssetExchangeContract")," must be deployed which is present in ",(0,r.kt)("inlineCode",{parentName:"li"},"core/network/besu/contracts/interop/manageAssetAny.sol"),". This contract is deployed along with application contract."),(0,r.kt)("li",{parentName:"ul"},"Application contract ",(0,r.kt)("inlineCode",{parentName:"li"},"simpleasset"),", located in ",(0,r.kt)("inlineCode",{parentName:"li"},"samples/besu/simpleasset")," directory (for ",(0,r.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview"},"Asset Exchange"),"), which supports creation, modification, transfer, and deletion, as well as locking, unlocking, and claiming, of simple ",(0,r.kt)("inlineCode",{parentName:"li"},"AliceERC20")," and ",(0,r.kt)("inlineCode",{parentName:"li"},"BobERC20")," tokens (examples of fungible assets), or ",(0,r.kt)("inlineCode",{parentName:"li"},"AliceERC721")," and ",(0,r.kt)("inlineCode",{parentName:"li"},"BobERC721")," tokens (example of non-fungible assets), or ",(0,r.kt)("inlineCode",{parentName:"li"},"AliceERC1155")," and ",(0,r.kt)("inlineCode",{parentName:"li"},"BobERC1155")," tokens (example of hybrid assets).")),(0,r.kt)("p",null,"To deploy ",(0,r.kt)("inlineCode",{parentName:"p"},"simpleasset")," with ",(0,r.kt)("inlineCode",{parentName:"p"},"AssetExchangeContract")," on both Besu networks, navigate to ",(0,r.kt)("inlineCode",{parentName:"p"},"samples/besu/simpleasset")," folder, and run:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make deploy-contracts\n")),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:"left"},"If you chose to launch only one of the two networks, then for ",(0,r.kt)("inlineCode",{parentName:"td"},"Network1"),", run ",(0,r.kt)("inlineCode",{parentName:"td"},"make deploy-contract-network1"),", and for ",(0,r.kt)("inlineCode",{parentName:"td"},"Network2"),", run ",(0,r.kt)("inlineCode",{parentName:"td"},"deploy-contract-network2"))))),(0,r.kt)("h3",{id:"besu-client-besu-cli"},"Besu Client (besu-cli)"),(0,r.kt)("p",null,"The CLI is used to interact with a Besu network, configure it and run contract transactions to record data on the ledger or query data."),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"besu-cli")," Node.js source code is located in the ",(0,r.kt)("inlineCode",{parentName:"p"},"samples/besu/besu-cli")," folder."),(0,r.kt)("h4",{id:"prerequisites-3"},"Prerequisites"),(0,r.kt)("p",null,"If you are using a Linux system, make sure that lib64 is installed."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:"left"},"For the Node.js version of the ",(0,r.kt)("inlineCode",{parentName:"td"},"besu-cli"),", the setup and running instructions below were tested with all Node.js versions from v11.14.0 to v14.17.3.")))),(0,r.kt)("h4",{id:"installation-1"},"Installation"),(0,r.kt)("p",null,"You can install ",(0,r.kt)("inlineCode",{parentName:"p"},"besu-cli")," as follows:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"samples/besu/besu-cli")," folder."),(0,r.kt)("li",{parentName:"ul"},"Run the following to install dependencies:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make build-local\n"))),(0,r.kt)("li",{parentName:"ul"},"Use the ",(0,r.kt)("inlineCode",{parentName:"li"},"besu-cli")," executable in the ",(0,r.kt)("inlineCode",{parentName:"li"},"bin")," folder for ",(0,r.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/ledger-initialization"},"subsequent actions"),".")),(0,r.kt)("h2",{id:"tear-down-the-setup"},"Tear Down the Setup"),(0,r.kt)("p",null,"Bring down the test network's components as follows:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Simply terminate the various relays and drivers, which are running in the foreground in different terminals"),(0,r.kt)("li",{parentName:"ul"},"To bring down the running Corda network:",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"tests/network-setups/corda")," folder."),(0,r.kt)("li",{parentName:"ul"},"Run the following:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make clean\n"))))),(0,r.kt)("li",{parentName:"ul"},"To bring down all the running Fabric networks:",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"tests/network-setups/fabric/dev")," folder."),(0,r.kt)("li",{parentName:"ul"},"Run the following:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make clean\n"))))),(0,r.kt)("li",{parentName:"ul"},"To bring down all the running Besu networks:",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"tests/network-setups/besu")," folder."),(0,r.kt)("li",{parentName:"ul"},"Run the following:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make clean\n")))))))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/378badfe.578d0d9f.js b/assets/js/378badfe.578d0d9f.js deleted file mode 100644 index 06173e0c0..000000000 --- a/assets/js/378badfe.578d0d9f.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[369],{3905:(e,t,i)=>{i.d(t,{Zo:()=>h,kt:()=>m});var n=i(7294);function a(e,t,i){return t in e?Object.defineProperty(e,t,{value:i,enumerable:!0,configurable:!0,writable:!0}):e[t]=i,e}function o(e,t){var i=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),i.push.apply(i,n)}return i}function s(e){for(var t=1;t<arguments.length;t++){var i=null!=arguments[t]?arguments[t]:{};t%2?o(Object(i),!0).forEach((function(t){a(e,t,i[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(i)):o(Object(i)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(i,t))}))}return e}function r(e,t){if(null==e)return{};var i,n,a=function(e,t){if(null==e)return{};var i,n,a={},o=Object.keys(e);for(n=0;n<o.length;n++)i=o[n],t.indexOf(i)>=0||(a[i]=e[i]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n<o.length;n++)i=o[n],t.indexOf(i)>=0||Object.prototype.propertyIsEnumerable.call(e,i)&&(a[i]=e[i])}return a}var c=n.createContext({}),l=function(e){var t=n.useContext(c),i=t;return e&&(i="function"==typeof e?e(t):s(s({},t),e)),i},h=function(e){var t=l(e.components);return n.createElement(c.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},u=n.forwardRef((function(e,t){var i=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,h=r(e,["components","mdxType","originalType","parentName"]),p=l(i),u=a,m=p["".concat(c,".").concat(u)]||p[u]||d[u]||o;return i?n.createElement(m,s(s({ref:t},h),{},{components:i})):n.createElement(m,s({ref:t},h))}));function m(e,t){var i=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=i.length,s=new Array(o);s[0]=u;var r={};for(var c in t)hasOwnProperty.call(t,c)&&(r[c]=t[c]);r.originalType=e,r[p]="string"==typeof e?e:a,s[1]=r;for(var l=2;l<o;l++)s[l]=i[l];return n.createElement.apply(null,s)}return n.createElement.apply(null,i)}u.displayName="MDXCreateElement"},7094:(e,t,i)=>{i.r(t),i.d(t,{assets:()=>c,contentTitle:()=>s,default:()=>d,frontMatter:()=>o,metadata:()=>r,toc:()=>l});var n=i(7462),a=(i(7294),i(3905));const o={},s=void 0,r={permalink:"/weaver-dlt-interoperability/blog/2021/01/21/cross-chain-asset",source:"@site/blog/2021-01-21-cross-chain-asset.md",title:"cross-chain-asset",description:"\x3c!--",date:"2021-01-21T00:00:00.000Z",formattedDate:"January 21, 2021",tags:[],readingTime:10.435,hasTruncateMarker:!1,authors:[],frontMatter:{},nextItem:{title:"emergence-enterprise-interoperability",permalink:"/weaver-dlt-interoperability/blog/2021/01/21/emergence-enterprise-interoperability"}},c={authorsImageUrls:[]},l=[{value:"tags: enterprise, interoperability, asset-exchange",id:"tags-enterprise-interoperability-asset-exchange",level:2},{value:"Introduction",id:"introduction",level:2},{value:"Motivation and Use-case",id:"motivation-and-use-case",level:2},{value:"Cross-Chain Asset Exchange on Public Blockchains",id:"cross-chain-asset-exchange-on-public-blockchains",level:2},{value:"Extending Protocol Design To Permissioned Blockchains",id:"extending-protocol-design-to-permissioned-blockchains",level:2},{value:"Conclusion",id:"conclusion",level:2}],h={toc:l},p="wrapper";function d(e){let{components:t,...o}=e;return(0,a.kt)(p,(0,n.Z)({},h,o,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("hr",null),(0,a.kt)("p",null,"slug: cross-chain-asset\ntitle: Enabling Cross-Chain Asset Exchange On Permissioned Blockchains\nauthor: Yining Hu, Ermyas Abebe, Dileban Karunamoorthy, Venkatraman Ramakrishna\nauthor_title: Contributors\nauthor_url: ",(0,a.kt)("a",{parentName:"p",href:"https://hyperledger-labs.github.io/weaver-dlt-interoperability/"},"https://hyperledger-labs.github.io/weaver-dlt-interoperability/")),(0,a.kt)("h2",{id:"tags-enterprise-interoperability-asset-exchange"},"tags: ","[enterprise, interoperability, asset-exchange]"),(0,a.kt)("h2",{id:"introduction"},"Introduction"),(0,a.kt)("p",null,"Recent years have witnessed a growing demand for enabling interoperability across independent blockchains. Cross-chain asset exchange is a significant step towards blockchain interoperability. For public blockchains, the most popular application for asset exchange is cryptocurrency exchange. For permissioned blockchains, cross-chain asset exchange can be useful in ",(0,a.kt)("a",{parentName:"p",href:"https://www.mas.gov.sg/-/media/MAS/ProjectUbin/Project-Ubin-DvP-on-Distributed-Ledger-Technologies.pdf"},"Delivery Versus Payment (DvP)")," and ",(0,a.kt)("a",{parentName:"p",href:"https://www.mas.gov.sg/-/media/Jasper-Ubin-Design-Paper.pdf"},"cross-border payment")," scenarios. There exist various protocols designed for asset exchange on public blockchains. However, a widely adopted standard for designing such protocols for permissioned blockchains still does not exist. Moreover, most existing protocols are designed for public blockchains and their suitability to be applied to permissioned blockchains is unclear."),(0,a.kt)("p",null,"In this article, we aim to lay out a set of requirements for designing cross-chain asset exchange protocols between permissioned blockchains. First we present a canonical motivating use case and then list the various patterns that such cases will follow in real-life scenarios. We then present a short survey of existing cross-chain exchange protocols for public blockchains, following which we summarise the building blocks, core mechanisms and security properties commonly involved in the protocol designs. We then analyse the requirements imposed by permissioned blockchains in comparison to public blockchains, and discuss the additional properties with respect to these restrictions."),(0,a.kt)("h2",{id:"motivation-and-use-case"},"Motivation and Use-case"),(0,a.kt)("p",null,"In traditional financial markets parties trade assets such as securities and derivatives for cash or other assets. To reduce risk, various clearing and settlement processes and intermediaries are often involved. One form of settlement is a DvP where the transfer of securities is performed only in the event of a corresponding payment. This arrangement reduces principal risk by ensuring that both parties receive their end of the exchange. However, settlement in financial markets are slow and time consuming. It also involves counterparty risks and requires intermediaries."),(0,a.kt)("p",null,"Over the past few years, we have been seeing significant efforts in digitising and tokenising both currencies and securities on Distributed Ledger Technology (DLT) infrastructures. On the one hand we have seen concerted efforts around Central Bank Digital Currencies (CBDC) being added to the landscape of other blockchain based payment networks. On the other hand, we have also seen efforts such as that from the Australian Stock Exchange (ASX) to replace its current settlement system--Clearing House Electronic Subregister System (CHESS) with a DLT based platform by 2021."),(0,a.kt)("p",null,"Against this backdrop, a number of central banks have been exploring the potential of performing DvP settlement across a currency ledger and a securities ledger. In this article, we use this as a motivating use-case for our discussions. The scenario involves two decentralised ledgers, namely, a currency ledger and a securities ledger, based on different DLT protocols performing a coordinated transfer of assets in their respective ledgers. Figure 1 depicts this scenario in the context of two organisations--Bank A and Bank B--in which Bank B wants to purchase some securities owned by Bank A and both organisations have accounts on both ledgers. To effect this exchange the following two transactions will have to happen atomically across both networks: i) transfer of payment from Bank B's currency account to Bank A while at the same time ii) the entitlements of the designated securities is transferred from Bank A to Bank B. The scenario would need to guarantee that after the transaction execution, either both parties have their end of the exchange or neither does and that this exchange is performed in a timely manner. "),(0,a.kt)("p",null,(0,a.kt)("img",{alt:"alt text",src:i(8073).Z,width:"904",height:"400"})),(0,a.kt)("p",null,"Figure 1. A typical DvP use-case."),(0,a.kt)("p",null,"Cross-chain transactions involving the movement of assets can generally take the form of either an asset exchange between parties or of value transfer from one network to another. The latter involves a scenario in which an asset in one network is locked or burned and a corresponding asset of similar value is issued in a corresponding network. This process generally involves validators or asset issuers in either or both ends of the network. While there are numerous use cases for this model in permissionless context, in this post we primarily focus on asset exchange scenarios, which are more broadly applicable in enterprise use-cases. Asset exchange scenarios generally involve two users swapping corresponding assets managed by the different networks, as in the example illustrated earlier. In asset exchange scenarios involving only two parties, both parties have accounts on both networks, although this might not be the case for exchanges involving more than two parties or networks."),(0,a.kt)("h2",{id:"cross-chain-asset-exchange-on-public-blockchains"},"Cross-Chain Asset Exchange on Public Blockchains"),(0,a.kt)("p",null,"Similar scenarios that involve a pair of transactions being coordinated across distinct blockchains have been studied for public blockchains. One main application area is to enable decentralised exchange across crypto-currency networks. To achieve this, a number of cross-chain asset exchange protocols have been proposed. The original atomic swap protocol was proposed by ",(0,a.kt)("a",{parentName:"p",href:"https://en.bitcoin.it/wiki/Atomic_swap"},"TierNolan")," in the Bitcoin Forum. The protocol leverages trusted escrow services on both blockchains and relies on the asset owners for execution. ",(0,a.kt)("a",{parentName:"p",href:"https://summa.one/"},"Prestwich")," later improved the protocol by removing the trusted escrow services and using a smart contract to automatically execute the swap. Both protocols, however, are asymmetric and hence enforce a particular sequence of events. More recently, a group of researchers developed ",(0,a.kt)("a",{parentName:"p",href:"https://arwen.io/whitepaper.pdf"},"Arwen"),", which guarantees the symmetricality of the protocol and further eases the asset owners' responsibilities in the protocol execution. "),(0,a.kt)("p",null,"We below first discuss the common patterns involved in the protocol design. More specifically, we present the main building blocks, core mechanisms, and security properties achieved by these protocols. "),(0,a.kt)("h1",{id:"building-blocks"},"Building blocks"),(0,a.kt)("p",null,"The design of a cross-chain asset exchange protocol in general contain the following building blocks: 1) the infrastructure for cross-chain state verification, and 2) the asset exchange protocol that specifies parties and sequences involved in the protocol execution. Cross-chain state verification can be performed by the exchanging parties themselves or by an external party."),(0,a.kt)("h1",{id:"core-mechanisms"},"Core Mechanisms"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("p",{parentName:"li"},"Fund locking: To initialise an asset exchange, it is common for one or both parties to first lock up funds with a fund-withholding party on his or her own blockchain. Temporary fund locking ensures the locked fund cannot be used for other purposes while the exchange is being executed. This scheme is often used with a specified timeout to provide flexibility for reclaiming locked funds if the exchange does not take place.")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("p",{parentName:"li"},"Fund redeeming: In general, the execution requires a pair of transactions to occur on both blockchains, e.g., from User A to User B on Chain A and from User B to User A on Chain B. When certain conditions are met, the locked funds can be redeemed by, or paid to the respective users. The execution of the exchange can be carried out by users themselves, or through other trusted third parties. These trusted third parties can be stand-alone parties that are not otherwise involved in both blockchains, or part of either blockchain. ")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("p",{parentName:"li"},"Refund: For protocols that are initialised with a temporary fund-locking, the locked funds can usually be reclaimed by the initial owner after a specified timeout. "))),(0,a.kt)("h1",{id:"security-properties"},"Security Properties"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("p",{parentName:"li"},"Atomicity: Atomicity is also sometimes referred to as safety. In general, atomicity implies indivisibility and irreducibility, namely, an atomic operation must be performed entirely or not performed at all. In the case of cross-chain asset exchange, when User A sends a payment to User B on Chain A, User B should also send corresponding delivery to User A on Chain B.")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("p",{parentName:"li"},"Liveness: Specifies the design of an asset exchange protocol should ensure no party can be tricked into locking up funds forever or for a very long time."))),(0,a.kt)("h2",{id:"extending-protocol-design-to-permissioned-blockchains"},"Extending Protocol Design To Permissioned Blockchains"),(0,a.kt)("p",null,"Requirements of Permissioned Blockchains\nAs public blockchains offer decentralisation and transparency, existing cross-chain asset exchange protocols on public blockchains are often designed for users to voluntarily participant and execute. To ensure secure execution of these protocols, their designs usually incorporate economic incentives, together with on-chain punishment schemes. To ensure liveness, these protocols usually leverage group consensus and fault-tolerance."),(0,a.kt)("p",null,"Permissioned blockchains on the other hand require privacy. Additional economic incentives and punishments are often not required besides the existing business relationships and established legal jurisdictions. Therefore, compared to public blockchains, the design of cross-chain asset exchange protocols on permissioned blockchains allows a higher level of centralisation and requires auditability and individual or group accountability for off-chain dispute resolution rather than economic incentives and on-chain punishments. Moreover, as permissioned blockchains themselves offer a higher throughput and faster transaction processing than public blockchains, the asset exchange protocol ideally should not introduce significant processing overheads that limit the transaction processing capability."),(0,a.kt)("p",null,"Therefore, the challenges in designing cross-chain asset exchange protocols for permissioned networks can be summarised as follow:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Permissioned networks are usually confidential by design, thus restricting access for its internal members and external clients. State verification is hard to achieve across distinct permissioned blockchains. Cross-chain asset exchange protocols must therefore incorporate additional mechanisms to overcome these challenges."),(0,a.kt)("li",{parentName:"ul"},"Unlike public blockchains, permissioned blockchains derive their security from and the ability to hold parties accountable for their actions. Any party acting maliciously should be identified and penalized during an off-chain dispute resolution process. Thus we can relax some of the constraints of the exchange protocol. For example, we can leverage trusted third-parties instead of having to financially incentivise regular users to participate in running the protocol.")),(0,a.kt)("h1",{id:"additional-properties"},"Additional Properties"),(0,a.kt)("p",null,"In addition to following the same set of building blocks, core mechanisms and security properties as public protocols, we also identify an additional set of desired properties for permissioned blockchains."),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("p",{parentName:"li"},"Scalability: Scalability is often restricted by two factors. Firstly, the transaction processing capability of the underlying infrastructures. When a protocol relies on public blockchains, the throughput is consequently limited by the transaction processing of the blockchains themselves. In contrast, some protocols are off-chain, which usually allow faster transaction processing. Secondly, for protocols that involve third parties for fund-locking, such as ",(0,a.kt)("a",{parentName:"p",href:"https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=8835387"},"Xclaim")," and ",(0,a.kt)("a",{parentName:"p",href:"https://arxiv.org/pdf/1908.03999.pdf"},"Dogethereum"),", the amount of money owned by these third parties limits the number of transaction requests they can process. As permissioned blockchains in general have a higher throughput compared to public blockchains, the protocol design should not trade off scalability.")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("p",{parentName:"li"},"Auditability: Auditability for public blockchains specifies that any party with read right should be able to detect protocol failure. On permissioned blockchains, however, as parties have limited visibility over the ledger state, who can detect protocol failure will most-likely depend on the use-case. In addition, financial regulatory requirements such as AML and CTF might require cross-chain traceability and auditability of exchange transactions (i.e. it should be easy to trace why Alice just transferred Bob $1M on a CBDC network).")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("p",{parentName:"li"},"Accountability: Accountability says faulty parties should be held accountable. This can refer to individual accountability or group accountability. As it is hard to enforce on-chain punishments on permissioned blockchains, the protocol design should at least allow adversaries to be held accountable.")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("p",{parentName:"li"},"Compatibility: Compatibility specifies how easy it is to implement the protocol on other blockchain platforms. The protocol design should be generic and not to be limited to particular blockchain platforms.")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("p",{parentName:"li"},"Extensibility: Extensibility specifies how easy it is to extend the protocol to other use cases, for instance, from two parties to multiple parties, or from one particular transaction pattern to other transaction patterns. ")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("p",{parentName:"li"},"Privacy: Privacy is usually not automatically guaranteed by public blockchains. For sensitive use-cases, extra mechanisms such as a ",(0,a.kt)("a",{parentName:"p",href:"https://dl.acm.org/doi/pdf/10.1145/3319535.3363221?casa_token=_CXTS4E4hVsAAAAA:9YXRV8SUF7ljmdn2iovE1la3_j6Yn7O1oKqrdZZwxrO_u_Dg2sRqjYdVcTUCLFayNd-s8AWZfELaKA"},"trusted execution environment (TEE)")," can be used. Privacy is also of vital importance when it comes to permissioned blockchains. Most existing cross-chain protocols are designed for public blockchains. As the execution of these protocols may require asset owners or third-parties to access states on either blockchain ledger, executing a cross-chain asset exchange can put user privacy at risk.")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("p",{parentName:"li"},"Low Cost: As many of the cross-chain exchange protocols involve sending on-chain transactions, the concern over number of transactions and transaction fees arises when the protocol design involves a public blockchain."))),(0,a.kt)("h2",{id:"conclusion"},"Conclusion"),(0,a.kt)("p",null,"To summarise, in this article we tackle the problem of enabling cross-chain asset exchange on permissioned blockchains and evaluate the different requirements imposed by public blockchains and permissioned blockchains. We also articulate a set of desired properties to guide the design of cross-chain asset exchange protocols."),(0,a.kt)("p",null,"For general-purpose interoperability of enterprise blockchains, we have developed the ",(0,a.kt)("a",{parentName:"p",href:"https://hyperledger-labs.github.io/weaver-dlt-interoperability/"},"Weaver")," tool that incorporates a cross-chain state verification engine to enable cross-chain state sharing and verification. Please check out our documentation for implementation details and example applications."))}d.isMDXComponent=!0},8073:(e,t,i)=>{i.d(t,{Z:()=>n});const n=i.p+"assets/images/simple-dvp-13ac15534a3f185903ac1784bc5f1031.png"}}]); \ No newline at end of file diff --git a/assets/js/bdfaba9c.6d7ad1af.js b/assets/js/378badfe.d591ecc6.js similarity index 78% rename from assets/js/bdfaba9c.6d7ad1af.js rename to assets/js/378badfe.d591ecc6.js index 967ecadcd..7dc7ed291 100644 --- a/assets/js/bdfaba9c.6d7ad1af.js +++ b/assets/js/378badfe.d591ecc6.js @@ -1 +1 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[2981],{3905:(e,t,i)=>{i.d(t,{Zo:()=>h,kt:()=>m});var n=i(7294);function a(e,t,i){return t in e?Object.defineProperty(e,t,{value:i,enumerable:!0,configurable:!0,writable:!0}):e[t]=i,e}function o(e,t){var i=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),i.push.apply(i,n)}return i}function s(e){for(var t=1;t<arguments.length;t++){var i=null!=arguments[t]?arguments[t]:{};t%2?o(Object(i),!0).forEach((function(t){a(e,t,i[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(i)):o(Object(i)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(i,t))}))}return e}function r(e,t){if(null==e)return{};var i,n,a=function(e,t){if(null==e)return{};var i,n,a={},o=Object.keys(e);for(n=0;n<o.length;n++)i=o[n],t.indexOf(i)>=0||(a[i]=e[i]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n<o.length;n++)i=o[n],t.indexOf(i)>=0||Object.prototype.propertyIsEnumerable.call(e,i)&&(a[i]=e[i])}return a}var c=n.createContext({}),l=function(e){var t=n.useContext(c),i=t;return e&&(i="function"==typeof e?e(t):s(s({},t),e)),i},h=function(e){var t=l(e.components);return n.createElement(c.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},u=n.forwardRef((function(e,t){var i=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,h=r(e,["components","mdxType","originalType","parentName"]),p=l(i),u=a,m=p["".concat(c,".").concat(u)]||p[u]||d[u]||o;return i?n.createElement(m,s(s({ref:t},h),{},{components:i})):n.createElement(m,s({ref:t},h))}));function m(e,t){var i=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=i.length,s=new Array(o);s[0]=u;var r={};for(var c in t)hasOwnProperty.call(t,c)&&(r[c]=t[c]);r.originalType=e,r[p]="string"==typeof e?e:a,s[1]=r;for(var l=2;l<o;l++)s[l]=i[l];return n.createElement.apply(null,s)}return n.createElement.apply(null,i)}u.displayName="MDXCreateElement"},1339:(e,t,i)=>{i.r(t),i.d(t,{assets:()=>c,contentTitle:()=>s,default:()=>d,frontMatter:()=>o,metadata:()=>r,toc:()=>l});var n=i(7462),a=(i(7294),i(3905));const o={},s=void 0,r={permalink:"/weaver-dlt-interoperability/blog/2021/01/21/cross-chain-asset",source:"@site/blog/2021-01-21-cross-chain-asset.md",title:"cross-chain-asset",description:"\x3c!--",date:"2021-01-21T00:00:00.000Z",formattedDate:"January 21, 2021",tags:[],readingTime:10.435,hasTruncateMarker:!1,authors:[],frontMatter:{},nextItem:{title:"emergence-enterprise-interoperability",permalink:"/weaver-dlt-interoperability/blog/2021/01/21/emergence-enterprise-interoperability"}},c={authorsImageUrls:[]},l=[{value:"tags: enterprise, interoperability, asset-exchange",id:"tags-enterprise-interoperability-asset-exchange",level:2},{value:"Introduction",id:"introduction",level:2},{value:"Motivation and Use-case",id:"motivation-and-use-case",level:2},{value:"Cross-Chain Asset Exchange on Public Blockchains",id:"cross-chain-asset-exchange-on-public-blockchains",level:2},{value:"Extending Protocol Design To Permissioned Blockchains",id:"extending-protocol-design-to-permissioned-blockchains",level:2},{value:"Conclusion",id:"conclusion",level:2}],h={toc:l},p="wrapper";function d(e){let{components:t,...o}=e;return(0,a.kt)(p,(0,n.Z)({},h,o,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("hr",null),(0,a.kt)("p",null,"slug: cross-chain-asset\ntitle: Enabling Cross-Chain Asset Exchange On Permissioned Blockchains\nauthor: Yining Hu, Ermyas Abebe, Dileban Karunamoorthy, Venkatraman Ramakrishna\nauthor_title: Contributors\nauthor_url: ",(0,a.kt)("a",{parentName:"p",href:"https://hyperledger-labs.github.io/weaver-dlt-interoperability/"},"https://hyperledger-labs.github.io/weaver-dlt-interoperability/")),(0,a.kt)("h2",{id:"tags-enterprise-interoperability-asset-exchange"},"tags: ","[enterprise, interoperability, asset-exchange]"),(0,a.kt)("h2",{id:"introduction"},"Introduction"),(0,a.kt)("p",null,"Recent years have witnessed a growing demand for enabling interoperability across independent blockchains. Cross-chain asset exchange is a significant step towards blockchain interoperability. For public blockchains, the most popular application for asset exchange is cryptocurrency exchange. For permissioned blockchains, cross-chain asset exchange can be useful in ",(0,a.kt)("a",{parentName:"p",href:"https://www.mas.gov.sg/-/media/MAS/ProjectUbin/Project-Ubin-DvP-on-Distributed-Ledger-Technologies.pdf"},"Delivery Versus Payment (DvP)")," and ",(0,a.kt)("a",{parentName:"p",href:"https://www.mas.gov.sg/-/media/Jasper-Ubin-Design-Paper.pdf"},"cross-border payment")," scenarios. There exist various protocols designed for asset exchange on public blockchains. However, a widely adopted standard for designing such protocols for permissioned blockchains still does not exist. Moreover, most existing protocols are designed for public blockchains and their suitability to be applied to permissioned blockchains is unclear."),(0,a.kt)("p",null,"In this article, we aim to lay out a set of requirements for designing cross-chain asset exchange protocols between permissioned blockchains. First we present a canonical motivating use case and then list the various patterns that such cases will follow in real-life scenarios. We then present a short survey of existing cross-chain exchange protocols for public blockchains, following which we summarise the building blocks, core mechanisms and security properties commonly involved in the protocol designs. We then analyse the requirements imposed by permissioned blockchains in comparison to public blockchains, and discuss the additional properties with respect to these restrictions."),(0,a.kt)("h2",{id:"motivation-and-use-case"},"Motivation and Use-case"),(0,a.kt)("p",null,"In traditional financial markets parties trade assets such as securities and derivatives for cash or other assets. To reduce risk, various clearing and settlement processes and intermediaries are often involved. One form of settlement is a DvP where the transfer of securities is performed only in the event of a corresponding payment. This arrangement reduces principal risk by ensuring that both parties receive their end of the exchange. However, settlement in financial markets are slow and time consuming. It also involves counterparty risks and requires intermediaries."),(0,a.kt)("p",null,"Over the past few years, we have been seeing significant efforts in digitising and tokenising both currencies and securities on Distributed Ledger Technology (DLT) infrastructures. On the one hand we have seen concerted efforts around Central Bank Digital Currencies (CBDC) being added to the landscape of other blockchain based payment networks. On the other hand, we have also seen efforts such as that from the Australian Stock Exchange (ASX) to replace its current settlement system--Clearing House Electronic Subregister System (CHESS) with a DLT based platform by 2021."),(0,a.kt)("p",null,"Against this backdrop, a number of central banks have been exploring the potential of performing DvP settlement across a currency ledger and a securities ledger. In this article, we use this as a motivating use-case for our discussions. The scenario involves two decentralised ledgers, namely, a currency ledger and a securities ledger, based on different DLT protocols performing a coordinated transfer of assets in their respective ledgers. Figure 1 depicts this scenario in the context of two organisations--Bank A and Bank B--in which Bank B wants to purchase some securities owned by Bank A and both organisations have accounts on both ledgers. To effect this exchange the following two transactions will have to happen atomically across both networks: i) transfer of payment from Bank B's currency account to Bank A while at the same time ii) the entitlements of the designated securities is transferred from Bank A to Bank B. The scenario would need to guarantee that after the transaction execution, either both parties have their end of the exchange or neither does and that this exchange is performed in a timely manner. "),(0,a.kt)("p",null,(0,a.kt)("img",{alt:"alt text",src:i(8073).Z,width:"904",height:"400"})),(0,a.kt)("p",null,"Figure 1. A typical DvP use-case."),(0,a.kt)("p",null,"Cross-chain transactions involving the movement of assets can generally take the form of either an asset exchange between parties or of value transfer from one network to another. The latter involves a scenario in which an asset in one network is locked or burned and a corresponding asset of similar value is issued in a corresponding network. This process generally involves validators or asset issuers in either or both ends of the network. While there are numerous use cases for this model in permissionless context, in this post we primarily focus on asset exchange scenarios, which are more broadly applicable in enterprise use-cases. Asset exchange scenarios generally involve two users swapping corresponding assets managed by the different networks, as in the example illustrated earlier. In asset exchange scenarios involving only two parties, both parties have accounts on both networks, although this might not be the case for exchanges involving more than two parties or networks."),(0,a.kt)("h2",{id:"cross-chain-asset-exchange-on-public-blockchains"},"Cross-Chain Asset Exchange on Public Blockchains"),(0,a.kt)("p",null,"Similar scenarios that involve a pair of transactions being coordinated across distinct blockchains have been studied for public blockchains. One main application area is to enable decentralised exchange across crypto-currency networks. To achieve this, a number of cross-chain asset exchange protocols have been proposed. The original atomic swap protocol was proposed by ",(0,a.kt)("a",{parentName:"p",href:"https://en.bitcoin.it/wiki/Atomic_swap"},"TierNolan")," in the Bitcoin Forum. The protocol leverages trusted escrow services on both blockchains and relies on the asset owners for execution. ",(0,a.kt)("a",{parentName:"p",href:"https://summa.one/"},"Prestwich")," later improved the protocol by removing the trusted escrow services and using a smart contract to automatically execute the swap. Both protocols, however, are asymmetric and hence enforce a particular sequence of events. More recently, a group of researchers developed ",(0,a.kt)("a",{parentName:"p",href:"https://arwen.io/whitepaper.pdf"},"Arwen"),", which guarantees the symmetricality of the protocol and further eases the asset owners' responsibilities in the protocol execution. "),(0,a.kt)("p",null,"We below first discuss the common patterns involved in the protocol design. More specifically, we present the main building blocks, core mechanisms, and security properties achieved by these protocols. "),(0,a.kt)("h1",{id:"building-blocks"},"Building blocks"),(0,a.kt)("p",null,"The design of a cross-chain asset exchange protocol in general contain the following building blocks: 1) the infrastructure for cross-chain state verification, and 2) the asset exchange protocol that specifies parties and sequences involved in the protocol execution. Cross-chain state verification can be performed by the exchanging parties themselves or by an external party."),(0,a.kt)("h1",{id:"core-mechanisms"},"Core Mechanisms"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("p",{parentName:"li"},"Fund locking: To initialise an asset exchange, it is common for one or both parties to first lock up funds with a fund-withholding party on his or her own blockchain. Temporary fund locking ensures the locked fund cannot be used for other purposes while the exchange is being executed. This scheme is often used with a specified timeout to provide flexibility for reclaiming locked funds if the exchange does not take place.")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("p",{parentName:"li"},"Fund redeeming: In general, the execution requires a pair of transactions to occur on both blockchains, e.g., from User A to User B on Chain A and from User B to User A on Chain B. When certain conditions are met, the locked funds can be redeemed by, or paid to the respective users. The execution of the exchange can be carried out by users themselves, or through other trusted third parties. These trusted third parties can be stand-alone parties that are not otherwise involved in both blockchains, or part of either blockchain. ")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("p",{parentName:"li"},"Refund: For protocols that are initialised with a temporary fund-locking, the locked funds can usually be reclaimed by the initial owner after a specified timeout. "))),(0,a.kt)("h1",{id:"security-properties"},"Security Properties"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("p",{parentName:"li"},"Atomicity: Atomicity is also sometimes referred to as safety. In general, atomicity implies indivisibility and irreducibility, namely, an atomic operation must be performed entirely or not performed at all. In the case of cross-chain asset exchange, when User A sends a payment to User B on Chain A, User B should also send corresponding delivery to User A on Chain B.")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("p",{parentName:"li"},"Liveness: Specifies the design of an asset exchange protocol should ensure no party can be tricked into locking up funds forever or for a very long time."))),(0,a.kt)("h2",{id:"extending-protocol-design-to-permissioned-blockchains"},"Extending Protocol Design To Permissioned Blockchains"),(0,a.kt)("p",null,"Requirements of Permissioned Blockchains\nAs public blockchains offer decentralisation and transparency, existing cross-chain asset exchange protocols on public blockchains are often designed for users to voluntarily participant and execute. To ensure secure execution of these protocols, their designs usually incorporate economic incentives, together with on-chain punishment schemes. To ensure liveness, these protocols usually leverage group consensus and fault-tolerance."),(0,a.kt)("p",null,"Permissioned blockchains on the other hand require privacy. Additional economic incentives and punishments are often not required besides the existing business relationships and established legal jurisdictions. Therefore, compared to public blockchains, the design of cross-chain asset exchange protocols on permissioned blockchains allows a higher level of centralisation and requires auditability and individual or group accountability for off-chain dispute resolution rather than economic incentives and on-chain punishments. Moreover, as permissioned blockchains themselves offer a higher throughput and faster transaction processing than public blockchains, the asset exchange protocol ideally should not introduce significant processing overheads that limit the transaction processing capability."),(0,a.kt)("p",null,"Therefore, the challenges in designing cross-chain asset exchange protocols for permissioned networks can be summarised as follow:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Permissioned networks are usually confidential by design, thus restricting access for its internal members and external clients. State verification is hard to achieve across distinct permissioned blockchains. Cross-chain asset exchange protocols must therefore incorporate additional mechanisms to overcome these challenges."),(0,a.kt)("li",{parentName:"ul"},"Unlike public blockchains, permissioned blockchains derive their security from and the ability to hold parties accountable for their actions. Any party acting maliciously should be identified and penalized during an off-chain dispute resolution process. Thus we can relax some of the constraints of the exchange protocol. For example, we can leverage trusted third-parties instead of having to financially incentivise regular users to participate in running the protocol.")),(0,a.kt)("h1",{id:"additional-properties"},"Additional Properties"),(0,a.kt)("p",null,"In addition to following the same set of building blocks, core mechanisms and security properties as public protocols, we also identify an additional set of desired properties for permissioned blockchains."),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("p",{parentName:"li"},"Scalability: Scalability is often restricted by two factors. Firstly, the transaction processing capability of the underlying infrastructures. When a protocol relies on public blockchains, the throughput is consequently limited by the transaction processing of the blockchains themselves. In contrast, some protocols are off-chain, which usually allow faster transaction processing. Secondly, for protocols that involve third parties for fund-locking, such as ",(0,a.kt)("a",{parentName:"p",href:"https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=8835387"},"Xclaim")," and ",(0,a.kt)("a",{parentName:"p",href:"https://arxiv.org/pdf/1908.03999.pdf"},"Dogethereum"),", the amount of money owned by these third parties limits the number of transaction requests they can process. As permissioned blockchains in general have a higher throughput compared to public blockchains, the protocol design should not trade off scalability.")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("p",{parentName:"li"},"Auditability: Auditability for public blockchains specifies that any party with read right should be able to detect protocol failure. On permissioned blockchains, however, as parties have limited visibility over the ledger state, who can detect protocol failure will most-likely depend on the use-case. In addition, financial regulatory requirements such as AML and CTF might require cross-chain traceability and auditability of exchange transactions (i.e. it should be easy to trace why Alice just transferred Bob $1M on a CBDC network).")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("p",{parentName:"li"},"Accountability: Accountability says faulty parties should be held accountable. This can refer to individual accountability or group accountability. As it is hard to enforce on-chain punishments on permissioned blockchains, the protocol design should at least allow adversaries to be held accountable.")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("p",{parentName:"li"},"Compatibility: Compatibility specifies how easy it is to implement the protocol on other blockchain platforms. The protocol design should be generic and not to be limited to particular blockchain platforms.")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("p",{parentName:"li"},"Extensibility: Extensibility specifies how easy it is to extend the protocol to other use cases, for instance, from two parties to multiple parties, or from one particular transaction pattern to other transaction patterns. ")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("p",{parentName:"li"},"Privacy: Privacy is usually not automatically guaranteed by public blockchains. For sensitive use-cases, extra mechanisms such as a ",(0,a.kt)("a",{parentName:"p",href:"https://dl.acm.org/doi/pdf/10.1145/3319535.3363221?casa_token=_CXTS4E4hVsAAAAA:9YXRV8SUF7ljmdn2iovE1la3_j6Yn7O1oKqrdZZwxrO_u_Dg2sRqjYdVcTUCLFayNd-s8AWZfELaKA"},"trusted execution environment (TEE)")," can be used. Privacy is also of vital importance when it comes to permissioned blockchains. Most existing cross-chain protocols are designed for public blockchains. As the execution of these protocols may require asset owners or third-parties to access states on either blockchain ledger, executing a cross-chain asset exchange can put user privacy at risk.")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("p",{parentName:"li"},"Low Cost: As many of the cross-chain exchange protocols involve sending on-chain transactions, the concern over number of transactions and transaction fees arises when the protocol design involves a public blockchain."))),(0,a.kt)("h2",{id:"conclusion"},"Conclusion"),(0,a.kt)("p",null,"To summarise, in this article we tackle the problem of enabling cross-chain asset exchange on permissioned blockchains and evaluate the different requirements imposed by public blockchains and permissioned blockchains. We also articulate a set of desired properties to guide the design of cross-chain asset exchange protocols."),(0,a.kt)("p",null,"For general-purpose interoperability of enterprise blockchains, we have developed the ",(0,a.kt)("a",{parentName:"p",href:"https://hyperledger-labs.github.io/weaver-dlt-interoperability/"},"Weaver")," tool that incorporates a cross-chain state verification engine to enable cross-chain state sharing and verification. Please check out our documentation for implementation details and example applications."))}d.isMDXComponent=!0},8073:(e,t,i)=>{i.d(t,{Z:()=>n});const n=i.p+"assets/images/simple-dvp-13ac15534a3f185903ac1784bc5f1031.png"}}]); \ No newline at end of file +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[8567],{5680:(e,t,i)=>{i.d(t,{xA:()=>h,yg:()=>g});var n=i(6540);function a(e,t,i){return t in e?Object.defineProperty(e,t,{value:i,enumerable:!0,configurable:!0,writable:!0}):e[t]=i,e}function o(e,t){var i=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),i.push.apply(i,n)}return i}function s(e){for(var t=1;t<arguments.length;t++){var i=null!=arguments[t]?arguments[t]:{};t%2?o(Object(i),!0).forEach((function(t){a(e,t,i[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(i)):o(Object(i)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(i,t))}))}return e}function r(e,t){if(null==e)return{};var i,n,a=function(e,t){if(null==e)return{};var i,n,a={},o=Object.keys(e);for(n=0;n<o.length;n++)i=o[n],t.indexOf(i)>=0||(a[i]=e[i]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n<o.length;n++)i=o[n],t.indexOf(i)>=0||Object.prototype.propertyIsEnumerable.call(e,i)&&(a[i]=e[i])}return a}var c=n.createContext({}),l=function(e){var t=n.useContext(c),i=t;return e&&(i="function"==typeof e?e(t):s(s({},t),e)),i},h=function(e){var t=l(e.components);return n.createElement(c.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},u=n.forwardRef((function(e,t){var i=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,h=r(e,["components","mdxType","originalType","parentName"]),p=l(i),u=a,g=p["".concat(c,".").concat(u)]||p[u]||d[u]||o;return i?n.createElement(g,s(s({ref:t},h),{},{components:i})):n.createElement(g,s({ref:t},h))}));function g(e,t){var i=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=i.length,s=new Array(o);s[0]=u;var r={};for(var c in t)hasOwnProperty.call(t,c)&&(r[c]=t[c]);r.originalType=e,r[p]="string"==typeof e?e:a,s[1]=r;for(var l=2;l<o;l++)s[l]=i[l];return n.createElement.apply(null,s)}return n.createElement.apply(null,i)}u.displayName="MDXCreateElement"},7814:(e,t,i)=>{i.r(t),i.d(t,{assets:()=>c,contentTitle:()=>s,default:()=>d,frontMatter:()=>o,metadata:()=>r,toc:()=>l});var n=i(8168),a=(i(6540),i(5680));const o={},s=void 0,r={permalink:"/weaver-dlt-interoperability/blog/2021/01/21/cross-chain-asset",source:"@site/blog/2021-01-21-cross-chain-asset.md",title:"cross-chain-asset",description:"\x3c!--",date:"2021-01-21T00:00:00.000Z",formattedDate:"January 21, 2021",tags:[],readingTime:10.435,hasTruncateMarker:!1,authors:[],frontMatter:{},nextItem:{title:"emergence-enterprise-interoperability",permalink:"/weaver-dlt-interoperability/blog/2021/01/21/emergence-enterprise-interoperability"}},c={authorsImageUrls:[]},l=[{value:"tags: enterprise, interoperability, asset-exchange",id:"tags-enterprise-interoperability-asset-exchange",level:2},{value:"Introduction",id:"introduction",level:2},{value:"Motivation and Use-case",id:"motivation-and-use-case",level:2},{value:"Cross-Chain Asset Exchange on Public Blockchains",id:"cross-chain-asset-exchange-on-public-blockchains",level:2},{value:"Extending Protocol Design To Permissioned Blockchains",id:"extending-protocol-design-to-permissioned-blockchains",level:2},{value:"Conclusion",id:"conclusion",level:2}],h={toc:l},p="wrapper";function d(e){let{components:t,...o}=e;return(0,a.yg)(p,(0,n.A)({},h,o,{components:t,mdxType:"MDXLayout"}),(0,a.yg)("hr",null),(0,a.yg)("p",null,"slug: cross-chain-asset\ntitle: Enabling Cross-Chain Asset Exchange On Permissioned Blockchains\nauthor: Yining Hu, Ermyas Abebe, Dileban Karunamoorthy, Venkatraman Ramakrishna\nauthor_title: Contributors\nauthor_url: ",(0,a.yg)("a",{parentName:"p",href:"https://hyperledger-labs.github.io/weaver-dlt-interoperability/"},"https://hyperledger-labs.github.io/weaver-dlt-interoperability/")),(0,a.yg)("h2",{id:"tags-enterprise-interoperability-asset-exchange"},"tags: ","[enterprise, interoperability, asset-exchange]"),(0,a.yg)("h2",{id:"introduction"},"Introduction"),(0,a.yg)("p",null,"Recent years have witnessed a growing demand for enabling interoperability across independent blockchains. Cross-chain asset exchange is a significant step towards blockchain interoperability. For public blockchains, the most popular application for asset exchange is cryptocurrency exchange. For permissioned blockchains, cross-chain asset exchange can be useful in ",(0,a.yg)("a",{parentName:"p",href:"https://www.mas.gov.sg/-/media/MAS/ProjectUbin/Project-Ubin-DvP-on-Distributed-Ledger-Technologies.pdf"},"Delivery Versus Payment (DvP)")," and ",(0,a.yg)("a",{parentName:"p",href:"https://www.mas.gov.sg/-/media/Jasper-Ubin-Design-Paper.pdf"},"cross-border payment")," scenarios. There exist various protocols designed for asset exchange on public blockchains. However, a widely adopted standard for designing such protocols for permissioned blockchains still does not exist. Moreover, most existing protocols are designed for public blockchains and their suitability to be applied to permissioned blockchains is unclear."),(0,a.yg)("p",null,"In this article, we aim to lay out a set of requirements for designing cross-chain asset exchange protocols between permissioned blockchains. First we present a canonical motivating use case and then list the various patterns that such cases will follow in real-life scenarios. We then present a short survey of existing cross-chain exchange protocols for public blockchains, following which we summarise the building blocks, core mechanisms and security properties commonly involved in the protocol designs. We then analyse the requirements imposed by permissioned blockchains in comparison to public blockchains, and discuss the additional properties with respect to these restrictions."),(0,a.yg)("h2",{id:"motivation-and-use-case"},"Motivation and Use-case"),(0,a.yg)("p",null,"In traditional financial markets parties trade assets such as securities and derivatives for cash or other assets. To reduce risk, various clearing and settlement processes and intermediaries are often involved. One form of settlement is a DvP where the transfer of securities is performed only in the event of a corresponding payment. This arrangement reduces principal risk by ensuring that both parties receive their end of the exchange. However, settlement in financial markets are slow and time consuming. It also involves counterparty risks and requires intermediaries."),(0,a.yg)("p",null,"Over the past few years, we have been seeing significant efforts in digitising and tokenising both currencies and securities on Distributed Ledger Technology (DLT) infrastructures. On the one hand we have seen concerted efforts around Central Bank Digital Currencies (CBDC) being added to the landscape of other blockchain based payment networks. On the other hand, we have also seen efforts such as that from the Australian Stock Exchange (ASX) to replace its current settlement system--Clearing House Electronic Subregister System (CHESS) with a DLT based platform by 2021."),(0,a.yg)("p",null,"Against this backdrop, a number of central banks have been exploring the potential of performing DvP settlement across a currency ledger and a securities ledger. In this article, we use this as a motivating use-case for our discussions. The scenario involves two decentralised ledgers, namely, a currency ledger and a securities ledger, based on different DLT protocols performing a coordinated transfer of assets in their respective ledgers. Figure 1 depicts this scenario in the context of two organisations--Bank A and Bank B--in which Bank B wants to purchase some securities owned by Bank A and both organisations have accounts on both ledgers. To effect this exchange the following two transactions will have to happen atomically across both networks: i) transfer of payment from Bank B's currency account to Bank A while at the same time ii) the entitlements of the designated securities is transferred from Bank A to Bank B. The scenario would need to guarantee that after the transaction execution, either both parties have their end of the exchange or neither does and that this exchange is performed in a timely manner. "),(0,a.yg)("p",null,(0,a.yg)("img",{alt:"alt text",src:i(2132).A,width:"904",height:"400"})),(0,a.yg)("p",null,"Figure 1. A typical DvP use-case."),(0,a.yg)("p",null,"Cross-chain transactions involving the movement of assets can generally take the form of either an asset exchange between parties or of value transfer from one network to another. The latter involves a scenario in which an asset in one network is locked or burned and a corresponding asset of similar value is issued in a corresponding network. This process generally involves validators or asset issuers in either or both ends of the network. While there are numerous use cases for this model in permissionless context, in this post we primarily focus on asset exchange scenarios, which are more broadly applicable in enterprise use-cases. Asset exchange scenarios generally involve two users swapping corresponding assets managed by the different networks, as in the example illustrated earlier. In asset exchange scenarios involving only two parties, both parties have accounts on both networks, although this might not be the case for exchanges involving more than two parties or networks."),(0,a.yg)("h2",{id:"cross-chain-asset-exchange-on-public-blockchains"},"Cross-Chain Asset Exchange on Public Blockchains"),(0,a.yg)("p",null,"Similar scenarios that involve a pair of transactions being coordinated across distinct blockchains have been studied for public blockchains. One main application area is to enable decentralised exchange across crypto-currency networks. To achieve this, a number of cross-chain asset exchange protocols have been proposed. The original atomic swap protocol was proposed by ",(0,a.yg)("a",{parentName:"p",href:"https://en.bitcoin.it/wiki/Atomic_swap"},"TierNolan")," in the Bitcoin Forum. The protocol leverages trusted escrow services on both blockchains and relies on the asset owners for execution. ",(0,a.yg)("a",{parentName:"p",href:"https://summa.one/"},"Prestwich")," later improved the protocol by removing the trusted escrow services and using a smart contract to automatically execute the swap. Both protocols, however, are asymmetric and hence enforce a particular sequence of events. More recently, a group of researchers developed ",(0,a.yg)("a",{parentName:"p",href:"https://arwen.io/whitepaper.pdf"},"Arwen"),", which guarantees the symmetricality of the protocol and further eases the asset owners' responsibilities in the protocol execution. "),(0,a.yg)("p",null,"We below first discuss the common patterns involved in the protocol design. More specifically, we present the main building blocks, core mechanisms, and security properties achieved by these protocols. "),(0,a.yg)("h1",{id:"building-blocks"},"Building blocks"),(0,a.yg)("p",null,"The design of a cross-chain asset exchange protocol in general contain the following building blocks: 1) the infrastructure for cross-chain state verification, and 2) the asset exchange protocol that specifies parties and sequences involved in the protocol execution. Cross-chain state verification can be performed by the exchanging parties themselves or by an external party."),(0,a.yg)("h1",{id:"core-mechanisms"},"Core Mechanisms"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("p",{parentName:"li"},"Fund locking: To initialise an asset exchange, it is common for one or both parties to first lock up funds with a fund-withholding party on his or her own blockchain. Temporary fund locking ensures the locked fund cannot be used for other purposes while the exchange is being executed. This scheme is often used with a specified timeout to provide flexibility for reclaiming locked funds if the exchange does not take place.")),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("p",{parentName:"li"},"Fund redeeming: In general, the execution requires a pair of transactions to occur on both blockchains, e.g., from User A to User B on Chain A and from User B to User A on Chain B. When certain conditions are met, the locked funds can be redeemed by, or paid to the respective users. The execution of the exchange can be carried out by users themselves, or through other trusted third parties. These trusted third parties can be stand-alone parties that are not otherwise involved in both blockchains, or part of either blockchain. ")),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("p",{parentName:"li"},"Refund: For protocols that are initialised with a temporary fund-locking, the locked funds can usually be reclaimed by the initial owner after a specified timeout. "))),(0,a.yg)("h1",{id:"security-properties"},"Security Properties"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("p",{parentName:"li"},"Atomicity: Atomicity is also sometimes referred to as safety. In general, atomicity implies indivisibility and irreducibility, namely, an atomic operation must be performed entirely or not performed at all. In the case of cross-chain asset exchange, when User A sends a payment to User B on Chain A, User B should also send corresponding delivery to User A on Chain B.")),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("p",{parentName:"li"},"Liveness: Specifies the design of an asset exchange protocol should ensure no party can be tricked into locking up funds forever or for a very long time."))),(0,a.yg)("h2",{id:"extending-protocol-design-to-permissioned-blockchains"},"Extending Protocol Design To Permissioned Blockchains"),(0,a.yg)("p",null,"Requirements of Permissioned Blockchains\nAs public blockchains offer decentralisation and transparency, existing cross-chain asset exchange protocols on public blockchains are often designed for users to voluntarily participant and execute. To ensure secure execution of these protocols, their designs usually incorporate economic incentives, together with on-chain punishment schemes. To ensure liveness, these protocols usually leverage group consensus and fault-tolerance."),(0,a.yg)("p",null,"Permissioned blockchains on the other hand require privacy. Additional economic incentives and punishments are often not required besides the existing business relationships and established legal jurisdictions. Therefore, compared to public blockchains, the design of cross-chain asset exchange protocols on permissioned blockchains allows a higher level of centralisation and requires auditability and individual or group accountability for off-chain dispute resolution rather than economic incentives and on-chain punishments. Moreover, as permissioned blockchains themselves offer a higher throughput and faster transaction processing than public blockchains, the asset exchange protocol ideally should not introduce significant processing overheads that limit the transaction processing capability."),(0,a.yg)("p",null,"Therefore, the challenges in designing cross-chain asset exchange protocols for permissioned networks can be summarised as follow:"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},"Permissioned networks are usually confidential by design, thus restricting access for its internal members and external clients. State verification is hard to achieve across distinct permissioned blockchains. Cross-chain asset exchange protocols must therefore incorporate additional mechanisms to overcome these challenges."),(0,a.yg)("li",{parentName:"ul"},"Unlike public blockchains, permissioned blockchains derive their security from and the ability to hold parties accountable for their actions. Any party acting maliciously should be identified and penalized during an off-chain dispute resolution process. Thus we can relax some of the constraints of the exchange protocol. For example, we can leverage trusted third-parties instead of having to financially incentivise regular users to participate in running the protocol.")),(0,a.yg)("h1",{id:"additional-properties"},"Additional Properties"),(0,a.yg)("p",null,"In addition to following the same set of building blocks, core mechanisms and security properties as public protocols, we also identify an additional set of desired properties for permissioned blockchains."),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("p",{parentName:"li"},"Scalability: Scalability is often restricted by two factors. Firstly, the transaction processing capability of the underlying infrastructures. When a protocol relies on public blockchains, the throughput is consequently limited by the transaction processing of the blockchains themselves. In contrast, some protocols are off-chain, which usually allow faster transaction processing. Secondly, for protocols that involve third parties for fund-locking, such as ",(0,a.yg)("a",{parentName:"p",href:"https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=8835387"},"Xclaim")," and ",(0,a.yg)("a",{parentName:"p",href:"https://arxiv.org/pdf/1908.03999.pdf"},"Dogethereum"),", the amount of money owned by these third parties limits the number of transaction requests they can process. As permissioned blockchains in general have a higher throughput compared to public blockchains, the protocol design should not trade off scalability.")),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("p",{parentName:"li"},"Auditability: Auditability for public blockchains specifies that any party with read right should be able to detect protocol failure. On permissioned blockchains, however, as parties have limited visibility over the ledger state, who can detect protocol failure will most-likely depend on the use-case. In addition, financial regulatory requirements such as AML and CTF might require cross-chain traceability and auditability of exchange transactions (i.e. it should be easy to trace why Alice just transferred Bob $1M on a CBDC network).")),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("p",{parentName:"li"},"Accountability: Accountability says faulty parties should be held accountable. This can refer to individual accountability or group accountability. As it is hard to enforce on-chain punishments on permissioned blockchains, the protocol design should at least allow adversaries to be held accountable.")),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("p",{parentName:"li"},"Compatibility: Compatibility specifies how easy it is to implement the protocol on other blockchain platforms. The protocol design should be generic and not to be limited to particular blockchain platforms.")),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("p",{parentName:"li"},"Extensibility: Extensibility specifies how easy it is to extend the protocol to other use cases, for instance, from two parties to multiple parties, or from one particular transaction pattern to other transaction patterns. ")),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("p",{parentName:"li"},"Privacy: Privacy is usually not automatically guaranteed by public blockchains. For sensitive use-cases, extra mechanisms such as a ",(0,a.yg)("a",{parentName:"p",href:"https://dl.acm.org/doi/pdf/10.1145/3319535.3363221?casa_token=_CXTS4E4hVsAAAAA:9YXRV8SUF7ljmdn2iovE1la3_j6Yn7O1oKqrdZZwxrO_u_Dg2sRqjYdVcTUCLFayNd-s8AWZfELaKA"},"trusted execution environment (TEE)")," can be used. Privacy is also of vital importance when it comes to permissioned blockchains. Most existing cross-chain protocols are designed for public blockchains. As the execution of these protocols may require asset owners or third-parties to access states on either blockchain ledger, executing a cross-chain asset exchange can put user privacy at risk.")),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("p",{parentName:"li"},"Low Cost: As many of the cross-chain exchange protocols involve sending on-chain transactions, the concern over number of transactions and transaction fees arises when the protocol design involves a public blockchain."))),(0,a.yg)("h2",{id:"conclusion"},"Conclusion"),(0,a.yg)("p",null,"To summarise, in this article we tackle the problem of enabling cross-chain asset exchange on permissioned blockchains and evaluate the different requirements imposed by public blockchains and permissioned blockchains. We also articulate a set of desired properties to guide the design of cross-chain asset exchange protocols."),(0,a.yg)("p",null,"For general-purpose interoperability of enterprise blockchains, we have developed the ",(0,a.yg)("a",{parentName:"p",href:"https://hyperledger-labs.github.io/weaver-dlt-interoperability/"},"Weaver")," tool that incorporates a cross-chain state verification engine to enable cross-chain state sharing and verification. Please check out our documentation for implementation details and example applications."))}d.isMDXComponent=!0},2132:(e,t,i)=>{i.d(t,{A:()=>n});const n=i.p+"assets/images/simple-dvp-13ac15534a3f185903ac1784bc5f1031.png"}}]); \ No newline at end of file diff --git a/assets/js/3d094f56.7cba4bcd.js b/assets/js/3d094f56.3cdd6474.js similarity index 76% rename from assets/js/3d094f56.7cba4bcd.js rename to assets/js/3d094f56.3cdd6474.js index 5a4a5feed..989dbcde3 100644 --- a/assets/js/3d094f56.7cba4bcd.js +++ b/assets/js/3d094f56.3cdd6474.js @@ -1 +1 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[3278],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>g});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function o(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?i(Object(r),!0).forEach((function(t){a(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):i(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function l(e,t){if(null==e)return{};var r,n,a=function(e,t){if(null==e)return{};var r,n,a={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var c=n.createContext({}),s=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},p=function(e){var t=s(e.components);return n.createElement(c.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},y=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,i=e.originalType,c=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),u=s(r),y=a,g=u["".concat(c,".").concat(y)]||u[y]||d[y]||i;return r?n.createElement(g,o(o({ref:t},p),{},{components:r})):n.createElement(g,o({ref:t},p))}));function g(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=r.length,o=new Array(i);o[0]=y;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l[u]="string"==typeof e?e:a,o[1]=l;for(var s=2;s<i;s++)o[s]=r[s];return n.createElement.apply(null,o)}return n.createElement.apply(null,r)}y.displayName="MDXCreateElement"},6599:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>d,frontMatter:()=>i,metadata:()=>l,toc:()=>s});var n=r(7462),a=(r(7294),r(3905));const i={id:"legacy-integration",title:"Legacy Integration"},o=void 0,l={unversionedId:"external/user-stories/legacy-integration",id:"external/user-stories/legacy-integration",title:"Legacy Integration",description:"\x3c!--",source:"@site/docs/external/user-stories/legacy-integration.md",sourceDirName:"external/user-stories",slug:"/external/user-stories/legacy-integration",permalink:"/weaver-dlt-interoperability/docs/external/user-stories/legacy-integration",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/user-stories/legacy-integration.md",tags:[],version:"current",frontMatter:{id:"legacy-integration",title:"Legacy Integration"},sidebar:"Documentation",previous:{title:"DvP in Financial Markets",permalink:"/weaver-dlt-interoperability/docs/external/user-stories/financial-markets"},next:{title:"Overview",permalink:"/weaver-dlt-interoperability/docs/external/architecture-and-design/overview"}},c={},s=[],p={toc:s},u="wrapper";function d(e){let{components:t,...i}=e;return(0,a.kt)(u,(0,n.Z)({},p,i,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"A standard for self-contained messages respresenting state in distributed ledgers, along with proofs of validity, enables interoperability with legacy enterprise applications. These messages can be consumed, stored or forwarded by any traditional centralized application."),(0,a.kt)("p",null,(0,a.kt)("img",{src:r(8707).Z,width:"1476",height:"640"})))}d.isMDXComponent=!0},8707:(e,t,r)=>{r.d(t,{Z:()=>n});const n=r.p+"assets/images/legacy-integration-3fbbc48cb19a686e81a706f31da4a6c3.jpg"}}]); \ No newline at end of file +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[5120],{5680:(e,t,r)=>{r.d(t,{xA:()=>p,yg:()=>g});var n=r(6540);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function o(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?i(Object(r),!0).forEach((function(t){a(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):i(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function l(e,t){if(null==e)return{};var r,n,a=function(e,t){if(null==e)return{};var r,n,a={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var c=n.createContext({}),s=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},p=function(e){var t=s(e.components);return n.createElement(c.Provider,{value:t},e.children)},u="mdxType",y={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,i=e.originalType,c=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),u=s(r),d=a,g=u["".concat(c,".").concat(d)]||u[d]||y[d]||i;return r?n.createElement(g,o(o({ref:t},p),{},{components:r})):n.createElement(g,o({ref:t},p))}));function g(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=r.length,o=new Array(i);o[0]=d;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l[u]="string"==typeof e?e:a,o[1]=l;for(var s=2;s<i;s++)o[s]=r[s];return n.createElement.apply(null,o)}return n.createElement.apply(null,r)}d.displayName="MDXCreateElement"},2912:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>y,frontMatter:()=>i,metadata:()=>l,toc:()=>s});var n=r(8168),a=(r(6540),r(5680));const i={id:"legacy-integration",title:"Legacy Integration"},o=void 0,l={unversionedId:"external/user-stories/legacy-integration",id:"external/user-stories/legacy-integration",title:"Legacy Integration",description:"\x3c!--",source:"@site/docs/external/user-stories/legacy-integration.md",sourceDirName:"external/user-stories",slug:"/external/user-stories/legacy-integration",permalink:"/weaver-dlt-interoperability/docs/external/user-stories/legacy-integration",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/user-stories/legacy-integration.md",tags:[],version:"current",frontMatter:{id:"legacy-integration",title:"Legacy Integration"},sidebar:"Documentation",previous:{title:"DvP in Financial Markets",permalink:"/weaver-dlt-interoperability/docs/external/user-stories/financial-markets"},next:{title:"Overview",permalink:"/weaver-dlt-interoperability/docs/external/architecture-and-design/overview"}},c={},s=[],p={toc:s},u="wrapper";function y(e){let{components:t,...i}=e;return(0,a.yg)(u,(0,n.A)({},p,i,{components:t,mdxType:"MDXLayout"}),(0,a.yg)("p",null,"A standard for self-contained messages respresenting state in distributed ledgers, along with proofs of validity, enables interoperability with legacy enterprise applications. These messages can be consumed, stored or forwarded by any traditional centralized application."),(0,a.yg)("p",null,(0,a.yg)("img",{src:r(6371).A,width:"1476",height:"640"})))}y.isMDXComponent=!0},6371:(e,t,r)=>{r.d(t,{A:()=>n});const n=r.p+"assets/images/legacy-integration-3fbbc48cb19a686e81a706f31da4a6c3.jpg"}}]); \ No newline at end of file diff --git a/assets/js/3d5da5a5.d09aca1d.js b/assets/js/3d5da5a5.fc2e20e6.js similarity index 77% rename from assets/js/3d5da5a5.d09aca1d.js rename to assets/js/3d5da5a5.fc2e20e6.js index 25c584f89..cd3651997 100644 --- a/assets/js/3d5da5a5.d09aca1d.js +++ b/assets/js/3d5da5a5.fc2e20e6.js @@ -1 +1 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[9178],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>f});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},i=Object.keys(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=r.createContext({}),c=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},d=function(e){var t=c(e.components);return r.createElement(l.Provider,{value:t},e.children)},h="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},u=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,l=e.parentName,d=s(e,["components","mdxType","originalType","parentName"]),h=c(n),u=a,f=h["".concat(l,".").concat(u)]||h[u]||p[u]||i;return n?r.createElement(f,o(o({ref:t},d),{},{components:n})):r.createElement(f,o({ref:t},d))}));function f(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,o=new Array(i);o[0]=u;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[h]="string"==typeof e?e:a,o[1]=s;for(var c=2;c<i;c++)o[c]=n[c];return r.createElement.apply(null,o)}return r.createElement.apply(null,n)}u.displayName="MDXCreateElement"},6456:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>o,default:()=>p,frontMatter:()=>i,metadata:()=>s,toc:()=>c});var r=n(7462),a=(n(7294),n(3905));const i={},o=void 0,s={permalink:"/weaver-dlt-interoperability/blog/2021/01/21/emergence-enterprise-interoperability",source:"@site/blog/2021-01-21-emergence-enterprise-interoperability.md",title:"emergence-enterprise-interoperability",description:"\x3c!--",date:"2021-01-21T00:00:00.000Z",formattedDate:"January 21, 2021",tags:[],readingTime:4.945,hasTruncateMarker:!1,authors:[],frontMatter:{},prevItem:{title:"cross-chain-asset",permalink:"/weaver-dlt-interoperability/blog/2021/01/21/cross-chain-asset"}},l={authorsImageUrls:[]},c=[{value:"tags: enterprise, interoperability",id:"tags-enterprise-interoperability",level:2},{value:"The Grand Vision",id:"the-grand-vision",level:2},{value:"Evolution of Private Networks",id:"evolution-of-private-networks",level:2},{value:"Diverse Platforms",id:"diverse-platforms",level:2},{value:"Blockchain Landscape",id:"blockchain-landscape",level:2},{value:"Challenges",id:"challenges",level:2}],d={toc:c},h="wrapper";function p(e){let{components:t,...n}=e;return(0,a.kt)(h,(0,r.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("hr",null),(0,a.kt)("p",null,"slug: emergence-enterprise-interoperability\ntitle: Emergence of Enterprise DLT Interoperability\nauthor: Venkatraman Ramakrishna\nauthor_title: Maintainer of Weaver\nauthor_url: ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/VRamakrishna"},"https://github.com/VRamakrishna"),"\nauthor_image_url: ",(0,a.kt)("a",{parentName:"p",href:"https://avatars2.githubusercontent.com/u/14888211?s=400&v=4"},"https://avatars2.githubusercontent.com/u/14888211?s=400&v=4")),(0,a.kt)("h2",{id:"tags-enterprise-interoperability"},"tags: ","[enterprise, interoperability]"),(0,a.kt)("p",null,"It is instructive to know the course taken by blockchain technology and its applications over the past few years, as this will allow us to understand where we are, where are headed, and thereby motivate the necessity of interoperability."),(0,a.kt)("h2",{id:"the-grand-vision"},"The Grand Vision"),(0,a.kt)("p",null,"The original vision of blockchain technology called for a global decentralized network of peers and clients that could conduct transactions at scale without requiring intermediation by trusted third parties. The Bitcoin network was the first example of this, and it was purposely left open for anyone to join precisely because its initiators hoped for a single global network somewhat akin to the internet."),(0,a.kt)("p",null,"But the limitations of Bitcoin as a transaction processing system soon became apparent, and the Ethereum network emerged to fill this gap, retaining the openness and scalability of Bitcoin while supporting arbitrary smart contracts over a shared ledger. But Ethereum too was not destined to be the single canonical global blockchain network that everyone would use."),(0,a.kt)("p",null,"Sub-groups within the Bitcoin and Ethereum communities dissented from the rest, thereby creating ",(0,a.kt)("em",{parentName:"p"},"forks"),", or separate networks with separate chains of blocks. Others found limitations in the usability of the existing networks or their consensus mechanisms (Proof of Work) and decided to build their own networks to which like-minded people could subscribe and in which they could conduct their transactions."),(0,a.kt)("p",null,"Therefore, the original Bitcoin (or even Ethereum) vision of a single global network was not to be, and networks with different clientele and different consensus protocols proliferated."),(0,a.kt)("p",null,"And then came private (or permissioned) networks......"),(0,a.kt)("h2",{id:"evolution-of-private-networks"},"Evolution of Private Networks"),(0,a.kt)("p",null,"Sometime in the first half of the previous decade, it was recognized that networks like Bitcoin and Ethereum were not suitable for much of the business that involves private enterprises, governmental institutions, and ordinary clients. Private networks then emerged as a means to retain the trustworthiness and consensus-based decision-making properties of blockchains (and distributed ledgers in general) while ensuring that:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Transactions and ledger state are privy only to a selected set of entities,"),(0,a.kt)("li",{parentName:"ul"},"Transactions can be audited by trusted authorities when required for dispute resolutions, and"),(0,a.kt)("li",{parentName:"ul"},"Higher performance and assurance can be gained using consensus protocols other than ",(0,a.kt)("em",{parentName:"li"},"proof-of-work"),".")),(0,a.kt)("p",null,"Since companies and consortia were wary of this new and unproven technology, the trend in industry these past few years has been to build ",(0,a.kt)("em",{parentName:"p"},"minimum viable ecosystems"),", i.e., networks of limited operational scope and participation. The goal being to evaluate the potential of blockchain, these networks were created to manage selected few assets and records. Needless to say, interoperation with other networks was not high on the priority list when such networks were designed and launched."),(0,a.kt)("p",null,"Many of these networks have been successfully validated and put into production. But a consequence of the decision to build limited-scope networks is that the processes they run (through smart contracts) and the assets and records they maintain on their ledgers are stuck in siloes, inaccessible to external entitites and networks. Yet, as we are discovering, processes and assets in such networks are inextricably linked in the real enterprise world. With all of the investment (in time and money) made in existing networks, reeingeneering or merging them will generally be hardsells. Also, some networks may wish to restrict operational control and ledger visibility to its current set of administrators and clientele. The only viable solution is to allow networks to interoperate, thereby breaking up the siloes, while retaining operational control."),(0,a.kt)("h2",{id:"diverse-platforms"},"Diverse Platforms"),(0,a.kt)("p",null,"Our present blockchain landscape (or ecosystem) is characterized not just by a plethora of networks, a mix of open and private, but also by the existence of several distinct blockchain technologies, each with a different storage technology, a different model for contracts and client applications, a different consensus protocol, and a different way of managing identity. Examples include Fabric, Iroha, Sawtooth, and Besu, all in the Hyperledger family, and Ethereum, Multichain, Cardano, and Komodo, outside it. There are also smart contract distributed ledger platforms that serve a similar set of business applications that are not blockchains at all, like R3's Corda."),(0,a.kt)("p",null,"Since there is no single blockchain, or distributed ledger, technology, the world agrees on, and because each offers a different set of advantages and disadvantages, the networks that exist today are built on a diverse set of such platforms."),(0,a.kt)("h2",{id:"blockchain-landscape"},"Blockchain Landscape"),(0,a.kt)("p",null,"Our present is, and our near future will be, characterized by the existence of independent networks, some of which offer open membership whereas others are restricted, built on diverse platforms that are mutually incompatible. Asking everyone to converge to a single global network running on a single canonical platform is almost impossible. So unless we wish entities and assets to remain trapped within siloes, it should be evident that interoperability amoong different networks and platforms is crucial to the success of blockchain."),(0,a.kt)("h2",{id:"challenges"},"Challenges"),(0,a.kt)("p",null,"Interlinking processes distributed across different networks or transferring or sharing assets and data may sound like a straightforward task, but the traditional method of service and API integration will not work in scenarios that involve permissioned networks."),(0,a.kt)("p",null,"This is because, as you will see in the ",(0,a.kt)("a",{parentName:"p",href:"/docs/external/user-stories/overview"},"user stories"),", entities that are interested in the asset or data record being shared may not be members of both networks. And even if a particular entity happens to be a member of both networks, it may be in its interest to present a false view of one network's ledger state to another."),(0,a.kt)("p",null,"Therefore, interoperation cannot be allowed to hinge on the trustworthiness of a particular network member, or by extension, a third party. In the stories we will encounter, it will be apparent how such situations may occur. This will make the unreliability of API integration across private networks clear and also motivate the need for consensus-based interoperation protocols."))}p.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[6405],{5680:(e,t,n)=>{n.d(t,{xA:()=>d,yg:()=>g});var r=n(6540);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},i=Object.keys(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=r.createContext({}),c=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},d=function(e){var t=c(e.components);return r.createElement(l.Provider,{value:t},e.children)},h="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},u=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,l=e.parentName,d=s(e,["components","mdxType","originalType","parentName"]),h=c(n),u=a,g=h["".concat(l,".").concat(u)]||h[u]||p[u]||i;return n?r.createElement(g,o(o({ref:t},d),{},{components:n})):r.createElement(g,o({ref:t},d))}));function g(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,o=new Array(i);o[0]=u;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[h]="string"==typeof e?e:a,o[1]=s;for(var c=2;c<i;c++)o[c]=n[c];return r.createElement.apply(null,o)}return r.createElement.apply(null,n)}u.displayName="MDXCreateElement"},6823:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>o,default:()=>p,frontMatter:()=>i,metadata:()=>s,toc:()=>c});var r=n(8168),a=(n(6540),n(5680));const i={},o=void 0,s={permalink:"/weaver-dlt-interoperability/blog/2021/01/21/emergence-enterprise-interoperability",source:"@site/blog/2021-01-21-emergence-enterprise-interoperability.md",title:"emergence-enterprise-interoperability",description:"\x3c!--",date:"2021-01-21T00:00:00.000Z",formattedDate:"January 21, 2021",tags:[],readingTime:4.945,hasTruncateMarker:!1,authors:[],frontMatter:{},prevItem:{title:"cross-chain-asset",permalink:"/weaver-dlt-interoperability/blog/2021/01/21/cross-chain-asset"}},l={authorsImageUrls:[]},c=[{value:"tags: enterprise, interoperability",id:"tags-enterprise-interoperability",level:2},{value:"The Grand Vision",id:"the-grand-vision",level:2},{value:"Evolution of Private Networks",id:"evolution-of-private-networks",level:2},{value:"Diverse Platforms",id:"diverse-platforms",level:2},{value:"Blockchain Landscape",id:"blockchain-landscape",level:2},{value:"Challenges",id:"challenges",level:2}],d={toc:c},h="wrapper";function p(e){let{components:t,...n}=e;return(0,a.yg)(h,(0,r.A)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,a.yg)("hr",null),(0,a.yg)("p",null,"slug: emergence-enterprise-interoperability\ntitle: Emergence of Enterprise DLT Interoperability\nauthor: Venkatraman Ramakrishna\nauthor_title: Maintainer of Weaver\nauthor_url: ",(0,a.yg)("a",{parentName:"p",href:"https://github.com/VRamakrishna"},"https://github.com/VRamakrishna"),"\nauthor_image_url: ",(0,a.yg)("a",{parentName:"p",href:"https://avatars2.githubusercontent.com/u/14888211?s=400&v=4"},"https://avatars2.githubusercontent.com/u/14888211?s=400&v=4")),(0,a.yg)("h2",{id:"tags-enterprise-interoperability"},"tags: ","[enterprise, interoperability]"),(0,a.yg)("p",null,"It is instructive to know the course taken by blockchain technology and its applications over the past few years, as this will allow us to understand where we are, where are headed, and thereby motivate the necessity of interoperability."),(0,a.yg)("h2",{id:"the-grand-vision"},"The Grand Vision"),(0,a.yg)("p",null,"The original vision of blockchain technology called for a global decentralized network of peers and clients that could conduct transactions at scale without requiring intermediation by trusted third parties. The Bitcoin network was the first example of this, and it was purposely left open for anyone to join precisely because its initiators hoped for a single global network somewhat akin to the internet."),(0,a.yg)("p",null,"But the limitations of Bitcoin as a transaction processing system soon became apparent, and the Ethereum network emerged to fill this gap, retaining the openness and scalability of Bitcoin while supporting arbitrary smart contracts over a shared ledger. But Ethereum too was not destined to be the single canonical global blockchain network that everyone would use."),(0,a.yg)("p",null,"Sub-groups within the Bitcoin and Ethereum communities dissented from the rest, thereby creating ",(0,a.yg)("em",{parentName:"p"},"forks"),", or separate networks with separate chains of blocks. Others found limitations in the usability of the existing networks or their consensus mechanisms (Proof of Work) and decided to build their own networks to which like-minded people could subscribe and in which they could conduct their transactions."),(0,a.yg)("p",null,"Therefore, the original Bitcoin (or even Ethereum) vision of a single global network was not to be, and networks with different clientele and different consensus protocols proliferated."),(0,a.yg)("p",null,"And then came private (or permissioned) networks......"),(0,a.yg)("h2",{id:"evolution-of-private-networks"},"Evolution of Private Networks"),(0,a.yg)("p",null,"Sometime in the first half of the previous decade, it was recognized that networks like Bitcoin and Ethereum were not suitable for much of the business that involves private enterprises, governmental institutions, and ordinary clients. Private networks then emerged as a means to retain the trustworthiness and consensus-based decision-making properties of blockchains (and distributed ledgers in general) while ensuring that:"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},"Transactions and ledger state are privy only to a selected set of entities,"),(0,a.yg)("li",{parentName:"ul"},"Transactions can be audited by trusted authorities when required for dispute resolutions, and"),(0,a.yg)("li",{parentName:"ul"},"Higher performance and assurance can be gained using consensus protocols other than ",(0,a.yg)("em",{parentName:"li"},"proof-of-work"),".")),(0,a.yg)("p",null,"Since companies and consortia were wary of this new and unproven technology, the trend in industry these past few years has been to build ",(0,a.yg)("em",{parentName:"p"},"minimum viable ecosystems"),", i.e., networks of limited operational scope and participation. The goal being to evaluate the potential of blockchain, these networks were created to manage selected few assets and records. Needless to say, interoperation with other networks was not high on the priority list when such networks were designed and launched."),(0,a.yg)("p",null,"Many of these networks have been successfully validated and put into production. But a consequence of the decision to build limited-scope networks is that the processes they run (through smart contracts) and the assets and records they maintain on their ledgers are stuck in siloes, inaccessible to external entitites and networks. Yet, as we are discovering, processes and assets in such networks are inextricably linked in the real enterprise world. With all of the investment (in time and money) made in existing networks, reeingeneering or merging them will generally be hardsells. Also, some networks may wish to restrict operational control and ledger visibility to its current set of administrators and clientele. The only viable solution is to allow networks to interoperate, thereby breaking up the siloes, while retaining operational control."),(0,a.yg)("h2",{id:"diverse-platforms"},"Diverse Platforms"),(0,a.yg)("p",null,"Our present blockchain landscape (or ecosystem) is characterized not just by a plethora of networks, a mix of open and private, but also by the existence of several distinct blockchain technologies, each with a different storage technology, a different model for contracts and client applications, a different consensus protocol, and a different way of managing identity. Examples include Fabric, Iroha, Sawtooth, and Besu, all in the Hyperledger family, and Ethereum, Multichain, Cardano, and Komodo, outside it. There are also smart contract distributed ledger platforms that serve a similar set of business applications that are not blockchains at all, like R3's Corda."),(0,a.yg)("p",null,"Since there is no single blockchain, or distributed ledger, technology, the world agrees on, and because each offers a different set of advantages and disadvantages, the networks that exist today are built on a diverse set of such platforms."),(0,a.yg)("h2",{id:"blockchain-landscape"},"Blockchain Landscape"),(0,a.yg)("p",null,"Our present is, and our near future will be, characterized by the existence of independent networks, some of which offer open membership whereas others are restricted, built on diverse platforms that are mutually incompatible. Asking everyone to converge to a single global network running on a single canonical platform is almost impossible. So unless we wish entities and assets to remain trapped within siloes, it should be evident that interoperability amoong different networks and platforms is crucial to the success of blockchain."),(0,a.yg)("h2",{id:"challenges"},"Challenges"),(0,a.yg)("p",null,"Interlinking processes distributed across different networks or transferring or sharing assets and data may sound like a straightforward task, but the traditional method of service and API integration will not work in scenarios that involve permissioned networks."),(0,a.yg)("p",null,"This is because, as you will see in the ",(0,a.yg)("a",{parentName:"p",href:"/docs/external/user-stories/overview"},"user stories"),", entities that are interested in the asset or data record being shared may not be members of both networks. And even if a particular entity happens to be a member of both networks, it may be in its interest to present a false view of one network's ledger state to another."),(0,a.yg)("p",null,"Therefore, interoperation cannot be allowed to hinge on the trustworthiness of a particular network member, or by extension, a third party. In the stories we will encounter, it will be apparent how such situations may occur. This will make the unreliability of API integration across private networks clear and also motivate the need for consensus-based interoperation protocols."))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/3ec01bef.7178ccff.js b/assets/js/3ec01bef.7178ccff.js deleted file mode 100644 index c7711be6b..000000000 --- a/assets/js/3ec01bef.7178ccff.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[867],{3905:(e,n,t)=>{t.d(n,{Zo:()=>s,kt:()=>m});var r=t(7294);function o(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function a(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function i(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?a(Object(t),!0).forEach((function(n){o(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):a(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function l(e,n){if(null==e)return{};var t,r,o=function(e,n){if(null==e)return{};var t,r,o={},a=Object.keys(e);for(r=0;r<a.length;r++)t=a[r],n.indexOf(t)>=0||(o[t]=e[t]);return o}(e,n);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)t=a[r],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var c=r.createContext({}),p=function(e){var n=r.useContext(c),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},s=function(e){var n=p(e.components);return r.createElement(c.Provider,{value:n},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},y=r.forwardRef((function(e,n){var t=e.components,o=e.mdxType,a=e.originalType,c=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),d=p(t),y=o,m=d["".concat(c,".").concat(y)]||d[y]||u[y]||a;return t?r.createElement(m,i(i({ref:n},s),{},{components:t})):r.createElement(m,i({ref:n},s))}));function m(e,n){var t=arguments,o=n&&n.mdxType;if("string"==typeof e||o){var a=t.length,i=new Array(a);i[0]=y;var l={};for(var c in n)hasOwnProperty.call(n,c)&&(l[c]=n[c]);l.originalType=e,l[d]="string"==typeof e?e:o,i[1]=l;for(var p=2;p<a;p++)i[p]=t[p];return r.createElement.apply(null,i)}return r.createElement.apply(null,t)}y.displayName="MDXCreateElement"},9636:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>i,default:()=>u,frontMatter:()=>a,metadata:()=>l,toc:()=>p});var r=t(7462),o=(t(7294),t(3905));const a={id:"governance-and-policies",title:"Governance and Policies"},i=void 0,l={unversionedId:"external/deployment-considerations/governance-and-policies",id:"external/deployment-considerations/governance-and-policies",title:"Governance and Policies",description:"\x3c!--",source:"@site/docs/external/deployment-considerations/governance-and-policies.md",sourceDirName:"external/deployment-considerations",slug:"/external/deployment-considerations/governance-and-policies",permalink:"/weaver-dlt-interoperability/docs/external/deployment-considerations/governance-and-policies",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/deployment-considerations/governance-and-policies.md",tags:[],version:"current",frontMatter:{id:"governance-and-policies",title:"Governance and Policies"},sidebar:"Documentation",previous:{title:"Deployment Patterns",permalink:"/weaver-dlt-interoperability/docs/external/deployment-considerations/deployment-patterns"},next:{title:"Legal and Regulation",permalink:"/weaver-dlt-interoperability/docs/external/deployment-considerations/legal-and-regulation"}},c={},p=[],s={toc:p},d="wrapper";function u(e){let{components:n,...t}=e;return(0,o.kt)(d,(0,r.Z)({},s,t,{components:n,mdxType:"MDXLayout"}))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/3ec01bef.bb2aa489.js b/assets/js/3ec01bef.bb2aa489.js new file mode 100644 index 000000000..ec95358bf --- /dev/null +++ b/assets/js/3ec01bef.bb2aa489.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[1590],{5680:(e,n,t)=>{t.d(n,{xA:()=>s,yg:()=>m});var r=t(6540);function o(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function a(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function i(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?a(Object(t),!0).forEach((function(n){o(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):a(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function l(e,n){if(null==e)return{};var t,r,o=function(e,n){if(null==e)return{};var t,r,o={},a=Object.keys(e);for(r=0;r<a.length;r++)t=a[r],n.indexOf(t)>=0||(o[t]=e[t]);return o}(e,n);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)t=a[r],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var c=r.createContext({}),p=function(e){var n=r.useContext(c),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},s=function(e){var n=p(e.components);return r.createElement(c.Provider,{value:n},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},y=r.forwardRef((function(e,n){var t=e.components,o=e.mdxType,a=e.originalType,c=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),d=p(t),y=o,m=d["".concat(c,".").concat(y)]||d[y]||u[y]||a;return t?r.createElement(m,i(i({ref:n},s),{},{components:t})):r.createElement(m,i({ref:n},s))}));function m(e,n){var t=arguments,o=n&&n.mdxType;if("string"==typeof e||o){var a=t.length,i=new Array(a);i[0]=y;var l={};for(var c in n)hasOwnProperty.call(n,c)&&(l[c]=n[c]);l.originalType=e,l[d]="string"==typeof e?e:o,i[1]=l;for(var p=2;p<a;p++)i[p]=t[p];return r.createElement.apply(null,i)}return r.createElement.apply(null,t)}y.displayName="MDXCreateElement"},6825:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>i,default:()=>u,frontMatter:()=>a,metadata:()=>l,toc:()=>p});var r=t(8168),o=(t(6540),t(5680));const a={id:"governance-and-policies",title:"Governance and Policies"},i=void 0,l={unversionedId:"external/deployment-considerations/governance-and-policies",id:"external/deployment-considerations/governance-and-policies",title:"Governance and Policies",description:"\x3c!--",source:"@site/docs/external/deployment-considerations/governance-and-policies.md",sourceDirName:"external/deployment-considerations",slug:"/external/deployment-considerations/governance-and-policies",permalink:"/weaver-dlt-interoperability/docs/external/deployment-considerations/governance-and-policies",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/deployment-considerations/governance-and-policies.md",tags:[],version:"current",frontMatter:{id:"governance-and-policies",title:"Governance and Policies"},sidebar:"Documentation",previous:{title:"Deployment Patterns",permalink:"/weaver-dlt-interoperability/docs/external/deployment-considerations/deployment-patterns"},next:{title:"Legal and Regulation",permalink:"/weaver-dlt-interoperability/docs/external/deployment-considerations/legal-and-regulation"}},c={},p=[],s={toc:p},d="wrapper";function u(e){let{components:n,...t}=e;return(0,o.yg)(d,(0,r.A)({},s,t,{components:n,mdxType:"MDXLayout"}))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/46d80676.746e3828.js b/assets/js/46d80676.746e3828.js new file mode 100644 index 000000000..287cbb9f3 --- /dev/null +++ b/assets/js/46d80676.746e3828.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[2016],{5680:(e,r,t)=>{t.d(r,{xA:()=>p,yg:()=>y});var n=t(6540);function o(e,r,t){return r in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function i(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);r&&(n=n.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),t.push.apply(t,n)}return t}function a(e){for(var r=1;r<arguments.length;r++){var t=null!=arguments[r]?arguments[r]:{};r%2?i(Object(t),!0).forEach((function(r){o(e,r,t[r])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):i(Object(t)).forEach((function(r){Object.defineProperty(e,r,Object.getOwnPropertyDescriptor(t,r))}))}return e}function c(e,r){if(null==e)return{};var t,n,o=function(e,r){if(null==e)return{};var t,n,o={},i=Object.keys(e);for(n=0;n<i.length;n++)t=i[n],r.indexOf(t)>=0||(o[t]=e[t]);return o}(e,r);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)t=i[n],r.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var l=n.createContext({}),s=function(e){var r=n.useContext(l),t=r;return e&&(t="function"==typeof e?e(r):a(a({},r),e)),t},p=function(e){var r=s(e.components);return n.createElement(l.Provider,{value:r},e.children)},d="mdxType",f={inlineCode:"code",wrapper:function(e){var r=e.children;return n.createElement(n.Fragment,{},r)}},u=n.forwardRef((function(e,r){var t=e.components,o=e.mdxType,i=e.originalType,l=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),d=s(t),u=o,y=d["".concat(l,".").concat(u)]||d[u]||f[u]||i;return t?n.createElement(y,a(a({ref:r},p),{},{components:t})):n.createElement(y,a({ref:r},p))}));function y(e,r){var t=arguments,o=r&&r.mdxType;if("string"==typeof e||o){var i=t.length,a=new Array(i);a[0]=u;var c={};for(var l in r)hasOwnProperty.call(r,l)&&(c[l]=r[l]);c.originalType=e,c[d]="string"==typeof e?e:o,a[1]=c;for(var s=2;s<i;s++)a[s]=t[s];return n.createElement.apply(null,a)}return n.createElement.apply(null,t)}u.displayName="MDXCreateElement"},8222:(e,r,t)=>{t.r(r),t.d(r,{assets:()=>l,contentTitle:()=>a,default:()=>f,frontMatter:()=>i,metadata:()=>c,toc:()=>s});var n=t(8168),o=(t(6540),t(5680));const i={id:"proofs-and-verification",title:"Proofs and Verification"},a=void 0,c={unversionedId:"external/security-model/proofs-and-verification",id:"external/security-model/proofs-and-verification",title:"Proofs and Verification",description:"\x3c!--",source:"@site/docs/external/security-model/proofs-and-verification.md",sourceDirName:"external/security-model",slug:"/external/security-model/proofs-and-verification",permalink:"/weaver-dlt-interoperability/docs/external/security-model/proofs-and-verification",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/security-model/proofs-and-verification.md",tags:[],version:"current",frontMatter:{id:"proofs-and-verification",title:"Proofs and Verification"},sidebar:"Documentation",previous:{title:"Access Control",permalink:"/weaver-dlt-interoperability/docs/external/security-model/access-control"},next:{title:"End-to-End Security",permalink:"/weaver-dlt-interoperability/docs/external/security-model/end-to-end-security"}},l={},s=[],p={toc:s},d="wrapper";function f(e){let{components:r,...t}=e;return(0,o.yg)(d,(0,n.A)({},p,t,{components:r,mdxType:"MDXLayout"}))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/46d80676.cf24df36.js b/assets/js/46d80676.cf24df36.js deleted file mode 100644 index 7b403c758..000000000 --- a/assets/js/46d80676.cf24df36.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[9219],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>y});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function a(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?i(Object(r),!0).forEach((function(t){o(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):i(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function c(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=n.createContext({}),s=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},p=function(e){var t=s(e.components);return n.createElement(l.Provider,{value:t},e.children)},d="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},u=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,i=e.originalType,l=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),d=s(r),u=o,y=d["".concat(l,".").concat(u)]||d[u]||f[u]||i;return r?n.createElement(y,a(a({ref:t},p),{},{components:r})):n.createElement(y,a({ref:t},p))}));function y(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=r.length,a=new Array(i);a[0]=u;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c[d]="string"==typeof e?e:o,a[1]=c;for(var s=2;s<i;s++)a[s]=r[s];return n.createElement.apply(null,a)}return n.createElement.apply(null,r)}u.displayName="MDXCreateElement"},2478:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>a,default:()=>f,frontMatter:()=>i,metadata:()=>c,toc:()=>s});var n=r(7462),o=(r(7294),r(3905));const i={id:"proofs-and-verification",title:"Proofs and Verification"},a=void 0,c={unversionedId:"external/security-model/proofs-and-verification",id:"external/security-model/proofs-and-verification",title:"Proofs and Verification",description:"\x3c!--",source:"@site/docs/external/security-model/proofs-and-verification.md",sourceDirName:"external/security-model",slug:"/external/security-model/proofs-and-verification",permalink:"/weaver-dlt-interoperability/docs/external/security-model/proofs-and-verification",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/security-model/proofs-and-verification.md",tags:[],version:"current",frontMatter:{id:"proofs-and-verification",title:"Proofs and Verification"},sidebar:"Documentation",previous:{title:"Access Control",permalink:"/weaver-dlt-interoperability/docs/external/security-model/access-control"},next:{title:"End-to-End Security",permalink:"/weaver-dlt-interoperability/docs/external/security-model/end-to-end-security"}},l={},s=[],p={toc:s},d="wrapper";function f(e){let{components:t,...r}=e;return(0,o.kt)(d,(0,n.Z)({},p,r,{components:t,mdxType:"MDXLayout"}))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/4972.7556188e.js b/assets/js/4972.7556188e.js deleted file mode 100644 index 20501afa3..000000000 --- a/assets/js/4972.7556188e.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[4972],{4972:(e,t,a)=>{a.r(t),a.d(t,{default:()=>i});var n=a(7294),l=a(5999),r=a(1944),o=a(3285);function i(){return n.createElement(n.Fragment,null,n.createElement(r.d,{title:(0,l.I)({id:"theme.NotFound.title",message:"Page Not Found"})}),n.createElement(o.Z,null,n.createElement("main",{className:"container margin-vert--xl"},n.createElement("div",{className:"row"},n.createElement("div",{className:"col col--6 col--offset-3"},n.createElement("h1",{className:"hero__title"},n.createElement(l.Z,{id:"theme.NotFound.title",description:"The title of the 404 page"},"Page Not Found")),n.createElement("p",null,n.createElement(l.Z,{id:"theme.NotFound.p1",description:"The first paragraph of the 404 page"},"We could not find what you were looking for.")),n.createElement("p",null,n.createElement(l.Z,{id:"theme.NotFound.p2",description:"The 2nd paragraph of the 404 page"},"Please contact the owner of the site that linked you to the original URL and let them know their link is broken.")))))))}}}]); \ No newline at end of file diff --git a/assets/js/53c981a7.6e360d3a.js b/assets/js/53c981a7.6e360d3a.js new file mode 100644 index 000000000..afda5144e --- /dev/null +++ b/assets/js/53c981a7.6e360d3a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[2990],{5680:(e,t,a)=>{a.d(t,{xA:()=>d,yg:()=>y});var n=a(6540);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function o(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function i(e){for(var t=1;t<arguments.length;t++){var a=null!=arguments[t]?arguments[t]:{};t%2?o(Object(a),!0).forEach((function(t){r(e,t,a[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(a)):o(Object(a)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(a,t))}))}return e}function l(e,t){if(null==e)return{};var a,n,r=function(e,t){if(null==e)return{};var a,n,r={},o=Object.keys(e);for(n=0;n<o.length;n++)a=o[n],t.indexOf(a)>=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n<o.length;n++)a=o[n],t.indexOf(a)>=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var s=n.createContext({}),p=function(e){var t=n.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},d=function(e){var t=p(e.components);return n.createElement(s.Provider,{value:t},e.children)},g="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,o=e.originalType,s=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),g=p(a),m=r,y=g["".concat(s,".").concat(m)]||g[m]||c[m]||o;return a?n.createElement(y,i(i({ref:t},d),{},{components:a})):n.createElement(y,i({ref:t},d))}));function y(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=a.length,i=new Array(o);i[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[g]="string"==typeof e?e:r,i[1]=l;for(var p=2;p<o;p++)i[p]=a[p];return n.createElement.apply(null,i)}return n.createElement.apply(null,a)}m.displayName="MDXCreateElement"},3633:(e,t,a)=>{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>c,frontMatter:()=>o,metadata:()=>l,toc:()=>p});var n=a(8168),r=(a(6540),a(5680));const o={id:"setup-local-docker",title:"Setup with Locally Built Dockerized Weaver Components",pagination_prev:"external/getting-started/test-network/overview",pagination_next:"external/getting-started/test-network/ledger-initialization"},i=void 0,l={unversionedId:"external/getting-started/test-network/setup-local-docker",id:"external/getting-started/test-network/setup-local-docker",title:"Setup with Locally Built Dockerized Weaver Components",description:"\x3c!--",source:"@site/docs/external/getting-started/test-network/setup-local-docker.md",sourceDirName:"external/getting-started/test-network",slug:"/external/getting-started/test-network/setup-local-docker",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-local-docker",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/getting-started/test-network/setup-local-docker.md",tags:[],version:"current",frontMatter:{id:"setup-local-docker",title:"Setup with Locally Built Dockerized Weaver Components",pagination_prev:"external/getting-started/test-network/overview",pagination_next:"external/getting-started/test-network/ledger-initialization"},sidebar:"Documentation",previous:{title:"Component Overview",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/overview"},next:{title:"Ledger Initialization",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/ledger-initialization"}},s={},p=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Software",id:"software",level:3},{value:"Credentials",id:"credentials",level:3},{value:"Getting the Code and Documentation",id:"getting-the-code-and-documentation",level:2},{value:"Common Structures",id:"common-structures",level:2},{value:"Securing Components",id:"securing-components",level:2},{value:"Hyperledger Fabric Components",id:"hyperledger-fabric-components",level:2},{value:"Fabric Interoperation Node SDK",id:"fabric-interoperation-node-sdk",level:3},{value:"Fabric Network",id:"fabric-network",level:3},{value:"Fabric Relay",id:"fabric-relay",level:3},{value:"Building Relay Image",id:"building-relay-image",level:4},{value:"Deployment",id:"deployment",level:4},{value:"Fabric Driver",id:"fabric-driver",level:3},{value:"Building",id:"building",level:4},{value:"Deployment",id:"deployment-1",level:4},{value:"Fabric IIN Agent",id:"fabric-iin-agent",level:3},{value:"Building",id:"building-1",level:4},{value:"Deployment",id:"deployment-2",level:4},{value:"Fabric Client (Application)",id:"fabric-client-application",level:3},{value:"Prerequisites",id:"prerequisites-1",level:4},{value:"Installation",id:"installation",level:4},{value:"Corda Components",id:"corda-components",level:2},{value:"Interoperation CorDapp",id:"interoperation-cordapp",level:3},{value:"Corda Interoperation SDK",id:"corda-interoperation-sdk",level:3},{value:"Corda Simple Application and Client (Application)",id:"corda-simple-application-and-client-application",level:3},{value:"Corda Network",id:"corda-network",level:3},{value:"Corda Relay",id:"corda-relay",level:3},{value:"Corda Driver",id:"corda-driver",level:3},{value:"Building",id:"building-2",level:4},{value:"Deployment",id:"deployment-3",level:4},{value:"Tear Down the Setup",id:"tear-down-the-setup",level:2},{value:"Relay",id:"relay",level:3},{value:"Fabric Driver",id:"fabric-driver-1",level:3},{value:"Corda Driver",id:"corda-driver-1",level:3},{value:"Corda Network",id:"corda-network-1",level:3},{value:"Fabric Network",id:"fabric-network-1",level:3}],d={toc:p},g="wrapper";function c(e){let{components:t,...a}=e;return(0,r.yg)(g,(0,n.A)({},d,a,{components:t,mdxType:"MDXLayout"}),(0,r.yg)("p",null,"In this document, we detail the steps using which you can bring up networks using the default configuration settings and by fetching pre-built Weaver interoperation modules, SDK libraries, and relay docker image, drivers docker images from GitHub Package repositories. To customize these settings (e.g., hostnames, ports), refer to the ",(0,r.yg)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/advanced-configuration"},"Advanced Configuration page"),"."),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:"left"},"All components are run within Docker containers, except client applications.")))),(0,r.yg)("p",null,"Follow the instructions below to build and run components followed by interoperation flows. These instructions have been tested on Ubuntu Linux (bash shell) and Mac OS. In general, they should work on any system and shell as long as the various dependencies have been installed and configured."),(0,r.yg)("h2",{id:"prerequisites"},"Prerequisites"),(0,r.yg)("h3",{id:"software"},"Software"),(0,r.yg)("p",null,"Before starting, make sure you have the following software installed on your host machine:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},"Curl: ",(0,r.yg)("em",{parentName:"p"},"install using package manager, like ",(0,r.yg)("inlineCode",{parentName:"em"},"apt")," on Debian/Ubuntu Linux"))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},"Git: ",(0,r.yg)("a",{parentName:"p",href:"https://git-scm.com/book/en/v2/Getting-Started-Installing-Git"},"sample instructions"))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},"Docker: ",(0,r.yg)("a",{parentName:"p",href:"https://docs.docker.com/engine/install/"},"sample instructions")," (Latest version)")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},"Docker-Compose: ",(0,r.yg)("a",{parentName:"p",href:"https://docs.docker.com/compose/install/"},"sample instructions")," (Version 1.28.2 or higher, but lower than version V2)")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},"Golang: ",(0,r.yg)("a",{parentName:"p",href:"https://golang.org/dl/"},"sample instructions")," (Version 1.16 or higher)")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},"Java (JDK and JRE): ",(0,r.yg)("a",{parentName:"p",href:"https://openjdk.java.net/install/"},"sample instructions")," (Version 8)")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},"Node.js and NPM: ",(0,r.yg)("a",{parentName:"p",href:"https://nodejs.org/en/download/package-manager/"},"sample instructions")," (Version 16 Supported)")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},"Yarn: ",(0,r.yg)("a",{parentName:"p",href:"https://classic.yarnpkg.com/en/docs/install/"},"sample instructions"))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},"Protoc (Protobuf compiler): ",(0,r.yg)("em",{parentName:"p"},"Golang should already be installed and configured.")),(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},"Default method: Run the following with ",(0,r.yg)("inlineCode",{parentName:"p"},"sudo")," if necessary. This will install both the protobuf compiler and the Go code generator plugins."),(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre"},"apt-get install protobuf-compiler\ngo install google.golang.org/protobuf/cmd/protoc-gen-go\ngo install google.golang.org/grpc/cmd/protoc-gen-go-grpc\n"))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},"If the above method installs an older version of ",(0,r.yg)("inlineCode",{parentName:"p"},"protoc")," (check using ",(0,r.yg)("inlineCode",{parentName:"p"},"protoc --version"),"), say below 3.12.x, you should download pre-compiled binaries instead. (With an older version, you may see errors while attempting to launch and setup the Fabric networks)."),(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre"},'sudo apt-get remove protobuf-compiler\ncurl -LO https://github.com/protocolbuffers/protobuf/releases/download/v3.15.6/protoc-3.15.6-linux-x86_64.zip\nsudo apt-get install unzip\nunzip protoc-3.15.6-linux-x86_64.zip -d <some-folder-path>\nexport PATH="$PATH:<some-folder-path>/bin"\ngo install google.golang.org/protobuf/cmd/protoc-gen-go\ngo install google.golang.org/grpc/cmd/protoc-gen-go-grpc\n')),(0,r.yg)("table",{parentName:"li"},(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:"left"},"The latest version at present is ",(0,r.yg)("inlineCode",{parentName:"td"},"3.15.6"),", but you should check the above link to find the most current version before running the above steps.")))))))),(0,r.yg)("h3",{id:"credentials"},"Credentials"),(0,r.yg)("p",null,"Make sure you have an SSH or GPG key registered in ",(0,r.yg)("a",{parentName:"p",href:"https://github.com"},"https://github.com")," to allow seamless cloning of repositories (at present, various setup scripts clone repositories using the ",(0,r.yg)("inlineCode",{parentName:"p"},"https://")," prefix but this may change to ",(0,r.yg)("inlineCode",{parentName:"p"},"git@")," in the future)."),(0,r.yg)("h2",{id:"getting-the-code-and-documentation"},"Getting the Code and Documentation"),(0,r.yg)("p",null,"Clone the ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability"},"weaver-dlt-interoperability")," repository. The code to get a basic test network up and running and test data-sharing interoperation flows lies in the subfolder ",(0,r.yg)("inlineCode",{parentName:"p"},"tests/network-setups"),", which should be your starting point, though the setups will rely on other parts of the repository, as you will find out in the instructions given on this page."),(0,r.yg)("h2",{id:"common-structures"},"Common Structures"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"common/protos")," folder contains structure definitions in the protobuf format that are used by all the different components. The various ",(0,r.yg)("inlineCode",{parentName:"p"},"common/protos-*")," folders are meant to contain compiled protobufs (in different languages)."),(0,r.yg)("p",null,"To compile the protobufs for JavaScript, do the following:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"common/protos-js")," folder."),(0,r.yg)("li",{parentName:"ul"},"Run the following command:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make build\n")))),(0,r.yg)("p",null,"To compile the protobufs for Golang, do the following:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"common/protos-go")," folder."),(0,r.yg)("li",{parentName:"ul"},"Run the following command:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make build\n")))),(0,r.yg)("p",null,"To compile the protobufs for Java, do the following:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"common/protos-java-kt")," folder."),(0,r.yg)("li",{parentName:"ul"},"Run the following command:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make build\n")))),(0,r.yg)("p",null,"To compile the protobufs for Solidity, do the following:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"common/protos-sol")," folder."),(0,r.yg)("li",{parentName:"ul"},"Run the following command:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make build\n")))),(0,r.yg)("p",null,"To compile the protobufs for Rust, do the following:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"common/protos-rs")," folder."),(0,r.yg)("li",{parentName:"ul"},"Run the following command:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make build\n")))),(0,r.yg)("h2",{id:"securing-components"},"Securing Components"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:"left"},"The relays and drivers corresponding to the different test networks you will encounter below can be run with or without TLS enabled. But the default files used in the demonstrations assume that either all relays and drivers are TLS-enabled or none are. Therefore, you should determine at the outset whether or not you wish to run the entire set of components in TLS-enabled mode, and select appropriate commands in the provided instructions.")))),(0,r.yg)("h2",{id:"hyperledger-fabric-components"},"Hyperledger Fabric Components"),(0,r.yg)("p",null,"Using the sequence of instructions below, you can start two separate Fabric networks, each with a single channel and application contract (chaincode). You can also start an interoperation contract, a relay and a ",(0,r.yg)("em",{parentName:"p"},"driver")," acting on behalf of each network. You can build a Fabric CLI tool with which you can initialize both networks' ledgers with access control policies, foreign networks' security groups (i.e., membership providers' certificate chains), and some sample key-value pairs that can be shared during subsequent interoperation flows."),(0,r.yg)("h3",{id:"fabric-interoperation-node-sdk"},"Fabric Interoperation Node SDK"),(0,r.yg)("p",null,"A client-layer library (companion to ",(0,r.yg)("inlineCode",{parentName:"p"},"hyperledger/fabric-sdk-node"),") is defined in the ",(0,r.yg)("inlineCode",{parentName:"p"},"sdks/fabric/interoperation-node-sdk")," folder. This contains functions for Fabric Gateway-based applications to exercise interoperation capabilities via relays and also several utility/helper functions. The Fabric-CLI tool, which we will use later, depends on this library."),(0,r.yg)("p",null,"To build the library, do the following:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"sdks/fabric/interoperation-node-sdk")," folder."),(0,r.yg)("li",{parentName:"ul"},"Run the following command:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make build-local\n")))),(0,r.yg)("h3",{id:"fabric-network"},"Fabric Network"),(0,r.yg)("p",null,"The code for this lies in the ",(0,r.yg)("inlineCode",{parentName:"p"},"tests/network-setups")," folder."),(0,r.yg)("p",null,"This folder contains code to create and launch networks ",(0,r.yg)("inlineCode",{parentName:"p"},"network1")," and ",(0,r.yg)("inlineCode",{parentName:"p"},"network2")," of identical specifications:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Network: 1 peer, 1 peer CA, 1 ordering service node, 1 ordering service CA"),(0,r.yg)("li",{parentName:"ul"},"Single channel named ",(0,r.yg)("inlineCode",{parentName:"li"},"mychannel")),(0,r.yg)("li",{parentName:"ul"},"One of the following contracts deployed on ",(0,r.yg)("inlineCode",{parentName:"li"},"mychannel"),", the choice depending on the ",(0,r.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/interoperability-modes"},"interoperability mode")," you wish to test:",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"simplestate")," (",(0,r.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/data-sharing"},"Data Sharing"),"): supports simple transactions (",(0,r.yg)("inlineCode",{parentName:"li"},"Create"),", ",(0,r.yg)("inlineCode",{parentName:"li"},"Read"),", ",(0,r.yg)("inlineCode",{parentName:"li"},"Update"),", ",(0,r.yg)("inlineCode",{parentName:"li"},"Delete"),") involving storage and lookup of <key, value> pairs."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"simplestatewithacl")," (",(0,r.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/data-sharing"},"Data Sharing"),"): identical to ",(0,r.yg)("inlineCode",{parentName:"li"},"simplestate")," but with extra security features to ensure that the Weaver infrastructure cannot be bypassed by a malicious client of the network."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"simpleasset")," (",(0,r.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview"},"Asset Exchange"),"): supports creation, modification, transfer, and deletion, as well as locking, unlocking, and claiming, of simple bonds and tokens (examples of non-fungible and fungible assets respectively)."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"simpleassetandinterop")," (",(0,r.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview"},"Asset Exchange"),"): identical to ",(0,r.yg)("inlineCode",{parentName:"li"},"simpleasset")," but where the locking, unlocking, and claiming logic is imported as a library in the chaincode rather than available in the common Fabric Interoperation Chaincode (a Weaver component)."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"simpleassettransfer")," (",(0,r.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview"},"Asset Exchange")," or ",(0,r.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-transfer"},"Asset Transfer"),"): augmentation of ",(0,r.yg)("inlineCode",{parentName:"li"},"simpleasset")," with asset pledging, claiming, and reclaiming features for cross-network transfers.")))),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:"left"},"For new users, we recommend testing the Data Sharing feature first with the ",(0,r.yg)("inlineCode",{parentName:"td"},"simplestate")," contract. To test the other modes, you can simply ",(0,r.yg)("a",{parentName:"td",href:"#tear-down-the-setup"},"tear down")," the Fabric networks and restart them with the appropriate chaincodes installed.")))),(0,r.yg)("p",null,"Follow the instructions below to build and launch the networks:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"tests/network-setups/fabric/dev")," folder."),(0,r.yg)("li",{parentName:"ul"},"To spin up both network1 and network2 with the interoperation chaincode and the default ",(0,r.yg)("inlineCode",{parentName:"li"},"simplestate")," chaincode installed, run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make start-interop-local\n"))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("em",{parentName:"li"},"To launch the networks with a different application chaincode from the above list, run"),":",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make start-interop-local CHAINCODE_NAME=<chaincode-name>\n"))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("em",{parentName:"li"},"To launch the networks with 2 organizations, each with a peer (this will enable more variation and experimentation, which you can attempt after testing interoperation protocols across basic network configurations), run"),":",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},'make start-interop-local PROFILE="2-nodes"\n')))),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:"left"},"If you do not wish to test Fabric-Fabric interoperation, you can choose to launch only one of the two networks along with its interoperation chaincode. For ",(0,r.yg)("inlineCode",{parentName:"td"},"network1"),", run ",(0,r.yg)("inlineCode",{parentName:"td"},"make start-interop-network1-local"),", and for ",(0,r.yg)("inlineCode",{parentName:"td"},"network2"),", run ",(0,r.yg)("inlineCode",{parentName:"td"},"make start-interop-network2-local"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:"left"},"If you wish to enable end-to-end confidentiality by default in the interoperation modules that are deployed during network launch, set the environment variable ",(0,r.yg)("inlineCode",{parentName:"td"},"E2E_CONFIDENTIALITY")," to ",(0,r.yg)("inlineCode",{parentName:"td"},"true")," in the command line as follows: ",(0,r.yg)("inlineCode",{parentName:"td"},"E2E_CONFIDENTIALITY=true make start-interop-local"))))),(0,r.yg)("p",null,"For more information, refer to the associated ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/tests/network-setups/fabric/dev"},"README"),"."),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},"Troubleshooting Tips"),":"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"If you see any errors during the launches, re-check the prerequisites (software installations and credentials). Ensure your network connection is working. As a safe bet, you can retry after cleanup: kill and remove all Docker containers and associated volumes."),(0,r.yg)("li",{parentName:"ul"},"If ",(0,r.yg)("inlineCode",{parentName:"li"},"protoc")," or ",(0,r.yg)("inlineCode",{parentName:"li"},"protoc-gen-go")," throws an error, reinstall ",(0,r.yg)("inlineCode",{parentName:"li"},"protoc")," and ",(0,r.yg)("inlineCode",{parentName:"li"},"protoc-gen-go")," using suggestions made in the Prerequisites section above.")),(0,r.yg)("h3",{id:"fabric-relay"},"Fabric Relay"),(0,r.yg)("p",null,"The relay is a module acting on behalf of a network, enabling interoperation flows with other networks by communicating with their relays.\nThe code for this lies in the ",(0,r.yg)("inlineCode",{parentName:"p"},"core/relay")," folder. Navigate to the ",(0,r.yg)("inlineCode",{parentName:"p"},"core/relay")," folder."),(0,r.yg)("h4",{id:"building-relay-image"},"Building Relay Image"),(0,r.yg)("p",null,"To build the docker image for relay, run:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make build-server-local\n")),(0,r.yg)("h4",{id:"deployment"},"Deployment"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"The ",(0,r.yg)("inlineCode",{parentName:"li"},"docker-compose.yaml")," in this folder is minimally configured with default values. To modify it for use with the Fabric testnets, run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make convert-compose-method2\n"))),(0,r.yg)("li",{parentName:"ul"},"The ",(0,r.yg)("inlineCode",{parentName:"li"},".env.n1")," and ",(0,r.yg)("inlineCode",{parentName:"li"},".env.n1.tls")," files in the ",(0,r.yg)("inlineCode",{parentName:"li"},"docker/testnet-envs")," directory contain environment variables used by the ",(0,r.yg)("inlineCode",{parentName:"li"},"network1")," relay at startup and runtime. Edit either of these files (depending on whether you wish to start the relay with or without TLS), and update the following value:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre"},"DOCKER_IMAGE_NAME=weaver-relay-server\n"))),(0,r.yg)("li",{parentName:"ul"},"Repeat the above step for ",(0,r.yg)("inlineCode",{parentName:"li"},".env.n2")," or ",(0,r.yg)("inlineCode",{parentName:"li"},".env.n2.tls")," in ",(0,r.yg)("inlineCode",{parentName:"li"},"docker/testnet-envs")," directory, which contain environment variables for the ",(0,r.yg)("inlineCode",{parentName:"li"},"network2")," relay."),(0,r.yg)("li",{parentName:"ul"},"To deploy the relay server for ",(0,r.yg)("inlineCode",{parentName:"li"},"network1")," without TLS, run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.n1'\n")),"Instead, to deploy the relay server with TLS, run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.n1.tls'\n"))),(0,r.yg)("li",{parentName:"ul"},"To deploy the relay server for ",(0,r.yg)("inlineCode",{parentName:"li"},"network2")," without TLS, run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.n2'\n")),"Instead, to deploy the relay server with TLS, run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.n2.tls'\n"))),(0,r.yg)("li",{parentName:"ul"},"After launching the relay(s), you can revert the ",(0,r.yg)("inlineCode",{parentName:"li"},"docker-compose.yaml")," changes by running:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make convert-compose-method1\n")))),(0,r.yg)("p",null,"For more information, see the ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/core/relay/relay-docker.md"},"relay-docker README"),"."),(0,r.yg)("h3",{id:"fabric-driver"},"Fabric Driver"),(0,r.yg)("p",null,"A driver is a DLT-specific plugin invoked by the relay while channelling external data queries to the local peer network and collecting a response with proofs. The Fabric driver is built as a Fabric client application on the ",(0,r.yg)("inlineCode",{parentName:"p"},"fabric-network")," NPM package.\nThe code for this lies in the ",(0,r.yg)("inlineCode",{parentName:"p"},"core/drivers/fabric-driver")," folder. Navigate to the ",(0,r.yg)("inlineCode",{parentName:"p"},"core/drivers/fabric-driver")," folder."),(0,r.yg)("h4",{id:"building"},"Building"),(0,r.yg)("p",null,"To build the fabric-driver image, run:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make build-image-local\n")),(0,r.yg)("h4",{id:"deployment-1"},"Deployment"),(0,r.yg)("p",null,"Use the following steps to run Fabric drivers in Docker containers:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"The ",(0,r.yg)("inlineCode",{parentName:"li"},".env.n1")," and ",(0,r.yg)("inlineCode",{parentName:"li"},".env.n1.tls")," files in the ",(0,r.yg)("inlineCode",{parentName:"li"},"docker-testnet-envs")," directory contain environment variables used by the ",(0,r.yg)("inlineCode",{parentName:"li"},"network1")," driver at startup and runtime. Edit either of these files (depending on whether you wish to start the relay with or without TLS) as follows:",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},"Replace ",(0,r.yg)("inlineCode",{parentName:"li"},"<PATH-TO-WEAVER>")," with the absolute path of the ",(0,r.yg)("inlineCode",{parentName:"li"},"weaver-dlt-interoperability")," clone folder."),(0,r.yg)("li",{parentName:"ul"},"Update the following value:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre"},"DOCKER_IMAGE_NAME=weaver-fabric-driver\n"))))),(0,r.yg)("li",{parentName:"ul"},"Repeat the above steps for ",(0,r.yg)("inlineCode",{parentName:"li"},".env.n2")," or ",(0,r.yg)("inlineCode",{parentName:"li"},".env.n2.tls")," in ",(0,r.yg)("inlineCode",{parentName:"li"},"docker-testnet-envs")," directory, which contain environment variables for the ",(0,r.yg)("inlineCode",{parentName:"li"},"network2")," driver."),(0,r.yg)("li",{parentName:"ul"},"To deploy the Fabric driver for ",(0,r.yg)("inlineCode",{parentName:"li"},"network1")," without TLS, run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.n1' NETWORK_NAME=$(grep NETWORK_NAME docker-testnet-envs/.env.n1 | cut -d '=' -f 2)\n")),"Instead, to deploy the driver with TLS, run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.n1.tls' NETWORK_NAME=$(grep NETWORK_NAME docker-testnet-envs/.env.n1.tls | cut -d '=' -f 2)\n"))),(0,r.yg)("li",{parentName:"ul"},"To deploy the Fabric driver for ",(0,r.yg)("inlineCode",{parentName:"li"},"network2")," without TLS, run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.n2' NETWORK_NAME=$(grep NETWORK_NAME docker-testnet-envs/.env.n2 | cut -d '=' -f 2)\n")),"Instead, to deploy the driver with TLS, run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.n2.tls' NETWORK_NAME=$(grep NETWORK_NAME docker-testnet-envs/.env.n2.tls | cut -d '=' -f 2)\n")))),(0,r.yg)("h3",{id:"fabric-iin-agent"},"Fabric IIN Agent"),(0,r.yg)("p",null,"IIN Agent is a client of a member of a DLT network or security domain with special permissions to update security domain identities and configurations on the ledger via the network's interoperation module. The code for this lies in the ",(0,r.yg)("inlineCode",{parentName:"p"},"core/identity-management/iin-agent")," folder. Navigate to the ",(0,r.yg)("inlineCode",{parentName:"p"},"core/identity-management/iin-agent")," folder."),(0,r.yg)("h4",{id:"building-1"},"Building"),(0,r.yg)("p",null,"To build the IIN Agent image, run:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make build-image-local\n")),(0,r.yg)("h4",{id:"deployment-2"},"Deployment"),(0,r.yg)("p",null,"Use the following steps to run Fabric IIN Agents in Docker containers:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"The ",(0,r.yg)("inlineCode",{parentName:"li"},".env.n1.org1")," and ",(0,r.yg)("inlineCode",{parentName:"li"},".env.n1.org1.tls")," files in the ",(0,r.yg)("inlineCode",{parentName:"li"},"docker-testnet/envs")," directory contain environment variables used by the iin-agent of ",(0,r.yg)("inlineCode",{parentName:"li"},"org1")," of ",(0,r.yg)("inlineCode",{parentName:"li"},"network1")," at startup and runtime. Edit either of these files (depending on whether you wish to start the relay with or without TLS) as follows:",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},"Replace ",(0,r.yg)("inlineCode",{parentName:"li"},"<PATH-TO-WEAVER>")," with the absolute path of the ",(0,r.yg)("inlineCode",{parentName:"li"},"weaver-dlt-interoperability")," clone folder."),(0,r.yg)("li",{parentName:"ul"},"Update the following value:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre"},"DOCKER_IMAGE_NAME=weaver-iin-agent\n"))),(0,r.yg)("li",{parentName:"ul"},"If Fabric network was started with 1 org, and IIN Agents are to be started with TLS enabled, update the ",(0,r.yg)("inlineCode",{parentName:"li"},"DNS_CONFIG_PATH")," variable as:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre"},"DNS_CONFIG_PATH=./docker-testnet/configs/dnsconfig-tls.json\n"))),(0,r.yg)("li",{parentName:"ul"},"If Fabric network was started with 2 orgs, and IIN Agents are to be started without TLS, update the ",(0,r.yg)("inlineCode",{parentName:"li"},"DNS_CONFIG_PATH")," variable as",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre"},"DNS_CONFIG_PATH=./docker-testnet/configs/dnsconfig-2-nodes.json\n"))),(0,r.yg)("li",{parentName:"ul"},"If Fabric network was started with 2 orgs and IIN Agents are to be started with TLS enabled, update the ",(0,r.yg)("inlineCode",{parentName:"li"},"DNS_CONFIG_PATH")," variable as:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre"},"DNS_CONFIG_PATH=./docker-testnet/configs/dnsconfig-tls-2-nodes.json\n"))))),(0,r.yg)("li",{parentName:"ul"},"Repeat the above steps for all other environment variable files (depending upon whether tls is enabled) in ",(0,r.yg)("inlineCode",{parentName:"li"},"docker-testnet/envs")," directory."),(0,r.yg)("li",{parentName:"ul"},"To deploy the Fabric IIN Agent for ",(0,r.yg)("inlineCode",{parentName:"li"},"org1")," of ",(0,r.yg)("inlineCode",{parentName:"li"},"network1")," without TLS, run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n1.org1' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n1.org1 | cut -d '=' -f 2)\n")),"Instead, to deploy the IIN Agent with TLS, run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n1.org1.tls' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n1.org1.tls | cut -d '=' -f 2)\n"))),(0,r.yg)("li",{parentName:"ul"},"To deploy the Fabric IIN Agent for ",(0,r.yg)("inlineCode",{parentName:"li"},"org2")," of ",(0,r.yg)("inlineCode",{parentName:"li"},"network1")," without TLS (",(0,r.yg)("em",{parentName:"li"},"only required if Fabric network was started with 2 orgs"),"), run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n1.org2' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n1.org2 | cut -d '=' -f 2)\n")),"Instead, to deploy the IIN Agent with TLS, run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n1.org2.tls' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n1.org2.tls | cut -d '=' -f 2)\n"))),(0,r.yg)("li",{parentName:"ul"},"To deploy the Fabric IIN Agent for ",(0,r.yg)("inlineCode",{parentName:"li"},"org1")," of ",(0,r.yg)("inlineCode",{parentName:"li"},"network2")," without TLS, run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n2.org1' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n2.org1 | cut -d '=' -f 2)\n")),"Instead, to deploy the IIN Agent with TLS, run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n2.org1.tls' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n2.org1.tls | cut -d '=' -f 2)\n"))),(0,r.yg)("li",{parentName:"ul"},"To deploy the Fabric IIN Agent for ",(0,r.yg)("inlineCode",{parentName:"li"},"org2")," of ",(0,r.yg)("inlineCode",{parentName:"li"},"network2")," without TLS (",(0,r.yg)("em",{parentName:"li"},"only required if Fabric network was started with 2 orgs"),"), run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n2.org2' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n2.org2 | cut -d '=' -f 2)\n")),"Instead, to deploy the IIN Agent with TLS, run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n2.org2.tls' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n2.org2.tls | cut -d '=' -f 2)\n")))),(0,r.yg)("h3",{id:"fabric-client-application"},"Fabric Client (Application)"),(0,r.yg)("p",null,"The CLI is used to interact with a Fabric network, configure it and run chaincode transactions to record data on the channel ledger or query data. It is also used to interact with remote networks through the relay in order to trigger an interoperation flow for data request and acceptance."),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"fabric-cli")," Node.js source code is located in the ",(0,r.yg)("inlineCode",{parentName:"p"},"samples/fabric/fabric-cli")," folder and the Golang source code in the ",(0,r.yg)("inlineCode",{parentName:"p"},"samples/fabric/go-cli")," folder."),(0,r.yg)("h4",{id:"prerequisites-1"},"Prerequisites"),(0,r.yg)("p",null,"If you are using a Linux system, make sure that lib64 is installed."),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:"left"},"For the Node.js version of the ",(0,r.yg)("inlineCode",{parentName:"td"},"fabric-cli"),", the setup and running instructions below were tested with all Node.js versions from v11.14.0 to v14.17.3.")))),(0,r.yg)("h4",{id:"installation"},"Installation"),(0,r.yg)("p",null,"You can install ",(0,r.yg)("inlineCode",{parentName:"p"},"fabric-cli")," as follows (for both the Node.js and Golang versions):"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"samples/fabric/fabric-cli")," folder (for the Node.js version) or the ",(0,r.yg)("inlineCode",{parentName:"li"},"samples/fabric/go-cli")," folder (for the Golang version)."),(0,r.yg)("li",{parentName:"ul"},"Run the following to install dependencies (for the Node.js version) or the executable (for the Golang version):",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make build-local\n"))),(0,r.yg)("li",{parentName:"ul"},"Use the ",(0,r.yg)("inlineCode",{parentName:"li"},"fabric-cli")," executable in the ",(0,r.yg)("inlineCode",{parentName:"li"},"bin")," folder for ",(0,r.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/ledger-initialization"},"subsequent actions"),".")),(0,r.yg)("h2",{id:"corda-components"},"Corda Components"),(0,r.yg)("p",null,"Using the sequence of instructions below, you can start a Corda network and run an application CorDapp on it. You can also run an interoperation CorDapp, a relay and a ",(0,r.yg)("em",{parentName:"p"},"driver")," acting on behalf of the network. You can initialize the network's vault with access control policies, foreign networks' security groups (i.e., membership providers' certificate chains), and some sample state values that can be shared during subsequent interoperation flows."),(0,r.yg)("h3",{id:"interoperation-cordapp"},"Interoperation CorDapp"),(0,r.yg)("p",null,"The interoperation CorDapp is deployed to run as part of any Corda application flow that involves cross-network interoperation."),(0,r.yg)("p",null,"Build the interoperation CorDapp as follows:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"core/network/corda-interop-app")," folder."),(0,r.yg)("li",{parentName:"ul"},"Run the following to create the JAR files on which other Corda network components will depend on:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make build-local\n")))),(0,r.yg)("h3",{id:"corda-interoperation-sdk"},"Corda Interoperation SDK"),(0,r.yg)("p",null,"A client-layer library is defined in the ",(0,r.yg)("inlineCode",{parentName:"p"},"sdks/corda")," folder. This contains functions for Corda based client applications to exercise interoperation capabilities via relays and also several utility/helper functions. The Corda Client tool, which we will use later, depends on this library."),(0,r.yg)("p",null,"To build the library, do the following:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"sdks/corda")," folder."),(0,r.yg)("li",{parentName:"ul"},"Run the following command (",(0,r.yg)("em",{parentName:"li"},"make sure there is no github.properties file present in the directory"),"):",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make build\n")))),(0,r.yg)("h3",{id:"corda-simple-application-and-client-application"},"Corda Simple Application and Client (Application)"),(0,r.yg)("p",null,"This is a simple CorDapp that maintains a state of type ",(0,r.yg)("inlineCode",{parentName:"p"},"SimpleState"),", which is a set of key-value pairs (of strings).\nThe code for this lies in the ",(0,r.yg)("inlineCode",{parentName:"p"},"samples/corda/corda-simple-application")," folder."),(0,r.yg)("p",null,"Build the ",(0,r.yg)("inlineCode",{parentName:"p"},"corda-simple-application")," CorDapp as follows:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"samples/corda/corda-simple-application")," folder."),(0,r.yg)("li",{parentName:"ul"},"Run the following:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make build-local\n")))),(0,r.yg)("h3",{id:"corda-network"},"Corda Network"),(0,r.yg)("p",null,"The Corda networks' code lies in the ",(0,r.yg)("inlineCode",{parentName:"p"},"tests/network-setups/corda")," folder. You can launch two separate Corda networks, namely ",(0,r.yg)("inlineCode",{parentName:"p"},"Corda_Network")," and ",(0,r.yg)("inlineCode",{parentName:"p"},"Corda_Network2"),". Each network runs the ",(0,r.yg)("inlineCode",{parentName:"p"},"samples/corda/corda-simple-application")," CorDapp by default, which maintains a state named ",(0,r.yg)("inlineCode",{parentName:"p"},"SimpleState")," containing a set of key-value pairs (of strings)."),(0,r.yg)("p",null,"Follow the instructions below to build and launch both networks:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"tests/network-setups/corda")," folder."),(0,r.yg)("li",{parentName:"ul"},"To spin up the Corda networks with the Interoperation CorDapps:",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},"Each consisting of 1 node and a notary (for data-transfer), run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make start-local\n"))),(0,r.yg)("li",{parentName:"ul"},"Each consisting of 2 nodes and a notary (for asset-exchange/transfer), run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},'make start-local PROFILE="2-nodes"\n'))),(0,r.yg)("li",{parentName:"ul"},"Each consisting of 3 nodes and a notary (for asset-exchange/transfer), run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},'make start-local PROFILE="3-nodes"\n')))))),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:"left"},"If you do not wish to test Corda-Corda interoperation, you can choose to launch only one of the two networks along with its interoperation CorDapp. For ",(0,r.yg)("inlineCode",{parentName:"td"},"Corda_Network"),", run ",(0,r.yg)("inlineCode",{parentName:"td"},"make start-network1-local"),", and for ",(0,r.yg)("inlineCode",{parentName:"td"},"Corda_Network2"),", run ",(0,r.yg)("inlineCode",{parentName:"td"},"make start-network2-local"),".")))),(0,r.yg)("p",null,"You should see the following message in the terminal:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre"},"Waiting for network node services to start\n")),(0,r.yg)("p",null,"The Corda nodes and notary may take a while (several minutes on memory-constrained systems) to start. If they start up successfully, you should something like the following for each network, though the number of node entries will depend on the profile you used to start the network with (replace ",(0,r.yg)("inlineCode",{parentName:"p"},"<network-name>")," with ",(0,r.yg)("inlineCode",{parentName:"p"},"Corda_Network")," or ",(0,r.yg)("inlineCode",{parentName:"p"},"Corda_Network2"),"):"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"PartyA node services started for network <network-name>\nPartyB node services started for network <network-name>\nPartyC node services started for network <network-name>\nNotary node services started for network <network-name>\n")),(0,r.yg)("h3",{id:"corda-relay"},"Corda Relay"),(0,r.yg)("p",null,"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"p"},"core/relay")," folder. Refer ",(0,r.yg)("a",{parentName:"p",href:"#building-relay-image"},"here")," to build the relay image if not already built. Now run a relay for ",(0,r.yg)("inlineCode",{parentName:"p"},"Corda_Network")," and/or ",(0,r.yg)("inlineCode",{parentName:"p"},"Corda_Network2")," in Docker container as follows:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"The ",(0,r.yg)("inlineCode",{parentName:"li"},"docker-compose.yaml")," in this folder is minimally configured with default values. To modify it for use with the Fabric testnets, run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make convert-compose-method2\n"))),(0,r.yg)("li",{parentName:"ul"},"The ",(0,r.yg)("inlineCode",{parentName:"li"},".env.corda")," and ",(0,r.yg)("inlineCode",{parentName:"li"},".env.corda.tls")," files in the ",(0,r.yg)("inlineCode",{parentName:"li"},"docker/testnet-envs")," directory contain environment variables used by the ",(0,r.yg)("inlineCode",{parentName:"li"},"Corda_Network")," relay at startup and runtime. Edit either of these files (depending on whether you wish to start the relay with or without TLS), and update the following value:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre"},"DOCKER_IMAGE_NAME=weaver-relay-server\n"))),(0,r.yg)("li",{parentName:"ul"},"Repeat the above step for ",(0,r.yg)("inlineCode",{parentName:"li"},".env.corda2")," or ",(0,r.yg)("inlineCode",{parentName:"li"},".env.corda2.tls")," in ",(0,r.yg)("inlineCode",{parentName:"li"},"docker/testnet-envs")," directory, which contain environment variables for the ",(0,r.yg)("inlineCode",{parentName:"li"},"Corda_Network2")," relay."),(0,r.yg)("li",{parentName:"ul"},"To deploy the relay server for ",(0,r.yg)("inlineCode",{parentName:"li"},"Corda_Network")," without TLS, run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.corda'\n")),"Instead, to deploy the relay server with TLS, run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.corda.tls'\n"))),(0,r.yg)("li",{parentName:"ul"},"To deploy the relay server for ",(0,r.yg)("inlineCode",{parentName:"li"},"Corda_Network2")," without TLS, run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.corda2'\n")),"Instead, to deploy the relay server with TLS, run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.corda2.tls'\n"))),(0,r.yg)("li",{parentName:"ul"},"After launching the relay(s), you can revert the ",(0,r.yg)("inlineCode",{parentName:"li"},"docker-compose.yaml")," changes by running:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make convert-compose-method1\n")))),(0,r.yg)("h3",{id:"corda-driver"},"Corda Driver"),(0,r.yg)("p",null,"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"p"},"core/drivers/corda-driver")," folder."),(0,r.yg)("h4",{id:"building-2"},"Building"),(0,r.yg)("p",null,"To build the corda driver docker image, run:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make image-local\n")),(0,r.yg)("h4",{id:"deployment-3"},"Deployment"),(0,r.yg)("p",null,"Use the following steps to run Corda drivers in Docker containers:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"The ",(0,r.yg)("inlineCode",{parentName:"li"},".env.corda")," and ",(0,r.yg)("inlineCode",{parentName:"li"},".env.corda.tls")," files in the ",(0,r.yg)("inlineCode",{parentName:"li"},"docker-testnet-envs")," directory contain environment variables used by the ",(0,r.yg)("inlineCode",{parentName:"li"},"Corda_Network")," driver at startup and runtime. Edit either of these files (depending on whether you wish to start the relay with or without TLS) to update the following value:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre"},"DOCKER_IMAGE_NAME=weaver-corda-driver\n"))),(0,r.yg)("li",{parentName:"ul"},"Repeat the above steps for ",(0,r.yg)("inlineCode",{parentName:"li"},".env.corda2")," or ",(0,r.yg)("inlineCode",{parentName:"li"},".env.corda2.tls")," in ",(0,r.yg)("inlineCode",{parentName:"li"},"docker-testnet-envs")," directory, which contain environment variables for the ",(0,r.yg)("inlineCode",{parentName:"li"},"Corda_Network2")," driver.")),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"To deploy the Corda driver for ",(0,r.yg)("inlineCode",{parentName:"li"},"Corda_Network")," without TLS, run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.corda'\n")),"Instead, to deploy the driver with TLS, run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.corda.tls'\n")),"If the driver starts successfully, it should log the following message when you run ",(0,r.yg)("inlineCode",{parentName:"li"},"docker logs corda-driver-Corda_Network"),":",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre"},"Corda driver gRPC server started. Listening on port 9099\n"))),(0,r.yg)("li",{parentName:"ul"},"To deploy the Corda driver for ",(0,r.yg)("inlineCode",{parentName:"li"},"Corda_Network2")," without TLS, run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.corda2'\n")),"Instead, to deploy the driver with TLS, run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.corda2.tls'\n")),"If the driver starts successfully, it should log the following message when you run ",(0,r.yg)("inlineCode",{parentName:"li"},"docker logs corda-driver-Corda_Network2"),":",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre"},"Corda driver gRPC server started. Listening on port 9098\n")))),(0,r.yg)("h2",{id:"tear-down-the-setup"},"Tear Down the Setup"),(0,r.yg)("p",null,"Bring down the various components as follows (",(0,r.yg)("em",{parentName:"p"},"Navigate to the root folder of your clone of the Weaver repository"),"):"),(0,r.yg)("h3",{id:"relay"},"Relay"),(0,r.yg)("p",null,"To bring down the relays (for all 3 networks), run:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"cd core/relay\nmake convert-compose-method2\nmake stop COMPOSE_ARG='--env-file .env.n1'\nmake stop COMPOSE_ARG='--env-file .env.n2'\nmake stop COMPOSE_ARG='--env-file .env.corda'\nmake stop COMPOSE_ARG='--env-file .env.corda2'\nmake convert-compose-method1\ncd -\n")),(0,r.yg)("h3",{id:"fabric-driver-1"},"Fabric Driver"),(0,r.yg)("p",null,"To bring down the fabric drivers (for both networks), run:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"cd core/drivers/fabric-driver\nmake stop COMPOSE_ARG='--env-file .env.n1'\nmake stop COMPOSE_ARG='--env-file .env.n2'\ncd -\n")),(0,r.yg)("h3",{id:"corda-driver-1"},"Corda Driver"),(0,r.yg)("p",null,"To bring down the corda driver, run:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"cd core/drivers/corda-driver\nmake stop COMPOSE_ARG='--env-file docker-testnet-envs/.env.corda'\nmake stop COMPOSE_ARG='--env-file docker-testnet-envs/.env.corda2'\ncd -\n")),(0,r.yg)("h3",{id:"corda-network-1"},"Corda Network"),(0,r.yg)("p",null,"To bring down the Corda network:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"cd tests/network-setups/corda\nmake clean\ncd -\n")),(0,r.yg)("h3",{id:"fabric-network-1"},"Fabric Network"),(0,r.yg)("p",null,"To bring down both of the Fabric networks along with weaver components:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"cd tests/network-setups/fabric/dev\nmake clean\ncd -\n")))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/53c981a7.f1b2bca9.js b/assets/js/53c981a7.f1b2bca9.js deleted file mode 100644 index a46a69788..000000000 --- a/assets/js/53c981a7.f1b2bca9.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[3773],{3905:(e,t,a)=>{a.d(t,{Zo:()=>d,kt:()=>u});var n=a(7294);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function o(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function i(e){for(var t=1;t<arguments.length;t++){var a=null!=arguments[t]?arguments[t]:{};t%2?o(Object(a),!0).forEach((function(t){r(e,t,a[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(a)):o(Object(a)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(a,t))}))}return e}function l(e,t){if(null==e)return{};var a,n,r=function(e,t){if(null==e)return{};var a,n,r={},o=Object.keys(e);for(n=0;n<o.length;n++)a=o[n],t.indexOf(a)>=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n<o.length;n++)a=o[n],t.indexOf(a)>=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var s=n.createContext({}),p=function(e){var t=n.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},d=function(e){var t=p(e.components);return n.createElement(s.Provider,{value:t},e.children)},c="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},k=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,o=e.originalType,s=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),c=p(a),k=r,u=c["".concat(s,".").concat(k)]||c[k]||m[k]||o;return a?n.createElement(u,i(i({ref:t},d),{},{components:a})):n.createElement(u,i({ref:t},d))}));function u(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=a.length,i=new Array(o);i[0]=k;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:r,i[1]=l;for(var p=2;p<o;p++)i[p]=a[p];return n.createElement.apply(null,i)}return n.createElement.apply(null,a)}k.displayName="MDXCreateElement"},2281:(e,t,a)=>{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>m,frontMatter:()=>o,metadata:()=>l,toc:()=>p});var n=a(7462),r=(a(7294),a(3905));const o={id:"setup-local-docker",title:"Setup with Locally Built Dockerized Weaver Components",pagination_prev:"external/getting-started/test-network/overview",pagination_next:"external/getting-started/test-network/ledger-initialization"},i=void 0,l={unversionedId:"external/getting-started/test-network/setup-local-docker",id:"external/getting-started/test-network/setup-local-docker",title:"Setup with Locally Built Dockerized Weaver Components",description:"\x3c!--",source:"@site/docs/external/getting-started/test-network/setup-local-docker.md",sourceDirName:"external/getting-started/test-network",slug:"/external/getting-started/test-network/setup-local-docker",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-local-docker",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/getting-started/test-network/setup-local-docker.md",tags:[],version:"current",frontMatter:{id:"setup-local-docker",title:"Setup with Locally Built Dockerized Weaver Components",pagination_prev:"external/getting-started/test-network/overview",pagination_next:"external/getting-started/test-network/ledger-initialization"},sidebar:"Documentation",previous:{title:"Component Overview",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/overview"},next:{title:"Ledger Initialization",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/ledger-initialization"}},s={},p=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Software",id:"software",level:3},{value:"Credentials",id:"credentials",level:3},{value:"Getting the Code and Documentation",id:"getting-the-code-and-documentation",level:2},{value:"Common Structures",id:"common-structures",level:2},{value:"Securing Components",id:"securing-components",level:2},{value:"Hyperledger Fabric Components",id:"hyperledger-fabric-components",level:2},{value:"Fabric Interoperation Node SDK",id:"fabric-interoperation-node-sdk",level:3},{value:"Fabric Network",id:"fabric-network",level:3},{value:"Fabric Relay",id:"fabric-relay",level:3},{value:"Building Relay Image",id:"building-relay-image",level:4},{value:"Deployment",id:"deployment",level:4},{value:"Fabric Driver",id:"fabric-driver",level:3},{value:"Building",id:"building",level:4},{value:"Deployment",id:"deployment-1",level:4},{value:"Fabric IIN Agent",id:"fabric-iin-agent",level:3},{value:"Building",id:"building-1",level:4},{value:"Deployment",id:"deployment-2",level:4},{value:"Fabric Client (Application)",id:"fabric-client-application",level:3},{value:"Prerequisites",id:"prerequisites-1",level:4},{value:"Installation",id:"installation",level:4},{value:"Corda Components",id:"corda-components",level:2},{value:"Interoperation CorDapp",id:"interoperation-cordapp",level:3},{value:"Corda Interoperation SDK",id:"corda-interoperation-sdk",level:3},{value:"Corda Simple Application and Client (Application)",id:"corda-simple-application-and-client-application",level:3},{value:"Corda Network",id:"corda-network",level:3},{value:"Corda Relay",id:"corda-relay",level:3},{value:"Corda Driver",id:"corda-driver",level:3},{value:"Building",id:"building-2",level:4},{value:"Deployment",id:"deployment-3",level:4},{value:"Tear Down the Setup",id:"tear-down-the-setup",level:2},{value:"Relay",id:"relay",level:3},{value:"Fabric Driver",id:"fabric-driver-1",level:3},{value:"Corda Driver",id:"corda-driver-1",level:3},{value:"Corda Network",id:"corda-network-1",level:3},{value:"Fabric Network",id:"fabric-network-1",level:3}],d={toc:p},c="wrapper";function m(e){let{components:t,...a}=e;return(0,r.kt)(c,(0,n.Z)({},d,a,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"In this document, we detail the steps using which you can bring up networks using the default configuration settings and by fetching pre-built Weaver interoperation modules, SDK libraries, and relay docker image, drivers docker images from Github Package repositories. To customize these settings (e.g., hostnames, ports), refer to the ",(0,r.kt)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/advanced-configuration"},"Advanced Configuration page"),"."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:"left"},"All components are run within Docker containers, except client applications.")))),(0,r.kt)("p",null,"Follow the instructions below to build and run components followed by interoperation flows. These instructions have been tested on Ubuntu Linux (bash shell) and Mac OS. In general, they should work on any system and shell as long as the various dependencies have been installed and configured."),(0,r.kt)("h2",{id:"prerequisites"},"Prerequisites"),(0,r.kt)("h3",{id:"software"},"Software"),(0,r.kt)("p",null,"Before starting, make sure you have the following software installed on your host machine:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Curl: ",(0,r.kt)("em",{parentName:"li"},"install using package manager, like ",(0,r.kt)("inlineCode",{parentName:"em"},"apt")," on Debian/Ubuntu Linux")),(0,r.kt)("li",{parentName:"ul"},"Git: ",(0,r.kt)("a",{parentName:"li",href:"https://git-scm.com/book/en/v2/Getting-Started-Installing-Git"},"sample instructions")),(0,r.kt)("li",{parentName:"ul"},"Docker: ",(0,r.kt)("a",{parentName:"li",href:"https://docs.docker.com/engine/install/"},"sample instructions")," (Latest version)"),(0,r.kt)("li",{parentName:"ul"},"Docker-Compose: ",(0,r.kt)("a",{parentName:"li",href:"https://docs.docker.com/compose/install/"},"sample instructions")," (Version 1.28.2 or higher, but lower than version V2)"),(0,r.kt)("li",{parentName:"ul"},"Golang: ",(0,r.kt)("a",{parentName:"li",href:"https://golang.org/dl/"},"sample instructions")," (Version 1.16 or higher)"),(0,r.kt)("li",{parentName:"ul"},"Java (JDK and JRE): ",(0,r.kt)("a",{parentName:"li",href:"https://openjdk.java.net/install/"},"sample instructions")," (Version 8)"),(0,r.kt)("li",{parentName:"ul"},"Node.js and NPM: ",(0,r.kt)("a",{parentName:"li",href:"https://nodejs.org/en/download/package-manager/"},"sample instructions")," (Version 16 Supported)"),(0,r.kt)("li",{parentName:"ul"},"Yarn: ",(0,r.kt)("a",{parentName:"li",href:"https://classic.yarnpkg.com/en/docs/install/"},"sample instructions")),(0,r.kt)("li",{parentName:"ul"},"Protoc (Protobuf compiler): ",(0,r.kt)("em",{parentName:"li"},"Golang should already be installed and configured."),(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"Default method: Run the following with ",(0,r.kt)("inlineCode",{parentName:"li"},"sudo")," if necessary. This will install both the protobuf compiler and the Go code generator plugins.",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},"apt-get install protobuf-compiler\ngo install google.golang.org/protobuf/cmd/protoc-gen-go\ngo install google.golang.org/grpc/cmd/protoc-gen-go-grpc\n"))),(0,r.kt)("li",{parentName:"ul"},"If the above method installs an older version of ",(0,r.kt)("inlineCode",{parentName:"li"},"protoc")," (check using ",(0,r.kt)("inlineCode",{parentName:"li"},"protoc --version"),"), say below 3.12.x, you should download pre-compiled binaries instead. (With an older version, you may see errors while attempting to launch and setup the Fabric networks).",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},'sudo apt-get remove protobuf-compiler\ncurl -LO https://github.com/protocolbuffers/protobuf/releases/download/v3.15.6/protoc-3.15.6-linux-x86_64.zip\nsudo apt-get install unzip\nunzip protoc-3.15.6-linux-x86_64.zip -d <some-folder-path>\nexport PATH="$PATH:<some-folder-path>/bin"\ngo install google.golang.org/protobuf/cmd/protoc-gen-go\ngo install google.golang.org/grpc/cmd/protoc-gen-go-grpc\n')),(0,r.kt)("table",{parentName:"li"},(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:"left"},"The latest version at present is ",(0,r.kt)("inlineCode",{parentName:"td"},"3.15.6"),", but you should check the above link to find the most current version before running the above steps.")))))))),(0,r.kt)("h3",{id:"credentials"},"Credentials"),(0,r.kt)("p",null,"Make sure you have an SSH or GPG key registered in ",(0,r.kt)("a",{parentName:"p",href:"https://github.com"},"https://github.com")," to allow seamless cloning of repositories (at present, various setup scripts clone repositories using the ",(0,r.kt)("inlineCode",{parentName:"p"},"https://")," prefix but this may change to ",(0,r.kt)("inlineCode",{parentName:"p"},"git@")," in the future)."),(0,r.kt)("h2",{id:"getting-the-code-and-documentation"},"Getting the Code and Documentation"),(0,r.kt)("p",null,"Clone the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability"},"weaver-dlt-interoperability")," repository. The code to get a basic test network up and running and test data-sharing interoperation flows lies in the subfolder ",(0,r.kt)("inlineCode",{parentName:"p"},"tests/network-setups"),", which should be your starting point, though the setups will rely on other parts of the repository, as you will find out in the instructions given on this page."),(0,r.kt)("h2",{id:"common-structures"},"Common Structures"),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"common/protos")," folder contains structure definitions in the protobuf format that are used by all the different components. The various ",(0,r.kt)("inlineCode",{parentName:"p"},"common/protos-*")," folders are meant to contain compiled protobufs (in different languages)."),(0,r.kt)("p",null,"To compile the protobufs for JavaScript, do the following:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"common/protos-js")," folder."),(0,r.kt)("li",{parentName:"ul"},"Run the following command:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make build\n")))),(0,r.kt)("p",null,"To compile the protobufs for Golang, do the following:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"common/protos-go")," folder."),(0,r.kt)("li",{parentName:"ul"},"Run the following command:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make build\n")))),(0,r.kt)("p",null,"To compile the protobufs for Java, do the following:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"common/protos-java-kt")," folder."),(0,r.kt)("li",{parentName:"ul"},"Run the following command:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make build\n")))),(0,r.kt)("h2",{id:"securing-components"},"Securing Components"),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:"left"},"The relays and drivers corresponding to the different test networks you will encounter below can be run with or without TLS enabled. But the default files used in the demonstrations assume that either all relays and drivers are TLS-enabled or none are. Therefore, you should determine at the outset whether or not you wish to run the entire set of components in TLS-enabled mode, and select appropriate commands in the provided instructions.")))),(0,r.kt)("h2",{id:"hyperledger-fabric-components"},"Hyperledger Fabric Components"),(0,r.kt)("p",null,"Using the sequence of instructions below, you can start two separate Fabric networks, each with a single channel and application contract (chaincode). You can also start an interoperation contract, a relay and a ",(0,r.kt)("em",{parentName:"p"},"driver")," acting on behalf of each network. You can build a Fabric CLI tool with which you can initialize both networks' ledgers with access control policies, foreign networks' security groups (i.e., membership providers' certificate chains), and some sample key-value pairs that can be shared during subsequent interoperation flows."),(0,r.kt)("h3",{id:"fabric-interoperation-node-sdk"},"Fabric Interoperation Node SDK"),(0,r.kt)("p",null,"A client-layer library (companion to ",(0,r.kt)("inlineCode",{parentName:"p"},"hyperledger/fabric-sdk-node"),") is defined in the ",(0,r.kt)("inlineCode",{parentName:"p"},"sdks/fabric/interoperation-node-sdk")," folder. This contains functions for Fabric Gateway-based applications to exercise interoperation capabilities via relays and also several utility/helper functions. The Fabric-CLI tool, which we will use later, depends on this library."),(0,r.kt)("p",null,"To build the library, do the following:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"sdks/fabric/interoperation-node-sdk")," folder."),(0,r.kt)("li",{parentName:"ul"},"Run the following command:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make build-local\n")))),(0,r.kt)("h3",{id:"fabric-network"},"Fabric Network"),(0,r.kt)("p",null,"The code for this lies in the ",(0,r.kt)("inlineCode",{parentName:"p"},"tests/network-setups")," folder."),(0,r.kt)("p",null,"This folder contains code to create and launch networks ",(0,r.kt)("inlineCode",{parentName:"p"},"network1")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"network2")," of identical specifications:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Network: 1 peer, 1 peer CA, 1 ordering service node, 1 ordering service CA"),(0,r.kt)("li",{parentName:"ul"},"Single channel named ",(0,r.kt)("inlineCode",{parentName:"li"},"mychannel")),(0,r.kt)("li",{parentName:"ul"},"One of the following contracts deployed on ",(0,r.kt)("inlineCode",{parentName:"li"},"mychannel"),", the choice depending on the ",(0,r.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/interoperability-modes"},"interoperability mode")," you wish to test:",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"simplestate")," (",(0,r.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/data-sharing"},"Data Sharing"),"): supports simple transactions (",(0,r.kt)("inlineCode",{parentName:"li"},"Create"),", ",(0,r.kt)("inlineCode",{parentName:"li"},"Read"),", ",(0,r.kt)("inlineCode",{parentName:"li"},"Update"),", ",(0,r.kt)("inlineCode",{parentName:"li"},"Delete"),") involving storage and lookup of <key, value> pairs."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"simplestatewithacl")," (",(0,r.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/data-sharing"},"Data Sharing"),"): identical to ",(0,r.kt)("inlineCode",{parentName:"li"},"simplestate")," but with extra security features to ensure that the Weaver infrastructure cannot be bypassed by a malicious client of the network."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"simpleasset")," (",(0,r.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview"},"Asset Exchange"),"): supports creation, modification, transfer, and deletion, as well as locking, unlocking, and claiming, of simple bonds and tokens (examples of non-fungible and fungible assets respectively)."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"simpleassetandinterop")," (",(0,r.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview"},"Asset Exchange"),"): identical to ",(0,r.kt)("inlineCode",{parentName:"li"},"simpleasset")," but where the locking, unlocking, and claiming logic is imported as a library in the chaincode rather than available in the common Fabric Interoperation Chaincode (a Weaver component)."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"simpleassettransfer")," (",(0,r.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview"},"Asset Exchange")," or ",(0,r.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-transfer"},"Asset Transfer"),"): augmentation of ",(0,r.kt)("inlineCode",{parentName:"li"},"simpleasset")," with asset pledging, claiming, and reclaiming features for cross-network transfers.")))),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:"left"},"For new users, we recommend testing the Data Sharing feature first with the ",(0,r.kt)("inlineCode",{parentName:"td"},"simplestate")," contract. To test the other modes, you can simply ",(0,r.kt)("a",{parentName:"td",href:"#tear-down-the-setup"},"tear down")," the Fabric networks and restart them with the appropriate chaincodes installed.")))),(0,r.kt)("p",null,"Follow the instructions below to build and launch the networks:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"tests/network-setups/fabric/dev")," folder."),(0,r.kt)("li",{parentName:"ul"},"To spin up both network1 and network2 with the interoperation chaincode and the default ",(0,r.kt)("inlineCode",{parentName:"li"},"simplestate")," chaincode installed, run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make start-interop-local\n"))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("em",{parentName:"li"},"To launch the networks with a different application chaincode from the above list, run"),":",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make start-interop-local CHAINCODE_NAME=<chaincode-name>\n"))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("em",{parentName:"li"},"To launch the networks with 2 organizations, each with a peer (this will enable more variation and experimentation, which you can attempt after testing interoperation protocols across basic network configurations), run"),":",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'make start-interop-local PROFILE="2-nodes"\n')))),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:"left"},"If you do not wish to test Fabric-Fabric interoperation, you can choose to launch only one of the two networks along with its interoperation chaincode. For ",(0,r.kt)("inlineCode",{parentName:"td"},"network1"),", run ",(0,r.kt)("inlineCode",{parentName:"td"},"make start-interop-network1-local"),", and for ",(0,r.kt)("inlineCode",{parentName:"td"},"network2"),", run ",(0,r.kt)("inlineCode",{parentName:"td"},"make start-interop-network2-local"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:"left"},"If you wish to enable end-to-end confidentiality by default in the interoperation modules that are deployed during network launch, set the environment variable ",(0,r.kt)("inlineCode",{parentName:"td"},"E2E_CONFIDENTIALITY")," to ",(0,r.kt)("inlineCode",{parentName:"td"},"true")," in the command line as follows: ",(0,r.kt)("inlineCode",{parentName:"td"},"E2E_CONFIDENTIALITY=true make start-interop-local"))))),(0,r.kt)("p",null,"For more information, refer to the associated ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/tests/network-setups/fabric/dev"},"README"),"."),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Troubleshooting Tips"),":"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"If you see any errors during the launches, re-check the prerequisites (software installations and credentials). Ensure your network connection is working. As a safe bet, you can retry after cleanup: kill and remove all Docker containers and associated volumes."),(0,r.kt)("li",{parentName:"ul"},"If ",(0,r.kt)("inlineCode",{parentName:"li"},"protoc")," or ",(0,r.kt)("inlineCode",{parentName:"li"},"protoc-gen-go")," throws an error, reinstall ",(0,r.kt)("inlineCode",{parentName:"li"},"protoc")," and ",(0,r.kt)("inlineCode",{parentName:"li"},"protoc-gen-go")," using suggestions made in the Prerequisites section above.")),(0,r.kt)("h3",{id:"fabric-relay"},"Fabric Relay"),(0,r.kt)("p",null,"The relay is a module acting on behalf of a network, enabling interoperation flows with other networks by communicating with their relays.\nThe code for this lies in the ",(0,r.kt)("inlineCode",{parentName:"p"},"core/relay")," folder. Navigate to the ",(0,r.kt)("inlineCode",{parentName:"p"},"core/relay")," folder."),(0,r.kt)("h4",{id:"building-relay-image"},"Building Relay Image"),(0,r.kt)("p",null,"To build the docker image for relay, run:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make build-server-local\n")),(0,r.kt)("h4",{id:"deployment"},"Deployment"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"The ",(0,r.kt)("inlineCode",{parentName:"li"},"docker-compose.yaml")," in this folder is minimally configured with default values. To modify it for use with the Fabric testnets, run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make convert-compose-method2\n"))),(0,r.kt)("li",{parentName:"ul"},"The ",(0,r.kt)("inlineCode",{parentName:"li"},".env.n1")," and ",(0,r.kt)("inlineCode",{parentName:"li"},".env.n1.tls")," files in the ",(0,r.kt)("inlineCode",{parentName:"li"},"docker/testnet-envs")," directory contain environment variables used by the ",(0,r.kt)("inlineCode",{parentName:"li"},"network1")," relay at startup and runtime. Edit either of these files (depending on whether you wish to start the relay with or without TLS), and update the following value:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},"DOCKER_IMAGE_NAME=weaver-relay-server\n"))),(0,r.kt)("li",{parentName:"ul"},"Repeat the above step for ",(0,r.kt)("inlineCode",{parentName:"li"},".env.n2")," or ",(0,r.kt)("inlineCode",{parentName:"li"},".env.n2.tls")," in ",(0,r.kt)("inlineCode",{parentName:"li"},"docker/testnet-envs")," directory, which contain environment variables for the ",(0,r.kt)("inlineCode",{parentName:"li"},"network2")," relay."),(0,r.kt)("li",{parentName:"ul"},"To deploy the relay server for ",(0,r.kt)("inlineCode",{parentName:"li"},"network1")," without TLS, run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.n1'\n")),"Instead, to deploy the relay server with TLS, run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.n1.tls'\n"))),(0,r.kt)("li",{parentName:"ul"},"To deploy the relay server for ",(0,r.kt)("inlineCode",{parentName:"li"},"network2")," without TLS, run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.n2'\n")),"Instead, to deploy the relay server with TLS, run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.n2.tls'\n"))),(0,r.kt)("li",{parentName:"ul"},"After launching the relay(s), you can revert the ",(0,r.kt)("inlineCode",{parentName:"li"},"docker-compose.yaml")," changes by running:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make convert-compose-method1\n")))),(0,r.kt)("p",null,"For more information, see the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/core/relay/relay-docker.md"},"relay-docker README"),"."),(0,r.kt)("h3",{id:"fabric-driver"},"Fabric Driver"),(0,r.kt)("p",null,"A driver is a DLT-specific plugin invoked by the relay while channelling external data queries to the local peer network and collecting a response with proofs. The Fabric driver is built as a Fabric client application on the ",(0,r.kt)("inlineCode",{parentName:"p"},"fabric-network")," NPM package.\nThe code for this lies in the ",(0,r.kt)("inlineCode",{parentName:"p"},"core/drivers/fabric-driver")," folder. Navigate to the ",(0,r.kt)("inlineCode",{parentName:"p"},"core/drivers/fabric-driver")," folder."),(0,r.kt)("h4",{id:"building"},"Building"),(0,r.kt)("p",null,"To build the fabric-driver image, run:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make build-image-local\n")),(0,r.kt)("h4",{id:"deployment-1"},"Deployment"),(0,r.kt)("p",null,"Use the following steps to run Fabric drivers in Docker containers:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"The ",(0,r.kt)("inlineCode",{parentName:"li"},".env.n1")," and ",(0,r.kt)("inlineCode",{parentName:"li"},".env.n1.tls")," files in the ",(0,r.kt)("inlineCode",{parentName:"li"},"docker-testnet-envs")," directory contain environment variables used by the ",(0,r.kt)("inlineCode",{parentName:"li"},"network1")," driver at startup and runtime. Edit either of these files (depending on whether you wish to start the relay with or without TLS) as follows:",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"Replace ",(0,r.kt)("inlineCode",{parentName:"li"},"<PATH-TO-WEAVER>")," with the absolute path of the ",(0,r.kt)("inlineCode",{parentName:"li"},"weaver-dlt-interoperability")," clone folder."),(0,r.kt)("li",{parentName:"ul"},"Update the following value:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},"DOCKER_IMAGE_NAME=weaver-fabric-driver\n"))))),(0,r.kt)("li",{parentName:"ul"},"Repeat the above steps for ",(0,r.kt)("inlineCode",{parentName:"li"},".env.n2")," or ",(0,r.kt)("inlineCode",{parentName:"li"},".env.n2.tls")," in ",(0,r.kt)("inlineCode",{parentName:"li"},"docker-testnet-envs")," directory, which contain environment variables for the ",(0,r.kt)("inlineCode",{parentName:"li"},"network2")," driver."),(0,r.kt)("li",{parentName:"ul"},"To deploy the Fabric driver for ",(0,r.kt)("inlineCode",{parentName:"li"},"network1")," without TLS, run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.n1' NETWORK_NAME=$(grep NETWORK_NAME docker-testnet-envs/.env.n1 | cut -d '=' -f 2)\n")),"Instead, to deploy the driver with TLS, run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.n1.tls' NETWORK_NAME=$(grep NETWORK_NAME docker-testnet-envs/.env.n1.tls | cut -d '=' -f 2)\n"))),(0,r.kt)("li",{parentName:"ul"},"To deploy the Fabric driver for ",(0,r.kt)("inlineCode",{parentName:"li"},"network2")," without TLS, run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.n2' NETWORK_NAME=$(grep NETWORK_NAME docker-testnet-envs/.env.n2 | cut -d '=' -f 2)\n")),"Instead, to deploy the driver with TLS, run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.n2.tls' NETWORK_NAME=$(grep NETWORK_NAME docker-testnet-envs/.env.n2.tls | cut -d '=' -f 2)\n")))),(0,r.kt)("h3",{id:"fabric-iin-agent"},"Fabric IIN Agent"),(0,r.kt)("p",null,"IIN Agent is a client of a member of a DLT network or security domain with special permissions to update security domain identities and configurations on the ledger via the network's interoperation module. The code for this lies in the ",(0,r.kt)("inlineCode",{parentName:"p"},"core/identity-management/iin-agent")," folder. Navigate to the ",(0,r.kt)("inlineCode",{parentName:"p"},"core/identity-management/iin-agent")," folder."),(0,r.kt)("h4",{id:"building-1"},"Building"),(0,r.kt)("p",null,"To build the IIN Agent image, run:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make build-image-local\n")),(0,r.kt)("h4",{id:"deployment-2"},"Deployment"),(0,r.kt)("p",null,"Use the following steps to run Fabric IIN Agents in Docker containers:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"The ",(0,r.kt)("inlineCode",{parentName:"li"},".env.n1.org1")," and ",(0,r.kt)("inlineCode",{parentName:"li"},".env.n1.org1.tls")," files in the ",(0,r.kt)("inlineCode",{parentName:"li"},"docker-testnet/envs")," directory contain environment variables used by the iin-agent of ",(0,r.kt)("inlineCode",{parentName:"li"},"org1")," of ",(0,r.kt)("inlineCode",{parentName:"li"},"network1")," at startup and runtime. Edit either of these files (depending on whether you wish to start the relay with or without TLS) as follows:",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"Replace ",(0,r.kt)("inlineCode",{parentName:"li"},"<PATH-TO-WEAVER>")," with the absolute path of the ",(0,r.kt)("inlineCode",{parentName:"li"},"weaver-dlt-interoperability")," clone folder."),(0,r.kt)("li",{parentName:"ul"},"Update the following value:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},"DOCKER_IMAGE_NAME=weaver-iin-agent\n"))),(0,r.kt)("li",{parentName:"ul"},"If Fabric network was started with 1 org, and IIN Agents are to be started with TLS enabled, update the ",(0,r.kt)("inlineCode",{parentName:"li"},"DNS_CONFIG_PATH")," variable as:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},"DNS_CONFIG_PATH=./docker-testnet/configs/dnsconfig-tls.json\n"))),(0,r.kt)("li",{parentName:"ul"},"If Fabric network was started with 2 orgs, and IIN Agents are to be started without TLS, update the ",(0,r.kt)("inlineCode",{parentName:"li"},"DNS_CONFIG_PATH")," variable as",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},"DNS_CONFIG_PATH=./docker-testnet/configs/dnsconfig-2-nodes.json\n"))),(0,r.kt)("li",{parentName:"ul"},"If Fabric network was started with 2 orgs and IIN Agents are to be started with TLS enabled, update the ",(0,r.kt)("inlineCode",{parentName:"li"},"DNS_CONFIG_PATH")," variable as:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},"DNS_CONFIG_PATH=./docker-testnet/configs/dnsconfig-tls-2-nodes.json\n"))))),(0,r.kt)("li",{parentName:"ul"},"Repeat the above steps for all other environment variable files (depending upon whether tls is enabled) in ",(0,r.kt)("inlineCode",{parentName:"li"},"docker-testnet/envs")," directory."),(0,r.kt)("li",{parentName:"ul"},"To deploy the Fabric IIN Agent for ",(0,r.kt)("inlineCode",{parentName:"li"},"org1")," of ",(0,r.kt)("inlineCode",{parentName:"li"},"network1")," without TLS, run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n1.org1' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n1.org1 | cut -d '=' -f 2)\n")),"Instead, to deploy the IIN Agent with TLS, run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n1.org1.tls' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n1.org1.tls | cut -d '=' -f 2)\n"))),(0,r.kt)("li",{parentName:"ul"},"To deploy the Fabric IIN Agent for ",(0,r.kt)("inlineCode",{parentName:"li"},"org2")," of ",(0,r.kt)("inlineCode",{parentName:"li"},"network1")," without TLS (",(0,r.kt)("em",{parentName:"li"},"only required if Fabric network was started with 2 orgs"),"), run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n1.org2' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n1.org2 | cut -d '=' -f 2)\n")),"Instead, to deploy the IIN Agent with TLS, run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n1.org2.tls' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n1.org2.tls | cut -d '=' -f 2)\n"))),(0,r.kt)("li",{parentName:"ul"},"To deploy the Fabric IIN Agent for ",(0,r.kt)("inlineCode",{parentName:"li"},"org1")," of ",(0,r.kt)("inlineCode",{parentName:"li"},"network2")," without TLS, run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n2.org1' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n2.org1 | cut -d '=' -f 2)\n")),"Instead, to deploy the IIN Agent with TLS, run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n2.org1.tls' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n2.org1.tls | cut -d '=' -f 2)\n"))),(0,r.kt)("li",{parentName:"ul"},"To deploy the Fabric IIN Agent for ",(0,r.kt)("inlineCode",{parentName:"li"},"org2")," of ",(0,r.kt)("inlineCode",{parentName:"li"},"network2")," without TLS (",(0,r.kt)("em",{parentName:"li"},"only required if Fabric network was started with 2 orgs"),"), run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n2.org2' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n2.org2 | cut -d '=' -f 2)\n")),"Instead, to deploy the IIN Agent with TLS, run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n2.org2.tls' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n2.org2.tls | cut -d '=' -f 2)\n")))),(0,r.kt)("h3",{id:"fabric-client-application"},"Fabric Client (Application)"),(0,r.kt)("p",null,"The CLI is used to interact with a Fabric network, configure it and run chaincode transactions to record data on the channel ledger or query data. It is also used to interact with remote networks through the relay in order to trigger an interoperation flow for data request and acceptance."),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"fabric-cli")," Node.js source code is located in the ",(0,r.kt)("inlineCode",{parentName:"p"},"samples/fabric/fabric-cli")," folder and the Golang source code in the ",(0,r.kt)("inlineCode",{parentName:"p"},"samples/fabric/go-cli")," folder."),(0,r.kt)("h4",{id:"prerequisites-1"},"Prerequisites"),(0,r.kt)("p",null,"If you are using a Linux system, make sure that lib64 is installed."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:"left"},"For the Node.js version of the ",(0,r.kt)("inlineCode",{parentName:"td"},"fabric-cli"),", the setup and running instructions below were tested with all Node.js versions from v11.14.0 to v14.17.3.")))),(0,r.kt)("h4",{id:"installation"},"Installation"),(0,r.kt)("p",null,"You can install ",(0,r.kt)("inlineCode",{parentName:"p"},"fabric-cli")," as follows (for both the Node.js and Golang versions):"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"samples/fabric/fabric-cli")," folder or the ",(0,r.kt)("inlineCode",{parentName:"li"},"samples/fabric/go-cli")," folder."),(0,r.kt)("li",{parentName:"ul"},"Run the following to install dependencies (for the Node.js version) or the executable (for the Golang version):",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make build-local\n"))),(0,r.kt)("li",{parentName:"ul"},"Use the ",(0,r.kt)("inlineCode",{parentName:"li"},"fabric-cli")," executable in the ",(0,r.kt)("inlineCode",{parentName:"li"},"bin")," folder for ",(0,r.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/ledger-initialization"},"subsequent actions"),".")),(0,r.kt)("h2",{id:"corda-components"},"Corda Components"),(0,r.kt)("p",null,"Using the sequence of instructions below, you can start a Corda network and run an application CorDapp on it. You can also run an interoperation CorDapp, a relay and a ",(0,r.kt)("em",{parentName:"p"},"driver")," acting on behalf of the network. You can initialize the network's vault with access control policies, foreign networks' security groups (i.e., membership providers' certificate chains), and some sample state values that can be shared during subsequent interoperation flows."),(0,r.kt)("h3",{id:"interoperation-cordapp"},"Interoperation CorDapp"),(0,r.kt)("p",null,"The interoperation CorDapp is deployed to run as part of any Corda application flow that involves cross-network interoperation."),(0,r.kt)("p",null,"Build the interoperation CorDapp as follows:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"core/network/corda-interop-app")," folder."),(0,r.kt)("li",{parentName:"ul"},"Run the following to create the JAR files on which other Corda network components will depend on:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make build-local\n")))),(0,r.kt)("h3",{id:"corda-interoperation-sdk"},"Corda Interoperation SDK"),(0,r.kt)("p",null,"A client-layer library is defined in the ",(0,r.kt)("inlineCode",{parentName:"p"},"sdks/corda")," folder. This contains functions for Corda based client applications to exercise interoperation capabilities via relays and also several utility/helper functions. The Corda Client tool, which we will use later, depends on this library."),(0,r.kt)("p",null,"To build the library, do the following:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"sdks/corda")," folder."),(0,r.kt)("li",{parentName:"ul"},"Run the following command (",(0,r.kt)("em",{parentName:"li"},"make sure there is no github.properties file present in the directory"),"):",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make build\n")))),(0,r.kt)("h3",{id:"corda-simple-application-and-client-application"},"Corda Simple Application and Client (Application)"),(0,r.kt)("p",null,"This is a simple CorDapp that maintains a state of type ",(0,r.kt)("inlineCode",{parentName:"p"},"SimpleState"),", which is a set of key-value pairs (of strings).\nThe code for this lies in the ",(0,r.kt)("inlineCode",{parentName:"p"},"samples/corda/corda-simple-application")," folder."),(0,r.kt)("p",null,"Build the ",(0,r.kt)("inlineCode",{parentName:"p"},"corda-simple-application")," CorDapp as follows:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"samples/corda/corda-simple-application")," folder."),(0,r.kt)("li",{parentName:"ul"},"Run the following:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make build-local\n")))),(0,r.kt)("h3",{id:"corda-network"},"Corda Network"),(0,r.kt)("p",null,"The Corda networks' code lies in the ",(0,r.kt)("inlineCode",{parentName:"p"},"tests/network-setups/corda")," folder. You can launch two separate Corda networks, namely ",(0,r.kt)("inlineCode",{parentName:"p"},"Corda_Network")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"Corda_Network2"),". Each network runs the ",(0,r.kt)("inlineCode",{parentName:"p"},"samples/corda/corda-simple-application")," CorDapp by default, which maintains a state named ",(0,r.kt)("inlineCode",{parentName:"p"},"SimpleState")," containing a set of key-value pairs (of strings)."),(0,r.kt)("p",null,"Follow the instructions below to build and launch both networks:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"tests/network-setups/corda")," folder."),(0,r.kt)("li",{parentName:"ul"},"To spin up the Corda networks with the Interoperation CorDapps:",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"Each consisting of 1 node and a notary (for data-transfer), run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make start-local\n"))),(0,r.kt)("li",{parentName:"ul"},"Each consisting of 2 nodes and a notary (for asset-exchange/transfer), run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'make start-local PROFILE="2-nodes"\n'))),(0,r.kt)("li",{parentName:"ul"},"Each consisting of 3 nodes and a notary (for asset-exchange/transfer), run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'make start-local PROFILE="3-nodes"\n')))))),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:"left"},"If you do not wish to test Corda-Corda interoperation, you can choose to launch only one of the two networks along with its interoperation CorDapp. For ",(0,r.kt)("inlineCode",{parentName:"td"},"Corda_Network"),", run ",(0,r.kt)("inlineCode",{parentName:"td"},"make start-network1-local"),", and for ",(0,r.kt)("inlineCode",{parentName:"td"},"Corda_Network2"),", run ",(0,r.kt)("inlineCode",{parentName:"td"},"make start-network2-local"),".")))),(0,r.kt)("p",null,"You should see the following message in the terminal:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"Waiting for network node services to start\n")),(0,r.kt)("p",null,"The Corda nodes and notary may take a while (several minutes on memory-constrained systems) to start. If they start up successfully, you should something like the following for each network, though the number of node entries will depend on the profile you used to start the network with (replace ",(0,r.kt)("inlineCode",{parentName:"p"},"<network-name>")," with ",(0,r.kt)("inlineCode",{parentName:"p"},"Corda_Network")," or ",(0,r.kt)("inlineCode",{parentName:"p"},"Corda_Network2"),"):"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"PartyA node services started for network <network-name>\nPartyB node services started for network <network-name>\nPartyC node services started for network <network-name>\nNotary node services started for network <network-name>\n")),(0,r.kt)("h3",{id:"corda-relay"},"Corda Relay"),(0,r.kt)("p",null,"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"p"},"core/relay")," folder. Refer ",(0,r.kt)("a",{parentName:"p",href:"#building-relay-image"},"here")," to build the relay image if not already built. Now run a relay for ",(0,r.kt)("inlineCode",{parentName:"p"},"Corda_Network")," and/or ",(0,r.kt)("inlineCode",{parentName:"p"},"Corda_Network2")," in Docker container as follows:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"The ",(0,r.kt)("inlineCode",{parentName:"li"},"docker-compose.yaml")," in this folder is minimally configured with default values. To modify it for use with the Fabric testnets, run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make convert-compose-method2\n"))),(0,r.kt)("li",{parentName:"ul"},"The ",(0,r.kt)("inlineCode",{parentName:"li"},".env.corda")," and ",(0,r.kt)("inlineCode",{parentName:"li"},".env.corda.tls")," files in the ",(0,r.kt)("inlineCode",{parentName:"li"},"docker/testnet-envs")," directory contain environment variables used by the ",(0,r.kt)("inlineCode",{parentName:"li"},"Corda_Network")," relay at startup and runtime. Edit either of these files (depending on whether you wish to start the relay with or without TLS), and update the following value:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},"DOCKER_IMAGE_NAME=weaver-relay-server\n"))),(0,r.kt)("li",{parentName:"ul"},"Repeat the above step for ",(0,r.kt)("inlineCode",{parentName:"li"},".env.corda2")," or ",(0,r.kt)("inlineCode",{parentName:"li"},".env.corda2.tls")," in ",(0,r.kt)("inlineCode",{parentName:"li"},"docker/testnet-envs")," directory, which contain environment variables for the ",(0,r.kt)("inlineCode",{parentName:"li"},"Corda_Network2")," relay."),(0,r.kt)("li",{parentName:"ul"},"To deploy the relay server for ",(0,r.kt)("inlineCode",{parentName:"li"},"Corda_Network")," without TLS, run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.corda'\n")),"Instead, to deploy the relay server with TLS, run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.corda.tls'\n"))),(0,r.kt)("li",{parentName:"ul"},"To deploy the relay server for ",(0,r.kt)("inlineCode",{parentName:"li"},"Corda_Network2")," without TLS, run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.corda2'\n")),"Instead, to deploy the relay server with TLS, run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.corda2.tls'\n"))),(0,r.kt)("li",{parentName:"ul"},"After launching the relay(s), you can revert the ",(0,r.kt)("inlineCode",{parentName:"li"},"docker-compose.yaml")," changes by running:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make convert-compose-method1\n")))),(0,r.kt)("h3",{id:"corda-driver"},"Corda Driver"),(0,r.kt)("p",null,"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"p"},"core/drivers/corda-driver")," folder."),(0,r.kt)("h4",{id:"building-2"},"Building"),(0,r.kt)("p",null,"To build the corda driver docker image, run:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make image-local\n")),(0,r.kt)("h4",{id:"deployment-3"},"Deployment"),(0,r.kt)("p",null,"Use the following steps to run Corda drivers in Docker containers:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"The ",(0,r.kt)("inlineCode",{parentName:"li"},".env.corda")," and ",(0,r.kt)("inlineCode",{parentName:"li"},".env.corda.tls")," files in the ",(0,r.kt)("inlineCode",{parentName:"li"},"docker-testnet-envs")," directory contain environment variables used by the ",(0,r.kt)("inlineCode",{parentName:"li"},"Corda_Network")," driver at startup and runtime. Edit either of these files (depending on whether you wish to start the relay with or without TLS) to update the following value:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},"DOCKER_IMAGE_NAME=weaver-corda-driver\n"))),(0,r.kt)("li",{parentName:"ul"},"Repeat the above steps for ",(0,r.kt)("inlineCode",{parentName:"li"},".env.corda2")," or ",(0,r.kt)("inlineCode",{parentName:"li"},".env.corda2.tls")," in ",(0,r.kt)("inlineCode",{parentName:"li"},"docker-testnet-envs")," directory, which contain environment variables for the ",(0,r.kt)("inlineCode",{parentName:"li"},"Corda_Network2")," driver.")),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"To deploy the Corda driver for ",(0,r.kt)("inlineCode",{parentName:"li"},"Corda_Network")," without TLS, run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.corda'\n")),"Instead, to deploy the driver with TLS, run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.corda.tls'\n")),"If the driver starts successfully, it should log the following message when you run ",(0,r.kt)("inlineCode",{parentName:"li"},"docker logs corda-driver-Corda_Network"),":",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},"Corda driver gRPC server started. Listening on port 9099\n"))),(0,r.kt)("li",{parentName:"ul"},"To deploy the Corda driver for ",(0,r.kt)("inlineCode",{parentName:"li"},"Corda_Network2")," without TLS, run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.corda2'\n")),"Instead, to deploy the driver with TLS, run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.corda2.tls'\n")),"If the driver starts successfully, it should log the following message when you run ",(0,r.kt)("inlineCode",{parentName:"li"},"docker logs corda-driver-Corda_Network2"),":",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},"Corda driver gRPC server started. Listening on port 9098\n")))),(0,r.kt)("h2",{id:"tear-down-the-setup"},"Tear Down the Setup"),(0,r.kt)("p",null,"Bring down the various components as follows (",(0,r.kt)("em",{parentName:"p"},"Navigate to the root folder of your clone of the Weaver repository"),"):"),(0,r.kt)("h3",{id:"relay"},"Relay"),(0,r.kt)("p",null,"To bring down the relays (for all 3 networks), run:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"cd core/relay\nmake convert-compose-method2\nmake stop COMPOSE_ARG='--env-file .env.n1'\nmake stop COMPOSE_ARG='--env-file .env.n2'\nmake stop COMPOSE_ARG='--env-file .env.corda'\nmake stop COMPOSE_ARG='--env-file .env.corda2'\nmake convert-compose-method1\ncd -\n")),(0,r.kt)("h3",{id:"fabric-driver-1"},"Fabric Driver"),(0,r.kt)("p",null,"To bring down the fabric drivers (for both networks), run:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"cd core/drivers/fabric-driver\nmake stop COMPOSE_ARG='--env-file .env.n1'\nmake stop COMPOSE_ARG='--env-file .env.n2'\ncd -\n")),(0,r.kt)("h3",{id:"corda-driver-1"},"Corda Driver"),(0,r.kt)("p",null,"To bring down the corda driver, run:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"cd core/drivers/corda-driver\nmake stop COMPOSE_ARG='--env-file docker-testnet-envs/.env.corda'\nmake stop COMPOSE_ARG='--env-file docker-testnet-envs/.env.corda2'\ncd -\n")),(0,r.kt)("h3",{id:"corda-network-1"},"Corda Network"),(0,r.kt)("p",null,"To bring down the Corda network:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"cd tests/network-setups/corda\nmake clean\ncd -\n")),(0,r.kt)("h3",{id:"fabric-network-1"},"Fabric Network"),(0,r.kt)("p",null,"To bring down both of the Fabric networks along with weaver components:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"cd tests/network-setups/fabric/dev\nmake clean\ncd -\n")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/56182e71.586ce5c7.js b/assets/js/56182e71.d6b1cfbf.js similarity index 61% rename from assets/js/56182e71.586ce5c7.js rename to assets/js/56182e71.d6b1cfbf.js index a9f32ab76..5e3c12131 100644 --- a/assets/js/56182e71.586ce5c7.js +++ b/assets/js/56182e71.d6b1cfbf.js @@ -1 +1 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[355],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>f});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},i=Object.keys(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=r.createContext({}),c=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},d=function(e){var t=c(e.components);return r.createElement(l.Provider,{value:t},e.children)},h="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},u=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,l=e.parentName,d=s(e,["components","mdxType","originalType","parentName"]),h=c(n),u=a,f=h["".concat(l,".").concat(u)]||h[u]||p[u]||i;return n?r.createElement(f,o(o({ref:t},d),{},{components:n})):r.createElement(f,o({ref:t},d))}));function f(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,o=new Array(i);o[0]=u;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[h]="string"==typeof e?e:a,o[1]=s;for(var c=2;c<i;c++)o[c]=n[c];return r.createElement.apply(null,o)}return r.createElement.apply(null,n)}u.displayName="MDXCreateElement"},6794:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>o,default:()=>p,frontMatter:()=>i,metadata:()=>s,toc:()=>c});var r=n(7462),a=(n(7294),n(3905));const i={},o=void 0,s={permalink:"/weaver-dlt-interoperability/blog/2021/01/21/emergence-enterprise-interoperability",source:"@site/blog/2021-01-21-emergence-enterprise-interoperability.md",title:"emergence-enterprise-interoperability",description:"\x3c!--",date:"2021-01-21T00:00:00.000Z",formattedDate:"January 21, 2021",tags:[],readingTime:4.945,hasTruncateMarker:!1,authors:[],frontMatter:{},prevItem:{title:"cross-chain-asset",permalink:"/weaver-dlt-interoperability/blog/2021/01/21/cross-chain-asset"}},l={authorsImageUrls:[]},c=[{value:"tags: enterprise, interoperability",id:"tags-enterprise-interoperability",level:2},{value:"The Grand Vision",id:"the-grand-vision",level:2},{value:"Evolution of Private Networks",id:"evolution-of-private-networks",level:2},{value:"Diverse Platforms",id:"diverse-platforms",level:2},{value:"Blockchain Landscape",id:"blockchain-landscape",level:2},{value:"Challenges",id:"challenges",level:2}],d={toc:c},h="wrapper";function p(e){let{components:t,...n}=e;return(0,a.kt)(h,(0,r.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("hr",null),(0,a.kt)("p",null,"slug: emergence-enterprise-interoperability\ntitle: Emergence of Enterprise DLT Interoperability\nauthor: Venkatraman Ramakrishna\nauthor_title: Maintainer of Weaver\nauthor_url: ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/VRamakrishna"},"https://github.com/VRamakrishna"),"\nauthor_image_url: ",(0,a.kt)("a",{parentName:"p",href:"https://avatars2.githubusercontent.com/u/14888211?s=400&v=4"},"https://avatars2.githubusercontent.com/u/14888211?s=400&v=4")),(0,a.kt)("h2",{id:"tags-enterprise-interoperability"},"tags: ","[enterprise, interoperability]"),(0,a.kt)("p",null,"It is instructive to know the course taken by blockchain technology and its applications over the past few years, as this will allow us to understand where we are, where are headed, and thereby motivate the necessity of interoperability."),(0,a.kt)("h2",{id:"the-grand-vision"},"The Grand Vision"),(0,a.kt)("p",null,"The original vision of blockchain technology called for a global decentralized network of peers and clients that could conduct transactions at scale without requiring intermediation by trusted third parties. The Bitcoin network was the first example of this, and it was purposely left open for anyone to join precisely because its initiators hoped for a single global network somewhat akin to the internet."),(0,a.kt)("p",null,"But the limitations of Bitcoin as a transaction processing system soon became apparent, and the Ethereum network emerged to fill this gap, retaining the openness and scalability of Bitcoin while supporting arbitrary smart contracts over a shared ledger. But Ethereum too was not destined to be the single canonical global blockchain network that everyone would use."),(0,a.kt)("p",null,"Sub-groups within the Bitcoin and Ethereum communities dissented from the rest, thereby creating ",(0,a.kt)("em",{parentName:"p"},"forks"),", or separate networks with separate chains of blocks. Others found limitations in the usability of the existing networks or their consensus mechanisms (Proof of Work) and decided to build their own networks to which like-minded people could subscribe and in which they could conduct their transactions."),(0,a.kt)("p",null,"Therefore, the original Bitcoin (or even Ethereum) vision of a single global network was not to be, and networks with different clientele and different consensus protocols proliferated."),(0,a.kt)("p",null,"And then came private (or permissioned) networks......"),(0,a.kt)("h2",{id:"evolution-of-private-networks"},"Evolution of Private Networks"),(0,a.kt)("p",null,"Sometime in the first half of the previous decade, it was recognized that networks like Bitcoin and Ethereum were not suitable for much of the business that involves private enterprises, governmental institutions, and ordinary clients. Private networks then emerged as a means to retain the trustworthiness and consensus-based decision-making properties of blockchains (and distributed ledgers in general) while ensuring that:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Transactions and ledger state are privy only to a selected set of entities,"),(0,a.kt)("li",{parentName:"ul"},"Transactions can be audited by trusted authorities when required for dispute resolutions, and"),(0,a.kt)("li",{parentName:"ul"},"Higher performance and assurance can be gained using consensus protocols other than ",(0,a.kt)("em",{parentName:"li"},"proof-of-work"),".")),(0,a.kt)("p",null,"Since companies and consortia were wary of this new and unproven technology, the trend in industry these past few years has been to build ",(0,a.kt)("em",{parentName:"p"},"minimum viable ecosystems"),", i.e., networks of limited operational scope and participation. The goal being to evaluate the potential of blockchain, these networks were created to manage selected few assets and records. Needless to say, interoperation with other networks was not high on the priority list when such networks were designed and launched."),(0,a.kt)("p",null,"Many of these networks have been successfully validated and put into production. But a consequence of the decision to build limited-scope networks is that the processes they run (through smart contracts) and the assets and records they maintain on their ledgers are stuck in siloes, inaccessible to external entitites and networks. Yet, as we are discovering, processes and assets in such networks are inextricably linked in the real enterprise world. With all of the investment (in time and money) made in existing networks, reeingeneering or merging them will generally be hardsells. Also, some networks may wish to restrict operational control and ledger visibility to its current set of administrators and clientele. The only viable solution is to allow networks to interoperate, thereby breaking up the siloes, while retaining operational control."),(0,a.kt)("h2",{id:"diverse-platforms"},"Diverse Platforms"),(0,a.kt)("p",null,"Our present blockchain landscape (or ecosystem) is characterized not just by a plethora of networks, a mix of open and private, but also by the existence of several distinct blockchain technologies, each with a different storage technology, a different model for contracts and client applications, a different consensus protocol, and a different way of managing identity. Examples include Fabric, Iroha, Sawtooth, and Besu, all in the Hyperledger family, and Ethereum, Multichain, Cardano, and Komodo, outside it. There are also smart contract distributed ledger platforms that serve a similar set of business applications that are not blockchains at all, like R3's Corda."),(0,a.kt)("p",null,"Since there is no single blockchain, or distributed ledger, technology, the world agrees on, and because each offers a different set of advantages and disadvantages, the networks that exist today are built on a diverse set of such platforms."),(0,a.kt)("h2",{id:"blockchain-landscape"},"Blockchain Landscape"),(0,a.kt)("p",null,"Our present is, and our near future will be, characterized by the existence of independent networks, some of which offer open membership whereas others are restricted, built on diverse platforms that are mutually incompatible. Asking everyone to converge to a single global network running on a single canonical platform is almost impossible. So unless we wish entities and assets to remain trapped within siloes, it should be evident that interoperability amoong different networks and platforms is crucial to the success of blockchain."),(0,a.kt)("h2",{id:"challenges"},"Challenges"),(0,a.kt)("p",null,"Interlinking processes distributed across different networks or transferring or sharing assets and data may sound like a straightforward task, but the traditional method of service and API integration will not work in scenarios that involve permissioned networks."),(0,a.kt)("p",null,"This is because, as you will see in the ",(0,a.kt)("a",{parentName:"p",href:"/docs/external/user-stories/overview"},"user stories"),", entities that are interested in the asset or data record being shared may not be members of both networks. And even if a particular entity happens to be a member of both networks, it may be in its interest to present a false view of one network's ledger state to another."),(0,a.kt)("p",null,"Therefore, interoperation cannot be allowed to hinge on the trustworthiness of a particular network member, or by extension, a third party. In the stories we will encounter, it will be apparent how such situations may occur. This will make the unreliability of API integration across private networks clear and also motivate the need for consensus-based interoperation protocols."))}p.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[5902],{5680:(e,t,n)=>{n.d(t,{xA:()=>d,yg:()=>g});var r=n(6540);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},i=Object.keys(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=r.createContext({}),c=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},d=function(e){var t=c(e.components);return r.createElement(l.Provider,{value:t},e.children)},h="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},u=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,l=e.parentName,d=s(e,["components","mdxType","originalType","parentName"]),h=c(n),u=a,g=h["".concat(l,".").concat(u)]||h[u]||p[u]||i;return n?r.createElement(g,o(o({ref:t},d),{},{components:n})):r.createElement(g,o({ref:t},d))}));function g(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,o=new Array(i);o[0]=u;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[h]="string"==typeof e?e:a,o[1]=s;for(var c=2;c<i;c++)o[c]=n[c];return r.createElement.apply(null,o)}return r.createElement.apply(null,n)}u.displayName="MDXCreateElement"},373:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>o,default:()=>p,frontMatter:()=>i,metadata:()=>s,toc:()=>c});var r=n(8168),a=(n(6540),n(5680));const i={},o=void 0,s={permalink:"/weaver-dlt-interoperability/blog/2021/01/21/emergence-enterprise-interoperability",source:"@site/blog/2021-01-21-emergence-enterprise-interoperability.md",title:"emergence-enterprise-interoperability",description:"\x3c!--",date:"2021-01-21T00:00:00.000Z",formattedDate:"January 21, 2021",tags:[],readingTime:4.945,hasTruncateMarker:!1,authors:[],frontMatter:{},prevItem:{title:"cross-chain-asset",permalink:"/weaver-dlt-interoperability/blog/2021/01/21/cross-chain-asset"}},l={authorsImageUrls:[]},c=[{value:"tags: enterprise, interoperability",id:"tags-enterprise-interoperability",level:2},{value:"The Grand Vision",id:"the-grand-vision",level:2},{value:"Evolution of Private Networks",id:"evolution-of-private-networks",level:2},{value:"Diverse Platforms",id:"diverse-platforms",level:2},{value:"Blockchain Landscape",id:"blockchain-landscape",level:2},{value:"Challenges",id:"challenges",level:2}],d={toc:c},h="wrapper";function p(e){let{components:t,...n}=e;return(0,a.yg)(h,(0,r.A)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,a.yg)("hr",null),(0,a.yg)("p",null,"slug: emergence-enterprise-interoperability\ntitle: Emergence of Enterprise DLT Interoperability\nauthor: Venkatraman Ramakrishna\nauthor_title: Maintainer of Weaver\nauthor_url: ",(0,a.yg)("a",{parentName:"p",href:"https://github.com/VRamakrishna"},"https://github.com/VRamakrishna"),"\nauthor_image_url: ",(0,a.yg)("a",{parentName:"p",href:"https://avatars2.githubusercontent.com/u/14888211?s=400&v=4"},"https://avatars2.githubusercontent.com/u/14888211?s=400&v=4")),(0,a.yg)("h2",{id:"tags-enterprise-interoperability"},"tags: ","[enterprise, interoperability]"),(0,a.yg)("p",null,"It is instructive to know the course taken by blockchain technology and its applications over the past few years, as this will allow us to understand where we are, where are headed, and thereby motivate the necessity of interoperability."),(0,a.yg)("h2",{id:"the-grand-vision"},"The Grand Vision"),(0,a.yg)("p",null,"The original vision of blockchain technology called for a global decentralized network of peers and clients that could conduct transactions at scale without requiring intermediation by trusted third parties. The Bitcoin network was the first example of this, and it was purposely left open for anyone to join precisely because its initiators hoped for a single global network somewhat akin to the internet."),(0,a.yg)("p",null,"But the limitations of Bitcoin as a transaction processing system soon became apparent, and the Ethereum network emerged to fill this gap, retaining the openness and scalability of Bitcoin while supporting arbitrary smart contracts over a shared ledger. But Ethereum too was not destined to be the single canonical global blockchain network that everyone would use."),(0,a.yg)("p",null,"Sub-groups within the Bitcoin and Ethereum communities dissented from the rest, thereby creating ",(0,a.yg)("em",{parentName:"p"},"forks"),", or separate networks with separate chains of blocks. Others found limitations in the usability of the existing networks or their consensus mechanisms (Proof of Work) and decided to build their own networks to which like-minded people could subscribe and in which they could conduct their transactions."),(0,a.yg)("p",null,"Therefore, the original Bitcoin (or even Ethereum) vision of a single global network was not to be, and networks with different clientele and different consensus protocols proliferated."),(0,a.yg)("p",null,"And then came private (or permissioned) networks......"),(0,a.yg)("h2",{id:"evolution-of-private-networks"},"Evolution of Private Networks"),(0,a.yg)("p",null,"Sometime in the first half of the previous decade, it was recognized that networks like Bitcoin and Ethereum were not suitable for much of the business that involves private enterprises, governmental institutions, and ordinary clients. Private networks then emerged as a means to retain the trustworthiness and consensus-based decision-making properties of blockchains (and distributed ledgers in general) while ensuring that:"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},"Transactions and ledger state are privy only to a selected set of entities,"),(0,a.yg)("li",{parentName:"ul"},"Transactions can be audited by trusted authorities when required for dispute resolutions, and"),(0,a.yg)("li",{parentName:"ul"},"Higher performance and assurance can be gained using consensus protocols other than ",(0,a.yg)("em",{parentName:"li"},"proof-of-work"),".")),(0,a.yg)("p",null,"Since companies and consortia were wary of this new and unproven technology, the trend in industry these past few years has been to build ",(0,a.yg)("em",{parentName:"p"},"minimum viable ecosystems"),", i.e., networks of limited operational scope and participation. The goal being to evaluate the potential of blockchain, these networks were created to manage selected few assets and records. Needless to say, interoperation with other networks was not high on the priority list when such networks were designed and launched."),(0,a.yg)("p",null,"Many of these networks have been successfully validated and put into production. But a consequence of the decision to build limited-scope networks is that the processes they run (through smart contracts) and the assets and records they maintain on their ledgers are stuck in siloes, inaccessible to external entitites and networks. Yet, as we are discovering, processes and assets in such networks are inextricably linked in the real enterprise world. With all of the investment (in time and money) made in existing networks, reeingeneering or merging them will generally be hardsells. Also, some networks may wish to restrict operational control and ledger visibility to its current set of administrators and clientele. The only viable solution is to allow networks to interoperate, thereby breaking up the siloes, while retaining operational control."),(0,a.yg)("h2",{id:"diverse-platforms"},"Diverse Platforms"),(0,a.yg)("p",null,"Our present blockchain landscape (or ecosystem) is characterized not just by a plethora of networks, a mix of open and private, but also by the existence of several distinct blockchain technologies, each with a different storage technology, a different model for contracts and client applications, a different consensus protocol, and a different way of managing identity. Examples include Fabric, Iroha, Sawtooth, and Besu, all in the Hyperledger family, and Ethereum, Multichain, Cardano, and Komodo, outside it. There are also smart contract distributed ledger platforms that serve a similar set of business applications that are not blockchains at all, like R3's Corda."),(0,a.yg)("p",null,"Since there is no single blockchain, or distributed ledger, technology, the world agrees on, and because each offers a different set of advantages and disadvantages, the networks that exist today are built on a diverse set of such platforms."),(0,a.yg)("h2",{id:"blockchain-landscape"},"Blockchain Landscape"),(0,a.yg)("p",null,"Our present is, and our near future will be, characterized by the existence of independent networks, some of which offer open membership whereas others are restricted, built on diverse platforms that are mutually incompatible. Asking everyone to converge to a single global network running on a single canonical platform is almost impossible. So unless we wish entities and assets to remain trapped within siloes, it should be evident that interoperability amoong different networks and platforms is crucial to the success of blockchain."),(0,a.yg)("h2",{id:"challenges"},"Challenges"),(0,a.yg)("p",null,"Interlinking processes distributed across different networks or transferring or sharing assets and data may sound like a straightforward task, but the traditional method of service and API integration will not work in scenarios that involve permissioned networks."),(0,a.yg)("p",null,"This is because, as you will see in the ",(0,a.yg)("a",{parentName:"p",href:"/docs/external/user-stories/overview"},"user stories"),", entities that are interested in the asset or data record being shared may not be members of both networks. And even if a particular entity happens to be a member of both networks, it may be in its interest to present a false view of one network's ledger state to another."),(0,a.yg)("p",null,"Therefore, interoperation cannot be allowed to hinge on the trustworthiness of a particular network member, or by extension, a third party. In the stories we will encounter, it will be apparent how such situations may occur. This will make the unreliability of API integration across private networks clear and also motivate the need for consensus-based interoperation protocols."))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/591644de.ca3c9ad9.js b/assets/js/591644de.1998781c.js similarity index 79% rename from assets/js/591644de.ca3c9ad9.js rename to assets/js/591644de.1998781c.js index 5f3bb6211..29f132986 100644 --- a/assets/js/591644de.ca3c9ad9.js +++ b/assets/js/591644de.1998781c.js @@ -1 +1 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[7295],{5970:e=>{e.exports=JSON.parse('{"permalink":"/weaver-dlt-interoperability/blog","page":1,"postsPerPage":10,"totalPages":1,"totalCount":2,"blogDescription":"Blog","blogTitle":"Blog"}')}}]); \ No newline at end of file +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[5937],{6428:e=>{e.exports=JSON.parse('{"permalink":"/weaver-dlt-interoperability/blog","page":1,"postsPerPage":10,"totalPages":1,"totalCount":2,"blogDescription":"Blog","blogTitle":"Blog"}')}}]); \ No newline at end of file diff --git a/assets/js/59395140.916d47ec.js b/assets/js/59395140.916d47ec.js new file mode 100644 index 000000000..47b80fa37 --- /dev/null +++ b/assets/js/59395140.916d47ec.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[3599],{5680:(e,t,r)=>{r.d(t,{xA:()=>p,yg:()=>y});var n=r(6540);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function o(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?i(Object(r),!0).forEach((function(t){a(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):i(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function l(e,t){if(null==e)return{};var r,n,a=function(e,t){if(null==e)return{};var r,n,a={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var s=n.createContext({}),c=function(e){var t=n.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},p=function(e){var t=c(e.components);return n.createElement(s.Provider,{value:t},e.children)},g="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},u=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,i=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),g=c(r),u=a,y=g["".concat(s,".").concat(u)]||g[u]||d[u]||i;return r?n.createElement(y,o(o({ref:t},p),{},{components:r})):n.createElement(y,o({ref:t},p))}));function y(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=r.length,o=new Array(i);o[0]=u;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[g]="string"==typeof e?e:a,o[1]=l;for(var c=2;c<i;c++)o[c]=r[c];return n.createElement.apply(null,o)}return n.createElement.apply(null,r)}u.displayName="MDXCreateElement"},645:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>d,frontMatter:()=>i,metadata:()=>l,toc:()=>c});var n=r(8168),a=(r(6540),r(5680));const i={id:"overview",title:"Asset Exchange",sidebar_label:"Overview",pagination_label:"Asset Exchange",pagination_prev:"external/getting-started/interop/overview"},o=void 0,l={unversionedId:"external/getting-started/interop/asset-exchange/overview",id:"external/getting-started/interop/asset-exchange/overview",title:"Asset Exchange",description:"\x3c!--",source:"@site/docs/external/getting-started/interop/asset-exchange/overview.md",sourceDirName:"external/getting-started/interop/asset-exchange",slug:"/external/getting-started/interop/asset-exchange/overview",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/getting-started/interop/asset-exchange/overview.md",tags:[],version:"current",frontMatter:{id:"overview",title:"Asset Exchange",sidebar_label:"Overview",pagination_label:"Asset Exchange",pagination_prev:"external/getting-started/interop/overview"},sidebar:"Documentation",previous:{title:"Testing Interoperation Modes",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/overview"},next:{title:"Fabric with Fabric",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-fabric"}},s={},c=[],p={toc:c},g="wrapper";function d(e){let{components:t,...r}=e;return(0,a.yg)(g,(0,n.A)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,a.yg)("p",null,"This document lists sample ways in which you can exercise the asset-exchange interoperation protocol on the test network ",(0,a.yg)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/overview"},"launched earlier"),"."),(0,a.yg)("p",null,"For this scenario, you only need the networks to be running with the appropriate contracts deployed and the ledgers bootstrapped. You do not need to run relays, drivers and IIN agents. You can run the following combinations of exchanges (",(0,a.yg)("em",{parentName:"p"},"other combinations of DLTs will be supported soon"),")."),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-fabric"},"Fabric with Fabric")),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-corda"},"Fabric with Corda")),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-besu"},"Fabric with Besu")),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/corda-corda"},"Corda with Corda")),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/corda-besu"},"Corda with Besu")),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/besu-besu"},"Besu with Besu"))))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/59395140.c27b3725.js b/assets/js/59395140.c27b3725.js deleted file mode 100644 index 13b237cf2..000000000 --- a/assets/js/59395140.c27b3725.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[8298],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>b});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function o(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?i(Object(r),!0).forEach((function(t){a(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):i(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function l(e,t){if(null==e)return{};var r,n,a=function(e,t){if(null==e)return{};var r,n,a={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var s=n.createContext({}),c=function(e){var t=n.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},p=function(e){var t=c(e.components);return n.createElement(s.Provider,{value:t},e.children)},d="mdxType",g={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},u=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,i=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),d=c(r),u=a,b=d["".concat(s,".").concat(u)]||d[u]||g[u]||i;return r?n.createElement(b,o(o({ref:t},p),{},{components:r})):n.createElement(b,o({ref:t},p))}));function b(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=r.length,o=new Array(i);o[0]=u;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[d]="string"==typeof e?e:a,o[1]=l;for(var c=2;c<i;c++)o[c]=r[c];return n.createElement.apply(null,o)}return n.createElement.apply(null,r)}u.displayName="MDXCreateElement"},8456:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>g,frontMatter:()=>i,metadata:()=>l,toc:()=>c});var n=r(7462),a=(r(7294),r(3905));const i={id:"overview",title:"Asset Exchange",sidebar_label:"Overview",pagination_label:"Asset Exchange",pagination_prev:"external/getting-started/interop/overview"},o=void 0,l={unversionedId:"external/getting-started/interop/asset-exchange/overview",id:"external/getting-started/interop/asset-exchange/overview",title:"Asset Exchange",description:"\x3c!--",source:"@site/docs/external/getting-started/interop/asset-exchange/overview.md",sourceDirName:"external/getting-started/interop/asset-exchange",slug:"/external/getting-started/interop/asset-exchange/overview",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/getting-started/interop/asset-exchange/overview.md",tags:[],version:"current",frontMatter:{id:"overview",title:"Asset Exchange",sidebar_label:"Overview",pagination_label:"Asset Exchange",pagination_prev:"external/getting-started/interop/overview"},sidebar:"Documentation",previous:{title:"Testing Interoperation Modes",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/overview"},next:{title:"Fabric with Fabric",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-fabric"}},s={},c=[],p={toc:c},d="wrapper";function g(e){let{components:t,...r}=e;return(0,a.kt)(d,(0,n.Z)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"This document lists sample ways in which you can exercise the asset-exchange interoperation protocol on the test network ",(0,a.kt)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/overview"},"launched earlier"),"."),(0,a.kt)("p",null,"For this scenario, you only need the networks to be running with the appropriate contracts deployed and the ledgers bootstrapped. You do not need to run relays, drivers and IIN agents. You can run the following combinations of exchanges (",(0,a.kt)("em",{parentName:"p"},"other combinations of DLTs will be supported soon"),")."),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-fabric"},"Fabric with Fabric")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-corda"},"Fabric with Corda")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-besu"},"Fabric with Besu")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/corda-corda"},"Corda with Corda")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/corda-besu"},"Corda with Besu")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/besu-besu"},"Besu with Besu"))))}g.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/5c41994f.0803097a.js b/assets/js/5c41994f.0803097a.js new file mode 100644 index 000000000..cd7ad5ad1 --- /dev/null +++ b/assets/js/5c41994f.0803097a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[5058],{5680:(e,a,t)=>{t.d(a,{xA:()=>p,yg:()=>y});var n=t(6540);function r(e,a,t){return a in e?Object.defineProperty(e,a,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[a]=t,e}function i(e,a){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);a&&(n=n.filter((function(a){return Object.getOwnPropertyDescriptor(e,a).enumerable}))),t.push.apply(t,n)}return t}function o(e){for(var a=1;a<arguments.length;a++){var t=null!=arguments[a]?arguments[a]:{};a%2?i(Object(t),!0).forEach((function(a){r(e,a,t[a])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):i(Object(t)).forEach((function(a){Object.defineProperty(e,a,Object.getOwnPropertyDescriptor(t,a))}))}return e}function l(e,a){if(null==e)return{};var t,n,r=function(e,a){if(null==e)return{};var t,n,r={},i=Object.keys(e);for(n=0;n<i.length;n++)t=i[n],a.indexOf(t)>=0||(r[t]=e[t]);return r}(e,a);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)t=i[n],a.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var s=n.createContext({}),c=function(e){var a=n.useContext(s),t=a;return e&&(t="function"==typeof e?e(a):o(o({},a),e)),t},p=function(e){var a=c(e.components);return n.createElement(s.Provider,{value:a},e.children)},d="mdxType",g={inlineCode:"code",wrapper:function(e){var a=e.children;return n.createElement(n.Fragment,{},a)}},m=n.forwardRef((function(e,a){var t=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),d=c(t),m=r,y=d["".concat(s,".").concat(m)]||d[m]||g[m]||i;return t?n.createElement(y,o(o({ref:a},p),{},{components:t})):n.createElement(y,o({ref:a},p))}));function y(e,a){var t=arguments,r=a&&a.mdxType;if("string"==typeof e||r){var i=t.length,o=new Array(i);o[0]=m;var l={};for(var s in a)hasOwnProperty.call(a,s)&&(l[s]=a[s]);l.originalType=e,l[d]="string"==typeof e?e:r,o[1]=l;for(var c=2;c<i;c++)o[c]=t[c];return n.createElement.apply(null,o)}return n.createElement.apply(null,t)}m.displayName="MDXCreateElement"},6457:(e,a,t)=>{t.r(a),t.d(a,{assets:()=>s,contentTitle:()=>o,default:()=>g,frontMatter:()=>i,metadata:()=>l,toc:()=>c});var n=t(8168),r=(t(6540),t(5680));const i={id:"fabric-corda",title:"Asset Exchange: Fabric with Corda",sidebar_label:"Fabric with Corda",pagination_label:"Fabric with Corda",pagination_prev:"external/getting-started/interop/asset-exchange/overview"},o=void 0,l={unversionedId:"external/getting-started/interop/asset-exchange/fabric-corda",id:"external/getting-started/interop/asset-exchange/fabric-corda",title:"Asset Exchange: Fabric with Corda",description:"We will demonstrate asset exchange of a bond in Fabric network1 with tokens on Corda_Network.",source:"@site/docs/external/getting-started/interop/asset-exchange/fabric-corda.md",sourceDirName:"external/getting-started/interop/asset-exchange",slug:"/external/getting-started/interop/asset-exchange/fabric-corda",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-corda",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/getting-started/interop/asset-exchange/fabric-corda.md",tags:[],version:"current",frontMatter:{id:"fabric-corda",title:"Asset Exchange: Fabric with Corda",sidebar_label:"Fabric with Corda",pagination_label:"Fabric with Corda",pagination_prev:"external/getting-started/interop/asset-exchange/overview"},sidebar:"Documentation",previous:{title:"Asset Exchange",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview"},next:{title:"Fabric with Besu",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-besu"}},s={},c=[],p={toc:c},d="wrapper";function g(e){let{components:a,...t}=e;return(0,r.yg)(d,(0,n.A)({},p,t,{components:a,mdxType:"MDXLayout"}),(0,r.yg)("p",null,"We will demonstrate asset exchange of a bond in Fabric ",(0,r.yg)("inlineCode",{parentName:"p"},"network1")," with tokens on ",(0,r.yg)("inlineCode",{parentName:"p"},"Corda_Network"),".\nFor Fabric commands, run from ",(0,r.yg)("inlineCode",{parentName:"p"},"samples/fabric/fabric-cli")," folder, and for Corda commands, run from ",(0,r.yg)("inlineCode",{parentName:"p"},"samples/corda/corda-simple-application")," folder, in your clone of the Weaver repository. Here ",(0,r.yg)("inlineCode",{parentName:"p"},"Alice")," and ",(0,r.yg)("inlineCode",{parentName:"p"},"Bob")," in Fabric ",(0,r.yg)("inlineCode",{parentName:"p"},"network1")," correspond to ",(0,r.yg)("inlineCode",{parentName:"p"},"PartyA")," (",(0,r.yg)("inlineCode",{parentName:"p"},"CORDA_PORT=10006"),") and ",(0,r.yg)("inlineCode",{parentName:"p"},"PartyB")," (",(0,r.yg)("inlineCode",{parentName:"p"},"CORDA_PORT=10009"),") in ",(0,r.yg)("inlineCode",{parentName:"p"},"Corda_Network")," respectively. Following are the step-by-step asset exchange process:"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:"left"},"The hash used in following steps can be replaced by any valid ",(0,r.yg)("inlineCode",{parentName:"td"},"SHA256")," hash.")))),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Run the following to verify the status of the bond assets owned by ",(0,r.yg)("inlineCode",{parentName:"li"},"alice")," and ",(0,r.yg)("inlineCode",{parentName:"li"},"bob")," in the Fabric network ",(0,r.yg)("inlineCode",{parentName:"li"},"network1")," from ",(0,r.yg)("inlineCode",{parentName:"li"},"samples/fabric/fabric-cli")," folder:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"./scripts/getAssetStatus.sh\n"))),(0,r.yg)("li",{parentName:"ul"},"Run the following to verify the status of the assets owned by ",(0,r.yg)("inlineCode",{parentName:"li"},"PartyA")," and ",(0,r.yg)("inlineCode",{parentName:"li"},"PartyB")," in the ",(0,r.yg)("inlineCode",{parentName:"li"},"Corda_Network")," from ",(0,r.yg)("inlineCode",{parentName:"li"},"samples/corda/corda-simple-application")," folder:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"./scripts/getAssetStatus.sh\n"))),(0,r.yg)("li",{parentName:"ul"},"Generate Secret-Hash Pair using following command (prints hash in base64):",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre"},"./bin/fabric-cli hash --hash_fn=SHA256 secrettext\n"))),(0,r.yg)("li",{parentName:"ul"},"Run the following to trigger ",(0,r.yg)("inlineCode",{parentName:"li"},"alice")," locking ",(0,r.yg)("inlineCode",{parentName:"li"},"bond01:a03")," for ",(0,r.yg)("inlineCode",{parentName:"li"},"bob")," in ",(0,r.yg)("inlineCode",{parentName:"li"},"network1")," for 60 mins:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset exchange lock --timeout-duration=3600 --locker=alice --recipient=bob --hashBase64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs= --target-network=network1 --param=bond01:a03\n"))),(0,r.yg)("li",{parentName:"ul"},"Run the following to verify ",(0,r.yg)("inlineCode",{parentName:"li"},"alice"),"'s lock:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset exchange is-locked --locker=alice --recipient=bob --target-network=network1 --param=bond01:a03\n"))),(0,r.yg)("li",{parentName:"ul"},"Run the following to trigger ",(0,r.yg)("inlineCode",{parentName:"li"},"PartyB")," locking ",(0,r.yg)("inlineCode",{parentName:"li"},"50")," units of token type ",(0,r.yg)("inlineCode",{parentName:"li"},"t1")," for ",(0,r.yg)("inlineCode",{parentName:"li"},"PartyA")," in ",(0,r.yg)("inlineCode",{parentName:"li"},"Corda_Network")," for 30 mins:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},'CORDA_PORT=10009 ./clients/build/install/clients/bin/clients lock-asset --fungible --hashBase64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs= --timeout=1800 --recipient="O=PartyA,L=London,C=GB" --param=t1:50\n')),"Note the ",(0,r.yg)("inlineCode",{parentName:"li"},"contract-id")," displayed after successful execution of the command, will be used in next steps. The output containing ",(0,r.yg)("inlineCode",{parentName:"li"},"contract-id")," would like this:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"HTLC Lock State created with contract ID Right(b=10448674_80d2bee7-5a5d-45df-b14e-60bac4ba1bf3).\n")),(0,r.yg)("inlineCode",{parentName:"li"},"contract-id")," is the alphanumeric text (with underscore and hyphens) after ",(0,r.yg)("inlineCode",{parentName:"li"},"b=")," within parenthesis."),(0,r.yg)("li",{parentName:"ul"},"Run the following to verify ",(0,r.yg)("inlineCode",{parentName:"li"},"PartyB"),"'s lock (can be verified by both parties):",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"CORDA_PORT=10006 ./clients/build/install/clients/bin/clients is-asset-locked --contract-id=<contract-id>\n"))),(0,r.yg)("li",{parentName:"ul"},"Run the following to trigger ",(0,r.yg)("inlineCode",{parentName:"li"},"PartyA"),"'s claim for ",(0,r.yg)("inlineCode",{parentName:"li"},"50")," units of token type ",(0,r.yg)("inlineCode",{parentName:"li"},"t1")," locked by ",(0,r.yg)("inlineCode",{parentName:"li"},"PartyB")," in ",(0,r.yg)("inlineCode",{parentName:"li"},"Corda_Network"),":",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"CORDA_PORT=10006 ./clients/build/install/clients/bin/clients claim-asset --secret=secrettext --contract-id=<contract-id>\n")),(0,r.yg)("inlineCode",{parentName:"li"},"PartyB")," can see its node's logs to get the revealed hash preimage, and use it to claim the bond in the Fabric network."),(0,r.yg)("li",{parentName:"ul"},"Run the following to trigger ",(0,r.yg)("inlineCode",{parentName:"li"},"bob"),"'s claim for ",(0,r.yg)("inlineCode",{parentName:"li"},"bond01:a03")," locked by ",(0,r.yg)("inlineCode",{parentName:"li"},"alice")," in ",(0,r.yg)("inlineCode",{parentName:"li"},"network1"),":",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset exchange claim --recipient=bob --locker=alice --target-network=network1 --param=bond01:a03 --secret=secrettext\n"))),(0,r.yg)("li",{parentName:"ul"},"Run the following to verify the status of the bond assets owned by ",(0,r.yg)("inlineCode",{parentName:"li"},"alice")," and ",(0,r.yg)("inlineCode",{parentName:"li"},"bob")," in the Fabric network ",(0,r.yg)("inlineCode",{parentName:"li"},"network1")," from ",(0,r.yg)("inlineCode",{parentName:"li"},"samples/fabric/fabric-cli")," folder:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"./scripts/getAssetStatus.sh\n"))),(0,r.yg)("li",{parentName:"ul"},"Run the following to verify the status of the assets owned by ",(0,r.yg)("inlineCode",{parentName:"li"},"PartyA")," and ",(0,r.yg)("inlineCode",{parentName:"li"},"PartyB")," in the ",(0,r.yg)("inlineCode",{parentName:"li"},"Corda_Network")," from ",(0,r.yg)("inlineCode",{parentName:"li"},"samples/corda/corda-simple-application")," folder:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"./scripts/getAssetStatus.sh\n")))),(0,r.yg)("p",null,"The above steps complete a successful asset exchange between Fabric and Corda networks.\nIn addition to the above commands, following commands can be run if specified timeout has expired and the locked asset remains unclaimed."),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"If ",(0,r.yg)("inlineCode",{parentName:"li"},"alice")," wants to unlock the bond asset, run the following to trigger ",(0,r.yg)("inlineCode",{parentName:"li"},"alice"),"'s re-claim for ",(0,r.yg)("inlineCode",{parentName:"li"},"bond01:a03")," locked in ",(0,r.yg)("inlineCode",{parentName:"li"},"network1"),":",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset exchange unlock --locker=alice --recipient=bob --target-network=network1 --param=bond01:a03\n"))),(0,r.yg)("li",{parentName:"ul"},"If ",(0,r.yg)("inlineCode",{parentName:"li"},"PartyB")," wants to unlock the token asset, run the following to trigger unlock for ",(0,r.yg)("inlineCode",{parentName:"li"},"t1:50")," locked in ",(0,r.yg)("inlineCode",{parentName:"li"},"Corda_Network"),":",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"CORDA_PORT=10009 ./clients/build/install/clients/bin/clients unlock-asset --contract-id=<contract-id>\n")))))}g.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/5c41994f.ddb8c2c1.js b/assets/js/5c41994f.ddb8c2c1.js deleted file mode 100644 index 12009883b..000000000 --- a/assets/js/5c41994f.ddb8c2c1.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[1637],{3905:(e,t,a)=>{a.d(t,{Zo:()=>p,kt:()=>b});var n=a(7294);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function i(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function o(e){for(var t=1;t<arguments.length;t++){var a=null!=arguments[t]?arguments[t]:{};t%2?i(Object(a),!0).forEach((function(t){r(e,t,a[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(a)):i(Object(a)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(a,t))}))}return e}function l(e,t){if(null==e)return{};var a,n,r=function(e,t){if(null==e)return{};var a,n,r={},i=Object.keys(e);for(n=0;n<i.length;n++)a=i[n],t.indexOf(a)>=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)a=i[n],t.indexOf(a)>=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var s=n.createContext({}),c=function(e){var t=n.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},p=function(e){var t=c(e.components);return n.createElement(s.Provider,{value:t},e.children)},d="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},k=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),d=c(a),k=r,b=d["".concat(s,".").concat(k)]||d[k]||m[k]||i;return a?n.createElement(b,o(o({ref:t},p),{},{components:a})):n.createElement(b,o({ref:t},p))}));function b(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=a.length,o=new Array(i);o[0]=k;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[d]="string"==typeof e?e:r,o[1]=l;for(var c=2;c<i;c++)o[c]=a[c];return n.createElement.apply(null,o)}return n.createElement.apply(null,a)}k.displayName="MDXCreateElement"},8411:(e,t,a)=>{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>m,frontMatter:()=>i,metadata:()=>l,toc:()=>c});var n=a(7462),r=(a(7294),a(3905));const i={id:"fabric-corda",title:"Asset Exchange: Fabric with Corda",sidebar_label:"Fabric with Corda",pagination_label:"Fabric with Corda",pagination_prev:"external/getting-started/interop/asset-exchange/overview"},o=void 0,l={unversionedId:"external/getting-started/interop/asset-exchange/fabric-corda",id:"external/getting-started/interop/asset-exchange/fabric-corda",title:"Asset Exchange: Fabric with Corda",description:"We will demonstrate asset exchange of a bond in Fabric network1 with tokens on Corda_Network.",source:"@site/docs/external/getting-started/interop/asset-exchange/fabric-corda.md",sourceDirName:"external/getting-started/interop/asset-exchange",slug:"/external/getting-started/interop/asset-exchange/fabric-corda",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-corda",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/getting-started/interop/asset-exchange/fabric-corda.md",tags:[],version:"current",frontMatter:{id:"fabric-corda",title:"Asset Exchange: Fabric with Corda",sidebar_label:"Fabric with Corda",pagination_label:"Fabric with Corda",pagination_prev:"external/getting-started/interop/asset-exchange/overview"},sidebar:"Documentation",previous:{title:"Asset Exchange",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview"},next:{title:"Fabric with Besu",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-besu"}},s={},c=[],p={toc:c},d="wrapper";function m(e){let{components:t,...a}=e;return(0,r.kt)(d,(0,n.Z)({},p,a,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"We will demonstrate asset exchange of a bond in Fabric ",(0,r.kt)("inlineCode",{parentName:"p"},"network1")," with tokens on ",(0,r.kt)("inlineCode",{parentName:"p"},"Corda_Network"),".\nFor Fabric commands, run from ",(0,r.kt)("inlineCode",{parentName:"p"},"samples/fabric/fabric-cli")," folder, and for Corda commands, run from ",(0,r.kt)("inlineCode",{parentName:"p"},"samples/corda/corda-simple-application")," folder. Here ",(0,r.kt)("inlineCode",{parentName:"p"},"Alice")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"Bob")," in Fabric ",(0,r.kt)("inlineCode",{parentName:"p"},"network1")," correspond to ",(0,r.kt)("inlineCode",{parentName:"p"},"PartyA")," (",(0,r.kt)("inlineCode",{parentName:"p"},"CORDA_PORT=10006"),") and ",(0,r.kt)("inlineCode",{parentName:"p"},"PartyB")," (",(0,r.kt)("inlineCode",{parentName:"p"},"CORDA_PORT=10009"),") in ",(0,r.kt)("inlineCode",{parentName:"p"},"Corda_Network")," respectively. Following are the step-by-step asset exchange process:"),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:"left"},"The hash used in following steps can be replaced by any valid ",(0,r.kt)("inlineCode",{parentName:"td"},"SHA256")," hash.")))),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Run the following to verify the status of the bond assets owned by ",(0,r.kt)("inlineCode",{parentName:"li"},"alice")," and ",(0,r.kt)("inlineCode",{parentName:"li"},"bob")," in the Fabric network ",(0,r.kt)("inlineCode",{parentName:"li"},"network1")," from ",(0,r.kt)("inlineCode",{parentName:"li"},"samples/fabric/fabric-cli")," folder:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"./scripts/getAssetStatus.sh\n"))),(0,r.kt)("li",{parentName:"ul"},"Run the following to verify the status of the assets owned by ",(0,r.kt)("inlineCode",{parentName:"li"},"PartyA")," and ",(0,r.kt)("inlineCode",{parentName:"li"},"PartyB")," in the ",(0,r.kt)("inlineCode",{parentName:"li"},"Corda_Network")," from ",(0,r.kt)("inlineCode",{parentName:"li"},"samples/corda/corda-simple-application")," folder:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"./scripts/getAssetStatus.sh\n"))),(0,r.kt)("li",{parentName:"ul"},"Generate Secret-Hash Pair using following command (prints hash in base64):",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},"./bin/fabric-cli hash --hash_fn=SHA256 secrettext\n"))),(0,r.kt)("li",{parentName:"ul"},"Run the following to trigger ",(0,r.kt)("inlineCode",{parentName:"li"},"alice")," locking ",(0,r.kt)("inlineCode",{parentName:"li"},"bond01:a03")," for ",(0,r.kt)("inlineCode",{parentName:"li"},"bob")," in ",(0,r.kt)("inlineCode",{parentName:"li"},"network1")," for 60 mins:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset exchange lock --timeout-duration=3600 --locker=alice --recipient=bob --hashBase64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs= --target-network=network1 --param=bond01:a03\n"))),(0,r.kt)("li",{parentName:"ul"},"Run the following to verify ",(0,r.kt)("inlineCode",{parentName:"li"},"alice"),"'s lock:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset exchange is-locked --locker=alice --recipient=bob --target-network=network1 --param=bond01:a03\n"))),(0,r.kt)("li",{parentName:"ul"},"Run the following to trigger ",(0,r.kt)("inlineCode",{parentName:"li"},"PartyB")," locking ",(0,r.kt)("inlineCode",{parentName:"li"},"50")," units of token type ",(0,r.kt)("inlineCode",{parentName:"li"},"t1")," for ",(0,r.kt)("inlineCode",{parentName:"li"},"PartyA")," in ",(0,r.kt)("inlineCode",{parentName:"li"},"Corda_Network")," for 30 mins:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'CORDA_PORT=10009 ./clients/build/install/clients/bin/clients lock-asset --fungible --hashBase64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs= --timeout=1800 --recipient="O=PartyA,L=London,C=GB" --param=t1:50\n')),"Note the ",(0,r.kt)("inlineCode",{parentName:"li"},"contract-id")," displayed after successful execution of the command, will be used in next steps. The output containing ",(0,r.kt)("inlineCode",{parentName:"li"},"contract-id")," would like this:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"HTLC Lock State created with contract ID Right(b=10448674_80d2bee7-5a5d-45df-b14e-60bac4ba1bf3).\n")),(0,r.kt)("inlineCode",{parentName:"li"},"contract-id")," is the alphanumeric text (with underscore and hyphens) after ",(0,r.kt)("inlineCode",{parentName:"li"},"b=")," within parenthesis."),(0,r.kt)("li",{parentName:"ul"},"Run the following to verify ",(0,r.kt)("inlineCode",{parentName:"li"},"PartyB"),"'s lock (can be verified by both parties):",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"CORDA_PORT=10006 ./clients/build/install/clients/bin/clients is-asset-locked --contract-id=<contract-id>\n"))),(0,r.kt)("li",{parentName:"ul"},"Run the following to trigger ",(0,r.kt)("inlineCode",{parentName:"li"},"PartyA"),"'s claim for ",(0,r.kt)("inlineCode",{parentName:"li"},"50")," units of token type ",(0,r.kt)("inlineCode",{parentName:"li"},"t1")," locked by ",(0,r.kt)("inlineCode",{parentName:"li"},"PartyB")," in ",(0,r.kt)("inlineCode",{parentName:"li"},"Corda_Network"),":",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"CORDA_PORT=10006 ./clients/build/install/clients/bin/clients claim-asset --secret=secrettext --contract-id=<contract-id>\n")),(0,r.kt)("inlineCode",{parentName:"li"},"PartyB")," can see its node's logs to get the revealed hash preimage, and use it to claim the bond in the Fabric network."),(0,r.kt)("li",{parentName:"ul"},"Run the following to trigger ",(0,r.kt)("inlineCode",{parentName:"li"},"bob"),"'s claim for ",(0,r.kt)("inlineCode",{parentName:"li"},"bond01:a03")," locked by ",(0,r.kt)("inlineCode",{parentName:"li"},"alice")," in ",(0,r.kt)("inlineCode",{parentName:"li"},"network1"),":",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset exchange claim --recipient=bob --locker=alice --target-network=network1 --param=bond01:a03 --secret=secrettext\n"))),(0,r.kt)("li",{parentName:"ul"},"Run the following to verify the status of the bond assets owned by ",(0,r.kt)("inlineCode",{parentName:"li"},"alice")," and ",(0,r.kt)("inlineCode",{parentName:"li"},"bob")," in the Fabric network ",(0,r.kt)("inlineCode",{parentName:"li"},"network1")," from ",(0,r.kt)("inlineCode",{parentName:"li"},"samples/fabric/fabric-cli")," folder:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"./scripts/getAssetStatus.sh\n"))),(0,r.kt)("li",{parentName:"ul"},"Run the following to verify the status of the assets owned by ",(0,r.kt)("inlineCode",{parentName:"li"},"PartyA")," and ",(0,r.kt)("inlineCode",{parentName:"li"},"PartyB")," in the ",(0,r.kt)("inlineCode",{parentName:"li"},"Corda_Network")," from ",(0,r.kt)("inlineCode",{parentName:"li"},"samples/corda/corda-simple-application")," folder:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"./scripts/getAssetStatus.sh\n")))),(0,r.kt)("p",null,"The above steps complete a successful asset exchange between Fabric and Corda networks.\nIn addition to the above commands, following commands can be run if specified timeout has expired and the locked asset remains unclaimed."),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"If ",(0,r.kt)("inlineCode",{parentName:"li"},"alice")," wants to unlock the bond asset, run the following to trigger ",(0,r.kt)("inlineCode",{parentName:"li"},"alice"),"'s re-claim for ",(0,r.kt)("inlineCode",{parentName:"li"},"bond01:a03")," locked in ",(0,r.kt)("inlineCode",{parentName:"li"},"network1"),":",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset exchange unlock --locker=alice --recipient=bob --target-network=network1 --param=bond01:a03\n"))),(0,r.kt)("li",{parentName:"ul"},"If ",(0,r.kt)("inlineCode",{parentName:"li"},"PartyB")," wants to unlock the token asset, run the following to trigger unlock for ",(0,r.kt)("inlineCode",{parentName:"li"},"t1:50")," locked in ",(0,r.kt)("inlineCode",{parentName:"li"},"Corda_Network"),":",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"CORDA_PORT=10009 ./clients/build/install/clients/bin/clients unlock-asset --contract-id=<contract-id>\n")))))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/61becdbc.f7024449.js b/assets/js/61becdbc.31328576.js similarity index 70% rename from assets/js/61becdbc.f7024449.js rename to assets/js/61becdbc.31328576.js index cb587d2ed..f98549fa6 100644 --- a/assets/js/61becdbc.f7024449.js +++ b/assets/js/61becdbc.31328576.js @@ -1 +1 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[8340],{5745:e=>{e.exports=JSON.parse('{"name":"docusaurus-plugin-content-pages","id":"default"}')}}]); \ No newline at end of file +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[5863],{4061:e=>{e.exports=JSON.parse('{"name":"docusaurus-plugin-content-pages","id":"default"}')}}]); \ No newline at end of file diff --git a/assets/js/64b157a3.8598d1d7.js b/assets/js/64b157a3.8598d1d7.js new file mode 100644 index 000000000..120bac6dc --- /dev/null +++ b/assets/js/64b157a3.8598d1d7.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[8110],{8027:e=>{e.exports=JSON.parse('{"blogPosts":[{"id":"/2021/01/21/cross-chain-asset","metadata":{"permalink":"/weaver-dlt-interoperability/blog/2021/01/21/cross-chain-asset","source":"@site/blog/2021-01-21-cross-chain-asset.md","title":"cross-chain-asset","description":"\x3c!--","date":"2021-01-21T00:00:00.000Z","formattedDate":"January 21, 2021","tags":[],"readingTime":10.435,"hasTruncateMarker":false,"authors":[],"frontMatter":{},"nextItem":{"title":"emergence-enterprise-interoperability","permalink":"/weaver-dlt-interoperability/blog/2021/01/21/emergence-enterprise-interoperability"}},"content":"\x3c!--\\n Copyright IBM Corp. All Rights Reserved.\\n\\n SPDX-License-Identifier: CC-BY-4.0\\n --\x3e\\n---\\nslug: cross-chain-asset\\ntitle: Enabling Cross-Chain Asset Exchange On Permissioned Blockchains\\nauthor: Yining Hu, Ermyas Abebe, Dileban Karunamoorthy, Venkatraman Ramakrishna\\nauthor_title: Contributors\\nauthor_url: https://hyperledger-labs.github.io/weaver-dlt-interoperability/\\ntags: [enterprise, interoperability, asset-exchange]\\n---\\n## Introduction\\nRecent years have witnessed a growing demand for enabling interoperability across independent blockchains. Cross-chain asset exchange is a significant step towards blockchain interoperability. For public blockchains, the most popular application for asset exchange is cryptocurrency exchange. For permissioned blockchains, cross-chain asset exchange can be useful in [Delivery Versus Payment (DvP)](https://www.mas.gov.sg/-/media/MAS/ProjectUbin/Project-Ubin-DvP-on-Distributed-Ledger-Technologies.pdf) and [cross-border payment](https://www.mas.gov.sg/-/media/Jasper-Ubin-Design-Paper.pdf) scenarios. There exist various protocols designed for asset exchange on public blockchains. However, a widely adopted standard for designing such protocols for permissioned blockchains still does not exist. Moreover, most existing protocols are designed for public blockchains and their suitability to be applied to permissioned blockchains is unclear.\\n\\nIn this article, we aim to lay out a set of requirements for designing cross-chain asset exchange protocols between permissioned blockchains. First we present a canonical motivating use case and then list the various patterns that such cases will follow in real-life scenarios. We then present a short survey of existing cross-chain exchange protocols for public blockchains, following which we summarise the building blocks, core mechanisms and security properties commonly involved in the protocol designs. We then analyse the requirements imposed by permissioned blockchains in comparison to public blockchains, and discuss the additional properties with respect to these restrictions.\\n\\n## Motivation and Use-case\\nIn traditional financial markets parties trade assets such as securities and derivatives for cash or other assets. To reduce risk, various clearing and settlement processes and intermediaries are often involved. One form of settlement is a DvP where the transfer of securities is performed only in the event of a corresponding payment. This arrangement reduces principal risk by ensuring that both parties receive their end of the exchange. However, settlement in financial markets are slow and time consuming. It also involves counterparty risks and requires intermediaries.\\n\\nOver the past few years, we have been seeing significant efforts in digitising and tokenising both currencies and securities on Distributed Ledger Technology (DLT) infrastructures. On the one hand we have seen concerted efforts around Central Bank Digital Currencies (CBDC) being added to the landscape of other blockchain based payment networks. On the other hand, we have also seen efforts such as that from the Australian Stock Exchange (ASX) to replace its current settlement system--Clearing House Electronic Subregister System (CHESS) with a DLT based platform by 2021.\\n\\nAgainst this backdrop, a number of central banks have been exploring the potential of performing DvP settlement across a currency ledger and a securities ledger. In this article, we use this as a motivating use-case for our discussions. The scenario involves two decentralised ledgers, namely, a currency ledger and a securities ledger, based on different DLT protocols performing a coordinated transfer of assets in their respective ledgers. Figure 1 depicts this scenario in the context of two organisations--Bank A and Bank B--in which Bank B wants to purchase some securities owned by Bank A and both organisations have accounts on both ledgers. To effect this exchange the following two transactions will have to happen atomically across both networks: i) transfer of payment from Bank B\'s currency account to Bank A while at the same time ii) the entitlements of the designated securities is transferred from Bank A to Bank B. The scenario would need to guarantee that after the transaction execution, either both parties have their end of the exchange or neither does and that this exchange is performed in a timely manner. \\n\\n![alt text](/simple-dvp.png)\\n\\nFigure 1. A typical DvP use-case.\\n\\nCross-chain transactions involving the movement of assets can generally take the form of either an asset exchange between parties or of value transfer from one network to another. The latter involves a scenario in which an asset in one network is locked or burned and a corresponding asset of similar value is issued in a corresponding network. This process generally involves validators or asset issuers in either or both ends of the network. While there are numerous use cases for this model in permissionless context, in this post we primarily focus on asset exchange scenarios, which are more broadly applicable in enterprise use-cases. Asset exchange scenarios generally involve two users swapping corresponding assets managed by the different networks, as in the example illustrated earlier. In asset exchange scenarios involving only two parties, both parties have accounts on both networks, although this might not be the case for exchanges involving more than two parties or networks.\\n\\n## Cross-Chain Asset Exchange on Public Blockchains\\nSimilar scenarios that involve a pair of transactions being coordinated across distinct blockchains have been studied for public blockchains. One main application area is to enable decentralised exchange across crypto-currency networks. To achieve this, a number of cross-chain asset exchange protocols have been proposed. The original atomic swap protocol was proposed by [TierNolan](https://en.bitcoin.it/wiki/Atomic_swap) in the Bitcoin Forum. The protocol leverages trusted escrow services on both blockchains and relies on the asset owners for execution. [Prestwich](https://summa.one/) later improved the protocol by removing the trusted escrow services and using a smart contract to automatically execute the swap. Both protocols, however, are asymmetric and hence enforce a particular sequence of events. More recently, a group of researchers developed [Arwen](https://arwen.io/whitepaper.pdf), which guarantees the symmetricality of the protocol and further eases the asset owners\' responsibilities in the protocol execution. \\n\\nWe below first discuss the common patterns involved in the protocol design. More specifically, we present the main building blocks, core mechanisms, and security properties achieved by these protocols. \\n\\n# Building blocks\\nThe design of a cross-chain asset exchange protocol in general contain the following building blocks: 1) the infrastructure for cross-chain state verification, and 2) the asset exchange protocol that specifies parties and sequences involved in the protocol execution. Cross-chain state verification can be performed by the exchanging parties themselves or by an external party.\\n\\n# Core Mechanisms\\n* Fund locking: To initialise an asset exchange, it is common for one or both parties to first lock up funds with a fund-withholding party on his or her own blockchain. Temporary fund locking ensures the locked fund cannot be used for other purposes while the exchange is being executed. This scheme is often used with a specified timeout to provide flexibility for reclaiming locked funds if the exchange does not take place.\\n\\n* Fund redeeming: In general, the execution requires a pair of transactions to occur on both blockchains, e.g., from User A to User B on Chain A and from User B to User A on Chain B. When certain conditions are met, the locked funds can be redeemed by, or paid to the respective users. The execution of the exchange can be carried out by users themselves, or through other trusted third parties. These trusted third parties can be stand-alone parties that are not otherwise involved in both blockchains, or part of either blockchain. \\n\\n* Refund: For protocols that are initialised with a temporary fund-locking, the locked funds can usually be reclaimed by the initial owner after a specified timeout. \\n\\n# Security Properties\\n* Atomicity: Atomicity is also sometimes referred to as safety. In general, atomicity implies indivisibility and irreducibility, namely, an atomic operation must be performed entirely or not performed at all. In the case of cross-chain asset exchange, when User A sends a payment to User B on Chain A, User B should also send corresponding delivery to User A on Chain B.\\n\\n* Liveness: Specifies the design of an asset exchange protocol should ensure no party can be tricked into locking up funds forever or for a very long time.\\n\\n## Extending Protocol Design To Permissioned Blockchains\\nRequirements of Permissioned Blockchains\\nAs public blockchains offer decentralisation and transparency, existing cross-chain asset exchange protocols on public blockchains are often designed for users to voluntarily participant and execute. To ensure secure execution of these protocols, their designs usually incorporate economic incentives, together with on-chain punishment schemes. To ensure liveness, these protocols usually leverage group consensus and fault-tolerance.\\n\\nPermissioned blockchains on the other hand require privacy. Additional economic incentives and punishments are often not required besides the existing business relationships and established legal jurisdictions. Therefore, compared to public blockchains, the design of cross-chain asset exchange protocols on permissioned blockchains allows a higher level of centralisation and requires auditability and individual or group accountability for off-chain dispute resolution rather than economic incentives and on-chain punishments. Moreover, as permissioned blockchains themselves offer a higher throughput and faster transaction processing than public blockchains, the asset exchange protocol ideally should not introduce significant processing overheads that limit the transaction processing capability.\\n\\nTherefore, the challenges in designing cross-chain asset exchange protocols for permissioned networks can be summarised as follow:\\n* Permissioned networks are usually confidential by design, thus restricting access for its internal members and external clients. State verification is hard to achieve across distinct permissioned blockchains. Cross-chain asset exchange protocols must therefore incorporate additional mechanisms to overcome these challenges.\\n* Unlike public blockchains, permissioned blockchains derive their security from and the ability to hold parties accountable for their actions. Any party acting maliciously should be identified and penalized during an off-chain dispute resolution process. Thus we can relax some of the constraints of the exchange protocol. For example, we can leverage trusted third-parties instead of having to financially incentivise regular users to participate in running the protocol.\\n\\n# Additional Properties\\nIn addition to following the same set of building blocks, core mechanisms and security properties as public protocols, we also identify an additional set of desired properties for permissioned blockchains.\\n\\n* Scalability: Scalability is often restricted by two factors. Firstly, the transaction processing capability of the underlying infrastructures. When a protocol relies on public blockchains, the throughput is consequently limited by the transaction processing of the blockchains themselves. In contrast, some protocols are off-chain, which usually allow faster transaction processing. Secondly, for protocols that involve third parties for fund-locking, such as [Xclaim](https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=8835387) and [Dogethereum](https://arxiv.org/pdf/1908.03999.pdf), the amount of money owned by these third parties limits the number of transaction requests they can process. As permissioned blockchains in general have a higher throughput compared to public blockchains, the protocol design should not trade off scalability.\\n\\n* Auditability: Auditability for public blockchains specifies that any party with read right should be able to detect protocol failure. On permissioned blockchains, however, as parties have limited visibility over the ledger state, who can detect protocol failure will most-likely depend on the use-case. In addition, financial regulatory requirements such as AML and CTF might require cross-chain traceability and auditability of exchange transactions (i.e. it should be easy to trace why Alice just transferred Bob $1M on a CBDC network).\\n\\n* Accountability: Accountability says faulty parties should be held accountable. This can refer to individual accountability or group accountability. As it is hard to enforce on-chain punishments on permissioned blockchains, the protocol design should at least allow adversaries to be held accountable.\\n\\n* Compatibility: Compatibility specifies how easy it is to implement the protocol on other blockchain platforms. The protocol design should be generic and not to be limited to particular blockchain platforms.\\n\\n* Extensibility: Extensibility specifies how easy it is to extend the protocol to other use cases, for instance, from two parties to multiple parties, or from one particular transaction pattern to other transaction patterns. \\n\\n* Privacy: Privacy is usually not automatically guaranteed by public blockchains. For sensitive use-cases, extra mechanisms such as a [trusted execution environment (TEE)](https://dl.acm.org/doi/pdf/10.1145/3319535.3363221?casa_token=_CXTS4E4hVsAAAAA:9YXRV8SUF7ljmdn2iovE1la3_j6Yn7O1oKqrdZZwxrO_u_Dg2sRqjYdVcTUCLFayNd-s8AWZfELaKA) can be used. Privacy is also of vital importance when it comes to permissioned blockchains. Most existing cross-chain protocols are designed for public blockchains. As the execution of these protocols may require asset owners or third-parties to access states on either blockchain ledger, executing a cross-chain asset exchange can put user privacy at risk.\\n\\n* Low Cost: As many of the cross-chain exchange protocols involve sending on-chain transactions, the concern over number of transactions and transaction fees arises when the protocol design involves a public blockchain.\\n\\n## Conclusion\\nTo summarise, in this article we tackle the problem of enabling cross-chain asset exchange on permissioned blockchains and evaluate the different requirements imposed by public blockchains and permissioned blockchains. We also articulate a set of desired properties to guide the design of cross-chain asset exchange protocols.\\n\\nFor general-purpose interoperability of enterprise blockchains, we have developed the [Weaver](https://hyperledger-labs.github.io/weaver-dlt-interoperability/) tool that incorporates a cross-chain state verification engine to enable cross-chain state sharing and verification. Please check out our documentation for implementation details and example applications."},{"id":"/2021/01/21/emergence-enterprise-interoperability","metadata":{"permalink":"/weaver-dlt-interoperability/blog/2021/01/21/emergence-enterprise-interoperability","source":"@site/blog/2021-01-21-emergence-enterprise-interoperability.md","title":"emergence-enterprise-interoperability","description":"\x3c!--","date":"2021-01-21T00:00:00.000Z","formattedDate":"January 21, 2021","tags":[],"readingTime":4.945,"hasTruncateMarker":false,"authors":[],"frontMatter":{},"prevItem":{"title":"cross-chain-asset","permalink":"/weaver-dlt-interoperability/blog/2021/01/21/cross-chain-asset"}},"content":"\x3c!--\\n Copyright IBM Corp. All Rights Reserved.\\n\\n SPDX-License-Identifier: CC-BY-4.0\\n --\x3e\\n---\\nslug: emergence-enterprise-interoperability\\ntitle: Emergence of Enterprise DLT Interoperability\\nauthor: Venkatraman Ramakrishna\\nauthor_title: Maintainer of Weaver\\nauthor_url: https://github.com/VRamakrishna\\nauthor_image_url: https://avatars2.githubusercontent.com/u/14888211?s=400&v=4\\ntags: [enterprise, interoperability]\\n---\\n\\nIt is instructive to know the course taken by blockchain technology and its applications over the past few years, as this will allow us to understand where we are, where are headed, and thereby motivate the necessity of interoperability.\\n\\n## The Grand Vision\\nThe original vision of blockchain technology called for a global decentralized network of peers and clients that could conduct transactions at scale without requiring intermediation by trusted third parties. The Bitcoin network was the first example of this, and it was purposely left open for anyone to join precisely because its initiators hoped for a single global network somewhat akin to the internet.\\n\\nBut the limitations of Bitcoin as a transaction processing system soon became apparent, and the Ethereum network emerged to fill this gap, retaining the openness and scalability of Bitcoin while supporting arbitrary smart contracts over a shared ledger. But Ethereum too was not destined to be the single canonical global blockchain network that everyone would use.\\n\\nSub-groups within the Bitcoin and Ethereum communities dissented from the rest, thereby creating _forks_, or separate networks with separate chains of blocks. Others found limitations in the usability of the existing networks or their consensus mechanisms (Proof of Work) and decided to build their own networks to which like-minded people could subscribe and in which they could conduct their transactions.\\n\\nTherefore, the original Bitcoin (or even Ethereum) vision of a single global network was not to be, and networks with different clientele and different consensus protocols proliferated.\\n\\nAnd then came private (or permissioned) networks......\\n\\n## Evolution of Private Networks\\nSometime in the first half of the previous decade, it was recognized that networks like Bitcoin and Ethereum were not suitable for much of the business that involves private enterprises, governmental institutions, and ordinary clients. Private networks then emerged as a means to retain the trustworthiness and consensus-based decision-making properties of blockchains (and distributed ledgers in general) while ensuring that:\\n- Transactions and ledger state are privy only to a selected set of entities,\\n- Transactions can be audited by trusted authorities when required for dispute resolutions, and\\n- Higher performance and assurance can be gained using consensus protocols other than _proof-of-work_.\\n\\nSince companies and consortia were wary of this new and unproven technology, the trend in industry these past few years has been to build _minimum viable ecosystems_, i.e., networks of limited operational scope and participation. The goal being to evaluate the potential of blockchain, these networks were created to manage selected few assets and records. Needless to say, interoperation with other networks was not high on the priority list when such networks were designed and launched.\\n\\nMany of these networks have been successfully validated and put into production. But a consequence of the decision to build limited-scope networks is that the processes they run (through smart contracts) and the assets and records they maintain on their ledgers are stuck in siloes, inaccessible to external entitites and networks. Yet, as we are discovering, processes and assets in such networks are inextricably linked in the real enterprise world. With all of the investment (in time and money) made in existing networks, reeingeneering or merging them will generally be hardsells. Also, some networks may wish to restrict operational control and ledger visibility to its current set of administrators and clientele. The only viable solution is to allow networks to interoperate, thereby breaking up the siloes, while retaining operational control.\\n\\n## Diverse Platforms\\nOur present blockchain landscape (or ecosystem) is characterized not just by a plethora of networks, a mix of open and private, but also by the existence of several distinct blockchain technologies, each with a different storage technology, a different model for contracts and client applications, a different consensus protocol, and a different way of managing identity. Examples include Fabric, Iroha, Sawtooth, and Besu, all in the Hyperledger family, and Ethereum, Multichain, Cardano, and Komodo, outside it. There are also smart contract distributed ledger platforms that serve a similar set of business applications that are not blockchains at all, like R3\'s Corda.\\n\\nSince there is no single blockchain, or distributed ledger, technology, the world agrees on, and because each offers a different set of advantages and disadvantages, the networks that exist today are built on a diverse set of such platforms.\\n\\n## Blockchain Landscape\\nOur present is, and our near future will be, characterized by the existence of independent networks, some of which offer open membership whereas others are restricted, built on diverse platforms that are mutually incompatible. Asking everyone to converge to a single global network running on a single canonical platform is almost impossible. So unless we wish entities and assets to remain trapped within siloes, it should be evident that interoperability amoong different networks and platforms is crucial to the success of blockchain.\\n\\n## Challenges\\n\\nInterlinking processes distributed across different networks or transferring or sharing assets and data may sound like a straightforward task, but the traditional method of service and API integration will not work in scenarios that involve permissioned networks.\\n\\nThis is because, as you will see in the [user stories](/docs/external/user-stories/overview), entities that are interested in the asset or data record being shared may not be members of both networks. And even if a particular entity happens to be a member of both networks, it may be in its interest to present a false view of one network\'s ledger state to another.\\n\\nTherefore, interoperation cannot be allowed to hinge on the trustworthiness of a particular network member, or by extension, a third party. In the stories we will encounter, it will be apparent how such situations may occur. This will make the unreliability of API integration across private networks clear and also motivate the need for consensus-based interoperation protocols."}]}')}}]); \ No newline at end of file diff --git a/assets/js/64b157a3.dc655d52.js b/assets/js/64b157a3.dc655d52.js deleted file mode 100644 index 339d5c6a9..000000000 --- a/assets/js/64b157a3.dc655d52.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[830],{9926:e=>{e.exports=JSON.parse('{"blogPosts":[{"id":"/2021/01/21/cross-chain-asset","metadata":{"permalink":"/weaver-dlt-interoperability/blog/2021/01/21/cross-chain-asset","source":"@site/blog/2021-01-21-cross-chain-asset.md","title":"cross-chain-asset","description":"\x3c!--","date":"2021-01-21T00:00:00.000Z","formattedDate":"January 21, 2021","tags":[],"readingTime":10.435,"hasTruncateMarker":false,"authors":[],"frontMatter":{},"nextItem":{"title":"emergence-enterprise-interoperability","permalink":"/weaver-dlt-interoperability/blog/2021/01/21/emergence-enterprise-interoperability"}},"content":"\x3c!--\\n Copyright IBM Corp. All Rights Reserved.\\n\\n SPDX-License-Identifier: CC-BY-4.0\\n --\x3e\\n---\\nslug: cross-chain-asset\\ntitle: Enabling Cross-Chain Asset Exchange On Permissioned Blockchains\\nauthor: Yining Hu, Ermyas Abebe, Dileban Karunamoorthy, Venkatraman Ramakrishna\\nauthor_title: Contributors\\nauthor_url: https://hyperledger-labs.github.io/weaver-dlt-interoperability/\\ntags: [enterprise, interoperability, asset-exchange]\\n---\\n## Introduction\\nRecent years have witnessed a growing demand for enabling interoperability across independent blockchains. Cross-chain asset exchange is a significant step towards blockchain interoperability. For public blockchains, the most popular application for asset exchange is cryptocurrency exchange. For permissioned blockchains, cross-chain asset exchange can be useful in [Delivery Versus Payment (DvP)](https://www.mas.gov.sg/-/media/MAS/ProjectUbin/Project-Ubin-DvP-on-Distributed-Ledger-Technologies.pdf) and [cross-border payment](https://www.mas.gov.sg/-/media/Jasper-Ubin-Design-Paper.pdf) scenarios. There exist various protocols designed for asset exchange on public blockchains. However, a widely adopted standard for designing such protocols for permissioned blockchains still does not exist. Moreover, most existing protocols are designed for public blockchains and their suitability to be applied to permissioned blockchains is unclear.\\n\\nIn this article, we aim to lay out a set of requirements for designing cross-chain asset exchange protocols between permissioned blockchains. First we present a canonical motivating use case and then list the various patterns that such cases will follow in real-life scenarios. We then present a short survey of existing cross-chain exchange protocols for public blockchains, following which we summarise the building blocks, core mechanisms and security properties commonly involved in the protocol designs. We then analyse the requirements imposed by permissioned blockchains in comparison to public blockchains, and discuss the additional properties with respect to these restrictions.\\n\\n## Motivation and Use-case\\nIn traditional financial markets parties trade assets such as securities and derivatives for cash or other assets. To reduce risk, various clearing and settlement processes and intermediaries are often involved. One form of settlement is a DvP where the transfer of securities is performed only in the event of a corresponding payment. This arrangement reduces principal risk by ensuring that both parties receive their end of the exchange. However, settlement in financial markets are slow and time consuming. It also involves counterparty risks and requires intermediaries.\\n\\nOver the past few years, we have been seeing significant efforts in digitising and tokenising both currencies and securities on Distributed Ledger Technology (DLT) infrastructures. On the one hand we have seen concerted efforts around Central Bank Digital Currencies (CBDC) being added to the landscape of other blockchain based payment networks. On the other hand, we have also seen efforts such as that from the Australian Stock Exchange (ASX) to replace its current settlement system--Clearing House Electronic Subregister System (CHESS) with a DLT based platform by 2021.\\n\\nAgainst this backdrop, a number of central banks have been exploring the potential of performing DvP settlement across a currency ledger and a securities ledger. In this article, we use this as a motivating use-case for our discussions. The scenario involves two decentralised ledgers, namely, a currency ledger and a securities ledger, based on different DLT protocols performing a coordinated transfer of assets in their respective ledgers. Figure 1 depicts this scenario in the context of two organisations--Bank A and Bank B--in which Bank B wants to purchase some securities owned by Bank A and both organisations have accounts on both ledgers. To effect this exchange the following two transactions will have to happen atomically across both networks: i) transfer of payment from Bank B\'s currency account to Bank A while at the same time ii) the entitlements of the designated securities is transferred from Bank A to Bank B. The scenario would need to guarantee that after the transaction execution, either both parties have their end of the exchange or neither does and that this exchange is performed in a timely manner. \\n\\n![alt text](/simple-dvp.png)\\n\\nFigure 1. A typical DvP use-case.\\n\\nCross-chain transactions involving the movement of assets can generally take the form of either an asset exchange between parties or of value transfer from one network to another. The latter involves a scenario in which an asset in one network is locked or burned and a corresponding asset of similar value is issued in a corresponding network. This process generally involves validators or asset issuers in either or both ends of the network. While there are numerous use cases for this model in permissionless context, in this post we primarily focus on asset exchange scenarios, which are more broadly applicable in enterprise use-cases. Asset exchange scenarios generally involve two users swapping corresponding assets managed by the different networks, as in the example illustrated earlier. In asset exchange scenarios involving only two parties, both parties have accounts on both networks, although this might not be the case for exchanges involving more than two parties or networks.\\n\\n## Cross-Chain Asset Exchange on Public Blockchains\\nSimilar scenarios that involve a pair of transactions being coordinated across distinct blockchains have been studied for public blockchains. One main application area is to enable decentralised exchange across crypto-currency networks. To achieve this, a number of cross-chain asset exchange protocols have been proposed. The original atomic swap protocol was proposed by [TierNolan](https://en.bitcoin.it/wiki/Atomic_swap) in the Bitcoin Forum. The protocol leverages trusted escrow services on both blockchains and relies on the asset owners for execution. [Prestwich](https://summa.one/) later improved the protocol by removing the trusted escrow services and using a smart contract to automatically execute the swap. Both protocols, however, are asymmetric and hence enforce a particular sequence of events. More recently, a group of researchers developed [Arwen](https://arwen.io/whitepaper.pdf), which guarantees the symmetricality of the protocol and further eases the asset owners\' responsibilities in the protocol execution. \\n\\nWe below first discuss the common patterns involved in the protocol design. More specifically, we present the main building blocks, core mechanisms, and security properties achieved by these protocols. \\n\\n# Building blocks\\nThe design of a cross-chain asset exchange protocol in general contain the following building blocks: 1) the infrastructure for cross-chain state verification, and 2) the asset exchange protocol that specifies parties and sequences involved in the protocol execution. Cross-chain state verification can be performed by the exchanging parties themselves or by an external party.\\n\\n# Core Mechanisms\\n* Fund locking: To initialise an asset exchange, it is common for one or both parties to first lock up funds with a fund-withholding party on his or her own blockchain. Temporary fund locking ensures the locked fund cannot be used for other purposes while the exchange is being executed. This scheme is often used with a specified timeout to provide flexibility for reclaiming locked funds if the exchange does not take place.\\n\\n* Fund redeeming: In general, the execution requires a pair of transactions to occur on both blockchains, e.g., from User A to User B on Chain A and from User B to User A on Chain B. When certain conditions are met, the locked funds can be redeemed by, or paid to the respective users. The execution of the exchange can be carried out by users themselves, or through other trusted third parties. These trusted third parties can be stand-alone parties that are not otherwise involved in both blockchains, or part of either blockchain. \\n\\n* Refund: For protocols that are initialised with a temporary fund-locking, the locked funds can usually be reclaimed by the initial owner after a specified timeout. \\n\\n# Security Properties\\n* Atomicity: Atomicity is also sometimes referred to as safety. In general, atomicity implies indivisibility and irreducibility, namely, an atomic operation must be performed entirely or not performed at all. In the case of cross-chain asset exchange, when User A sends a payment to User B on Chain A, User B should also send corresponding delivery to User A on Chain B.\\n\\n* Liveness: Specifies the design of an asset exchange protocol should ensure no party can be tricked into locking up funds forever or for a very long time.\\n\\n## Extending Protocol Design To Permissioned Blockchains\\nRequirements of Permissioned Blockchains\\nAs public blockchains offer decentralisation and transparency, existing cross-chain asset exchange protocols on public blockchains are often designed for users to voluntarily participant and execute. To ensure secure execution of these protocols, their designs usually incorporate economic incentives, together with on-chain punishment schemes. To ensure liveness, these protocols usually leverage group consensus and fault-tolerance.\\n\\nPermissioned blockchains on the other hand require privacy. Additional economic incentives and punishments are often not required besides the existing business relationships and established legal jurisdictions. Therefore, compared to public blockchains, the design of cross-chain asset exchange protocols on permissioned blockchains allows a higher level of centralisation and requires auditability and individual or group accountability for off-chain dispute resolution rather than economic incentives and on-chain punishments. Moreover, as permissioned blockchains themselves offer a higher throughput and faster transaction processing than public blockchains, the asset exchange protocol ideally should not introduce significant processing overheads that limit the transaction processing capability.\\n\\nTherefore, the challenges in designing cross-chain asset exchange protocols for permissioned networks can be summarised as follow:\\n* Permissioned networks are usually confidential by design, thus restricting access for its internal members and external clients. State verification is hard to achieve across distinct permissioned blockchains. Cross-chain asset exchange protocols must therefore incorporate additional mechanisms to overcome these challenges.\\n* Unlike public blockchains, permissioned blockchains derive their security from and the ability to hold parties accountable for their actions. Any party acting maliciously should be identified and penalized during an off-chain dispute resolution process. Thus we can relax some of the constraints of the exchange protocol. For example, we can leverage trusted third-parties instead of having to financially incentivise regular users to participate in running the protocol.\\n\\n# Additional Properties\\nIn addition to following the same set of building blocks, core mechanisms and security properties as public protocols, we also identify an additional set of desired properties for permissioned blockchains.\\n\\n* Scalability: Scalability is often restricted by two factors. Firstly, the transaction processing capability of the underlying infrastructures. When a protocol relies on public blockchains, the throughput is consequently limited by the transaction processing of the blockchains themselves. In contrast, some protocols are off-chain, which usually allow faster transaction processing. Secondly, for protocols that involve third parties for fund-locking, such as [Xclaim](https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=8835387) and [Dogethereum](https://arxiv.org/pdf/1908.03999.pdf), the amount of money owned by these third parties limits the number of transaction requests they can process. As permissioned blockchains in general have a higher throughput compared to public blockchains, the protocol design should not trade off scalability.\\n\\n* Auditability: Auditability for public blockchains specifies that any party with read right should be able to detect protocol failure. On permissioned blockchains, however, as parties have limited visibility over the ledger state, who can detect protocol failure will most-likely depend on the use-case. In addition, financial regulatory requirements such as AML and CTF might require cross-chain traceability and auditability of exchange transactions (i.e. it should be easy to trace why Alice just transferred Bob $1M on a CBDC network).\\n\\n* Accountability: Accountability says faulty parties should be held accountable. This can refer to individual accountability or group accountability. As it is hard to enforce on-chain punishments on permissioned blockchains, the protocol design should at least allow adversaries to be held accountable.\\n\\n* Compatibility: Compatibility specifies how easy it is to implement the protocol on other blockchain platforms. The protocol design should be generic and not to be limited to particular blockchain platforms.\\n\\n* Extensibility: Extensibility specifies how easy it is to extend the protocol to other use cases, for instance, from two parties to multiple parties, or from one particular transaction pattern to other transaction patterns. \\n\\n* Privacy: Privacy is usually not automatically guaranteed by public blockchains. For sensitive use-cases, extra mechanisms such as a [trusted execution environment (TEE)](https://dl.acm.org/doi/pdf/10.1145/3319535.3363221?casa_token=_CXTS4E4hVsAAAAA:9YXRV8SUF7ljmdn2iovE1la3_j6Yn7O1oKqrdZZwxrO_u_Dg2sRqjYdVcTUCLFayNd-s8AWZfELaKA) can be used. Privacy is also of vital importance when it comes to permissioned blockchains. Most existing cross-chain protocols are designed for public blockchains. As the execution of these protocols may require asset owners or third-parties to access states on either blockchain ledger, executing a cross-chain asset exchange can put user privacy at risk.\\n\\n* Low Cost: As many of the cross-chain exchange protocols involve sending on-chain transactions, the concern over number of transactions and transaction fees arises when the protocol design involves a public blockchain.\\n\\n## Conclusion\\nTo summarise, in this article we tackle the problem of enabling cross-chain asset exchange on permissioned blockchains and evaluate the different requirements imposed by public blockchains and permissioned blockchains. We also articulate a set of desired properties to guide the design of cross-chain asset exchange protocols.\\n\\nFor general-purpose interoperability of enterprise blockchains, we have developed the [Weaver](https://hyperledger-labs.github.io/weaver-dlt-interoperability/) tool that incorporates a cross-chain state verification engine to enable cross-chain state sharing and verification. Please check out our documentation for implementation details and example applications."},{"id":"/2021/01/21/emergence-enterprise-interoperability","metadata":{"permalink":"/weaver-dlt-interoperability/blog/2021/01/21/emergence-enterprise-interoperability","source":"@site/blog/2021-01-21-emergence-enterprise-interoperability.md","title":"emergence-enterprise-interoperability","description":"\x3c!--","date":"2021-01-21T00:00:00.000Z","formattedDate":"January 21, 2021","tags":[],"readingTime":4.945,"hasTruncateMarker":false,"authors":[],"frontMatter":{},"prevItem":{"title":"cross-chain-asset","permalink":"/weaver-dlt-interoperability/blog/2021/01/21/cross-chain-asset"}},"content":"\x3c!--\\n Copyright IBM Corp. All Rights Reserved.\\n\\n SPDX-License-Identifier: CC-BY-4.0\\n --\x3e\\n---\\nslug: emergence-enterprise-interoperability\\ntitle: Emergence of Enterprise DLT Interoperability\\nauthor: Venkatraman Ramakrishna\\nauthor_title: Maintainer of Weaver\\nauthor_url: https://github.com/VRamakrishna\\nauthor_image_url: https://avatars2.githubusercontent.com/u/14888211?s=400&v=4\\ntags: [enterprise, interoperability]\\n---\\n\\nIt is instructive to know the course taken by blockchain technology and its applications over the past few years, as this will allow us to understand where we are, where are headed, and thereby motivate the necessity of interoperability.\\n\\n## The Grand Vision\\nThe original vision of blockchain technology called for a global decentralized network of peers and clients that could conduct transactions at scale without requiring intermediation by trusted third parties. The Bitcoin network was the first example of this, and it was purposely left open for anyone to join precisely because its initiators hoped for a single global network somewhat akin to the internet.\\n\\nBut the limitations of Bitcoin as a transaction processing system soon became apparent, and the Ethereum network emerged to fill this gap, retaining the openness and scalability of Bitcoin while supporting arbitrary smart contracts over a shared ledger. But Ethereum too was not destined to be the single canonical global blockchain network that everyone would use.\\n\\nSub-groups within the Bitcoin and Ethereum communities dissented from the rest, thereby creating _forks_, or separate networks with separate chains of blocks. Others found limitations in the usability of the existing networks or their consensus mechanisms (Proof of Work) and decided to build their own networks to which like-minded people could subscribe and in which they could conduct their transactions.\\n\\nTherefore, the original Bitcoin (or even Ethereum) vision of a single global network was not to be, and networks with different clientele and different consensus protocols proliferated.\\n\\nAnd then came private (or permissioned) networks......\\n\\n## Evolution of Private Networks\\nSometime in the first half of the previous decade, it was recognized that networks like Bitcoin and Ethereum were not suitable for much of the business that involves private enterprises, governmental institutions, and ordinary clients. Private networks then emerged as a means to retain the trustworthiness and consensus-based decision-making properties of blockchains (and distributed ledgers in general) while ensuring that:\\n- Transactions and ledger state are privy only to a selected set of entities,\\n- Transactions can be audited by trusted authorities when required for dispute resolutions, and\\n- Higher performance and assurance can be gained using consensus protocols other than _proof-of-work_.\\n\\nSince companies and consortia were wary of this new and unproven technology, the trend in industry these past few years has been to build _minimum viable ecosystems_, i.e., networks of limited operational scope and participation. The goal being to evaluate the potential of blockchain, these networks were created to manage selected few assets and records. Needless to say, interoperation with other networks was not high on the priority list when such networks were designed and launched.\\n\\nMany of these networks have been successfully validated and put into production. But a consequence of the decision to build limited-scope networks is that the processes they run (through smart contracts) and the assets and records they maintain on their ledgers are stuck in siloes, inaccessible to external entitites and networks. Yet, as we are discovering, processes and assets in such networks are inextricably linked in the real enterprise world. With all of the investment (in time and money) made in existing networks, reeingeneering or merging them will generally be hardsells. Also, some networks may wish to restrict operational control and ledger visibility to its current set of administrators and clientele. The only viable solution is to allow networks to interoperate, thereby breaking up the siloes, while retaining operational control.\\n\\n## Diverse Platforms\\nOur present blockchain landscape (or ecosystem) is characterized not just by a plethora of networks, a mix of open and private, but also by the existence of several distinct blockchain technologies, each with a different storage technology, a different model for contracts and client applications, a different consensus protocol, and a different way of managing identity. Examples include Fabric, Iroha, Sawtooth, and Besu, all in the Hyperledger family, and Ethereum, Multichain, Cardano, and Komodo, outside it. There are also smart contract distributed ledger platforms that serve a similar set of business applications that are not blockchains at all, like R3\'s Corda.\\n\\nSince there is no single blockchain, or distributed ledger, technology, the world agrees on, and because each offers a different set of advantages and disadvantages, the networks that exist today are built on a diverse set of such platforms.\\n\\n## Blockchain Landscape\\nOur present is, and our near future will be, characterized by the existence of independent networks, some of which offer open membership whereas others are restricted, built on diverse platforms that are mutually incompatible. Asking everyone to converge to a single global network running on a single canonical platform is almost impossible. So unless we wish entities and assets to remain trapped within siloes, it should be evident that interoperability amoong different networks and platforms is crucial to the success of blockchain.\\n\\n## Challenges\\n\\nInterlinking processes distributed across different networks or transferring or sharing assets and data may sound like a straightforward task, but the traditional method of service and API integration will not work in scenarios that involve permissioned networks.\\n\\nThis is because, as you will see in the [user stories](/docs/external/user-stories/overview), entities that are interested in the asset or data record being shared may not be members of both networks. And even if a particular entity happens to be a member of both networks, it may be in its interest to present a false view of one network\'s ledger state to another.\\n\\nTherefore, interoperation cannot be allowed to hinge on the trustworthiness of a particular network member, or by extension, a third party. In the stories we will encounter, it will be apparent how such situations may occur. This will make the unreliability of API integration across private networks clear and also motivate the need for consensus-based interoperation protocols."}]}')}}]); \ No newline at end of file diff --git a/assets/js/6835b8cd.cc86f083.js b/assets/js/6835b8cd.84a5f344.js similarity index 82% rename from assets/js/6835b8cd.cc86f083.js rename to assets/js/6835b8cd.84a5f344.js index f11c3e61b..a52121406 100644 --- a/assets/js/6835b8cd.cc86f083.js +++ b/assets/js/6835b8cd.84a5f344.js @@ -1 +1 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[6445],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>u});var n=r(7294);function i(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function o(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?a(Object(r),!0).forEach((function(t){i(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):a(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function l(e,t){if(null==e)return{};var r,n,i=function(e,t){if(null==e)return{};var r,n,i={},a=Object.keys(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||(i[r]=e[r]);return i}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(i[r]=e[r])}return i}var s=n.createContext({}),c=function(e){var t=n.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},p=function(e){var t=c(e.components);return n.createElement(s.Provider,{value:t},e.children)},d="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},f=n.forwardRef((function(e,t){var r=e.components,i=e.mdxType,a=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),d=c(r),f=i,u=d["".concat(s,".").concat(f)]||d[f]||m[f]||a;return r?n.createElement(u,o(o({ref:t},p),{},{components:r})):n.createElement(u,o({ref:t},p))}));function u(e,t){var r=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var a=r.length,o=new Array(a);o[0]=f;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[d]="string"==typeof e?e:i,o[1]=l;for(var c=2;c<a;c++)o[c]=r[c];return n.createElement.apply(null,o)}return n.createElement.apply(null,r)}f.displayName="MDXCreateElement"},1626:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>m,frontMatter:()=>a,metadata:()=>l,toc:()=>c});var n=r(7462),i=(r(7294),r(3905));const a={id:"specifications",title:"Specifications"},o=void 0,l={unversionedId:"external/specifications",id:"external/specifications",title:"Specifications",description:"\x3c!--",source:"@site/docs/external/specifications.md",sourceDirName:"external",slug:"/external/specifications",permalink:"/weaver-dlt-interoperability/docs/external/specifications",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/specifications.md",tags:[],version:"current",frontMatter:{id:"specifications",title:"Specifications"},sidebar:"Documentation",previous:{title:"Legal and Regulation",permalink:"/weaver-dlt-interoperability/docs/external/deployment-considerations/legal-and-regulation"},next:{title:"Roadmap",permalink:"/weaver-dlt-interoperability/docs/external/roadmap"}},s={},c=[],p={toc:c},d="wrapper";function m(e){let{components:t,...r}=e;return(0,i.kt)(d,(0,n.Z)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"The Weaver specifications (",(0,i.kt)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/rfcs"},"RFCs"),") capture abstractions, models, protocols and data formats for enabling cross-ledger communication."),(0,i.kt)("p",null,"For newcomers who wish to find out more details about the Weaver design and wish to contribute to the code base, we recommend starting with the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/rfcs/models"},"models"),". Protocol engineers will find in ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/rfcs/models/infrastructure/relays.md"},"RFC: 01-009")," a useful overview of the relay model, and may then progress on to reading one of the existing protocols' design and implementation; e.g., the data sharing protocol in ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/rfcs/protocols/data-sharing/generic.md"},"RFC: 02-001"),". If you are interested in adding support for a new ledger technology, see the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/core/drivers"},"existing driver implementations")," and ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/core/network"},"existing interoperability module implementations"),". Where relevant we use ",(0,i.kt)("a",{parentName:"p",href:"https://tools.ietf.org/html/rfc5234"},"ABNF")," for formal syntax definitions."))}m.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[9102],{5680:(e,t,r)=>{r.d(t,{xA:()=>p,yg:()=>u});var n=r(6540);function i(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function o(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?a(Object(r),!0).forEach((function(t){i(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):a(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function l(e,t){if(null==e)return{};var r,n,i=function(e,t){if(null==e)return{};var r,n,i={},a=Object.keys(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||(i[r]=e[r]);return i}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(i[r]=e[r])}return i}var s=n.createContext({}),c=function(e){var t=n.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},p=function(e){var t=c(e.components);return n.createElement(s.Provider,{value:t},e.children)},d="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},f=n.forwardRef((function(e,t){var r=e.components,i=e.mdxType,a=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),d=c(r),f=i,u=d["".concat(s,".").concat(f)]||d[f]||m[f]||a;return r?n.createElement(u,o(o({ref:t},p),{},{components:r})):n.createElement(u,o({ref:t},p))}));function u(e,t){var r=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var a=r.length,o=new Array(a);o[0]=f;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[d]="string"==typeof e?e:i,o[1]=l;for(var c=2;c<a;c++)o[c]=r[c];return n.createElement.apply(null,o)}return n.createElement.apply(null,r)}f.displayName="MDXCreateElement"},2879:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>m,frontMatter:()=>a,metadata:()=>l,toc:()=>c});var n=r(8168),i=(r(6540),r(5680));const a={id:"specifications",title:"Specifications"},o=void 0,l={unversionedId:"external/specifications",id:"external/specifications",title:"Specifications",description:"\x3c!--",source:"@site/docs/external/specifications.md",sourceDirName:"external",slug:"/external/specifications",permalink:"/weaver-dlt-interoperability/docs/external/specifications",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/specifications.md",tags:[],version:"current",frontMatter:{id:"specifications",title:"Specifications"},sidebar:"Documentation",previous:{title:"Legal and Regulation",permalink:"/weaver-dlt-interoperability/docs/external/deployment-considerations/legal-and-regulation"},next:{title:"Roadmap",permalink:"/weaver-dlt-interoperability/docs/external/roadmap"}},s={},c=[],p={toc:c},d="wrapper";function m(e){let{components:t,...r}=e;return(0,i.yg)(d,(0,n.A)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,i.yg)("p",null,"The Weaver specifications (",(0,i.yg)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/rfcs"},"RFCs"),") capture abstractions, models, protocols and data formats for enabling cross-ledger communication."),(0,i.yg)("p",null,"For newcomers who wish to find out more details about the Weaver design and wish to contribute to the code base, we recommend starting with the ",(0,i.yg)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/rfcs/models"},"models"),". Protocol engineers will find in ",(0,i.yg)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/rfcs/models/infrastructure/relays.md"},"RFC: 01-009")," a useful overview of the relay model, and may then progress on to reading one of the existing protocols' design and implementation; e.g., the data sharing protocol in ",(0,i.yg)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/rfcs/protocols/data-sharing/generic.md"},"RFC: 02-001"),". If you are interested in adding support for a new ledger technology, see the ",(0,i.yg)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/core/drivers"},"existing driver implementations")," and ",(0,i.yg)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/core/network"},"existing interoperability module implementations"),". Where relevant we use ",(0,i.yg)("a",{parentName:"p",href:"https://tools.ietf.org/html/rfc5234"},"ABNF")," for formal syntax definitions."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/7291aaef.1adc7d99.js b/assets/js/7291aaef.1adc7d99.js deleted file mode 100644 index aeedbf6d7..000000000 --- a/assets/js/7291aaef.1adc7d99.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[1323],{3905:(e,t,r)=>{r.d(t,{Zo:()=>d,kt:()=>f});var n=r(7294);function i(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function o(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?a(Object(r),!0).forEach((function(t){i(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):a(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function s(e,t){if(null==e)return{};var r,n,i=function(e,t){if(null==e)return{};var r,n,i={},a=Object.keys(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||(i[r]=e[r]);return i}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(i[r]=e[r])}return i}var c=n.createContext({}),l=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},d=function(e){var t=l(e.components);return n.createElement(c.Provider,{value:t},e.children)},p="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},h=n.forwardRef((function(e,t){var r=e.components,i=e.mdxType,a=e.originalType,c=e.parentName,d=s(e,["components","mdxType","originalType","parentName"]),p=l(r),h=i,f=p["".concat(c,".").concat(h)]||p[h]||u[h]||a;return r?n.createElement(f,o(o({ref:t},d),{},{components:r})):n.createElement(f,o({ref:t},d))}));function f(e,t){var r=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var a=r.length,o=new Array(a);o[0]=h;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[p]="string"==typeof e?e:i,o[1]=s;for(var l=2;l<a;l++)o[l]=r[l];return n.createElement.apply(null,o)}return n.createElement.apply(null,r)}h.displayName="MDXCreateElement"},5123:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>u,frontMatter:()=>a,metadata:()=>s,toc:()=>l});var n=r(7462),i=(r(7294),r(3905));const a={id:"drivers",title:"Drivers"},o=void 0,s={unversionedId:"external/architecture-and-design/drivers",id:"external/architecture-and-design/drivers",title:"Drivers",description:"\x3c!--",source:"@site/docs/external/architecture-and-design/drivers.md",sourceDirName:"external/architecture-and-design",slug:"/external/architecture-and-design/drivers",permalink:"/weaver-dlt-interoperability/docs/external/architecture-and-design/drivers",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/architecture-and-design/drivers.md",tags:[],version:"current",frontMatter:{id:"drivers",title:"Drivers"},sidebar:"Documentation",previous:{title:"Relay",permalink:"/weaver-dlt-interoperability/docs/external/architecture-and-design/relay"},next:{title:"Weaver Dapps",permalink:"/weaver-dlt-interoperability/docs/external/architecture-and-design/weaver-dapps"}},c={},l=[],d={toc:l},p="wrapper";function u(e){let{components:t,...a}=e;return(0,i.kt)(p,(0,n.Z)({},d,a,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"The driver is responsible for all communication between the relay and its network. In the previous sections we have thought about the driver as a component of the relay. We have done this because conceptually it makes sense to think about it like that. However, in our reference implementation we have made it a seperate process which communicates with the relay via gRPC, as shown below. There are two main reasons for this:"),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},'There must exist a different driver for each network type (e.g. Fabric, Corda etc.) and therefore having the driver as a seperate process makes it easy to "plug" different drivers into the relay.'),(0,i.kt)("li",{parentName:"ol"},"A possible use case of the relay is that a single relay instance may have multiple drivers (e.g. if multiple entities in the network want to run their own driver). In this case, this plugin style approach of drivers makes it possible to do without having to modify code for each configuration.")),(0,i.kt)("p",null,(0,i.kt)("img",{src:r(2097).Z,width:"1550",height:"454"})))}u.isMDXComponent=!0},2097:(e,t,r)=>{r.d(t,{Z:()=>n});const n=r.p+"assets/images/driver_architecture-0d494884ad83fb801a8c71ddf7d2e509.png"}}]); \ No newline at end of file diff --git a/assets/js/7291aaef.9864c556.js b/assets/js/7291aaef.9864c556.js new file mode 100644 index 000000000..c0093a657 --- /dev/null +++ b/assets/js/7291aaef.9864c556.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[7489],{5680:(e,r,t)=>{t.d(r,{xA:()=>d,yg:()=>f});var n=t(6540);function i(e,r,t){return r in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function a(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);r&&(n=n.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),t.push.apply(t,n)}return t}function o(e){for(var r=1;r<arguments.length;r++){var t=null!=arguments[r]?arguments[r]:{};r%2?a(Object(t),!0).forEach((function(r){i(e,r,t[r])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):a(Object(t)).forEach((function(r){Object.defineProperty(e,r,Object.getOwnPropertyDescriptor(t,r))}))}return e}function s(e,r){if(null==e)return{};var t,n,i=function(e,r){if(null==e)return{};var t,n,i={},a=Object.keys(e);for(n=0;n<a.length;n++)t=a[n],r.indexOf(t)>=0||(i[t]=e[t]);return i}(e,r);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n<a.length;n++)t=a[n],r.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(i[t]=e[t])}return i}var c=n.createContext({}),l=function(e){var r=n.useContext(c),t=r;return e&&(t="function"==typeof e?e(r):o(o({},r),e)),t},d=function(e){var r=l(e.components);return n.createElement(c.Provider,{value:r},e.children)},p="mdxType",u={inlineCode:"code",wrapper:function(e){var r=e.children;return n.createElement(n.Fragment,{},r)}},h=n.forwardRef((function(e,r){var t=e.components,i=e.mdxType,a=e.originalType,c=e.parentName,d=s(e,["components","mdxType","originalType","parentName"]),p=l(t),h=i,f=p["".concat(c,".").concat(h)]||p[h]||u[h]||a;return t?n.createElement(f,o(o({ref:r},d),{},{components:t})):n.createElement(f,o({ref:r},d))}));function f(e,r){var t=arguments,i=r&&r.mdxType;if("string"==typeof e||i){var a=t.length,o=new Array(a);o[0]=h;var s={};for(var c in r)hasOwnProperty.call(r,c)&&(s[c]=r[c]);s.originalType=e,s[p]="string"==typeof e?e:i,o[1]=s;for(var l=2;l<a;l++)o[l]=t[l];return n.createElement.apply(null,o)}return n.createElement.apply(null,t)}h.displayName="MDXCreateElement"},6824:(e,r,t)=>{t.r(r),t.d(r,{assets:()=>c,contentTitle:()=>o,default:()=>u,frontMatter:()=>a,metadata:()=>s,toc:()=>l});var n=t(8168),i=(t(6540),t(5680));const a={id:"drivers",title:"Drivers"},o=void 0,s={unversionedId:"external/architecture-and-design/drivers",id:"external/architecture-and-design/drivers",title:"Drivers",description:"\x3c!--",source:"@site/docs/external/architecture-and-design/drivers.md",sourceDirName:"external/architecture-and-design",slug:"/external/architecture-and-design/drivers",permalink:"/weaver-dlt-interoperability/docs/external/architecture-and-design/drivers",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/architecture-and-design/drivers.md",tags:[],version:"current",frontMatter:{id:"drivers",title:"Drivers"},sidebar:"Documentation",previous:{title:"Relay",permalink:"/weaver-dlt-interoperability/docs/external/architecture-and-design/relay"},next:{title:"Weaver Dapps",permalink:"/weaver-dlt-interoperability/docs/external/architecture-and-design/weaver-dapps"}},c={},l=[],d={toc:l},p="wrapper";function u(e){let{components:r,...a}=e;return(0,i.yg)(p,(0,n.A)({},d,a,{components:r,mdxType:"MDXLayout"}),(0,i.yg)("p",null,"The driver is responsible for all communication between the relay and its network. In the previous sections we have thought about the driver as a component of the relay. We have done this because conceptually it makes sense to think about it like that. However, in our reference implementation we have made it a separate process which communicates with the relay via gRPC, as shown below. There are two main reasons for this:"),(0,i.yg)("ol",null,(0,i.yg)("li",{parentName:"ol"},'There must exist a different driver for each network type (e.g. Fabric, Corda etc.) and therefore having the driver as a separate process makes it easy to "plug" different drivers into the relay.'),(0,i.yg)("li",{parentName:"ol"},"A possible use case of the relay is that a single relay instance may have multiple drivers (e.g. if multiple entities in the network want to run their own driver). In this case, this plugin style approach of drivers makes it possible to do without having to modify code for each configuration.")),(0,i.yg)("p",null,(0,i.yg)("img",{src:t(595).A,width:"1550",height:"454"})))}u.isMDXComponent=!0},595:(e,r,t)=>{t.d(r,{A:()=>n});const n=t.p+"assets/images/driver_architecture-0d494884ad83fb801a8c71ddf7d2e509.png"}}]); \ No newline at end of file diff --git a/assets/js/814f3328.b40f362f.js b/assets/js/814f3328.f9bdbea6.js similarity index 85% rename from assets/js/814f3328.b40f362f.js rename to assets/js/814f3328.f9bdbea6.js index 0017a1ffc..50a07f71d 100644 --- a/assets/js/814f3328.b40f362f.js +++ b/assets/js/814f3328.f9bdbea6.js @@ -1 +1 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[2535],{5641:e=>{e.exports=JSON.parse('{"title":"Recent posts","items":[{"title":"cross-chain-asset","permalink":"/weaver-dlt-interoperability/blog/2021/01/21/cross-chain-asset"},{"title":"emergence-enterprise-interoperability","permalink":"/weaver-dlt-interoperability/blog/2021/01/21/emergence-enterprise-interoperability"}]}')}}]); \ No newline at end of file +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[7472],{5513:e=>{e.exports=JSON.parse('{"title":"Recent posts","items":[{"title":"cross-chain-asset","permalink":"/weaver-dlt-interoperability/blog/2021/01/21/cross-chain-asset"},{"title":"emergence-enterprise-interoperability","permalink":"/weaver-dlt-interoperability/blog/2021/01/21/emergence-enterprise-interoperability"}]}')}}]); \ No newline at end of file diff --git a/assets/js/8218.60a8b611.js b/assets/js/8218.60a8b611.js deleted file mode 100644 index da93f2143..000000000 --- a/assets/js/8218.60a8b611.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[8218],{9058:(e,t,a)=>{a.d(t,{Z:()=>h});var l=a(7294),r=a(6010),n=a(3285),o=a(7524),s=a(9960),i=a(5999);const m={sidebar:"sidebar_re4s",sidebarItemTitle:"sidebarItemTitle_pO2u",sidebarItemList:"sidebarItemList_Yudw",sidebarItem:"sidebarItem__DBe",sidebarItemLink:"sidebarItemLink_mo7H",sidebarItemLinkActive:"sidebarItemLinkActive_I1ZP"};function c(e){let{sidebar:t}=e;return l.createElement("aside",{className:"col col--3"},l.createElement("nav",{className:(0,r.Z)(m.sidebar,"thin-scrollbar"),"aria-label":(0,i.I)({id:"theme.blog.sidebar.navAriaLabel",message:"Blog recent posts navigation",description:"The ARIA label for recent posts in the blog sidebar"})},l.createElement("div",{className:(0,r.Z)(m.sidebarItemTitle,"margin-bottom--md")},t.title),l.createElement("ul",{className:(0,r.Z)(m.sidebarItemList,"clean-list")},t.items.map((e=>l.createElement("li",{key:e.permalink,className:m.sidebarItem},l.createElement(s.Z,{isNavLink:!0,to:e.permalink,className:m.sidebarItemLink,activeClassName:m.sidebarItemLinkActive},e.title)))))))}var u=a(3102);function d(e){let{sidebar:t}=e;return l.createElement("ul",{className:"menu__list"},t.items.map((e=>l.createElement("li",{key:e.permalink,className:"menu__list-item"},l.createElement(s.Z,{isNavLink:!0,to:e.permalink,className:"menu__link",activeClassName:"menu__link--active"},e.title)))))}function g(e){return l.createElement(u.Zo,{component:d,props:e})}function p(e){let{sidebar:t}=e;const a=(0,o.i)();return t?.items.length?"mobile"===a?l.createElement(g,{sidebar:t}):l.createElement(c,{sidebar:t}):null}function h(e){const{sidebar:t,toc:a,children:o,...s}=e,i=t&&t.items.length>0;return l.createElement(n.Z,s,l.createElement("div",{className:"container margin-vert--lg"},l.createElement("div",{className:"row"},l.createElement(p,{sidebar:t}),l.createElement("main",{className:(0,r.Z)("col",{"col--7":i,"col--9 col--offset-1":!i}),itemScope:!0,itemType:"http://schema.org/Blog"},o),a&&l.createElement("div",{className:"col col--2"},a))))}},756:(e,t,a)=>{a.d(t,{Z:()=>D});var l=a(7294),r=a(6010),n=a(9460),o=a(4996);function s(e){let{children:t,className:a}=e;const{frontMatter:r,assets:s}=(0,n.C)(),{withBaseUrl:i}=(0,o.C)(),m=s.image??r.image;return l.createElement("article",{className:a,itemProp:"blogPost",itemScope:!0,itemType:"http://schema.org/BlogPosting"},m&&l.createElement("meta",{itemProp:"image",content:i(m,{absolute:!0})}),t)}var i=a(9960);const m={title:"title_f1Hy"};function c(e){let{className:t}=e;const{metadata:a,isBlogPostPage:o}=(0,n.C)(),{permalink:s,title:c}=a,u=o?"h1":"h2";return l.createElement(u,{className:(0,r.Z)(m.title,t),itemProp:"headline"},o?c:l.createElement(i.Z,{itemProp:"url",to:s},c))}var u=a(5999),d=a(2263);const g=["zero","one","two","few","many","other"];function p(e){return g.filter((t=>e.includes(t)))}const h={locale:"en",pluralForms:p(["one","other"]),select:e=>1===e?"one":"other"};function b(){const{i18n:{currentLocale:e}}=(0,d.Z)();return(0,l.useMemo)((()=>{try{return function(e){const t=new Intl.PluralRules(e);return{locale:e,pluralForms:p(t.resolvedOptions().pluralCategories),select:e=>t.select(e)}}(e)}catch(t){return console.error(`Failed to use Intl.PluralRules for locale "${e}".\nDocusaurus will fallback to the default (English) implementation.\nError: ${t.message}\n`),h}}),[e])}function E(){const e=b();return{selectMessage:(t,a)=>function(e,t,a){const l=e.split("|");if(1===l.length)return l[0];l.length>a.pluralForms.length&&console.error(`For locale=${a.locale}, a maximum of ${a.pluralForms.length} plural forms are expected (${a.pluralForms.join(",")}), but the message contains ${l.length}: ${e}`);const r=a.select(t),n=a.pluralForms.indexOf(r);return l[Math.min(n,l.length-1)]}(a,t,e)}}const f={container:"container_mt6G"};function v(e){let{readingTime:t}=e;const a=function(){const{selectMessage:e}=E();return t=>{const a=Math.ceil(t);return e(a,(0,u.I)({id:"theme.blog.post.readingTime.plurals",description:'Pluralized label for "{readingTime} min read". Use as much plural forms (separated by "|") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)',message:"One min read|{readingTime} min read"},{readingTime:a}))}}();return l.createElement(l.Fragment,null,a(t))}function P(e){let{date:t,formattedDate:a}=e;return l.createElement("time",{dateTime:t,itemProp:"datePublished"},a)}function N(){return l.createElement(l.Fragment,null," \xb7 ")}function _(e){let{className:t}=e;const{metadata:a}=(0,n.C)(),{date:o,formattedDate:s,readingTime:i}=a;return l.createElement("div",{className:(0,r.Z)(f.container,"margin-vert--md",t)},l.createElement(P,{date:o,formattedDate:s}),void 0!==i&&l.createElement(l.Fragment,null,l.createElement(N,null),l.createElement(v,{readingTime:i})))}function Z(e){return e.href?l.createElement(i.Z,e):l.createElement(l.Fragment,null,e.children)}function k(e){let{author:t,className:a}=e;const{name:n,title:o,url:s,imageURL:i,email:m}=t,c=s||m&&`mailto:${m}`||void 0;return l.createElement("div",{className:(0,r.Z)("avatar margin-bottom--sm",a)},i&&l.createElement(Z,{href:c,className:"avatar__photo-link"},l.createElement("img",{className:"avatar__photo",src:i,alt:n})),n&&l.createElement("div",{className:"avatar__intro",itemProp:"author",itemScope:!0,itemType:"https://schema.org/Person"},l.createElement("div",{className:"avatar__name"},l.createElement(Z,{href:c,itemProp:"url"},l.createElement("span",{itemProp:"name"},n))),o&&l.createElement("small",{className:"avatar__subtitle",itemProp:"description"},o)))}const I={authorCol:"authorCol_Hf19",imageOnlyAuthorRow:"imageOnlyAuthorRow_pa_O",imageOnlyAuthorCol:"imageOnlyAuthorCol_G86a"};function C(e){let{className:t}=e;const{metadata:{authors:a},assets:o}=(0,n.C)();if(0===a.length)return null;const s=a.every((e=>{let{name:t}=e;return!t}));return l.createElement("div",{className:(0,r.Z)("margin-top--md margin-bottom--sm",s?I.imageOnlyAuthorRow:"row",t)},a.map(((e,t)=>l.createElement("div",{className:(0,r.Z)(!s&&"col col--6",s?I.imageOnlyAuthorCol:I.authorCol),key:t},l.createElement(k,{author:{...e,imageURL:o.authorsImageUrls[t]??e.imageURL}})))))}function w(){return l.createElement("header",null,l.createElement(c,null),l.createElement(_,null),l.createElement(C,null))}var y=a(8780),T=a(210);function F(e){let{children:t,className:a}=e;const{isBlogPostPage:o}=(0,n.C)();return l.createElement("div",{id:o?y.blogPostContainerID:void 0,className:(0,r.Z)("markdown",a),itemProp:"articleBody"},l.createElement(T.Z,null,t))}var L=a(4881),B=a(6233),A=a(7462);function M(){return l.createElement("b",null,l.createElement(u.Z,{id:"theme.blog.post.readMore",description:"The label used in blog post item excerpts to link to full blog posts"},"Read More"))}function R(e){const{blogPostTitle:t,...a}=e;return l.createElement(i.Z,(0,A.Z)({"aria-label":(0,u.I)({message:"Read more about {title}",id:"theme.blog.post.readMoreLabel",description:"The ARIA label for the link to full blog posts from excerpts"},{title:t})},a),l.createElement(M,null))}const O={blogPostFooterDetailsFull:"blogPostFooterDetailsFull_mRVl"};function x(){const{metadata:e,isBlogPostPage:t}=(0,n.C)(),{tags:a,title:o,editUrl:s,hasTruncateMarker:i}=e,m=!t&&i,c=a.length>0;return c||m||s?l.createElement("footer",{className:(0,r.Z)("row docusaurus-mt-lg",t&&O.blogPostFooterDetailsFull)},c&&l.createElement("div",{className:(0,r.Z)("col",{"col--9":m})},l.createElement(B.Z,{tags:a})),t&&s&&l.createElement("div",{className:"col margin-top--sm"},l.createElement(L.Z,{editUrl:s})),m&&l.createElement("div",{className:(0,r.Z)("col text--right",{"col--3":c})},l.createElement(R,{blogPostTitle:o,to:e.permalink}))):null}function D(e){let{children:t,className:a}=e;const o=function(){const{isBlogPostPage:e}=(0,n.C)();return e?void 0:"margin-bottom--xl"}();return l.createElement(s,{className:(0,r.Z)(o,a)},l.createElement(w,null),l.createElement(F,null,t),l.createElement(x,null))}},9460:(e,t,a)=>{a.d(t,{C:()=>s,n:()=>o});var l=a(7294),r=a(902);const n=l.createContext(null);function o(e){let{children:t,content:a,isBlogPostPage:r=!1}=e;const o=function(e){let{content:t,isBlogPostPage:a}=e;return(0,l.useMemo)((()=>({metadata:t.metadata,frontMatter:t.frontMatter,assets:t.assets,toc:t.toc,isBlogPostPage:a})),[t,a])}({content:a,isBlogPostPage:r});return l.createElement(n.Provider,{value:o},t)}function s(){const e=(0,l.useContext)(n);if(null===e)throw new r.i6("BlogPostProvider");return e}}}]); \ No newline at end of file diff --git a/assets/js/8379e623.676ec9ff.js b/assets/js/8379e623.a4328738.js similarity index 76% rename from assets/js/8379e623.676ec9ff.js rename to assets/js/8379e623.a4328738.js index 83f64e4fc..af491c94a 100644 --- a/assets/js/8379e623.676ec9ff.js +++ b/assets/js/8379e623.a4328738.js @@ -1 +1 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[3162],{3905:(e,t,r)=>{r.d(t,{Zo:()=>s,kt:()=>u});var n=r(7294);function i(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function o(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?a(Object(r),!0).forEach((function(t){i(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):a(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function l(e,t){if(null==e)return{};var r,n,i=function(e,t){if(null==e)return{};var r,n,i={},a=Object.keys(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||(i[r]=e[r]);return i}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(i[r]=e[r])}return i}var p=n.createContext({}),c=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},s=function(e){var t=c(e.components);return n.createElement(p.Provider,{value:t},e.children)},v="mdxType",g={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,i=e.mdxType,a=e.originalType,p=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),v=c(r),d=i,u=v["".concat(p,".").concat(d)]||v[d]||g[d]||a;return r?n.createElement(u,o(o({ref:t},s),{},{components:r})):n.createElement(u,o({ref:t},s))}));function u(e,t){var r=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var a=r.length,o=new Array(a);o[0]=d;var l={};for(var p in t)hasOwnProperty.call(t,p)&&(l[p]=t[p]);l.originalType=e,l[v]="string"==typeof e?e:i,o[1]=l;for(var c=2;c<a;c++)o[c]=r[c];return n.createElement.apply(null,o)}return n.createElement.apply(null,r)}d.displayName="MDXCreateElement"},8284:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>p,contentTitle:()=>o,default:()=>g,frontMatter:()=>a,metadata:()=>l,toc:()=>c});var n=r(7462),i=(r(7294),r(3905));const a={id:"overview",title:"Enabling Weaver in Existing DLT Applications Overview",sidebar_label:"Overview",pagination_label:"Enabling Weaver in Existing DLT Applications",pagination_prev:"external/getting-started/interop/overview"},o=void 0,l={unversionedId:"external/getting-started/enabling-weaver-network/overview",id:"external/getting-started/enabling-weaver-network/overview",title:"Enabling Weaver in Existing DLT Applications Overview",description:"\x3c!--",source:"@site/docs/external/getting-started/enabling-weaver-network/overview.md",sourceDirName:"external/getting-started/enabling-weaver-network",slug:"/external/getting-started/enabling-weaver-network/overview",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/overview",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/getting-started/enabling-weaver-network/overview.md",tags:[],version:"current",frontMatter:{id:"overview",title:"Enabling Weaver in Existing DLT Applications Overview",sidebar_label:"Overview",pagination_label:"Enabling Weaver in Existing DLT Applications",pagination_prev:"external/getting-started/interop/overview"},sidebar:"Documentation",previous:{title:"Testing Interoperation Modes",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/overview"},next:{title:"Hyperledger Fabric",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/fabric"}},p={},c=[],s={toc:c},v="wrapper";function g(e){let{components:t,...r}=e;return(0,i.kt)(v,(0,n.Z)({},s,r,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"If you have an existing DLT network and application suite built on any of the following platforms, follow the appropriate link below to understand how to adapt it to use Weaver capabilities for cross-network interactions."),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/fabric"},"Hyperledger Fabric")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/corda"},"R3 Corda")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/besu"},"Hyperledger Besu"))))}g.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[3872],{5680:(e,t,r)=>{r.d(t,{xA:()=>s,yg:()=>u});var n=r(6540);function i(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function o(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?a(Object(r),!0).forEach((function(t){i(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):a(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function l(e,t){if(null==e)return{};var r,n,i=function(e,t){if(null==e)return{};var r,n,i={},a=Object.keys(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||(i[r]=e[r]);return i}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(i[r]=e[r])}return i}var p=n.createContext({}),c=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},s=function(e){var t=c(e.components);return n.createElement(p.Provider,{value:t},e.children)},g="mdxType",v={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,i=e.mdxType,a=e.originalType,p=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),g=c(r),d=i,u=g["".concat(p,".").concat(d)]||g[d]||v[d]||a;return r?n.createElement(u,o(o({ref:t},s),{},{components:r})):n.createElement(u,o({ref:t},s))}));function u(e,t){var r=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var a=r.length,o=new Array(a);o[0]=d;var l={};for(var p in t)hasOwnProperty.call(t,p)&&(l[p]=t[p]);l.originalType=e,l[g]="string"==typeof e?e:i,o[1]=l;for(var c=2;c<a;c++)o[c]=r[c];return n.createElement.apply(null,o)}return n.createElement.apply(null,r)}d.displayName="MDXCreateElement"},4757:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>p,contentTitle:()=>o,default:()=>v,frontMatter:()=>a,metadata:()=>l,toc:()=>c});var n=r(8168),i=(r(6540),r(5680));const a={id:"overview",title:"Enabling Weaver in Existing DLT Applications Overview",sidebar_label:"Overview",pagination_label:"Enabling Weaver in Existing DLT Applications",pagination_prev:"external/getting-started/interop/overview"},o=void 0,l={unversionedId:"external/getting-started/enabling-weaver-network/overview",id:"external/getting-started/enabling-weaver-network/overview",title:"Enabling Weaver in Existing DLT Applications Overview",description:"\x3c!--",source:"@site/docs/external/getting-started/enabling-weaver-network/overview.md",sourceDirName:"external/getting-started/enabling-weaver-network",slug:"/external/getting-started/enabling-weaver-network/overview",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/overview",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/getting-started/enabling-weaver-network/overview.md",tags:[],version:"current",frontMatter:{id:"overview",title:"Enabling Weaver in Existing DLT Applications Overview",sidebar_label:"Overview",pagination_label:"Enabling Weaver in Existing DLT Applications",pagination_prev:"external/getting-started/interop/overview"},sidebar:"Documentation",previous:{title:"Testing Interoperation Modes",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/overview"},next:{title:"Hyperledger Fabric",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/fabric"}},p={},c=[],s={toc:c},g="wrapper";function v(e){let{components:t,...r}=e;return(0,i.yg)(g,(0,n.A)({},s,r,{components:t,mdxType:"MDXLayout"}),(0,i.yg)("p",null,"If you have an existing DLT network and application suite built on any of the following platforms, follow the appropriate link below to understand how to adapt it to use Weaver capabilities for cross-network interactions."),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/fabric"},"Hyperledger Fabric")),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/corda"},"R3 Corda")),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/besu"},"Hyperledger Besu"))))}v.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/85de58a0.4f92ebce.js b/assets/js/85de58a0.f37dd4f9.js similarity index 70% rename from assets/js/85de58a0.4f92ebce.js rename to assets/js/85de58a0.f37dd4f9.js index 23db55340..a803f2079 100644 --- a/assets/js/85de58a0.4f92ebce.js +++ b/assets/js/85de58a0.f37dd4f9.js @@ -1 +1 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[9530],{3905:(e,t,r)=>{r.d(t,{Zo:()=>c,kt:()=>m});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function o(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?i(Object(r),!0).forEach((function(t){a(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):i(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function s(e,t){if(null==e)return{};var r,n,a=function(e,t){if(null==e)return{};var r,n,a={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var l=n.createContext({}),d=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},c=function(e){var t=d(e.components);return n.createElement(l.Provider,{value:t},e.children)},p="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},u=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,i=e.originalType,l=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),p=d(r),u=a,m=p["".concat(l,".").concat(u)]||p[u]||h[u]||i;return r?n.createElement(m,o(o({ref:t},c),{},{components:r})):n.createElement(m,o({ref:t},c))}));function m(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=r.length,o=new Array(i);o[0]=u;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[p]="string"==typeof e?e:a,o[1]=s;for(var d=2;d<i;d++)o[d]=r[d];return n.createElement.apply(null,o)}return n.createElement.apply(null,r)}u.displayName="MDXCreateElement"},5680:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>o,default:()=>h,frontMatter:()=>i,metadata:()=>s,toc:()=>d});var n=r(7462),a=(r(7294),r(3905));const i={id:"interoperability-modes",title:"Interoperability Modes"},o=void 0,s={unversionedId:"external/interoperability-modes",id:"external/interoperability-modes",title:"Interoperability Modes",description:"\x3c!--",source:"@site/docs/external/interoperability-modes.md",sourceDirName:"external",slug:"/external/interoperability-modes",permalink:"/weaver-dlt-interoperability/docs/external/interoperability-modes",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/interoperability-modes.md",tags:[],version:"current",frontMatter:{id:"interoperability-modes",title:"Interoperability Modes"},sidebar:"Documentation",previous:{title:"Integration Patterns",permalink:"/weaver-dlt-interoperability/docs/external/what-is-interoperability/integration-patterns"},next:{title:"Design Principles",permalink:"/weaver-dlt-interoperability/docs/external/design-principles"}},l={},d=[{value:"Modes of Interoperability",id:"modes-of-interoperability",level:2},{value:"Asset Transfer",id:"asset-transfer",level:3},{value:"Asset Exchange",id:"asset-exchange",level:3},{value:"Data Sharing",id:"data-sharing",level:3},{value:"Identity",id:"identity",level:3}],c={toc:d},p="wrapper";function h(e){let{components:t,...i}=e;return(0,a.kt)(p,(0,n.Z)({},c,i,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h2",{id:"modes-of-interoperability"},"Modes of Interoperability"),(0,a.kt)("p",null,"We identify distinct modes or patterns of interoperation based on the nature and purpose of the artifact that two networks (or parties within) have a common interest in and the purpose they wish to achieve."),(0,a.kt)("p",null,"First, we will classify artifacts present on shared ledgers broadly into the following two types:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},"Assets"),": This is a ledger item that is associated with a single entity (or limited set of entities), representing the real-world ownership of that item by an entity. Bitcoins in the Bitcoin network and Ether on the Ethereum network are well-known examples, but assets repreenting a wide range of tangible goods can reside on blockchian ledgers, like property titles, bank drafts, precious stones, and financial instruments like bonds and securities."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},"Data Records"),': This is any information held on a ledger that describes the state of the world, context, or properties of an entity or object. It is not "owned" by, or associated with, specific entities, but is rather common knowledge within a blockchain network.')),(0,a.kt)("p",null,"The salient distinction between assets and data from an interoperability perspective is that the former may be present only in one network at any given instant in order to maintain its integrity whereas the latter can have copies in multiple networks without losing its value."),(0,a.kt)("p",null,"Three common modes in which independent networks will seek to interoperate are as follows. (We can also refer to them as three distinct purposes.)"),(0,a.kt)("h3",{id:"asset-transfer"},"Asset Transfer"),(0,a.kt)("p",null,"This refers to the movement of an asset from its source ledger to a consuming ledger. Since assets has ",(0,a.kt)("em",{parentName:"p"},"singleton")," ownership and can't be ",(0,a.kt)("em",{parentName:"p"},"double spent"),", the transfer of an asset should result in its burning or locking in the source ledger and its creation on the target ledger."),(0,a.kt)("p",null,"A typical asset transfer use case is illustrated in the figure below, where Party X initially holds Asset in Network A, and through interoperation transfers Asset to Party Y in Network B. The loss of Asset to X in A must occur simultaneously with the gain of Asset for Y in B;. i.e, these transactions must be ",(0,a.kt)("em",{parentName:"p"},"atomic"),'. ("Holding an asset" refers to a record on a network\'s shared ledger representing the ownership of that asset by a given entity.)'),(0,a.kt)("p",null,(0,a.kt)("img",{alt:"alt text",src:r(6837).Z,width:"2036",height:"438"})),(0,a.kt)("h3",{id:"asset-exchange"},"Asset Exchange"),(0,a.kt)("p",null,"This refers to the change of ownership of an asset in a source network and a corresponding change of ownership in another network. No asset leaves the network it resides in. The well-known terminology for asset exchange is 'Atomic Cross-Chain Swap'."),(0,a.kt)("p",null,(0,a.kt)("em",{parentName:"p"},"For example"),": two parties with both Bitcoin and Ethereum accounts may trade Bitcoin forEthereum based on an exchange rate agreed upon off-chain. We generalize this to permissioned networks, where it may be harder to provide guarantees of finality, and therby, atomicity."),(0,a.kt)("p",null,"The figure below illustrates a typical asset exchange. Initially, Party X holds Asset M in Network A and Party Y holds Asset N in Network B. Through interoperation, an exchange occurs whereby Y holds M in A and X holds N in B. The changes in these two networks occur atomically. (",(0,a.kt)("em",{parentName:"p"},"Note"),": in such a use case, both X and Y must be members of both networks.) See ",(0,a.kt)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/external/user-stories/financial-markets"},"DvP in Financial Markets")," for an example scenario illustrating asset exchanges."),(0,a.kt)("p",null,(0,a.kt)("img",{alt:"alt text",src:r(6865).Z,width:"2035",height:"493"})),(0,a.kt)("p",null,"Both the asset transfer and exchange patterns can be extrapolated to scenarios involving more than 2 parties, 2 assets, and 2 networks. The only fixed criterion is that the actions on all networks happen atomically. For the same reason, the infrastructure and protocols to support both asset transfers and exchanges overlap significantly."),(0,a.kt)("h3",{id:"data-sharing"},"Data Sharing"),(0,a.kt)("p",null,"This refers to the transfer of data from its source ledger to a consuming ledger. (In many scenarios, data records in one network ledger may need to be shared with another network ledger in order to drive forward a process on the latter.) The data transferred can be the result of invoking a contract or a database query. There are no technical limits to the number of times a given piece of data can be copied to other ledgers."),(0,a.kt)("p",null,"The below figure illustrates this pattern, where initially, Data Record is maintained only on Network A's ledger, and through interoperation, a copy resides on Network B's ledger. (",(0,a.kt)("em",{parentName:"p"},"Note"),": the data record may be transformed within Network B during the sharing process before a transaction is committed to its ledger.) See ",(0,a.kt)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/external/user-stories/global-trade"},"Global Trade")," for an example scenario illustrating data sharing."),(0,a.kt)("p",null,(0,a.kt)("img",{alt:"alt text",src:r(8599).Z,width:"2040",height:"464"})),(0,a.kt)("h3",{id:"identity"},"Identity"),(0,a.kt)("p",null,"This refers to the process by which identity can be expressed and comprehended beyond the boundaries of a single network. The ability to reason about identities as real-world entities along with credentials proving their membership in various networks is key to creating a trust basis that enables the three interoperability modes listed above. From that perspective, this kind of cross-network identity management lies on a higher plane than data and asset movements. For more details on our thinking, see the Interop RFC pages."))}h.isMDXComponent=!0},6865:(e,t,r)=>{r.d(t,{Z:()=>n});const n=r.p+"assets/images/asset-exchange-f3aa01d86894888c878ee18561ea8f50.png"},6837:(e,t,r)=>{r.d(t,{Z:()=>n});const n=r.p+"assets/images/asset-transfer-01821cf352ef4c0a973cac3e405f6531.png"},8599:(e,t,r)=>{r.d(t,{Z:()=>n});const n=r.p+"assets/images/data-transfer-60b2aa913b352980f681ab4cfb192591.png"}}]); \ No newline at end of file +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[1031],{5680:(e,t,r)=>{r.d(t,{xA:()=>c,yg:()=>y});var n=r(6540);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function o(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?i(Object(r),!0).forEach((function(t){a(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):i(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function s(e,t){if(null==e)return{};var r,n,a=function(e,t){if(null==e)return{};var r,n,a={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var l=n.createContext({}),d=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},c=function(e){var t=d(e.components);return n.createElement(l.Provider,{value:t},e.children)},p="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},g=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,i=e.originalType,l=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),p=d(r),g=a,y=p["".concat(l,".").concat(g)]||p[g]||h[g]||i;return r?n.createElement(y,o(o({ref:t},c),{},{components:r})):n.createElement(y,o({ref:t},c))}));function y(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=r.length,o=new Array(i);o[0]=g;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[p]="string"==typeof e?e:a,o[1]=s;for(var d=2;d<i;d++)o[d]=r[d];return n.createElement.apply(null,o)}return n.createElement.apply(null,r)}g.displayName="MDXCreateElement"},5291:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>o,default:()=>h,frontMatter:()=>i,metadata:()=>s,toc:()=>d});var n=r(8168),a=(r(6540),r(5680));const i={id:"interoperability-modes",title:"Interoperability Modes"},o=void 0,s={unversionedId:"external/interoperability-modes",id:"external/interoperability-modes",title:"Interoperability Modes",description:"\x3c!--",source:"@site/docs/external/interoperability-modes.md",sourceDirName:"external",slug:"/external/interoperability-modes",permalink:"/weaver-dlt-interoperability/docs/external/interoperability-modes",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/interoperability-modes.md",tags:[],version:"current",frontMatter:{id:"interoperability-modes",title:"Interoperability Modes"},sidebar:"Documentation",previous:{title:"Integration Patterns",permalink:"/weaver-dlt-interoperability/docs/external/what-is-interoperability/integration-patterns"},next:{title:"Design Principles",permalink:"/weaver-dlt-interoperability/docs/external/design-principles"}},l={},d=[{value:"Modes of Interoperability",id:"modes-of-interoperability",level:2},{value:"Asset Transfer",id:"asset-transfer",level:3},{value:"Asset Exchange",id:"asset-exchange",level:3},{value:"Data Sharing",id:"data-sharing",level:3},{value:"Identity",id:"identity",level:3}],c={toc:d},p="wrapper";function h(e){let{components:t,...i}=e;return(0,a.yg)(p,(0,n.A)({},c,i,{components:t,mdxType:"MDXLayout"}),(0,a.yg)("h2",{id:"modes-of-interoperability"},"Modes of Interoperability"),(0,a.yg)("p",null,"We identify distinct modes or patterns of interoperation based on the nature and purpose of the artifact that two networks (or parties within) have a common interest in and the purpose they wish to achieve."),(0,a.yg)("p",null,"First, we will classify artifacts present on shared ledgers broadly into the following two types:"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("strong",{parentName:"li"},"Assets"),": This is a ledger item that is associated with a single entity (or limited set of entities), representing the real-world ownership of that item by an entity. Bitcoins in the Bitcoin network and Ether on the Ethereum network are well-known examples, but assets repreenting a wide range of tangible goods can reside on blockchian ledgers, like property titles, bank drafts, precious stones, and financial instruments like bonds and securities."),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("strong",{parentName:"li"},"Data Records"),': This is any information held on a ledger that describes the state of the world, context, or properties of an entity or object. It is not "owned" by, or associated with, specific entities, but is rather common knowledge within a blockchain network.')),(0,a.yg)("p",null,"The salient distinction between assets and data from an interoperability perspective is that the former may be present only in one network at any given instant in order to maintain its integrity whereas the latter can have copies in multiple networks without losing its value."),(0,a.yg)("p",null,"Three common modes in which independent networks will seek to interoperate are as follows. (We can also refer to them as three distinct purposes.)"),(0,a.yg)("h3",{id:"asset-transfer"},"Asset Transfer"),(0,a.yg)("p",null,"This refers to the movement of an asset from its source ledger to a consuming ledger. Since assets has ",(0,a.yg)("em",{parentName:"p"},"singleton")," ownership and can't be ",(0,a.yg)("em",{parentName:"p"},"double spent"),", the transfer of an asset should result in its burning or locking in the source ledger and its creation on the target ledger."),(0,a.yg)("p",null,"A typical asset transfer use case is illustrated in the figure below, where Party X initially holds Asset in Network A, and through interoperation transfers Asset to Party Y in Network B. The loss of Asset to X in A must occur simultaneously with the gain of Asset for Y in B;. i.e, these transactions must be ",(0,a.yg)("em",{parentName:"p"},"atomic"),'. ("Holding an asset" refers to a record on a network\'s shared ledger representing the ownership of that asset by a given entity.)'),(0,a.yg)("p",null,(0,a.yg)("img",{alt:"alt text",src:r(8263).A,width:"2036",height:"438"})),(0,a.yg)("h3",{id:"asset-exchange"},"Asset Exchange"),(0,a.yg)("p",null,"This refers to the change of ownership of an asset in a source network and a corresponding change of ownership in another network. No asset leaves the network it resides in. The well-known terminology for asset exchange is 'Atomic Cross-Chain Swap'."),(0,a.yg)("p",null,(0,a.yg)("em",{parentName:"p"},"For example"),": two parties with both Bitcoin and Ethereum accounts may trade Bitcoin forEthereum based on an exchange rate agreed upon off-chain. We generalize this to permissioned networks, where it may be harder to provide guarantees of finality, and therby, atomicity."),(0,a.yg)("p",null,"The figure below illustrates a typical asset exchange. Initially, Party X holds Asset M in Network A and Party Y holds Asset N in Network B. Through interoperation, an exchange occurs whereby Y holds M in A and X holds N in B. The changes in these two networks occur atomically. (",(0,a.yg)("em",{parentName:"p"},"Note"),": in such a use case, both X and Y must be members of both networks.) See ",(0,a.yg)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/external/user-stories/financial-markets"},"DvP in Financial Markets")," for an example scenario illustrating asset exchanges."),(0,a.yg)("p",null,(0,a.yg)("img",{alt:"alt text",src:r(1841).A,width:"2035",height:"493"})),(0,a.yg)("p",null,"Both the asset transfer and exchange patterns can be extrapolated to scenarios involving more than 2 parties, 2 assets, and 2 networks. The only fixed criterion is that the actions on all networks happen atomically. For the same reason, the infrastructure and protocols to support both asset transfers and exchanges overlap significantly."),(0,a.yg)("h3",{id:"data-sharing"},"Data Sharing"),(0,a.yg)("p",null,"This refers to the transfer of data from its source ledger to a consuming ledger. (In many scenarios, data records in one network ledger may need to be shared with another network ledger in order to drive forward a process on the latter.) The data transferred can be the result of invoking a contract or a database query. There are no technical limits to the number of times a given piece of data can be copied to other ledgers."),(0,a.yg)("p",null,"The below figure illustrates this pattern, where initially, Data Record is maintained only on Network A's ledger, and through interoperation, a copy resides on Network B's ledger. (",(0,a.yg)("em",{parentName:"p"},"Note"),": the data record may be transformed within Network B during the sharing process before a transaction is committed to its ledger.) See ",(0,a.yg)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/external/user-stories/global-trade"},"Global Trade")," for an example scenario illustrating data sharing."),(0,a.yg)("p",null,(0,a.yg)("img",{alt:"alt text",src:r(7367).A,width:"2040",height:"464"})),(0,a.yg)("h3",{id:"identity"},"Identity"),(0,a.yg)("p",null,"This refers to the process by which identity can be expressed and comprehended beyond the boundaries of a single network. The ability to reason about identities as real-world entities along with credentials proving their membership in various networks is key to creating a trust basis that enables the three interoperability modes listed above. From that perspective, this kind of cross-network identity management lies on a higher plane than data and asset movements. For more details on our thinking, see the Interop RFC pages."))}h.isMDXComponent=!0},1841:(e,t,r)=>{r.d(t,{A:()=>n});const n=r.p+"assets/images/asset-exchange-f3aa01d86894888c878ee18561ea8f50.png"},8263:(e,t,r)=>{r.d(t,{A:()=>n});const n=r.p+"assets/images/asset-transfer-01821cf352ef4c0a973cac3e405f6531.png"},7367:(e,t,r)=>{r.d(t,{A:()=>n});const n=r.p+"assets/images/data-transfer-60b2aa913b352980f681ab4cfb192591.png"}}]); \ No newline at end of file diff --git a/assets/js/8758c959.729751f4.js b/assets/js/8758c959.729751f4.js deleted file mode 100644 index 59743bd29..000000000 --- a/assets/js/8758c959.729751f4.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[7459],{3905:(e,t,a)=>{a.d(t,{Zo:()=>h,kt:()=>u});var r=a(7294);function n(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function i(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,r)}return a}function o(e){for(var t=1;t<arguments.length;t++){var a=null!=arguments[t]?arguments[t]:{};t%2?i(Object(a),!0).forEach((function(t){n(e,t,a[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(a)):i(Object(a)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(a,t))}))}return e}function s(e,t){if(null==e)return{};var a,r,n=function(e,t){if(null==e)return{};var a,r,n={},i=Object.keys(e);for(r=0;r<i.length;r++)a=i[r],t.indexOf(a)>=0||(n[a]=e[a]);return n}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r<i.length;r++)a=i[r],t.indexOf(a)>=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(n[a]=e[a])}return n}var l=r.createContext({}),d=function(e){var t=r.useContext(l),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},h=function(e){var t=d(e.components);return r.createElement(l.Provider,{value:t},e.children)},c="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},p=r.forwardRef((function(e,t){var a=e.components,n=e.mdxType,i=e.originalType,l=e.parentName,h=s(e,["components","mdxType","originalType","parentName"]),c=d(a),p=n,u=c["".concat(l,".").concat(p)]||c[p]||m[p]||i;return a?r.createElement(u,o(o({ref:t},h),{},{components:a})):r.createElement(u,o({ref:t},h))}));function u(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var i=a.length,o=new Array(i);o[0]=p;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[c]="string"==typeof e?e:n,o[1]=s;for(var d=2;d<i;d++)o[d]=a[d];return r.createElement.apply(null,o)}return r.createElement.apply(null,a)}p.displayName="MDXCreateElement"},1288:(e,t,a)=>{a.r(t),a.d(t,{assets:()=>l,contentTitle:()=>o,default:()=>m,frontMatter:()=>i,metadata:()=>s,toc:()=>d});var r=a(7462),n=(a(7294),a(3905));const i={id:"decentralized-identity",title:"Decentralized Identity"},o=void 0,s={unversionedId:"external/architecture-and-design/decentralized-identity",id:"external/architecture-and-design/decentralized-identity",title:"Decentralized Identity",description:"\x3c!--",source:"@site/docs/external/architecture-and-design/decentralized-identity.md",sourceDirName:"external/architecture-and-design",slug:"/external/architecture-and-design/decentralized-identity",permalink:"/weaver-dlt-interoperability/docs/external/architecture-and-design/decentralized-identity",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/architecture-and-design/decentralized-identity.md",tags:[],version:"current",frontMatter:{id:"decentralized-identity",title:"Decentralized Identity"},sidebar:"Documentation",previous:{title:"Weaver Dapps",permalink:"/weaver-dlt-interoperability/docs/external/architecture-and-design/weaver-dapps"},next:{title:"Authentication",permalink:"/weaver-dlt-interoperability/docs/external/security-model/authentication"}},l={},d=[{value:"Identity Plane: Strawman Approach",id:"identity-plane-strawman-approach",level:3},{value:"Networks as Groups of Self-Sovereign Members",id:"networks-as-groups-of-self-sovereign-members",level:3},{value:"Distributed Identity Management Infrastructure",id:"distributed-identity-management-infrastructure",level:3},{value:"Interoperation Identity Network",id:"interoperation-identity-network",level:4},{value:"Network Membership Credentials",id:"network-membership-credentials",level:4},{value:"Identity Info: Units of Exchange",id:"identity-info-units-of-exchange",level:4},{value:"IIN Agents as Member Representatives",id:"iin-agents-as-member-representatives",level:4},{value:"Protocols",id:"protocols",level:4},{value:"References",id:"references",level:3}],h={toc:d},c="wrapper";function m(e){let{components:t,...i}=e;return(0,n.kt)(c,(0,r.Z)({},h,i,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("p",null,"Interoperation for asset or data transfers/exchanges relies on a message-passing infratructure and pan-network data processing modules, as we have seen in earlier pages. But there is yet another crucial basis these data processing modules need to satisfy our design principles of network independence and avoidance of trust parties. This is the ability of a network as a whole and of its individual members to accurately identify and authenticate another network's members."),(0,n.kt)("p",null,"Further, for the networks to remain independent and interact ad hoc with each other, we cannot impose a central authority that unifies their private identity management systems. So the identity basis of interoperation must be decentralized, leading inevitably to the requirement of exchanging identity information across networks as a pre-requisite for asset and data transfers/exchanges. This is illustrated in the figure below where interoperation protocols are classified in two planes (or tiers), data and identity, with the former depending on the latter."),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"alt text",src:a(4482).Z,width:"1659",height:"829"})),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"In the ",(0,n.kt)("strong",{parentName:"li"},"data plane")," lies the protocols that effect the actual exchanges of data and assets. The figure above illustrates a typical data-sharing instance, where the network at the left requests a data record from the right. The latter receives the request via the two relays (not explicitly marked in this diagram) and runs an access control check through consensus in its ",(0,n.kt)("em",{parentName:"li"},"interop module")," before responding with the data record and supporting proof. The network at the left receives the data and proof, again via the two relays, and verifies the data using the supplied proof. ",(0,n.kt)("strong",{parentName:"li"},"Note: since a core part of both request and proof are digital signatures of network members, the ability to identify and authenticate network members is necessary to perform these endpoint functions"),"."),(0,n.kt)("li",{parentName:"ul"},"Here is where the ",(0,n.kt)("strong",{parentName:"li"},"identity plane")," enters the picture, as a trust anchor for the data plane. The most general function of this plane is illustrated in the figure, where the networks get each others' identity and configuration (i.e., membership structure and network topology) information. This exchange has as its own trust basis (or dependency) a set of identity providers and verifiers. (",(0,n.kt)("em",{parentName:"li"},"Note"),": these identity providers and verifiers may belong to the two networks or they could be external entities.) The outcome of the exchange is a record of the other network's identity and configuration information on one's ledger, which can then be looked up in a data plane protocol instance.")),(0,n.kt)("h3",{id:"identity-plane-strawman-approach"},"Identity Plane: Strawman Approach"),(0,n.kt)("p",null,"The simplest identity plane protocol involves a direct exchange of identity information between representatives of the two networks: in other words, an API integration. But this approach suffers from the same drawbacks that API integration in the data plane would. It diminishes a blockchain network to a single trusted spokesperson, exposing that network to risk. Even if such a spokesperson could be designated, appropriately framing access control policies for potentially every other blockchain network in the world would be very challenging. This approach is therefore insecure and not scalable, and therefore ought to be treated purely as a strawman."),(0,n.kt)("h3",{id:"networks-as-groups-of-self-sovereign-members"},"Networks as Groups of Self-Sovereign Members"),(0,n.kt)("p",null,"A secure and sustainable identity plane plaform can be built on the basis of ",(0,n.kt)("em",{parentName:"p"},"self-sovereign identity")," and ",(0,n.kt)("em",{parentName:"p"},"decentralized identifiers"),". We recognize that:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"Each constituent member of a blockchain network may already possess an identity from a third-party provider"),(0,n.kt)("li",{parentName:"ul"},"Membership within a network can be treated as a property of a sovereign organization rather than subordination to a network's governing authority"),(0,n.kt)("li",{parentName:"ul"},"DIDs allow members to control who they wish to share their identities with and the levels of exposure"),(0,n.kt)("li",{parentName:"ul"},"Network membership lists and individual members' identities can respectively be validated by different providers, thereby maintaining decentralization of infrastructure")),(0,n.kt)("h3",{id:"distributed-identity-management-infrastructure"},"Distributed Identity Management Infrastructure"),(0,n.kt)("p",null,"The distributed identity management infrastructure for interoperation is illustrated in the figure below. We assume the existence of one or more ",(0,n.kt)("em",{parentName:"p"},"Interoperation Identity Networks (IINs)")," that act as registries and credential validators for the organizations that form the memberships of blockchain networks."),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"alt text",src:a(5132).Z,width:"1381",height:"632"})),(0,n.kt)("p",null,"An IIN can be built from scratch to facilitate blockchain interoperation, but it can also be an augmentation of an existing decentralized identity provider or registry. Its purpose is to maintain identity records and credentials for organizations and validate these to third parties as per the desire of the identity or credential owner. In this model, an IIN can itself be reputed or it can bring together many reputed and trusted identity providers (called ",(0,n.kt)("em",{parentName:"p"},"stewards"),") into a shared network. As long as the members of two blockchain networks have shared trust in one or more IINs, an identity plane exchange can be effected, thereby setting the foundation for data and asset transfers."),(0,n.kt)("h4",{id:"interoperation-identity-network"},"Interoperation Identity Network"),(0,n.kt)("p",null,"The ideal IIN architecture is illustrated in the figure below, inspired by Hyperleder Indy, whose architecture is used in our canonical (or reference) implementation. Built on a DLT itself, an Indy-based IIN can provide the combination of assurance and decentralization that a centralized registry cannot. Further, such an IIN will support the entire SSI and DID standard, maintaining credential schemas and verification keys, and issuing ",(0,n.kt)("em",{parentName:"p"},"verifiable credentials")," that can be used for privacy-preserving authentications."),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"alt text",src:a(5834).Z,width:"1727",height:"818"})),(0,n.kt)("p",null,"An IIN is modeled as a network with a distributed shared ledger, implemented using an Indy Node Pool and running BFT consensus. The ledger is also (ideally) meant to be publicly accessible, though there is nothing preventing our protocols from working with a private IIN."),(0,n.kt)("p",null,"A canonical IIN maintains the following:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"DID records corresponding to organizations that are members of one or more blockchain networks, whose salient attributes include:",(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},"Unique (within an IIN) identifier or ",(0,n.kt)("em",{parentName:"li"},"verinym")," for the identity owner"),(0,n.kt)("li",{parentName:"ul"},"Service endpoint for the identity owner"),(0,n.kt)("li",{parentName:"ul"},"Credential schemas"),(0,n.kt)("li",{parentName:"ul"},"Credential definitions (public keys used to authenticate signed credentials)")))),(0,n.kt)("p",null,"Every IIN has a set of bootstrapped ",(0,n.kt)("em",{parentName:"p"},"trust anchors")," called ",(0,n.kt)("em",{parentName:"p"},"stewards"),". A steward can create other trust anchors by issuing them suitable credentials. The trust anchors are the primary identity providers in our distributed identity management architecture. They can be existing reputed authorities or identity providers who are trusted to certify blockchain networks' memberships, or they can be created ad hoc by a consortium representing the members of a blockchain network."),(0,n.kt)("p",null,"For one blockchain network to discover and validate another in the identity plane, it must trust one or more IINs and trust anchors who can provide that validation. We envision a shared and mutually reinforcing trust among stewards and other anchors within an IIN. An anchor could gain trust by virtue of joining a well-established IIN. Similarly, an IIN bootstrapped with well-known stewards gains trust because of the collective reputations of those stewards."),(0,n.kt)("p",null,"Examples of entities that can act as stewards or trust anchors within IINs: the Sovrin Foundation (an organization dedicated to enabling open-source digital ID management, and which also maintains Indy), companies like Maersk or Walmart that have founded real-world blockchain networks, companies like IBM or R3 that maintain popular DLT platforms."),(0,n.kt)("p",null,"IINs don't have to be built on Indy. Alternatives like Sidetree exist, providing similar functionality. There are also various existing DID registries that are already issuing credentials to existing organizations. To the extent possible, we would like to leverage all of this existing infrastructure and not force any network menmber to find yet another identity provider. Therefore, these existing registries or networks can be used as IINs: the only requirement is that they follow the standards for SSI and DIDs and issuing VCs."),(0,n.kt)("h4",{id:"network-membership-credentials"},"Network Membership Credentials"),(0,n.kt)("p",null,"Two kinds of credentials (each with a schema and a definition) are maintained on an IIN ledger:"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},(0,n.kt)("strong",{parentName:"li"},"Member list"),": This contains a network name or ID and a set of DIDs of that network's members.")),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"This is a per-network credential whose schema and verification key must be maintained on an IIN."),(0,n.kt)("li",{parentName:"ul"},"This is issued by a steward or trust anchor in an IIN and is associated with that steward's or anchor's DID.")),(0,n.kt)("ol",{start:2},(0,n.kt)("li",{parentName:"ol"},(0,n.kt)("strong",{parentName:"li"},"Membership"),": This contains an oranization's attributes, including the set of IDs of networks to which it belongs.")),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"This is designed to be an extensible credential, i.e., support more attributes in the future."),(0,n.kt)("li",{parentName:"ul"},"An existing membership credential (of the VC form) can be used as long as it matches the schema recorded on an IIN."),(0,n.kt)("li",{parentName:"ul"},"The issuer must be a steward or trust anchor (or equivalent, if it's a non-Indy registry) in an IIN."),(0,n.kt)("li",{parentName:"ul"},"This is associated with the member's DID.")),(0,n.kt)("h4",{id:"identity-info-units-of-exchange"},"Identity Info: Units of Exchange"),(0,n.kt)("p",null,"The IIN is used to discover the membership list of a foreign network and establish the authenticity of its members. Memnbership credentials are independent of blockchain networks."),(0,n.kt)("p",null,"But data plane transfers and exchanges require knowledge of in-network identities and certificates, which are issued by a network's membership manager(s) to peers and clients. These are not shared through IINs for several reasons. First, the volume of this information can be quite high and further it is subject to change based on a network's internal needs. Also, a network or its members may not wish to expose all this information to an IIN, which is designed to be publicly accessible. Therefore, it is infeasible or undesirable to shared network-specific credentials via established IINs. Instead, we will enable the ",(0,n.kt)("em",{parentName:"p"},"peer-to-peer")," exchange of such credentials after the membership discovery and validation procedure is complete."),(0,n.kt)("p",null,"Specifically, the identity information for a network member consists of the set of certificate chains of the membership managers for that particular member (organization). These consist of one or more hierarchies of root and intermediate CA certificates. For example:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"In Fabric, each organization uses one or more MSPs (",(0,n.kt)("em",{parentName:"li"},"membership service providers"),"), each running one or more root and intermediate Fabric-CA servers. Any network peer belonging to an organization is issued a certificate authorized by one of these certificate chains. To authenticate a network peer or client in a data plane protocol, knowledge of these certificate chains is essential."),(0,n.kt)("li",{parentName:"ul"},"In Corda, the entire network typically consists of a hierarchy of CAs, from a root to multiple ",(0,n.kt)("em",{parentName:"li"},"doormen"),", and from each doorman to multiple nodes. Finally, the certificates used to sign transactions are issued by the node CAs. Therefore, knowledge of the root, doormen, and node CA certificates is essential for authenticating signers.")),(0,n.kt)("p",null,"More generally, each unit of exchange corresponding to a network member is a ",(0,n.kt)("em",{parentName:"p"},"Security Group"),", so-called because each network member is an independent organization in its own right with a security domain."),(0,n.kt)("h4",{id:"iin-agents-as-member-representatives"},"IIN Agents as Member Representatives"),(0,n.kt)("p",null,'Every network member needs a proxy (either an abstraction or a separate module) for communication with IINs and with the members of foreign networks in the identity plane. We use the term "IIN Agent" to refer to this proxy, and illustrate its functioning as a module within a Fabric network through the reference diagram below.'),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"alt text",src:a(3537).Z,width:"1528",height:"847"})),(0,n.kt)("p",null,"In the reference implementation, IIN Agents are built as Hyperledger Aries nodes and communicate with each other and with IIN stewards and trust anchors using the Aries protocol. (IIN stewards and trust anchors are also built as Aries nodes.)"),(0,n.kt)("p",null,"The list of trusted IINs is recorded on the local network's shared ledger, as illustrated in the figure (and thereby agreed through network consensus). To be able to interoperate with another network, the latter's members must have identity records maintained by sume subset of these trusted IINs and their VCs must be issued by these IINs stewards and trust anchors."),(0,n.kt)("h4",{id:"protocols"},"Protocols"),(0,n.kt)("p",null,"Let us consider a scenario where ",(0,n.kt)("em",{parentName:"p"},"NETWORK 1")," and ",(0,n.kt)("em",{parentName:"p"},"NETWORK 2")," wish to interoperate, and their respective member organizations are as follows:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("em",{parentName:"li"},"NETWORK 1"),": Org3, Org4, Org5"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("em",{parentName:"li"},"NETWORK 2"),": Org1, Org2")),(0,n.kt)("p",null,"Each network discovers the other's member list and obtains and records ech member's security group to the local shared ledger. We can enumerate these as follows:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("em",{parentName:"li"},"NETWORK 1")," discovers and registers ",(0,n.kt)("em",{parentName:"li"},"NETWORK 2"),":Org1"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("em",{parentName:"li"},"NETWORK 1")," discovers and registers ",(0,n.kt)("em",{parentName:"li"},"NETWORK 2"),":Org2"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("em",{parentName:"li"},"NETWORK 2")," discovers and registers ",(0,n.kt)("em",{parentName:"li"},"NETWORK 1"),":Org3"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("em",{parentName:"li"},"NETWORK 2")," discovers and registers ",(0,n.kt)("em",{parentName:"li"},"NETWORK 1"),":Org4"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("em",{parentName:"li"},"NETWORK 2")," discovers and registers ",(0,n.kt)("em",{parentName:"li"},"NETWORK 1"),":Org5")),(0,n.kt)("p",null,"Each of these can be done in parallel and each discovery and registration operation is idempotent as long as the security group of a network member does not change."),(0,n.kt)("p",null,"The high-level workflow for discovery and registration is illustrated below (using ",(0,n.kt)("em",{parentName:"p"},"NETWORK 2")," as the seeker and ",(0,n.kt)("em",{parentName:"p"},"NETWORK 1")," as the provider)."),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"alt text",src:a(7089).Z,width:"1505",height:"739"})),(0,n.kt)("p",null,"(",(0,n.kt)("em",{parentName:"p"},"Note"),': "Network unit" is synonymous with "network member")'),(0,n.kt)("p",null,"Prerequisites for this process are:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"The member list credential of ",(0,n.kt)("em",{parentName:"li"},"NETWORK 1")," is provided by a steward or trust anchor in a particular IIN which is also on the trust list recorded in the ledger of ",(0,n.kt)("em",{parentName:"li"},"NETWORK 2"),"."),(0,n.kt)("li",{parentName:"ul"},"The membership credentials for both organizations in ",(0,n.kt)("em",{parentName:"li"},"NETWORK 1")," are supplied by one or more IINs that are on the trust list of ",(0,n.kt)("em",{parentName:"li"},"NETWORK 2"),"."),(0,n.kt)("li",{parentName:"ul"},"Each of the 5 organizations (2 in ",(0,n.kt)("em",{parentName:"li"},"NETWORK 1")," and 3 in ",(0,n.kt)("em",{parentName:"li"},"NETWORK 2"),") has an IIN Agent running on their behalf.")),(0,n.kt)("p",null,"Let us take the example of ",(0,n.kt)("em",{parentName:"p"},"NETWORK 2")," having already obtained the security group info for Org4 and Org5 in ",(0,n.kt)("em",{parentName:"p"},"NETWORK 1"),". It is now discovering and registering ",(0,n.kt)("em",{parentName:"p"},"NETWORK 1"),":Org3. We assume that there is a single IIN with a single Steward for validating member list as well as membership credentials for all members of both the networks."),(0,n.kt)("p",null,(0,n.kt)("em",{parentName:"p"},"Note"),": we assume here for simplicity that a steward as a reputed identity provider has a mechanism to validate the bona fides of an orgganization and its membership in a given network. There are other techniques involving group signatures that could be applied to corroborate an organization's claim to network membership rather than requiring a steward to use an out-of-band security mechanism, but that is presently beyond the scope of this design."),(0,n.kt)("p",null,"The discovery and registration procedure steps are as follows:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"The IIN Agent for Org3 registers its membership to ",(0,n.kt)("em",{parentName:"li"},"NETWORK 1")," at the Steward in IIN:",(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("em",{parentName:"li"},"NETWORK 1"),":Org3 gets a DID (verinym) issued"),(0,n.kt)("li",{parentName:"ul"},"The Steward updates the member list credential for ",(0,n.kt)("em",{parentName:"li"},"NETWORK 1")," to include Org3"),(0,n.kt)("li",{parentName:"ul"},"Org3 obtains a membership credential from Steward"))),(0,n.kt)("li",{parentName:"ul"},"The IIN Agent for Org3 issues itself a self-signed VC containing its security group info"),(0,n.kt)("li",{parentName:"ul"},"The IIN Agent for ",(0,n.kt)("em",{parentName:"li"},"NETWORK 2"),":Org2 (only one organization in the network needs to do this) obtains the new member list credential from Steward in IIN and validates it using the IIN ledger records"),(0,n.kt)("li",{parentName:"ul"},"The IIN Agent for ",(0,n.kt)("em",{parentName:"li"},"NETWORK 2"),":Org2 discovers that Org3 is a member of ",(0,n.kt)("em",{parentName:"li"},"NETWORK 1"),", fetches Org3's membership credential from Org3's IIN Agent, and validates it using the IIN ledger records"),(0,n.kt)("li",{parentName:"ul"},"The IIN agent for ",(0,n.kt)("em",{parentName:"li"},"NETWORK 2"),":Org2 fetches the self-signed security group credential from the IIN agent of ",(0,n.kt)("em",{parentName:"li"},"NETWORK 1"),":Org3 and validates it"),(0,n.kt)("li",{parentName:"ul"},"The IIN agent for ",(0,n.kt)("em",{parentName:"li"},"NETWORK 2"),":Org2 triggers a flow among the IIN Agents of ",(0,n.kt)("em",{parentName:"li"},"NETWORK 2")," to collect signatures endorsing the security group info for ",(0,n.kt)("em",{parentName:"li"},"NETWORK 1"),":Org3 fetched above",(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},"The IIN Agent for ",(0,n.kt)("em",{parentName:"li"},"NETWORK 2"),":Org1 gets this endorsement request, and validates both the membership credential and the security group info for ",(0,n.kt)("em",{parentName:"li"},"NETWORK 1"),":Org3 by communicating with the Steward, the IIN ledger, and the IIN Agent for ",(0,n.kt)("em",{parentName:"li"},"NETWORK 1"),":Org3"),(0,n.kt)("li",{parentName:"ul"},"The IIN Agent for ",(0,n.kt)("em",{parentName:"li"},"NETWORK 2"),":Org1 signs the request from Org2 containing the security group info for ",(0,n.kt)("em",{parentName:"li"},"NETWORK 1"),":Org3 after the above check succeeds"))),(0,n.kt)("li",{parentName:"ul"},"When the IIN agent for ",(0,n.kt)("em",{parentName:"li"},"NETWORK 2"),":Org2 gets signatures from the IIN Agents representing each member of ",(0,n.kt)("em",{parentName:"li"},"NETWORK 2"),", it submits the security group info for ",(0,n.kt)("em",{parentName:"li"},"NETWORK 1"),":Org3 alon with the signatures to the ",(0,n.kt)("em",{parentName:"li"},"interop module")," (typically smart contract) for recording on the ledger of ",(0,n.kt)("em",{parentName:"li"},"NETWORK 2"),(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},"Now the ledger of ",(0,n.kt)("em",{parentName:"li"},"NETWORK 2")," contains the identities and certificates of all three members of ",(0,n.kt)("em",{parentName:"li"},"NETWORK 1"),": Org3,Org4,Org5, and data plane interoperation may ensue.")))),(0,n.kt)("p",null,(0,n.kt)("em",{parentName:"p"},"Note"),": the last step above (recording to the local ledger via the ",(0,n.kt)("em",{parentName:"p"},"interop module"),") may be performed by IIN Agents of both Org1 and Org2 as they have no means of synchronizing their actions, but this recording will be idempotent and hence not cause any harm."),(0,n.kt)("p",null,"The process above is illustrated with a few more details in the sequence of protocol diagrams below."),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"alt text",src:a(9806).Z,width:"1667",height:"867"})),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"alt text",src:a(9418).Z,width:"1761",height:"879"})),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"alt text",src:a(786).Z,width:"1748",height:"923"})),(0,n.kt)("h3",{id:"references"},"References"),(0,n.kt)("p",null,"Bishakh Chandra Ghosh, Venkatraman Ramakrishna, Chander Govindarajan, Dushyant Behl, Dileban Karunamoorthy, Ermyas Abebe, Sandip Chakraborty, ",(0,n.kt)("a",{parentName:"p",href:"https://arxiv.org/abs/2104.03277"},"Decentralized Cross-Network Identity Management for Blockchain Interoperation"),", ",(0,n.kt)("em",{parentName:"p"},"ICBC 2021")))}m.isMDXComponent=!0},5132:(e,t,a)=>{a.d(t,{Z:()=>r});const r=a.p+"assets/images/decentralized-id-mgmt-arch-7ed4587b65ff744dfc673abd501e4ba7.jpg"},4482:(e,t,a)=>{a.d(t,{Z:()=>r});const r=a.p+"assets/images/identity-data-planes-debbbfc93b380e8b7d19d806f5bd6938.jpg"},3537:(e,t,a)=>{a.d(t,{Z:()=>r});const r=a.p+"assets/images/iin-augmented-network-825564146ecf315409523fc5143b91e4.jpg"},5834:(e,t,a)=>{a.d(t,{Z:()=>r});const r=a.p+"assets/images/iin-5a100d43a34ee6ee2a1d8e630c3e918d.jpg"},9418:(e,t,a)=>{a.d(t,{Z:()=>r});const r=a.p+"assets/images/protocol-get-info-phase-9c3977e73e33da03ef6ceb6024cb2a85.jpg"},7089:(e,t,a)=>{a.d(t,{Z:()=>r});const r=a.p+"assets/images/protocol-identity-overview-1b83a4b8fd6f467e31e44f86f2b5fdc1.jpg"},9806:(e,t,a)=>{a.d(t,{Z:()=>r});const r=a.p+"assets/images/protocol-registration-phase-f6105952390836cc034643eebbee5009.jpg"},786:(e,t,a)=>{a.d(t,{Z:()=>r});const r=a.p+"assets/images/protocol-update-info-phase-560b85ccf7c2f12f83dd6c2fec1fbbcd.jpg"}}]); \ No newline at end of file diff --git a/assets/js/8758c959.748c2c34.js b/assets/js/8758c959.748c2c34.js new file mode 100644 index 000000000..d0965e255 --- /dev/null +++ b/assets/js/8758c959.748c2c34.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[8317],{5680:(e,t,a)=>{a.d(t,{xA:()=>h,yg:()=>p});var r=a(6540);function n(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function i(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,r)}return a}function o(e){for(var t=1;t<arguments.length;t++){var a=null!=arguments[t]?arguments[t]:{};t%2?i(Object(a),!0).forEach((function(t){n(e,t,a[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(a)):i(Object(a)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(a,t))}))}return e}function s(e,t){if(null==e)return{};var a,r,n=function(e,t){if(null==e)return{};var a,r,n={},i=Object.keys(e);for(r=0;r<i.length;r++)a=i[r],t.indexOf(a)>=0||(n[a]=e[a]);return n}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r<i.length;r++)a=i[r],t.indexOf(a)>=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(n[a]=e[a])}return n}var l=r.createContext({}),d=function(e){var t=r.useContext(l),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},h=function(e){var t=d(e.components);return r.createElement(l.Provider,{value:t},e.children)},c="mdxType",g={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var a=e.components,n=e.mdxType,i=e.originalType,l=e.parentName,h=s(e,["components","mdxType","originalType","parentName"]),c=d(a),m=n,p=c["".concat(l,".").concat(m)]||c[m]||g[m]||i;return a?r.createElement(p,o(o({ref:t},h),{},{components:a})):r.createElement(p,o({ref:t},h))}));function p(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var i=a.length,o=new Array(i);o[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[c]="string"==typeof e?e:n,o[1]=s;for(var d=2;d<i;d++)o[d]=a[d];return r.createElement.apply(null,o)}return r.createElement.apply(null,a)}m.displayName="MDXCreateElement"},6076:(e,t,a)=>{a.r(t),a.d(t,{assets:()=>l,contentTitle:()=>o,default:()=>g,frontMatter:()=>i,metadata:()=>s,toc:()=>d});var r=a(8168),n=(a(6540),a(5680));const i={id:"decentralized-identity",title:"Decentralized Identity"},o=void 0,s={unversionedId:"external/architecture-and-design/decentralized-identity",id:"external/architecture-and-design/decentralized-identity",title:"Decentralized Identity",description:"\x3c!--",source:"@site/docs/external/architecture-and-design/decentralized-identity.md",sourceDirName:"external/architecture-and-design",slug:"/external/architecture-and-design/decentralized-identity",permalink:"/weaver-dlt-interoperability/docs/external/architecture-and-design/decentralized-identity",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/architecture-and-design/decentralized-identity.md",tags:[],version:"current",frontMatter:{id:"decentralized-identity",title:"Decentralized Identity"},sidebar:"Documentation",previous:{title:"Weaver Dapps",permalink:"/weaver-dlt-interoperability/docs/external/architecture-and-design/weaver-dapps"},next:{title:"Authentication",permalink:"/weaver-dlt-interoperability/docs/external/security-model/authentication"}},l={},d=[{value:"Identity Plane: Strawman Approach",id:"identity-plane-strawman-approach",level:3},{value:"Networks as Groups of Self-Sovereign Members",id:"networks-as-groups-of-self-sovereign-members",level:3},{value:"Distributed Identity Management Infrastructure",id:"distributed-identity-management-infrastructure",level:3},{value:"Interoperation Identity Network",id:"interoperation-identity-network",level:4},{value:"Network Membership Credentials",id:"network-membership-credentials",level:4},{value:"Identity Info: Units of Exchange",id:"identity-info-units-of-exchange",level:4},{value:"IIN Agents as Member Representatives",id:"iin-agents-as-member-representatives",level:4},{value:"Protocols",id:"protocols",level:4},{value:"References",id:"references",level:3}],h={toc:d},c="wrapper";function g(e){let{components:t,...i}=e;return(0,n.yg)(c,(0,r.A)({},h,i,{components:t,mdxType:"MDXLayout"}),(0,n.yg)("p",null,"Interoperation for asset or data transfers/exchanges relies on a message-passing infratructure and pan-network data processing modules, as we have seen in earlier pages. But there is yet another crucial basis these data processing modules need to satisfy our design principles of network independence and avoidance of trust parties. This is the ability of a network as a whole and of its individual members to accurately identify and authenticate another network's members."),(0,n.yg)("p",null,"Further, for the networks to remain independent and interact ad hoc with each other, we cannot impose a central authority that unifies their private identity management systems. So the identity basis of interoperation must be decentralized, leading inevitably to the requirement of exchanging identity information across networks as a pre-requisite for asset and data transfers/exchanges. This is illustrated in the figure below where interoperation protocols are classified in two planes (or tiers), data and identity, with the former depending on the latter."),(0,n.yg)("p",null,(0,n.yg)("img",{alt:"alt text",src:a(2014).A,width:"1659",height:"829"})),(0,n.yg)("ul",null,(0,n.yg)("li",{parentName:"ul"},"In the ",(0,n.yg)("strong",{parentName:"li"},"data plane")," lies the protocols that effect the actual exchanges of data and assets. The figure above illustrates a typical data-sharing instance, where the network at the left requests a data record from the right. The latter receives the request via the two relays (not explicitly marked in this diagram) and runs an access control check through consensus in its ",(0,n.yg)("em",{parentName:"li"},"interop module")," before responding with the data record and supporting proof. The network at the left receives the data and proof, again via the two relays, and verifies the data using the supplied proof. ",(0,n.yg)("strong",{parentName:"li"},"Note: since a core part of both request and proof are digital signatures of network members, the ability to identify and authenticate network members is necessary to perform these endpoint functions"),"."),(0,n.yg)("li",{parentName:"ul"},"Here is where the ",(0,n.yg)("strong",{parentName:"li"},"identity plane")," enters the picture, as a trust anchor for the data plane. The most general function of this plane is illustrated in the figure, where the networks get each others' identity and configuration (i.e., membership structure and network topology) information. This exchange has as its own trust basis (or dependency) a set of identity providers and verifiers. (",(0,n.yg)("em",{parentName:"li"},"Note"),": these identity providers and verifiers may belong to the two networks or they could be external entities.) The outcome of the exchange is a record of the other network's identity and configuration information on one's ledger, which can then be looked up in a data plane protocol instance.")),(0,n.yg)("h3",{id:"identity-plane-strawman-approach"},"Identity Plane: Strawman Approach"),(0,n.yg)("p",null,"The simplest identity plane protocol involves a direct exchange of identity information between representatives of the two networks: in other words, an API integration. But this approach suffers from the same drawbacks that API integration in the data plane would. It diminishes a blockchain network to a single trusted spokesperson, exposing that network to risk. Even if such a spokesperson could be designated, appropriately framing access control policies for potentially every other blockchain network in the world would be very challenging. This approach is therefore insecure and not scalable, and therefore ought to be treated purely as a strawman."),(0,n.yg)("h3",{id:"networks-as-groups-of-self-sovereign-members"},"Networks as Groups of Self-Sovereign Members"),(0,n.yg)("p",null,"A secure and sustainable identity plane plaform can be built on the basis of ",(0,n.yg)("em",{parentName:"p"},"self-sovereign identity")," and ",(0,n.yg)("em",{parentName:"p"},"decentralized identifiers"),". We recognize that:"),(0,n.yg)("ul",null,(0,n.yg)("li",{parentName:"ul"},"Each constituent member of a blockchain network may already possess an identity from a third-party provider"),(0,n.yg)("li",{parentName:"ul"},"Membership within a network can be treated as a property of a sovereign organization rather than subordination to a network's governing authority"),(0,n.yg)("li",{parentName:"ul"},"DIDs allow members to control who they wish to share their identities with and the levels of exposure"),(0,n.yg)("li",{parentName:"ul"},"Network membership lists and individual members' identities can respectively be validated by different providers, thereby maintaining decentralization of infrastructure")),(0,n.yg)("h3",{id:"distributed-identity-management-infrastructure"},"Distributed Identity Management Infrastructure"),(0,n.yg)("p",null,"The distributed identity management infrastructure for interoperation is illustrated in the figure below. We assume the existence of one or more ",(0,n.yg)("em",{parentName:"p"},"Interoperation Identity Networks (IINs)")," that act as registries and credential validators for the organizations that form the memberships of blockchain networks."),(0,n.yg)("p",null,(0,n.yg)("img",{alt:"alt text",src:a(5588).A,width:"1381",height:"632"})),(0,n.yg)("p",null,"An IIN can be built from scratch to facilitate blockchain interoperation, but it can also be an augmentation of an existing decentralized identity provider or registry. Its purpose is to maintain identity records and credentials for organizations and validate these to third parties as per the desire of the identity or credential owner. In this model, an IIN can itself be reputed or it can bring together many reputed and trusted identity providers (called ",(0,n.yg)("em",{parentName:"p"},"stewards"),") into a shared network. As long as the members of two blockchain networks have shared trust in one or more IINs, an identity plane exchange can be effected, thereby setting the foundation for data and asset transfers."),(0,n.yg)("h4",{id:"interoperation-identity-network"},"Interoperation Identity Network"),(0,n.yg)("p",null,"The ideal IIN architecture is illustrated in the figure below, inspired by Hyperleder Indy, whose architecture is used in our canonical (or reference) implementation. Built on a DLT itself, an Indy-based IIN can provide the combination of assurance and decentralization that a centralized registry cannot. Further, such an IIN will support the entire SSI and DID standard, maintaining credential schemas and verification keys, and issuing ",(0,n.yg)("em",{parentName:"p"},"verifiable credentials")," that can be used for privacy-preserving authentications."),(0,n.yg)("p",null,(0,n.yg)("img",{alt:"alt text",src:a(8115).A,width:"1727",height:"818"})),(0,n.yg)("p",null,"An IIN is modeled as a network with a distributed shared ledger, implemented using an Indy Node Pool and running BFT consensus. The ledger is also (ideally) meant to be publicly accessible, though there is nothing preventing our protocols from working with a private IIN."),(0,n.yg)("p",null,"A canonical IIN maintains the following:"),(0,n.yg)("ul",null,(0,n.yg)("li",{parentName:"ul"},"DID records corresponding to organizations that are members of one or more blockchain networks, whose salient attributes include:",(0,n.yg)("ul",{parentName:"li"},(0,n.yg)("li",{parentName:"ul"},"Unique (within an IIN) identifier or ",(0,n.yg)("em",{parentName:"li"},"verinym")," for the identity owner"),(0,n.yg)("li",{parentName:"ul"},"Service endpoint for the identity owner"),(0,n.yg)("li",{parentName:"ul"},"Credential schemas"),(0,n.yg)("li",{parentName:"ul"},"Credential definitions (public keys used to authenticate signed credentials)")))),(0,n.yg)("p",null,"Every IIN has a set of bootstrapped ",(0,n.yg)("em",{parentName:"p"},"trust anchors")," called ",(0,n.yg)("em",{parentName:"p"},"stewards"),". A steward can create other trust anchors by issuing them suitable credentials. The trust anchors are the primary identity providers in our distributed identity management architecture. They can be existing reputed authorities or identity providers who are trusted to certify blockchain networks' memberships, or they can be created ad hoc by a consortium representing the members of a blockchain network."),(0,n.yg)("p",null,"For one blockchain network to discover and validate another in the identity plane, it must trust one or more IINs and trust anchors who can provide that validation. We envision a shared and mutually reinforcing trust among stewards and other anchors within an IIN. An anchor could gain trust by virtue of joining a well-established IIN. Similarly, an IIN bootstrapped with well-known stewards gains trust because of the collective reputations of those stewards."),(0,n.yg)("p",null,"Examples of entities that can act as stewards or trust anchors within IINs: the Sovrin Foundation (an organization dedicated to enabling open-source digital ID management, and which also maintains Indy), companies like Maersk or Walmart that have founded real-world blockchain networks, companies like IBM or R3 that maintain popular DLT platforms."),(0,n.yg)("p",null,"IINs don't have to be built on Indy. Alternatives like Sidetree exist, providing similar functionality. There are also various existing DID registries that are already issuing credentials to existing organizations. To the extent possible, we would like to leverage all of this existing infrastructure and not force any network menmber to find yet another identity provider. Therefore, these existing registries or networks can be used as IINs: the only requirement is that they follow the standards for SSI and DIDs and issuing VCs."),(0,n.yg)("h4",{id:"network-membership-credentials"},"Network Membership Credentials"),(0,n.yg)("p",null,"Two kinds of credentials (each with a schema and a definition) are maintained on an IIN ledger:"),(0,n.yg)("ol",null,(0,n.yg)("li",{parentName:"ol"},(0,n.yg)("strong",{parentName:"li"},"Member list"),": This contains a network name or ID and a set of DIDs of that network's members.")),(0,n.yg)("ul",null,(0,n.yg)("li",{parentName:"ul"},"This is a per-network credential whose schema and verification key must be maintained on an IIN."),(0,n.yg)("li",{parentName:"ul"},"This is issued by a steward or trust anchor in an IIN and is associated with that steward's or anchor's DID.")),(0,n.yg)("ol",{start:2},(0,n.yg)("li",{parentName:"ol"},(0,n.yg)("strong",{parentName:"li"},"Membership"),": This contains an oranization's attributes, including the set of IDs of networks to which it belongs.")),(0,n.yg)("ul",null,(0,n.yg)("li",{parentName:"ul"},"This is designed to be an extensible credential, i.e., support more attributes in the future."),(0,n.yg)("li",{parentName:"ul"},"An existing membership credential (of the VC form) can be used as long as it matches the schema recorded on an IIN."),(0,n.yg)("li",{parentName:"ul"},"The issuer must be a steward or trust anchor (or equivalent, if it's a non-Indy registry) in an IIN."),(0,n.yg)("li",{parentName:"ul"},"This is associated with the member's DID.")),(0,n.yg)("h4",{id:"identity-info-units-of-exchange"},"Identity Info: Units of Exchange"),(0,n.yg)("p",null,"The IIN is used to discover the membership list of a foreign network and establish the authenticity of its members. Memnbership credentials are independent of blockchain networks."),(0,n.yg)("p",null,"But data plane transfers and exchanges require knowledge of in-network identities and certificates, which are issued by a network's membership manager(s) to peers and clients. These are not shared through IINs for several reasons. First, the volume of this information can be quite high and further it is subject to change based on a network's internal needs. Also, a network or its members may not wish to expose all this information to an IIN, which is designed to be publicly accessible. Therefore, it is infeasible or undesirable to shared network-specific credentials via established IINs. Instead, we will enable the ",(0,n.yg)("em",{parentName:"p"},"peer-to-peer")," exchange of such credentials after the membership discovery and validation procedure is complete."),(0,n.yg)("p",null,"Specifically, the identity information for a network member consists of the set of certificate chains of the membership managers for that particular member (organization). These consist of one or more hierarchies of root and intermediate CA certificates. For example:"),(0,n.yg)("ul",null,(0,n.yg)("li",{parentName:"ul"},"In Fabric, each organization uses one or more MSPs (",(0,n.yg)("em",{parentName:"li"},"membership service providers"),"), each running one or more root and intermediate Fabric-CA servers. Any network peer belonging to an organization is issued a certificate authorized by one of these certificate chains. To authenticate a network peer or client in a data plane protocol, knowledge of these certificate chains is essential."),(0,n.yg)("li",{parentName:"ul"},"In Corda, the entire network typically consists of a hierarchy of CAs, from a root to multiple ",(0,n.yg)("em",{parentName:"li"},"doormen"),", and from each doorman to multiple nodes. Finally, the certificates used to sign transactions are issued by the node CAs. Therefore, knowledge of the root, doormen, and node CA certificates is essential for authenticating signers.")),(0,n.yg)("p",null,"More generally, each unit of exchange corresponding to a network member is a ",(0,n.yg)("em",{parentName:"p"},"Security Group"),", so-called because each network member is an independent organization in its own right with a security domain."),(0,n.yg)("h4",{id:"iin-agents-as-member-representatives"},"IIN Agents as Member Representatives"),(0,n.yg)("p",null,'Every network member needs a proxy (either an abstraction or a separate module) for communication with IINs and with the members of foreign networks in the identity plane. We use the term "IIN Agent" to refer to this proxy, and illustrate its functioning as a module within a Fabric network through the reference diagram below.'),(0,n.yg)("p",null,(0,n.yg)("img",{alt:"alt text",src:a(607).A,width:"1528",height:"847"})),(0,n.yg)("p",null,"In the reference implementation, IIN Agents are built as Hyperledger Aries nodes and communicate with each other and with IIN stewards and trust anchors using the Aries protocol. (IIN stewards and trust anchors are also built as Aries nodes.)"),(0,n.yg)("p",null,"The list of trusted IINs is recorded on the local network's shared ledger, as illustrated in the figure (and thereby agreed through network consensus). To be able to interoperate with another network, the latter's members must have identity records maintained by sume subset of these trusted IINs and their VCs must be issued by these IINs stewards and trust anchors."),(0,n.yg)("h4",{id:"protocols"},"Protocols"),(0,n.yg)("p",null,"Let us consider a scenario where ",(0,n.yg)("em",{parentName:"p"},"NETWORK 1")," and ",(0,n.yg)("em",{parentName:"p"},"NETWORK 2")," wish to interoperate, and their respective member organizations are as follows:"),(0,n.yg)("ul",null,(0,n.yg)("li",{parentName:"ul"},(0,n.yg)("em",{parentName:"li"},"NETWORK 1"),": Org3, Org4, Org5"),(0,n.yg)("li",{parentName:"ul"},(0,n.yg)("em",{parentName:"li"},"NETWORK 2"),": Org1, Org2")),(0,n.yg)("p",null,"Each network discovers the other's member list and obtains and records ech member's security group to the local shared ledger. We can enumerate these as follows:"),(0,n.yg)("ul",null,(0,n.yg)("li",{parentName:"ul"},(0,n.yg)("em",{parentName:"li"},"NETWORK 1")," discovers and registers ",(0,n.yg)("em",{parentName:"li"},"NETWORK 2"),":Org1"),(0,n.yg)("li",{parentName:"ul"},(0,n.yg)("em",{parentName:"li"},"NETWORK 1")," discovers and registers ",(0,n.yg)("em",{parentName:"li"},"NETWORK 2"),":Org2"),(0,n.yg)("li",{parentName:"ul"},(0,n.yg)("em",{parentName:"li"},"NETWORK 2")," discovers and registers ",(0,n.yg)("em",{parentName:"li"},"NETWORK 1"),":Org3"),(0,n.yg)("li",{parentName:"ul"},(0,n.yg)("em",{parentName:"li"},"NETWORK 2")," discovers and registers ",(0,n.yg)("em",{parentName:"li"},"NETWORK 1"),":Org4"),(0,n.yg)("li",{parentName:"ul"},(0,n.yg)("em",{parentName:"li"},"NETWORK 2")," discovers and registers ",(0,n.yg)("em",{parentName:"li"},"NETWORK 1"),":Org5")),(0,n.yg)("p",null,"Each of these can be done in parallel and each discovery and registration operation is idempotent as long as the security group of a network member does not change."),(0,n.yg)("p",null,"The high-level workflow for discovery and registration is illustrated below (using ",(0,n.yg)("em",{parentName:"p"},"NETWORK 2")," as the seeker and ",(0,n.yg)("em",{parentName:"p"},"NETWORK 1")," as the provider)."),(0,n.yg)("p",null,(0,n.yg)("img",{alt:"alt text",src:a(1366).A,width:"1505",height:"739"})),(0,n.yg)("p",null,"(",(0,n.yg)("em",{parentName:"p"},"Note"),': "Network unit" is synonymous with "network member")'),(0,n.yg)("p",null,"Prerequisites for this process are:"),(0,n.yg)("ul",null,(0,n.yg)("li",{parentName:"ul"},"The member list credential of ",(0,n.yg)("em",{parentName:"li"},"NETWORK 1")," is provided by a steward or trust anchor in a particular IIN which is also on the trust list recorded in the ledger of ",(0,n.yg)("em",{parentName:"li"},"NETWORK 2"),"."),(0,n.yg)("li",{parentName:"ul"},"The membership credentials for both organizations in ",(0,n.yg)("em",{parentName:"li"},"NETWORK 1")," are supplied by one or more IINs that are on the trust list of ",(0,n.yg)("em",{parentName:"li"},"NETWORK 2"),"."),(0,n.yg)("li",{parentName:"ul"},"Each of the 5 organizations (2 in ",(0,n.yg)("em",{parentName:"li"},"NETWORK 1")," and 3 in ",(0,n.yg)("em",{parentName:"li"},"NETWORK 2"),") has an IIN Agent running on their behalf.")),(0,n.yg)("p",null,"Let us take the example of ",(0,n.yg)("em",{parentName:"p"},"NETWORK 2")," having already obtained the security group info for Org4 and Org5 in ",(0,n.yg)("em",{parentName:"p"},"NETWORK 1"),". It is now discovering and registering ",(0,n.yg)("em",{parentName:"p"},"NETWORK 1"),":Org3. We assume that there is a single IIN with a single Steward for validating member list as well as membership credentials for all members of both the networks."),(0,n.yg)("p",null,(0,n.yg)("em",{parentName:"p"},"Note"),": we assume here for simplicity that a steward as a reputed identity provider has a mechanism to validate the bona fides of an orgganization and its membership in a given network. There are other techniques involving group signatures that could be applied to corroborate an organization's claim to network membership rather than requiring a steward to use an out-of-band security mechanism, but that is presently beyond the scope of this design."),(0,n.yg)("p",null,"The discovery and registration procedure steps are as follows:"),(0,n.yg)("ul",null,(0,n.yg)("li",{parentName:"ul"},"The IIN Agent for Org3 registers its membership to ",(0,n.yg)("em",{parentName:"li"},"NETWORK 1")," at the Steward in IIN:",(0,n.yg)("ul",{parentName:"li"},(0,n.yg)("li",{parentName:"ul"},(0,n.yg)("em",{parentName:"li"},"NETWORK 1"),":Org3 gets a DID (verinym) issued"),(0,n.yg)("li",{parentName:"ul"},"The Steward updates the member list credential for ",(0,n.yg)("em",{parentName:"li"},"NETWORK 1")," to include Org3"),(0,n.yg)("li",{parentName:"ul"},"Org3 obtains a membership credential from Steward"))),(0,n.yg)("li",{parentName:"ul"},"The IIN Agent for Org3 issues itself a self-signed VC containing its security group info"),(0,n.yg)("li",{parentName:"ul"},"The IIN Agent for ",(0,n.yg)("em",{parentName:"li"},"NETWORK 2"),":Org2 (only one organization in the network needs to do this) obtains the new member list credential from Steward in IIN and validates it using the IIN ledger records"),(0,n.yg)("li",{parentName:"ul"},"The IIN Agent for ",(0,n.yg)("em",{parentName:"li"},"NETWORK 2"),":Org2 discovers that Org3 is a member of ",(0,n.yg)("em",{parentName:"li"},"NETWORK 1"),", fetches Org3's membership credential from Org3's IIN Agent, and validates it using the IIN ledger records"),(0,n.yg)("li",{parentName:"ul"},"The IIN agent for ",(0,n.yg)("em",{parentName:"li"},"NETWORK 2"),":Org2 fetches the self-signed security group credential from the IIN agent of ",(0,n.yg)("em",{parentName:"li"},"NETWORK 1"),":Org3 and validates it"),(0,n.yg)("li",{parentName:"ul"},"The IIN agent for ",(0,n.yg)("em",{parentName:"li"},"NETWORK 2"),":Org2 triggers a flow among the IIN Agents of ",(0,n.yg)("em",{parentName:"li"},"NETWORK 2")," to collect signatures endorsing the security group info for ",(0,n.yg)("em",{parentName:"li"},"NETWORK 1"),":Org3 fetched above",(0,n.yg)("ul",{parentName:"li"},(0,n.yg)("li",{parentName:"ul"},"The IIN Agent for ",(0,n.yg)("em",{parentName:"li"},"NETWORK 2"),":Org1 gets this endorsement request, and validates both the membership credential and the security group info for ",(0,n.yg)("em",{parentName:"li"},"NETWORK 1"),":Org3 by communicating with the Steward, the IIN ledger, and the IIN Agent for ",(0,n.yg)("em",{parentName:"li"},"NETWORK 1"),":Org3"),(0,n.yg)("li",{parentName:"ul"},"The IIN Agent for ",(0,n.yg)("em",{parentName:"li"},"NETWORK 2"),":Org1 signs the request from Org2 containing the security group info for ",(0,n.yg)("em",{parentName:"li"},"NETWORK 1"),":Org3 after the above check succeeds"))),(0,n.yg)("li",{parentName:"ul"},"When the IIN agent for ",(0,n.yg)("em",{parentName:"li"},"NETWORK 2"),":Org2 gets signatures from the IIN Agents representing each member of ",(0,n.yg)("em",{parentName:"li"},"NETWORK 2"),", it submits the security group info for ",(0,n.yg)("em",{parentName:"li"},"NETWORK 1"),":Org3 alon with the signatures to the ",(0,n.yg)("em",{parentName:"li"},"interop module")," (typically smart contract) for recording on the ledger of ",(0,n.yg)("em",{parentName:"li"},"NETWORK 2"),(0,n.yg)("ul",{parentName:"li"},(0,n.yg)("li",{parentName:"ul"},"Now the ledger of ",(0,n.yg)("em",{parentName:"li"},"NETWORK 2")," contains the identities and certificates of all three members of ",(0,n.yg)("em",{parentName:"li"},"NETWORK 1"),": Org3,Org4,Org5, and data plane interoperation may ensue.")))),(0,n.yg)("p",null,(0,n.yg)("em",{parentName:"p"},"Note"),": the last step above (recording to the local ledger via the ",(0,n.yg)("em",{parentName:"p"},"interop module"),") may be performed by IIN Agents of both Org1 and Org2 as they have no means of synchronizing their actions, but this recording will be idempotent and hence not cause any harm."),(0,n.yg)("p",null,"The process above is illustrated with a few more details in the sequence of protocol diagrams below."),(0,n.yg)("p",null,(0,n.yg)("img",{alt:"alt text",src:a(6719).A,width:"1667",height:"867"})),(0,n.yg)("p",null,(0,n.yg)("img",{alt:"alt text",src:a(9705).A,width:"1761",height:"879"})),(0,n.yg)("p",null,(0,n.yg)("img",{alt:"alt text",src:a(2802).A,width:"1748",height:"923"})),(0,n.yg)("h3",{id:"references"},"References"),(0,n.yg)("p",null,"Bishakh Chandra Ghosh, Venkatraman Ramakrishna, Chander Govindarajan, Dushyant Behl, Dileban Karunamoorthy, Ermyas Abebe, Sandip Chakraborty, ",(0,n.yg)("a",{parentName:"p",href:"https://arxiv.org/abs/2104.03277"},"Decentralized Cross-Network Identity Management for Blockchain Interoperation"),", ",(0,n.yg)("em",{parentName:"p"},"ICBC 2021")))}g.isMDXComponent=!0},5588:(e,t,a)=>{a.d(t,{A:()=>r});const r=a.p+"assets/images/decentralized-id-mgmt-arch-7ed4587b65ff744dfc673abd501e4ba7.jpg"},2014:(e,t,a)=>{a.d(t,{A:()=>r});const r=a.p+"assets/images/identity-data-planes-debbbfc93b380e8b7d19d806f5bd6938.jpg"},607:(e,t,a)=>{a.d(t,{A:()=>r});const r=a.p+"assets/images/iin-augmented-network-825564146ecf315409523fc5143b91e4.jpg"},8115:(e,t,a)=>{a.d(t,{A:()=>r});const r=a.p+"assets/images/iin-5a100d43a34ee6ee2a1d8e630c3e918d.jpg"},9705:(e,t,a)=>{a.d(t,{A:()=>r});const r=a.p+"assets/images/protocol-get-info-phase-9c3977e73e33da03ef6ceb6024cb2a85.jpg"},1366:(e,t,a)=>{a.d(t,{A:()=>r});const r=a.p+"assets/images/protocol-identity-overview-1b83a4b8fd6f467e31e44f86f2b5fdc1.jpg"},6719:(e,t,a)=>{a.d(t,{A:()=>r});const r=a.p+"assets/images/protocol-registration-phase-f6105952390836cc034643eebbee5009.jpg"},2802:(e,t,a)=>{a.d(t,{A:()=>r});const r=a.p+"assets/images/protocol-update-info-phase-560b85ccf7c2f12f83dd6c2fec1fbbcd.jpg"}}]); \ No newline at end of file diff --git a/assets/js/8b2840ea.ce0dc2e8.js b/assets/js/8b2840ea.ce0dc2e8.js new file mode 100644 index 000000000..2d8c685b3 --- /dev/null +++ b/assets/js/8b2840ea.ce0dc2e8.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[6325],{5680:(e,a,n)=>{n.d(a,{xA:()=>g,yg:()=>m});var t=n(6540);function r(e,a,n){return a in e?Object.defineProperty(e,a,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[a]=n,e}function i(e,a){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var t=Object.getOwnPropertySymbols(e);a&&(t=t.filter((function(a){return Object.getOwnPropertyDescriptor(e,a).enumerable}))),n.push.apply(n,t)}return n}function l(e){for(var a=1;a<arguments.length;a++){var n=null!=arguments[a]?arguments[a]:{};a%2?i(Object(n),!0).forEach((function(a){r(e,a,n[a])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(a){Object.defineProperty(e,a,Object.getOwnPropertyDescriptor(n,a))}))}return e}function o(e,a){if(null==e)return{};var n,t,r=function(e,a){if(null==e)return{};var n,t,r={},i=Object.keys(e);for(t=0;t<i.length;t++)n=i[t],a.indexOf(n)>=0||(r[n]=e[n]);return r}(e,a);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(t=0;t<i.length;t++)n=i[t],a.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=t.createContext({}),p=function(e){var a=t.useContext(s),n=a;return e&&(n="function"==typeof e?e(a):l(l({},a),e)),n},g=function(e){var a=p(e.components);return t.createElement(s.Provider,{value:a},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var a=e.children;return t.createElement(t.Fragment,{},a)}},y=t.forwardRef((function(e,a){var n=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,g=o(e,["components","mdxType","originalType","parentName"]),d=p(n),y=r,m=d["".concat(s,".").concat(y)]||d[y]||c[y]||i;return n?t.createElement(m,l(l({ref:a},g),{},{components:n})):t.createElement(m,l({ref:a},g))}));function m(e,a){var n=arguments,r=a&&a.mdxType;if("string"==typeof e||r){var i=n.length,l=new Array(i);l[0]=y;var o={};for(var s in a)hasOwnProperty.call(a,s)&&(o[s]=a[s]);o.originalType=e,o[d]="string"==typeof e?e:r,l[1]=o;for(var p=2;p<i;p++)l[p]=n[p];return t.createElement.apply(null,l)}return t.createElement.apply(null,n)}y.displayName="MDXCreateElement"},3698:(e,a,n)=>{n.r(a),n.d(a,{assets:()=>s,contentTitle:()=>l,default:()=>c,frontMatter:()=>i,metadata:()=>o,toc:()=>p});var t=n(8168),r=(n(6540),n(5680));const i={id:"setup-packages",title:"Setup with Imported Weaver Components",pagination_prev:"external/getting-started/test-network/overview",pagination_next:"external/getting-started/test-network/ledger-initialization"},l=void 0,o={unversionedId:"external/getting-started/test-network/setup-packages",id:"external/getting-started/test-network/setup-packages",title:"Setup with Imported Weaver Components",description:"\x3c!--",source:"@site/docs/external/getting-started/test-network/setup-packages.md",sourceDirName:"external/getting-started/test-network",slug:"/external/getting-started/test-network/setup-packages",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-packages",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/getting-started/test-network/setup-packages.md",tags:[],version:"current",frontMatter:{id:"setup-packages",title:"Setup with Imported Weaver Components",pagination_prev:"external/getting-started/test-network/overview",pagination_next:"external/getting-started/test-network/ledger-initialization"},sidebar:"Documentation",previous:{title:"Component Overview",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/overview"},next:{title:"Ledger Initialization",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/ledger-initialization"}},s={},p=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Software",id:"software",level:3},{value:"Credentials",id:"credentials",level:3},{value:"Getting the Code and Documentation",id:"getting-the-code-and-documentation",level:2},{value:"Securing Components",id:"securing-components",level:2},{value:"Hyperledger Fabric Components",id:"hyperledger-fabric-components",level:2},{value:"Fabric Network",id:"fabric-network",level:3},{value:"Fabric Client (fabric-cli)",id:"fabric-client-fabric-cli",level:3},{value:"Prerequisites",id:"prerequisites-1",level:4},{value:"Installation",id:"installation",level:4},{value:"Fabric Relay",id:"fabric-relay",level:3},{value:"Building",id:"building",level:4},{value:"Deployment",id:"deployment",level:4},{value:"Fabric Driver",id:"fabric-driver",level:3},{value:"Configuring",id:"configuring",level:4},{value:"Building",id:"building-1",level:4},{value:"Running",id:"running",level:4},{value:"Fabric IIN Agent",id:"fabric-iin-agent",level:3},{value:"Building",id:"building-2",level:4},{value:"Configuration",id:"configuration",level:4},{value:"Security Domain Configuration",id:"security-domain-configuration",level:4},{value:"DNS Configuration",id:"dns-configuration",level:4},{value:"Environment Variables",id:"environment-variables",level:4},{value:"Deployment",id:"deployment-1",level:4},{value:"Corda Components",id:"corda-components",level:2},{value:"Corda Network",id:"corda-network",level:3},{value:"Running with Interoperation CorDapp from GitHub Packages",id:"running-with-interoperation-cordapp-from-github-packages",level:4},{value:"Corda Relay",id:"corda-relay",level:3},{value:"Corda Driver",id:"corda-driver",level:3},{value:"Building Corda Driver",id:"building-corda-driver",level:4},{value:"Configuring",id:"configuring-1",level:4},{value:"Running",id:"running-1",level:4},{value:"Tear Down the Setup",id:"tear-down-the-setup",level:2}],g={toc:p},d="wrapper";function c(e){let{components:a,...n}=e;return(0,r.yg)(d,(0,t.A)({},g,n,{components:a,mdxType:"MDXLayout"}),(0,r.yg)("p",null,"In this document, we detail the steps using which you can bring up networks using the default configuration settings and by fetching pre-built Weaver interoperation modules, SDK libraries, and relay drivers from GitHub Package repositories. To customize these settings (e.g., hostnames, ports), refer to the ",(0,r.yg)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/advanced-configuration"},"Advanced Configuration page"),"."),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:"left"},"The default configuration is for a development setup, therefore all components are run on ",(0,r.yg)("inlineCode",{parentName:"td"},"localhost"),", many within Docker containers.")))),(0,r.yg)("p",null,"Follow the instructions below to build and run components followed by interoperation flows. These instructions have been tested on Ubuntu Linux (bash shell) and Mac OS. In general, they should work on any system and shell as long as the various dependencies have been installed and configured."),(0,r.yg)("h2",{id:"prerequisites"},"Prerequisites"),(0,r.yg)("h3",{id:"software"},"Software"),(0,r.yg)("p",null,"Before starting, make sure you have the following software installed on your host machine:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Curl: ",(0,r.yg)("em",{parentName:"li"},"install using package manager, like ",(0,r.yg)("inlineCode",{parentName:"em"},"apt")," on Debian/Ubuntu Linux")),(0,r.yg)("li",{parentName:"ul"},"Git: ",(0,r.yg)("a",{parentName:"li",href:"https://git-scm.com/book/en/v2/Getting-Started-Installing-Git"},"sample instructions")),(0,r.yg)("li",{parentName:"ul"},"Docker: ",(0,r.yg)("a",{parentName:"li",href:"https://docs.docker.com/engine/install/"},"sample instructions")," (Latest version)"),(0,r.yg)("li",{parentName:"ul"},"Docker-Compose: ",(0,r.yg)("a",{parentName:"li",href:"https://docs.docker.com/compose/install/"},"sample instructions")," (Version 1.28.2 or higher, but lower than version V2)"),(0,r.yg)("li",{parentName:"ul"},"Golang: ",(0,r.yg)("a",{parentName:"li",href:"https://golang.org/dl/"},"sample instructions")," (Version 1.16 or higher)"),(0,r.yg)("li",{parentName:"ul"},"Java (JDK and JRE): ",(0,r.yg)("a",{parentName:"li",href:"https://openjdk.java.net/install/"},"sample instructions")," (Version 8)"),(0,r.yg)("li",{parentName:"ul"},"Node.js and NPM: ",(0,r.yg)("a",{parentName:"li",href:"https://nodejs.org/en/download/package-manager/"},"sample instructions")," (Version 16 Supported)"),(0,r.yg)("li",{parentName:"ul"},"Yarn: ",(0,r.yg)("a",{parentName:"li",href:"https://classic.yarnpkg.com/en/docs/install/"},"sample instructions")),(0,r.yg)("li",{parentName:"ul"},"Rust: ",(0,r.yg)("a",{parentName:"li",href:"https://www.rust-lang.org/tools/install"},"sample instructions"),(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},"To avoid errors during Weaver Relay compilation, update certain packages (on which the Weaver Relay is dependent) to their latest versions as follows:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre"},"cargo update -p nom\ncargo update -p lexical-core\n")))))),(0,r.yg)("h3",{id:"credentials"},"Credentials"),(0,r.yg)("p",null,"Make sure you have an SSH or GPG key registered in ",(0,r.yg)("a",{parentName:"p",href:"https://github.com"},"https://github.com")," to allow seamless cloning of repositories (at present, various setup scripts clone repositories using the ",(0,r.yg)("inlineCode",{parentName:"p"},"https://")," prefix but this may change to ",(0,r.yg)("inlineCode",{parentName:"p"},"git@")," in the future)."),(0,r.yg)("p",null,"Create a personal access token with ",(0,r.yg)("inlineCode",{parentName:"p"},"read:packages")," access in GitHub in order to use modules published in GitHub packages. Refer ",(0,r.yg)("a",{parentName:"p",href:"https://docs.github.com/en/github/authenticating-to-github/keeping-your-account-and-data-secure/creating-a-personal-access-token"},"Creating a Personal Access Token")," for help."),(0,r.yg)("h2",{id:"getting-the-code-and-documentation"},"Getting the Code and Documentation"),(0,r.yg)("p",null,"Clone the ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability"},"weaver-dlt-interoperability")," repository. The code to get a basic test network up and running and test data-sharing interoperation flows lies in the subfolder ",(0,r.yg)("inlineCode",{parentName:"p"},"tests/network-setups"),", which should be your starting point, though the setups will rely on other parts of the repository, as you will find out in the instructions given on this page."),(0,r.yg)("h2",{id:"securing-components"},"Securing Components"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:"left"},"The relays and drivers corresponding to the different test networks you will encounter below can be run with or without TLS enabled. But the default files used in the demonstrations assume that either all relays and drivers are TLS-enabled or none are. Therefore, you should determine at the outset whether or not you wish to run the entire set of components in TLS-enabled mode, and select appropriate commands in the provided instructions.")))),(0,r.yg)("h2",{id:"hyperledger-fabric-components"},"Hyperledger Fabric Components"),(0,r.yg)("p",null,"Using the sequence of instructions below, you can start two separate Fabric networks, each with a single channel and application contract (chaincode). You can also start an interoperation contract, a relay, and a ",(0,r.yg)("em",{parentName:"p"},"driver")," acting on behalf of each network. You can build a Fabric CLI tool with which you can initialize both networks' ledgers with access control policies, foreign networks' security groups (i.e., membership providers' certificate chains), and some sample key-value pairs that can be shared during subsequent interoperation flows."),(0,r.yg)("h3",{id:"fabric-network"},"Fabric Network"),(0,r.yg)("p",null,"The code for this lies in the ",(0,r.yg)("inlineCode",{parentName:"p"},"tests/network-setups")," folder."),(0,r.yg)("p",null,"This folder contains code to create and launch networks ",(0,r.yg)("inlineCode",{parentName:"p"},"network1")," and ",(0,r.yg)("inlineCode",{parentName:"p"},"network2")," of identical specifications:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Network: 1 peer, 1 peer CA, 1 ordering service node, 1 ordering service CA"),(0,r.yg)("li",{parentName:"ul"},"Single channel named ",(0,r.yg)("inlineCode",{parentName:"li"},"mychannel")),(0,r.yg)("li",{parentName:"ul"},"One of the following contracts deployed on ",(0,r.yg)("inlineCode",{parentName:"li"},"mychannel"),", the choice depending on the ",(0,r.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/interoperability-modes"},"interoperability mode")," you wish to test:",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"simplestate")," (",(0,r.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/data-sharing"},"Data Sharing"),"): supports simple transactions (",(0,r.yg)("inlineCode",{parentName:"li"},"Create"),", ",(0,r.yg)("inlineCode",{parentName:"li"},"Read"),", ",(0,r.yg)("inlineCode",{parentName:"li"},"Update"),", ",(0,r.yg)("inlineCode",{parentName:"li"},"Delete"),") involving storage and lookup of <key, value> pairs."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"simplestatewithacl")," (",(0,r.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/data-sharing"},"Data Sharing"),"): identical to ",(0,r.yg)("inlineCode",{parentName:"li"},"simplestate")," but with extra security features to ensure that the Weaver infrastructure cannot be bypassed by a malicious client of the network."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"simpleasset")," (",(0,r.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview"},"Asset Exchange"),"): supports creation, modification, transfer, and deletion, as well as locking, unlocking, and claiming, of simple bonds and tokens (examples of non-fungible and fungible assets respectively)."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"simpleassetandinterop")," (",(0,r.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview"},"Asset Exchange"),"): identical to ",(0,r.yg)("inlineCode",{parentName:"li"},"simpleasset")," but where the locking, unlocking, and claiming logic is imported as a library in the chaincode rather than available in the common Fabric Interoperation Chaincode (a Weaver component)."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"simpleassettransfer")," (",(0,r.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview"},"Asset Exchange")," or ",(0,r.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-transfer"},"Asset Transfer"),"): augmentation of ",(0,r.yg)("inlineCode",{parentName:"li"},"simpleasset")," with asset pledging, claiming, and reclaiming features for cross-network transfers.")))),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:"left"},"For new users, we recommend testing the Data Sharing feature first with the ",(0,r.yg)("inlineCode",{parentName:"td"},"simplestate")," contract. To test the other modes, you can simply ",(0,r.yg)("a",{parentName:"td",href:"#tear-down-the-setup"},"tear down")," the Fabric networks and restart them with the appropriate chaincodes installed.")))),(0,r.yg)("p",null,"Follow the instructions below to build and launch the networks:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"tests/network-setups/fabric/dev")," folder."),(0,r.yg)("li",{parentName:"ul"},"To spin up both network1 and network2 with the interoperation chaincode and the default ",(0,r.yg)("inlineCode",{parentName:"li"},"simplestate")," chaincode installed, run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make start-interop\n"))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("em",{parentName:"li"},"To launch the networks with a different application chaincode from the above list, run"),":",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make start-interop CHAINCODE_NAME=<chaincode-name>\n"))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("em",{parentName:"li"},"To launch the networks with 2 organizations, each with a peer (this will enable more variation and experimentation, which you can attempt after testing interoperation protocols across basic network configurations), run"),":",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},'make start-interop-local PROFILE="2-nodes"\n')))),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:"left"},"If you do not wish to test Fabric-Fabric interoperation, you can choose to launch only one of the two networks along with its interoperation chaincode. For ",(0,r.yg)("inlineCode",{parentName:"td"},"network1"),", run ",(0,r.yg)("inlineCode",{parentName:"td"},"make start-interop-network1"),", and for ",(0,r.yg)("inlineCode",{parentName:"td"},"network2"),", run ",(0,r.yg)("inlineCode",{parentName:"td"},"make start-interop-network2"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:"left"},"If you wish to enable end-to-end confidentiality by default in the interoperation modules that are deployed during network launch, set the environment variable ",(0,r.yg)("inlineCode",{parentName:"td"},"E2E_CONFIDENTIALITY")," to ",(0,r.yg)("inlineCode",{parentName:"td"},"true")," in the command line as follows: ",(0,r.yg)("inlineCode",{parentName:"td"},"E2E_CONFIDENTIALITY=true make start-interop"))))),(0,r.yg)("p",null,"For more information, refer to the associated ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/tests/network-setups/fabric/dev"},"README"),"."),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},"Troubleshooting Tips"),":"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"If you see any errors during the launches, re-check the prerequisites (software installations and credentials). Ensure your network connection is working. As a safe bet, you can retry after cleanup: kill and remove all Docker containers and associated volumes.")),(0,r.yg)("h3",{id:"fabric-client-fabric-cli"},"Fabric Client (fabric-cli)"),(0,r.yg)("p",null,"The CLI is used to interact with a Fabric network, configure it and run chaincode transactions to record data on the channel ledger or query data. It is also used to interact with remote networks through the relay to trigger an interoperation flow for data request and acceptance."),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"fabric-cli")," Node.js source code is located in the ",(0,r.yg)("inlineCode",{parentName:"p"},"samples/fabric/fabric-cli")," folder and the Golang source code in the ",(0,r.yg)("inlineCode",{parentName:"p"},"samples/fabric/go-cli")," folder."),(0,r.yg)("h4",{id:"prerequisites-1"},"Prerequisites"),(0,r.yg)("p",null,"If you are using a Linux system, make sure that lib64 is installed."),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:"left"},"For the Node.js version of the ",(0,r.yg)("inlineCode",{parentName:"td"},"fabric-cli"),", the setup and running instructions below were tested with all Node.js versions from v11.14.0 to v14.17.3.")))),(0,r.yg)("h4",{id:"installation"},"Installation"),(0,r.yg)("p",null,"You can install ",(0,r.yg)("inlineCode",{parentName:"p"},"fabric-cli")," as follows (for both the Node.js and Golang versions):"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"samples/fabric/fabric-cli")," folder (for the Node.js version) or the ",(0,r.yg)("inlineCode",{parentName:"li"},"samples/fabric/go-cli")," folder (for the Golang version)."),(0,r.yg)("li",{parentName:"ul"},"Create ",(0,r.yg)("inlineCode",{parentName:"li"},".npmrc")," from template ",(0,r.yg)("inlineCode",{parentName:"li"},".npmrc.template"),", by replacing ",(0,r.yg)("inlineCode",{parentName:"li"},"<personal-access-token>")," with yours created ",(0,r.yg)("a",{parentName:"li",href:"#package-access-token"},"above"),".."),(0,r.yg)("li",{parentName:"ul"},"Run the following to install dependencies (for the Node.js version) or the executable (for the Golang version):",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make build\n"))),(0,r.yg)("li",{parentName:"ul"},"Use the ",(0,r.yg)("inlineCode",{parentName:"li"},"fabric-cli")," executable in the ",(0,r.yg)("inlineCode",{parentName:"li"},"bin")," folder for ",(0,r.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/ledger-initialization"},"subsequent actions"),".")),(0,r.yg)("h3",{id:"fabric-relay"},"Fabric Relay"),(0,r.yg)("p",null,"The relay is a module acting on behalf of a network, enabling interoperation flows with other networks by communicating with their relays.\nThe code for this lies in the ",(0,r.yg)("inlineCode",{parentName:"p"},"core/relay")," folder."),(0,r.yg)("h4",{id:"building"},"Building"),(0,r.yg)("p",null,(0,r.yg)("em",{parentName:"p"},"Prerequisite"),": make sure Rust is already installed and that the ",(0,r.yg)("inlineCode",{parentName:"p"},"cargo")," executable is in your system path (after installation of Rust, this should be available in ",(0,r.yg)("inlineCode",{parentName:"p"},"$HOME/.cargo/bin"),"); you can also ensure this by running ",(0,r.yg)("inlineCode",{parentName:"p"},'source "$HOME/.cargo/env"'),"."),(0,r.yg)("p",null,"Build the generic (i.e., common to all DLTs) relay module as follows:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"core/relay")," folder."),(0,r.yg)("li",{parentName:"ul"},"Run the following:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make\n"))),(0,r.yg)("li",{parentName:"ul"},"If you observe errors during the above compilation, update certain packages (on which the Weaver Relay is dependent) to their latest versions and recompile as follows:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make update-pkgs\nmake\n")))),(0,r.yg)("h4",{id:"deployment"},"Deployment"),(0,r.yg)("p",null,"An instance or a relay can be run using a suitable configuration file. Samples are available in the ",(0,r.yg)("inlineCode",{parentName:"p"},"core/relay/config")," folder."),(0,r.yg)("p",null,"Run a relay for ",(0,r.yg)("inlineCode",{parentName:"p"},"network1")," as follows:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"core/relay")," folder."),(0,r.yg)("li",{parentName:"ul"},"To launch the server without TLS, leave the configuration file ",(0,r.yg)("inlineCode",{parentName:"li"},"config/Fabric_Relay.toml")," in its default state. Otherwise, edit it to set TLS flags for this relay and the other relays and drivers it will connect to in this demonstration as follows:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-toml"},'.\n.\ncert_path="credentials/fabric_cert.pem"\nkey_path="credentials/fabric_key"\ntls=true\n.\n.\n[relays]\n[relays.Corda_Relay]\nhostname="localhost"\nport="9081"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n[relays.Corda_Relay2]\nhostname="localhost"\nport="9082"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n[relays.Fabric_Relay2]\nhostname="localhost"\nport="9083"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n.\n.\n[drivers]\n[drivers.Fabric]\nhostname="localhost"\nport="9090"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n.\n.\n'))),(0,r.yg)("li",{parentName:"ul"},"To launch the server, simply run the following:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"RELAY_CONFIG=config/Fabric_Relay.toml cargo run --bin server\n")))),(0,r.yg)("p",null,"Run a relay for ",(0,r.yg)("inlineCode",{parentName:"p"},"network2")," as follows (",(0,r.yg)("em",{parentName:"p"},"do this only if you have launched both Fabric networks ",(0,r.yg)("inlineCode",{parentName:"em"},"network1")," and ",(0,r.yg)("inlineCode",{parentName:"em"},"network2")," and wish to test interoperation between them"),")"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"core/relay")," folder."),(0,r.yg)("li",{parentName:"ul"},"To launch the server without TLS, leave the configuration file ",(0,r.yg)("inlineCode",{parentName:"li"},"config/Fabric_Relay2.toml")," in its default state. Otherwise, edit it to set TLS flags for this relay and the other relays and drivers it will connect to in this demonstration as follows:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-toml"},'.\n.\ncert_path="credentials/fabric_cert.pem"\nkey_path="credentials/fabric_key"\ntls=true\n.\n.\n[relays]\n[relays.Corda_Relay]\nhostname="localhost"\nport="9081"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n[relays.Corda_Relay2]\nhostname="localhost"\nport="9082"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n[relays.Fabric_Relay]\nhostname="localhost"\nport="9080"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n.\n.\n[drivers]\n[drivers.Fabric]\nhostname="localhost"\nport="9095"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n.\n.\n'))),(0,r.yg)("li",{parentName:"ul"},"To launch the server, simply run the following:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"RELAY_CONFIG=config/Fabric_Relay2.toml cargo run --bin server\n")))),(0,r.yg)("p",null,"For more information, see the ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/core/relay"},"relay README"),"."),(0,r.yg)("h3",{id:"fabric-driver"},"Fabric Driver"),(0,r.yg)("p",null,"A driver is a DLT-specific plugin invoked by the relay while conveying external data queries to the local peer network and collecting a response with proofs. The Fabric driver is built as a Fabric client application on the ",(0,r.yg)("inlineCode",{parentName:"p"},"fabric-network")," NPM package.\nThe code for this lies in the ",(0,r.yg)("inlineCode",{parentName:"p"},"core/drivers/fabric-driver")," folder."),(0,r.yg)("h4",{id:"configuring"},"Configuring"),(0,r.yg)("p",null,"In the ",(0,r.yg)("inlineCode",{parentName:"p"},"core/drivers/fabric-driver")," folder, copy ",(0,r.yg)("inlineCode",{parentName:"p"},".env.template")," to ",(0,r.yg)("inlineCode",{parentName:"p"},".env")," and update ",(0,r.yg)("inlineCode",{parentName:"p"},"CONNECTION_PROFILE")," to point to the connection profile of the Fabric network (e.g. ",(0,r.yg)("inlineCode",{parentName:"p"},"<PATH-TO-WEAVER>/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json"),")"),(0,r.yg)("p",null,"Configure ",(0,r.yg)("inlineCode",{parentName:"p"},"fabric-driver")," for ",(0,r.yg)("inlineCode",{parentName:"p"},"network1")," as follows:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"core/drivers/fabric-driver")," folder."),(0,r.yg)("li",{parentName:"ul"},"Create a ",(0,r.yg)("inlineCode",{parentName:"li"},".env")," file by copying ",(0,r.yg)("inlineCode",{parentName:"li"},".env.template")," and setting suitable parameter values:",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},"The ",(0,r.yg)("inlineCode",{parentName:"li"},"CONNECTION_PROFILE")," should point to the absolute path of the connection profile for ",(0,r.yg)("inlineCode",{parentName:"li"},"network1"),".",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},"For this exercise, specify the path ",(0,r.yg)("inlineCode",{parentName:"li"},"<PATH-TO-WEAVER>/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json")," (",(0,r.yg)("em",{parentName:"li"},"you must specify the full absolute path here"),")."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"<PATH-TO-WEAVER>")," here is the absolute path of the ",(0,r.yg)("inlineCode",{parentName:"li"},"weaver-dlt-interoperability")," clone folder."))),(0,r.yg)("li",{parentName:"ul"},"If you wish to start the driver without TLS, set the following parameter values:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre"},"RELAY_TLS=false\nRELAY_TLSCA_CERT_PATH=\nDRIVER_TLS=false\nDRIVER_TLS_CERT_PATH=\nDRIVER_TLS_KEY_PATH=\n")),"Otherwise, if you wish to start the driver with TLS enabled, set the following parameter values (replace ",(0,r.yg)("inlineCode",{parentName:"li"},"<PATH-TO-WEAVER>")," with the absolute path of the ",(0,r.yg)("inlineCode",{parentName:"li"},"weaver-dlt-interoperability")," clone folder):",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre"},"RELAY_TLS=true\nRELAY_TLSCA_CERT_PATH=<PATH-TO-WEAVER>/core/relay/credentials/fabric_ca_cert.pem\nDRIVER_TLS=true\nDRIVER_TLS_CERT_PATH=<PATH-TO-WEAVER>/core/relay/credentials/fabric_cert.pem\nDRIVER_TLS_KEY_PATH=<PATH-TO-WEAVER>/core/relay/credentials/fabric_key\n"))),(0,r.yg)("li",{parentName:"ul"},"Leave the default values unchanged for the other parameters. The relay and driver endpoints as well as the network name are already specified.")))),(0,r.yg)("h4",{id:"building-1"},"Building"),(0,r.yg)("p",null,"Build the Fabric driver module as follows:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"core/drivers/fabric-driver")," folder."),(0,r.yg)("li",{parentName:"ul"},"Create ",(0,r.yg)("inlineCode",{parentName:"li"},".npmrc")," from template ",(0,r.yg)("inlineCode",{parentName:"li"},".npmrc.template"),", by replacing ",(0,r.yg)("inlineCode",{parentName:"li"},"<personal-access-token>")," with yours created above."),(0,r.yg)("li",{parentName:"ul"},"Run the following:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make build\n")))),(0,r.yg)("h4",{id:"running"},"Running"),(0,r.yg)("p",null,"Run a Fabric driver for ",(0,r.yg)("inlineCode",{parentName:"p"},"network1")," as follows:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"core/drivers/fabric-driver")," folder."),(0,r.yg)("li",{parentName:"ul"},"Run the following:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"npm run dev\n")))),(0,r.yg)("p",null,"Run a Fabric driver for ",(0,r.yg)("inlineCode",{parentName:"p"},"network2")," as follows (",(0,r.yg)("em",{parentName:"p"},"do this only if you wish to test interoperation between the two Fabric networks ",(0,r.yg)("inlineCode",{parentName:"em"},"network1")," and ",(0,r.yg)("inlineCode",{parentName:"em"},"network2")),")"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"core/drivers/fabric-driver")," folder."),(0,r.yg)("li",{parentName:"ul"},"Run the following:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"CONNECTION_PROFILE=<PATH-TO-WEAVER>/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/connection-org1.json NETWORK_NAME=network2 RELAY_ENDPOINT=localhost:9083 DRIVER_ENDPOINT=localhost:9095 npm run dev\n")))),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:"left"},"The variables we specified earlier in the ",(0,r.yg)("inlineCode",{parentName:"td"},".env")," for ",(0,r.yg)("inlineCode",{parentName:"td"},"network1")," are now passed in the command line. Alternatively, you can make a copy of the ",(0,r.yg)("inlineCode",{parentName:"td"},"fabric-driver")," folder with a different name and create a separate ",(0,r.yg)("inlineCode",{parentName:"td"},".env")," file within it that contains links to the connection profile, relay, and driver for ",(0,r.yg)("inlineCode",{parentName:"td"},"network2"),".")))),(0,r.yg)("h3",{id:"fabric-iin-agent"},"Fabric IIN Agent"),(0,r.yg)("p",null,"IIN Agent is a client of a member of a DLT network or security domain with special permissions to update security domain identities and configurations on the ledger via the network's interoperation module. The code for this lies in the ",(0,r.yg)("inlineCode",{parentName:"p"},"core/identity-management/iin-agent")," folder. Navigate to the ",(0,r.yg)("inlineCode",{parentName:"p"},"core/identity-management/iin-agent")," folder."),(0,r.yg)("h4",{id:"building-2"},"Building"),(0,r.yg)("p",null,"Build the IIN Agent as follows:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"core/drivers/fabric-driver")," folder."),(0,r.yg)("li",{parentName:"ul"},"Create ",(0,r.yg)("inlineCode",{parentName:"li"},".npmrc")," from template ",(0,r.yg)("inlineCode",{parentName:"li"},".npmrc.template"),", by replacing ",(0,r.yg)("inlineCode",{parentName:"li"},"<personal-access-token>")," with yours created above."),(0,r.yg)("li",{parentName:"ul"},"Run the following:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make build\n")))),(0,r.yg)("h4",{id:"configuration"},"Configuration"),(0,r.yg)("p",null,"Ledger config file specifies ledger specific IIN Agent details such as identity and which network and organization to connect to."),(0,r.yg)("ol",null,(0,r.yg)("li",{parentName:"ol"},(0,r.yg)("p",{parentName:"li"},"To create config file for ",(0,r.yg)("inlineCode",{parentName:"p"},"Org1MSP"),"'s Fabric IIN Agent of ",(0,r.yg)("inlineCode",{parentName:"p"},"network1"),", follow the steps:"),(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},"Create copy of template config file for Fabric IIN Agent: ",(0,r.yg)("inlineCode",{parentName:"li"},"src/fabric-ledger/config.json.template"),", say to location ",(0,r.yg)("inlineCode",{parentName:"li"},"src/fabric-ledger/config-n1-org1.json"),"."),(0,r.yg)("li",{parentName:"ul"},"Replace ",(0,r.yg)("inlineCode",{parentName:"li"},"<path-to-connection-profile>")," with ",(0,r.yg)("inlineCode",{parentName:"li"},"<PATH-TO-WEAVER>/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json"),", where replace ",(0,r.yg)("inlineCode",{parentName:"li"},"<PATH-TO-WEAVER>")," with the absolute path location of your clone of Weaver."),(0,r.yg)("li",{parentName:"ul"},"Set ",(0,r.yg)("inlineCode",{parentName:"li"},"mspId")," as ",(0,r.yg)("inlineCode",{parentName:"li"},"Org1MSP"),"."),(0,r.yg)("li",{parentName:"ul"},"Set ",(0,r.yg)("inlineCode",{parentName:"li"},"agent.affiliation")," as ",(0,r.yg)("inlineCode",{parentName:"li"},"org1.department1"),"."))),(0,r.yg)("li",{parentName:"ol"},(0,r.yg)("p",{parentName:"li"},"To create config file for ",(0,r.yg)("inlineCode",{parentName:"p"},"Org2MSP"),"'s Fabric IIN Agent of ",(0,r.yg)("inlineCode",{parentName:"p"},"network1"),", repeat ",(0,r.yg)("inlineCode",{parentName:"p"},"Step 1")," with different name for config file, say ",(0,r.yg)("inlineCode",{parentName:"p"},"src/fabric-ledger/config-n1-org2.json"),", and replace ",(0,r.yg)("inlineCode",{parentName:"p"},"org1")," with ",(0,r.yg)("inlineCode",{parentName:"p"},"org2")," and ",(0,r.yg)("inlineCode",{parentName:"p"},"Org1MSP")," with ",(0,r.yg)("inlineCode",{parentName:"p"},"Org2MSP"),".")),(0,r.yg)("li",{parentName:"ol"},(0,r.yg)("p",{parentName:"li"},"To create config file for ",(0,r.yg)("inlineCode",{parentName:"p"},"Org1MSP"),"'s Fabric IIN Agent of ",(0,r.yg)("inlineCode",{parentName:"p"},"network2"),", repeat ",(0,r.yg)("inlineCode",{parentName:"p"},"Step 1")," with different name for config file, say ",(0,r.yg)("inlineCode",{parentName:"p"},"src/fabric-ledger/config-n2-org1.json"),", and replace ",(0,r.yg)("inlineCode",{parentName:"p"},"network1")," with ",(0,r.yg)("inlineCode",{parentName:"p"},"network2"),".")),(0,r.yg)("li",{parentName:"ol"},(0,r.yg)("p",{parentName:"li"},"To create config file for ",(0,r.yg)("inlineCode",{parentName:"p"},"Org2MSP"),"'s Fabric IIN Agent of ",(0,r.yg)("inlineCode",{parentName:"p"},"network2"),", repeat ",(0,r.yg)("inlineCode",{parentName:"p"},"Step 1")," with different name for config file, say ",(0,r.yg)("inlineCode",{parentName:"p"},"src/fabric-ledger/config-n2-org2.json"),", and replace ",(0,r.yg)("inlineCode",{parentName:"p"},"network1")," with ",(0,r.yg)("inlineCode",{parentName:"p"},"network2"),", ",(0,r.yg)("inlineCode",{parentName:"p"},"org1")," with ",(0,r.yg)("inlineCode",{parentName:"p"},"org2")," and ",(0,r.yg)("inlineCode",{parentName:"p"},"Org1MSP")," with ",(0,r.yg)("inlineCode",{parentName:"p"},"Org2MSP"),"."))),(0,r.yg)("h4",{id:"security-domain-configuration"},"Security Domain Configuration"),(0,r.yg)("p",null,"Security Domain config file specifies the scope of security domain, which can be a channel in Fabric networks or list of nodes. File ",(0,r.yg)("inlineCode",{parentName:"p"},"docker-testnet/configs/security-domain-config.json")," can be used for Weaver testnets."),(0,r.yg)("h4",{id:"dns-configuration"},"DNS Configuration"),(0,r.yg)("p",null,"To allow an IIN Agent's to be able to discover other IIN Agents, a config file for DNS is required. Create one ",(0,r.yg)("inlineCode",{parentName:"p"},"dnsconfig.json")," by creating a copy of template ",(0,r.yg)("inlineCode",{parentName:"p"},"dnsconfig.json.template"),", and replace the values with:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"If Fabric networks are started with 1 org, and IIN Agent are to be started without TLS, use following values:")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-json"},'{\n "network1": {\n "Org1MSP": {\n "endpoint": "localhost:9500",\n "tls": false,\n "tlsCACertPath": ""\n }\n },\n "network2": {\n "Org1MSP": {\n "endpoint": "localhost:9501",\n "tls": false,\n "tlsCACertPath": ""\n }\n }\n}\n')),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"If Fabric networks are started with 1 org, and IIN Agent are to be started with TLS, use following values:")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-json"},'{\n "network1": {\n "Org1MSP": {\n "endpoint": "localhost:9500",\n "tls": true,\n "tlsCACertPath": "../../relay/credentials/fabric_ca_cert.pem"\n }\n },\n "network2": {\n "Org1MSP": {\n "endpoint": "localhost:9501",\n "tls": true,\n "tlsCACertPath": "../../relay/credentials/fabric_ca_cert.pem"\n }\n }\n}\n')),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"If Fabric networks are started with 2 orgs, and IIN Agent are to be started without TLS, use following values:")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-json"},'{\n "network1": {\n "Org1MSP": {\n "endpoint": "localhost:9500",\n "tls": false,\n "tlsCACertPath": ""\n },\n "Org2MSP": {\n "endpoint": "localhost:9510",\n "tls": false,\n "tlsCACertPath": ""\n }\n },\n "network2": {\n "Org1MSP": {\n "endpoint": "localhost:9501",\n "tls": false,\n "tlsCACertPath": ""\n },\n "Org2MSP": {\n "endpoint": "localhost:9511",\n "tls": false,\n "tlsCACertPath": ""\n }\n }\n}\n')),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"If Fabric networks are started with 2 orgs, and IIN Agent are to be started with TLS, use following values:")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-json"},'{\n "network1": {\n "Org1MSP": {\n "endpoint": "localhost:9500",\n "tls": true,\n "tlsCACertPath": "../../relay/credentials/fabric_ca_cert.pem"\n },\n "Org2MSP": {\n "endpoint": "localhost:9510",\n "tls": true,\n "tlsCACertPath": "../../relay/credentials/fabric_ca_cert.pem"\n }\n },\n "network2": {\n "Org1MSP": {\n "endpoint": "localhost:9501",\n "tls": true,\n "tlsCACertPath": "../../relay/credentials/fabric_ca_cert.pem"\n },\n "Org2MSP": {\n "endpoint": "localhost:9511",\n "tls": true,\n "tlsCACertPath": "../../relay/credentials/fabric_ca_cert.pem"\n }\n }\n}\n')),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:"left"},"The variables we specified earlier in the ",(0,r.yg)("inlineCode",{parentName:"td"},".env")," for ",(0,r.yg)("inlineCode",{parentName:"td"},"network1")," are now passed in the command line. Alternatively, you can make a copy of the ",(0,r.yg)("inlineCode",{parentName:"td"},"fabric-driver")," folder with a different name and create a separate ",(0,r.yg)("inlineCode",{parentName:"td"},".env")," file within it that contains links to the connection profile, relay, and driver for ",(0,r.yg)("inlineCode",{parentName:"td"},"network2"),".")))),(0,r.yg)("h4",{id:"environment-variables"},"Environment Variables"),(0,r.yg)("p",null,"To configure environment variables for ",(0,r.yg)("inlineCode",{parentName:"p"},"Org1MSP"),"'s Fabric IIN Agent of ",(0,r.yg)("inlineCode",{parentName:"p"},"network1"),", follow the steps:"),(0,r.yg)("ol",null,(0,r.yg)("li",{parentName:"ol"},"Create a copy of ",(0,r.yg)("inlineCode",{parentName:"li"},".env.template")," as ",(0,r.yg)("inlineCode",{parentName:"li"},".env"),", and update following values based on previous configuration file paths:")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre"},"IIN_AGENT_ENDPOINT=localhost:9500\nMEMBER_ID=Org1MSP\nSECURITY_DOMAIN=network1\nDLT_TYPE=fabric\nCONFIG_PATH=./src/fabric-ledger/config-n1-org1.json\nDNS_CONFIG_PATH=./dnsconfig.json\nSECURITY_DOMAIN_CONFIG_PATH=./docker-testnet/configs/security-domain-config.json\nWEAVER_CONTRACT_ID=interop\nAUTO_SYNC=true\n")),(0,r.yg)("ol",{start:2},(0,r.yg)("li",{parentName:"ol"},"If IIN Agent has to be started with TLS enabled, also update following values:")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre"},"IIN_AGENT_TLS=false\nIIN_AGENT_TLS_CERT_PATH=../../relay/credentials/fabric_cert.pem\nIIN_AGENT_TLS_KEY_PATH=../../relay/credentials/fabric_key\n")),(0,r.yg)("h4",{id:"deployment-1"},"Deployment"),(0,r.yg)("p",null,"Use the following steps to run Fabric IIN Agents in host machine:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"To start IIN Agent for ",(0,r.yg)("inlineCode",{parentName:"li"},"Org1MSP")," of ",(0,r.yg)("inlineCode",{parentName:"li"},"network1"),", run:")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"npm run dev\n")),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"To start IIN Agent for ",(0,r.yg)("inlineCode",{parentName:"li"},"Org2MSP")," of ",(0,r.yg)("inlineCode",{parentName:"li"},"network1")," (",(0,r.yg)("em",{parentName:"li"},"only required if Fabric network was started with 2 orgs"),"), run:")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"IIN_AGENT_ENDPOINT=localhost:9510 MEMBER_ID=Org2MSP CONFIG_PATH=./src/fabric-ledger/config-n1-org2.json npm run dev\n")),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"To start IIN Agent for ",(0,r.yg)("inlineCode",{parentName:"li"},"Org1MSP")," of ",(0,r.yg)("inlineCode",{parentName:"li"},"network2"),", run:")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"IIN_AGENT_ENDPOINT=localhost:9501 SECURITY_DOMAIN=network2 CONFIG_PATH=./src/fabric-ledger/config-n2-org1.json npm run dev\n")),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"To start IIN Agent for ",(0,r.yg)("inlineCode",{parentName:"li"},"Org2MSP")," of ",(0,r.yg)("inlineCode",{parentName:"li"},"network2")," (",(0,r.yg)("em",{parentName:"li"},"only required if Fabric network was started with 2 orgs"),"), run:")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"IIN_AGENT_ENDPOINT=localhost:9511 MEMBER_ID=Org2MSP SECURITY_DOMAIN=network2 CONFIG_PATH=./src/fabric-ledger/config-n2-org2.json npm run dev\n")),(0,r.yg)("h2",{id:"corda-components"},"Corda Components"),(0,r.yg)("p",null,"Using the sequence of instructions below, you can start a Corda network and run an application CorDapp on it. You can also run an interoperation CorDapp, a relay and a ",(0,r.yg)("em",{parentName:"p"},"driver")," acting on behalf of the network. You can initialize the network's vault with access control policies, foreign networks' security groups (i.e., membership providers' certificate chains), and some sample state values that can be shared during subsequent interoperation flows."),(0,r.yg)("h3",{id:"corda-network"},"Corda Network"),(0,r.yg)("p",null,"The Corda networks' code lies in the ",(0,r.yg)("inlineCode",{parentName:"p"},"tests/network-setups/corda")," folder. You can launch two separate Corda networks, namely ",(0,r.yg)("inlineCode",{parentName:"p"},"Corda_Network")," and ",(0,r.yg)("inlineCode",{parentName:"p"},"Corda_Network2"),". Each network runs the ",(0,r.yg)("inlineCode",{parentName:"p"},"samples/corda/corda-simple-application")," CorDapp by default, which maintains a state named ",(0,r.yg)("inlineCode",{parentName:"p"},"SimpleState")," containing a set of key-value pairs (of strings)."),(0,r.yg)("p",null,"The following steps will, in addition to launching the network, build the CorDapp and a Corda client in ",(0,r.yg)("inlineCode",{parentName:"p"},"samples/corda/corda-simple-application/client"),"."),(0,r.yg)("h4",{id:"running-with-interoperation-cordapp-from-github-packages"},"Running with Interoperation CorDapp from GitHub Packages"),(0,r.yg)("p",null,"Follow the instructions below to build and launch the network:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"tests/network-setups/corda")," folder."),(0,r.yg)("li",{parentName:"ul"},"Create a copy of ",(0,r.yg)("inlineCode",{parentName:"li"},"github.properties.template")," as ",(0,r.yg)("inlineCode",{parentName:"li"},"github.properties"),"."),(0,r.yg)("li",{parentName:"ul"},"Replace ",(0,r.yg)("inlineCode",{parentName:"li"},"<GITHUB email>")," with your GitHub email, and ",(0,r.yg)("inlineCode",{parentName:"li"},"<GITHUB Personal Access Token>")," with the access token created ",(0,r.yg)("a",{parentName:"li",href:"#package-access-token"},"above"),"."),(0,r.yg)("li",{parentName:"ul"},"To spin up the Corda networks with the Interoperation CorDapps:",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},"Each consisting of 1 node and a notary (for data-transfer), run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make start\n"))),(0,r.yg)("li",{parentName:"ul"},"Each consisting of 2 nodes and a notary (for asset-exchange/transfer), run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},'make start PROFILE="2-nodes"\n'))),(0,r.yg)("li",{parentName:"ul"},"Each consisting of 3 nodes and a notary (for asset-exchange/transfer), run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},'make start PROFILE="3-nodes"\n')))))),(0,r.yg)("p",null,"You should see the following message in the terminal:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre"},"Waiting for network node services to start\n")),(0,r.yg)("p",null,"The Corda nodes and notary may take a while (several minutes on memory-constrained systems) to start. If they start up successfully, you should something like the following for each network, though the number of node entries will depend on the profile you used to start the network with (replace ",(0,r.yg)("inlineCode",{parentName:"p"},"<network-name>")," with ",(0,r.yg)("inlineCode",{parentName:"p"},"Corda_Network")," or ",(0,r.yg)("inlineCode",{parentName:"p"},"Corda_Network2"),"):"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"PartyA node services started for network <network-name>\nPartyB node services started for network <network-name>\nPartyC node services started for network <network-name>\nNotary node services started for network <network-name>\n")),(0,r.yg)("h3",{id:"corda-relay"},"Corda Relay"),(0,r.yg)("p",null,"The relay was built earlier, so you just need to use a different configuration file to start a relay for the Corda network."),(0,r.yg)("p",null,"Run a relay for ",(0,r.yg)("inlineCode",{parentName:"p"},"Corda_Network")," as follows:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"p"},"core/relay")," folder.")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},"(Make sure you've already built the relay by running ",(0,r.yg)("inlineCode",{parentName:"p"},"make"),".)")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},"To launch the server without TLS, leave the configuration file ",(0,r.yg)("inlineCode",{parentName:"p"},"config/Corda_Relay.toml")," in its default state. Otherwise, edit it to set TLS flags for this relay and the other relays and drivers it will connect to in this demonstration as follows:"),(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-toml"},'.\n.\ncert_path="credentials/fabric_cert.pem"\nkey_path="credentials/fabric_key"\ntls=true\n.\n.\n[relays]\n[relays.Fabric_Relay]\nhostname="localhost"\nport="9080"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n[relays.Fabric_Relay2]\nhostname="localhost"\nport="9083"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n[relays.Corda_Relay2]\nhostname="localhost"\nport="9082"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n.\n.\n[drivers]\n[drivers.Corda]\nhostname="localhost"\nport="9099"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n.\n.\n'))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},"To launch the server, simply run the following:"),(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"RELAY_CONFIG=config/Corda_Relay.toml cargo run --bin server\n")),(0,r.yg)("p",{parentName:"li"},"If the relay starts up successfully, the following will be logged on your terminal:"),(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre"},'Relay Name: "Corda_Relay"\nRelayServer listening on [::1]:9081\n')))),(0,r.yg)("p",null,"Run a relay for ",(0,r.yg)("inlineCode",{parentName:"p"},"Corda_Network2")," as follows (",(0,r.yg)("em",{parentName:"p"},"do this only if you have launched both Corda networks ",(0,r.yg)("inlineCode",{parentName:"em"},"Corda_Network")," and ",(0,r.yg)("inlineCode",{parentName:"em"},"Corda_Network2")," and wish to test interoperation between them"),")"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"p"},"core/relay")," folder.")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},"To launch the server without TLS, leave the configuration file ",(0,r.yg)("inlineCode",{parentName:"p"},"config/Corda_Relay2.toml")," in its default state. Otherwise, edit it to set TLS flags for this relay and the other relays and drivers it will connect to in this demonstration as follows:"),(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-toml"},'.\n.\ncert_path="credentials/fabric_cert.pem"\nkey_path="credentials/fabric_key"\ntls=true\n.\n.\n[relays]\n[relays.Fabric_Relay]\nhostname="localhost"\nport="9080"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n[relays.Fabric_Relay2]\nhostname="localhost"\nport="9083"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n[relays.Corda_Relay]\nhostname="localhost"\nport="9081"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n.\n.\n[drivers]\n[drivers.Corda]\nhostname="localhost"\nport="9098"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n.\n.\n'))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},"To launch the server, simply run the following:"),(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"RELAY_CONFIG=config/Corda_Relay2.toml cargo run --bin server\n")),(0,r.yg)("p",{parentName:"li"},"If the relay starts up successfully, the following will be logged on your terminal:"),(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre"},'Relay Name: "Corda2_Relay"\nRelayServer listening on [::1]:9082\n')))),(0,r.yg)("h3",{id:"corda-driver"},"Corda Driver"),(0,r.yg)("p",null,"The code for this lies in the ",(0,r.yg)("inlineCode",{parentName:"p"},"core/drivers/corda-driver")," folder."),(0,r.yg)("h4",{id:"building-corda-driver"},"Building Corda Driver"),(0,r.yg)("p",null,"Build the Corda driver module as follows:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"core/drivers/corda-driver")," folder."),(0,r.yg)("li",{parentName:"ul"},"Create a copy of ",(0,r.yg)("inlineCode",{parentName:"li"},"github.properties.template")," as ",(0,r.yg)("inlineCode",{parentName:"li"},"github.properties"),"."),(0,r.yg)("li",{parentName:"ul"},"Replace ",(0,r.yg)("inlineCode",{parentName:"li"},"<GITHUB email>")," with your GitHub email, and ",(0,r.yg)("inlineCode",{parentName:"li"},"<GITHUB Personal Access Token>")," with the access token created ",(0,r.yg)("a",{parentName:"li",href:"#package-access-token"},"above"),"."),(0,r.yg)("li",{parentName:"ul"},"Run the following:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make build\n")))),(0,r.yg)("h4",{id:"configuring-1"},"Configuring"),(0,r.yg)("p",null,"Configure the drivers as follows (you can skip this if you wish to run the drivers without TLS):"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"core/drivers/corda-driver")," folder and create a ",(0,r.yg)("inlineCode",{parentName:"li"},".env")," file."),(0,r.yg)("li",{parentName:"ul"},"To run the drivers without TLS, set the following default values:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre"},"RELAY_TLS=false\nRELAY_TLSCA_TRUST_STORE=\nRELAY_TLSCA_TRUST_STORE_PASSWORD=\nRELAY_TLSCA_CERT_PATHS=\n"))),(0,r.yg)("li",{parentName:"ul"},"To run the drivers with TLS, set the following values (replace ",(0,r.yg)("inlineCode",{parentName:"li"},"<PATH-TO-WEAVER>")," with the absolute path of the ",(0,r.yg)("inlineCode",{parentName:"li"},"weaver-dlt-interoperability")," clone folder):",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre"},"RELAY_TLS=true\nRELAY_TLSCA_TRUST_STORE=<PATH-TO-WEAVER>/core/relay/credentials/fabric_trust_store.jks\nRELAY_TLSCA_TRUST_STORE_PASSWORD=trelay\nRELAY_TLSCA_CERT_PATHS=<PATH-TO-WEAVER>/core/relay/credentials/fabric_ca_cert.pem\n")))),(0,r.yg)("h4",{id:"running-1"},"Running"),(0,r.yg)("p",null,"Run a Corda driver as follows:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"core/drivers/corda-driver")," folder."),(0,r.yg)("li",{parentName:"ul"},"Run the following to start Corda driver for ",(0,r.yg)("inlineCode",{parentName:"li"},"Corda_Network"),":",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"./build/install/corda-driver/bin/corda-driver\n")),"If the driver starts successfully, it should log the following message on your terminal:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre"},"Corda driver gRPC server started. Listening on port 9099\n"))),(0,r.yg)("li",{parentName:"ul"},"Run the following to start Corda driver for ",(0,r.yg)("inlineCode",{parentName:"li"},"Corda_Network2"),":",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"DRIVER_PORT=9098 ./build/install/corda-driver/bin/corda-driver\n")),"If the driver starts successfully, it should log the following message on your terminal:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre"},"Corda driver gRPC server started. Listening on port 9098\n")))),(0,r.yg)("h2",{id:"tear-down-the-setup"},"Tear Down the Setup"),(0,r.yg)("p",null,"Bring down the test network's components as follows:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Simply terminate the various relays and drivers, which are running in the foreground in different terminals"),(0,r.yg)("li",{parentName:"ul"},"To bring down the running Corda network:",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"tests/network-setups/corda")," folder."),(0,r.yg)("li",{parentName:"ul"},"Run the following:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make clean\n"))))),(0,r.yg)("li",{parentName:"ul"},"To bring down all the running Fabric networks:",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"tests/network-setups/fabric/dev")," folder."),(0,r.yg)("li",{parentName:"ul"},"Run the following:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make clean\n")))))))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/8b2840ea.e4813590.js b/assets/js/8b2840ea.e4813590.js deleted file mode 100644 index 9b586e59e..000000000 --- a/assets/js/8b2840ea.e4813590.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[9935],{3905:(e,t,a)=>{a.d(t,{Zo:()=>d,kt:()=>k});var n=a(7294);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function i(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function l(e){for(var t=1;t<arguments.length;t++){var a=null!=arguments[t]?arguments[t]:{};t%2?i(Object(a),!0).forEach((function(t){r(e,t,a[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(a)):i(Object(a)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(a,t))}))}return e}function o(e,t){if(null==e)return{};var a,n,r=function(e,t){if(null==e)return{};var a,n,r={},i=Object.keys(e);for(n=0;n<i.length;n++)a=i[n],t.indexOf(a)>=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)a=i[n],t.indexOf(a)>=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var s=n.createContext({}),p=function(e){var t=n.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):l(l({},t),e)),a},d=function(e){var t=p(e.components);return n.createElement(s.Provider,{value:t},e.children)},c="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},u=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,d=o(e,["components","mdxType","originalType","parentName"]),c=p(a),u=r,k=c["".concat(s,".").concat(u)]||c[u]||m[u]||i;return a?n.createElement(k,l(l({ref:t},d),{},{components:a})):n.createElement(k,l({ref:t},d))}));function k(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=a.length,l=new Array(i);l[0]=u;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[c]="string"==typeof e?e:r,l[1]=o;for(var p=2;p<i;p++)l[p]=a[p];return n.createElement.apply(null,l)}return n.createElement.apply(null,a)}u.displayName="MDXCreateElement"},8568:(e,t,a)=>{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>m,frontMatter:()=>i,metadata:()=>o,toc:()=>p});var n=a(7462),r=(a(7294),a(3905));const i={id:"setup-packages",title:"Setup with Imported Weaver Components",pagination_prev:"external/getting-started/test-network/overview",pagination_next:"external/getting-started/test-network/ledger-initialization"},l=void 0,o={unversionedId:"external/getting-started/test-network/setup-packages",id:"external/getting-started/test-network/setup-packages",title:"Setup with Imported Weaver Components",description:"\x3c!--",source:"@site/docs/external/getting-started/test-network/setup-packages.md",sourceDirName:"external/getting-started/test-network",slug:"/external/getting-started/test-network/setup-packages",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-packages",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/getting-started/test-network/setup-packages.md",tags:[],version:"current",frontMatter:{id:"setup-packages",title:"Setup with Imported Weaver Components",pagination_prev:"external/getting-started/test-network/overview",pagination_next:"external/getting-started/test-network/ledger-initialization"},sidebar:"Documentation",previous:{title:"Component Overview",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/overview"},next:{title:"Ledger Initialization",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/ledger-initialization"}},s={},p=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Software",id:"software",level:3},{value:"Credentials",id:"credentials",level:3},{value:"Getting the Code and Documentation",id:"getting-the-code-and-documentation",level:2},{value:"Securing Components",id:"securing-components",level:2},{value:"Hyperledger Fabric Components",id:"hyperledger-fabric-components",level:2},{value:"Fabric Network",id:"fabric-network",level:3},{value:"Fabric Client (fabric-cli)",id:"fabric-client-fabric-cli",level:3},{value:"Prerequisites",id:"prerequisites-1",level:4},{value:"Installation",id:"installation",level:4},{value:"Fabric Relay",id:"fabric-relay",level:3},{value:"Building",id:"building",level:4},{value:"Deployment",id:"deployment",level:4},{value:"Fabric Driver",id:"fabric-driver",level:3},{value:"Configuring",id:"configuring",level:4},{value:"Building",id:"building-1",level:4},{value:"Running",id:"running",level:4},{value:"Fabric IIN Agent",id:"fabric-iin-agent",level:3},{value:"Building",id:"building-2",level:4},{value:"Configuration",id:"configuration",level:4},{value:"Security Domain Configuration",id:"security-domain-configuration",level:4},{value:"DNS Configuration",id:"dns-configuration",level:4},{value:"Environment Variables",id:"environment-variables",level:4},{value:"Deployment",id:"deployment-1",level:4},{value:"Corda Components",id:"corda-components",level:2},{value:"Corda Network",id:"corda-network",level:3},{value:"Running with Interoperation CorDapp from Github Packages",id:"running-with-interoperation-cordapp-from-github-packages",level:4},{value:"Corda Relay",id:"corda-relay",level:3},{value:"Corda Driver",id:"corda-driver",level:3},{value:"Building Corda Driver",id:"building-corda-driver",level:4},{value:"Configuring",id:"configuring-1",level:4},{value:"Running",id:"running-1",level:4},{value:"Tear Down the Setup",id:"tear-down-the-setup",level:2}],d={toc:p},c="wrapper";function m(e){let{components:t,...a}=e;return(0,r.kt)(c,(0,n.Z)({},d,a,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"In this document, we detail the steps using which you can bring up networks using the default configuration settings and by fetching pre-built Weaver interoperation modules, SDK libraries, and relay drivers from Github Package repositories. To customize these settings (e.g., hostnames, ports), refer to the ",(0,r.kt)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/advanced-configuration"},"Advanced Configuration page"),"."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:"left"},"The default configuration is for a development setup, therefore all components are run on ",(0,r.kt)("inlineCode",{parentName:"td"},"localhost"),", many within Docker containers.")))),(0,r.kt)("p",null,"Follow the instructions below to build and run components followed by interoperation flows. These instructions have been tested on Ubuntu Linux (bash shell) and Mac OS. In general, they should work on any system and shell as long as the various dependencies have been installed and configured."),(0,r.kt)("h2",{id:"prerequisites"},"Prerequisites"),(0,r.kt)("h3",{id:"software"},"Software"),(0,r.kt)("p",null,"Before starting, make sure you have the following software installed on your host machine:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Curl: ",(0,r.kt)("em",{parentName:"li"},"install using package manager, like ",(0,r.kt)("inlineCode",{parentName:"em"},"apt")," on Debian/Ubuntu Linux")),(0,r.kt)("li",{parentName:"ul"},"Git: ",(0,r.kt)("a",{parentName:"li",href:"https://git-scm.com/book/en/v2/Getting-Started-Installing-Git"},"sample instructions")),(0,r.kt)("li",{parentName:"ul"},"Docker: ",(0,r.kt)("a",{parentName:"li",href:"https://docs.docker.com/engine/install/"},"sample instructions")," (Latest version)"),(0,r.kt)("li",{parentName:"ul"},"Docker-Compose: ",(0,r.kt)("a",{parentName:"li",href:"https://docs.docker.com/compose/install/"},"sample instructions")," (Version 1.28.2 or higher, but lower than version V2)"),(0,r.kt)("li",{parentName:"ul"},"Golang: ",(0,r.kt)("a",{parentName:"li",href:"https://golang.org/dl/"},"sample instructions")," (Version 1.16 or higher)"),(0,r.kt)("li",{parentName:"ul"},"Java (JDK and JRE): ",(0,r.kt)("a",{parentName:"li",href:"https://openjdk.java.net/install/"},"sample instructions")," (Version 8)"),(0,r.kt)("li",{parentName:"ul"},"Node.js and NPM: ",(0,r.kt)("a",{parentName:"li",href:"https://nodejs.org/en/download/package-manager/"},"sample instructions")," (Version 16 Supported)"),(0,r.kt)("li",{parentName:"ul"},"Yarn: ",(0,r.kt)("a",{parentName:"li",href:"https://classic.yarnpkg.com/en/docs/install/"},"sample instructions")),(0,r.kt)("li",{parentName:"ul"},"Rust: ",(0,r.kt)("a",{parentName:"li",href:"https://www.rust-lang.org/tools/install"},"sample instructions"),(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"To avoid errors during Weaver Relay compilation, update certain packages (on which the Weaver Relay is dependent) to their latest versions as follows:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},"cargo update -p nom\ncargo update -p lexical-core\n")))))),(0,r.kt)("h3",{id:"credentials"},"Credentials"),(0,r.kt)("p",null,"Make sure you have an SSH or GPG key registered in ",(0,r.kt)("a",{parentName:"p",href:"https://github.com"},"https://github.com")," to allow seamless cloning of repositories (at present, various setup scripts clone repositories using the ",(0,r.kt)("inlineCode",{parentName:"p"},"https://")," prefix but this may change to ",(0,r.kt)("inlineCode",{parentName:"p"},"git@")," in the future)."),(0,r.kt)("p",null,"Create a personal access token with ",(0,r.kt)("inlineCode",{parentName:"p"},"read:packages")," access in github in order to use modules published in github packages. Refer ",(0,r.kt)("a",{parentName:"p",href:"https://docs.github.com/en/github/authenticating-to-github/keeping-your-account-and-data-secure/creating-a-personal-access-token"},"Creating a Personal Access Token")," for help."),(0,r.kt)("h2",{id:"getting-the-code-and-documentation"},"Getting the Code and Documentation"),(0,r.kt)("p",null,"Clone the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability"},"weaver-dlt-interoperability")," repository. The code to get a basic test network up and running and test data-sharing interoperation flows lies in the subfolder ",(0,r.kt)("inlineCode",{parentName:"p"},"tests/network-setups"),", which should be your starting point, though the setups will rely on other parts of the repository, as you will find out in the instructions given on this page."),(0,r.kt)("h2",{id:"securing-components"},"Securing Components"),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:"left"},"The relays and drivers corresponding to the different test networks you will encounter below can be run with or without TLS enabled. But the default files used in the demonstrations assume that either all relays and drivers are TLS-enabled or none are. Therefore, you should determine at the outset whether or not you wish to run the entire set of components in TLS-enabled mode, and select appropriate commands in the provided instructions.")))),(0,r.kt)("h2",{id:"hyperledger-fabric-components"},"Hyperledger Fabric Components"),(0,r.kt)("p",null,"Using the sequence of instructions below, you can start two separate Fabric networks, each with a single channel and application contract (chaincode). You can also start an interoperation contract, a relay, and a ",(0,r.kt)("em",{parentName:"p"},"driver")," acting on behalf of each network. You can build a Fabric CLI tool with which you can initialize both networks' ledgers with access control policies, foreign networks' security groups (i.e., membership providers' certificate chains), and some sample key-value pairs that can be shared during subsequent interoperation flows."),(0,r.kt)("h3",{id:"fabric-network"},"Fabric Network"),(0,r.kt)("p",null,"The code for this lies in the ",(0,r.kt)("inlineCode",{parentName:"p"},"tests/network-setups")," folder."),(0,r.kt)("p",null,"This folder contains code to create and launch networks ",(0,r.kt)("inlineCode",{parentName:"p"},"network1")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"network2")," of identical specifications:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Network: 1 peer, 1 peer CA, 1 ordering service node, 1 ordering service CA"),(0,r.kt)("li",{parentName:"ul"},"Single channel named ",(0,r.kt)("inlineCode",{parentName:"li"},"mychannel")),(0,r.kt)("li",{parentName:"ul"},"One of the following contracts deployed on ",(0,r.kt)("inlineCode",{parentName:"li"},"mychannel"),", the choice depending on the ",(0,r.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/interoperability-modes"},"interoperability mode")," you wish to test:",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"simplestate")," (",(0,r.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/data-sharing"},"Data Sharing"),"): supports simple transactions (",(0,r.kt)("inlineCode",{parentName:"li"},"Create"),", ",(0,r.kt)("inlineCode",{parentName:"li"},"Read"),", ",(0,r.kt)("inlineCode",{parentName:"li"},"Update"),", ",(0,r.kt)("inlineCode",{parentName:"li"},"Delete"),") involving storage and lookup of <key, value> pairs."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"simplestatewithacl")," (",(0,r.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/data-sharing"},"Data Sharing"),"): identical to ",(0,r.kt)("inlineCode",{parentName:"li"},"simplestate")," but with extra security features to ensure that the Weaver infrastructure cannot be bypassed by a malicious client of the network."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"simpleasset")," (",(0,r.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview"},"Asset Exchange"),"): supports creation, modification, transfer, and deletion, as well as locking, unlocking, and claiming, of simple bonds and tokens (examples of non-fungible and fungible assets respectively)."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"simpleassetandinterop")," (",(0,r.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview"},"Asset Exchange"),"): identical to ",(0,r.kt)("inlineCode",{parentName:"li"},"simpleasset")," but where the locking, unlocking, and claiming logic is imported as a library in the chaincode rather than available in the common Fabric Interoperation Chaincode (a Weaver component)."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"simpleassettransfer")," (",(0,r.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview"},"Asset Exchange")," or ",(0,r.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-transfer"},"Asset Transfer"),"): augmentation of ",(0,r.kt)("inlineCode",{parentName:"li"},"simpleasset")," with asset pledging, claiming, and reclaiming features for cross-network transfers.")))),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:"left"},"For new users, we recommend testing the Data Sharing feature first with the ",(0,r.kt)("inlineCode",{parentName:"td"},"simplestate")," contract. To test the other modes, you can simply ",(0,r.kt)("a",{parentName:"td",href:"#tear-down-the-setup"},"tear down")," the Fabric networks and restart them with the appropriate chaincodes installed.")))),(0,r.kt)("p",null,"Follow the instructions below to build and launch the networks:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"tests/network-setups/fabric/dev")," folder."),(0,r.kt)("li",{parentName:"ul"},"To spin up both network1 and network2 with the interoperation chaincode and the default ",(0,r.kt)("inlineCode",{parentName:"li"},"simplestate")," chaincode installed, run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make start-interop\n"))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("em",{parentName:"li"},"To launch the networks with a different application chaincode from the above list, run"),":",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make start-interop CHAINCODE_NAME=<chaincode-name>\n"))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("em",{parentName:"li"},"To launch the networks with 2 organizations, each with a peer (this will enable more variation and experimentation, which you can attempt after testing interoperation protocols across basic network configurations), run"),":",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'make start-interop-local PROFILE="2-nodes"\n')))),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:"left"},"If you do not wish to test Fabric-Fabric interoperation, you can choose to launch only one of the two networks along with its interoperation chaincode. For ",(0,r.kt)("inlineCode",{parentName:"td"},"network1"),", run ",(0,r.kt)("inlineCode",{parentName:"td"},"make start-interop-network1"),", and for ",(0,r.kt)("inlineCode",{parentName:"td"},"network2"),", run ",(0,r.kt)("inlineCode",{parentName:"td"},"make start-interop-network2"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:"left"},"If you wish to enable end-to-end confidentiality by default in the interoperation modules that are deployed during network launch, set the environment variable ",(0,r.kt)("inlineCode",{parentName:"td"},"E2E_CONFIDENTIALITY")," to ",(0,r.kt)("inlineCode",{parentName:"td"},"true")," in the command line as follows: ",(0,r.kt)("inlineCode",{parentName:"td"},"E2E_CONFIDENTIALITY=true make start-interop"))))),(0,r.kt)("p",null,"For more information, refer to the associated ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/tests/network-setups/fabric/dev"},"README"),"."),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Troubleshooting Tips"),":"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"If you see any errors during the launches, re-check the prerequisites (software installations and credentials). Ensure your network connection is working. As a safe bet, you can retry after cleanup: kill and remove all Docker containers and associated volumes.")),(0,r.kt)("h3",{id:"fabric-client-fabric-cli"},"Fabric Client (fabric-cli)"),(0,r.kt)("p",null,"The CLI is used to interact with a Fabric network, configure it and run chaincode transactions to record data on the channel ledger or query data. It is also used to interact with remote networks through the relay to trigger an interoperation flow for data request and acceptance."),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"fabric-cli")," Node.js source code is located in the ",(0,r.kt)("inlineCode",{parentName:"p"},"samples/fabric/fabric-cli")," folder and the Golang source code in the ",(0,r.kt)("inlineCode",{parentName:"p"},"samples/fabric/go-cli")," folder."),(0,r.kt)("h4",{id:"prerequisites-1"},"Prerequisites"),(0,r.kt)("p",null,"If you are using a Linux system, make sure that lib64 is installed."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:"left"},"For the Node.js version of the ",(0,r.kt)("inlineCode",{parentName:"td"},"fabric-cli"),", the setup and running instructions below were tested with all Node.js versions from v11.14.0 to v14.17.3.")))),(0,r.kt)("h4",{id:"installation"},"Installation"),(0,r.kt)("p",null,"You can install ",(0,r.kt)("inlineCode",{parentName:"p"},"fabric-cli")," as follows (for both the Node.js and Golang versions):"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"samples/fabric/fabric-cli")," folder or the ",(0,r.kt)("inlineCode",{parentName:"li"},"samples/fabric/go-cli")," folder."),(0,r.kt)("li",{parentName:"ul"},"Create ",(0,r.kt)("inlineCode",{parentName:"li"},".npmrc")," from template ",(0,r.kt)("inlineCode",{parentName:"li"},".npmrc.template"),", by replacing ",(0,r.kt)("inlineCode",{parentName:"li"},"<personal-access-token>")," with yours created ",(0,r.kt)("a",{parentName:"li",href:"#package-access-token"},"above"),".."),(0,r.kt)("li",{parentName:"ul"},"Run the following to install dependencies (for the Node.js version) or the executable (for the Golang version):",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make build\n"))),(0,r.kt)("li",{parentName:"ul"},"Use the ",(0,r.kt)("inlineCode",{parentName:"li"},"fabric-cli")," executable in the ",(0,r.kt)("inlineCode",{parentName:"li"},"bin")," folder for ",(0,r.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/ledger-initialization"},"subsequent actions"),".")),(0,r.kt)("h3",{id:"fabric-relay"},"Fabric Relay"),(0,r.kt)("p",null,"The relay is a module acting on behalf of a network, enabling interoperation flows with other networks by communicating with their relays.\nThe code for this lies in the ",(0,r.kt)("inlineCode",{parentName:"p"},"core/relay")," folder."),(0,r.kt)("h4",{id:"building"},"Building"),(0,r.kt)("p",null,(0,r.kt)("em",{parentName:"p"},"Prerequisite"),": make sure Rust is already installed and that the ",(0,r.kt)("inlineCode",{parentName:"p"},"cargo")," executable is in your system path (after installation of Rust, this should be available in ",(0,r.kt)("inlineCode",{parentName:"p"},"$HOME/.cargo/bin"),"); you can also ensure this by running ",(0,r.kt)("inlineCode",{parentName:"p"},'source "$HOME/.cargo/env"'),"."),(0,r.kt)("p",null,"Build the generic (i.e., common to all DLTs) relay module as follows:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"core/relay")," folder."),(0,r.kt)("li",{parentName:"ul"},"Run the following:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make\n"))),(0,r.kt)("li",{parentName:"ul"},"To avoid errors during Weaver Relay compilation, update certain packages (on which the Weaver Relay is dependent) to their latest versions as follows:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make update-pkgs\n")))),(0,r.kt)("h4",{id:"deployment"},"Deployment"),(0,r.kt)("p",null,"An instance or a relay can be run using a suitable configuration file. Samples are available in the ",(0,r.kt)("inlineCode",{parentName:"p"},"core/relay/config")," folder."),(0,r.kt)("p",null,"Run a relay for ",(0,r.kt)("inlineCode",{parentName:"p"},"network1")," as follows:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"core/relay")," folder."),(0,r.kt)("li",{parentName:"ul"},"To launch the server without TLS, leave the configuration file ",(0,r.kt)("inlineCode",{parentName:"li"},"config/Fabric_Relay.toml")," in its default state. Otherwise, edit it to set TLS flags for this relay and the other relays and drivers it will connect to in this demonstration as follows:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-toml"},'.\n.\ncert_path="credentials/fabric_cert.pem"\nkey_path="credentials/fabric_key"\ntls=true\n.\n.\n[relays]\n[relays.Corda_Relay]\nhostname="localhost"\nport="9081"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n[relays.Corda_Relay2]\nhostname="localhost"\nport="9082"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n[relays.Fabric_Relay2]\nhostname="localhost"\nport="9083"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n.\n.\n[drivers]\n[drivers.Fabric]\nhostname="localhost"\nport="9090"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n.\n.\n'))),(0,r.kt)("li",{parentName:"ul"},"To launch the server, simply run the following:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"RELAY_CONFIG=config/Fabric_Relay.toml cargo run --bin server\n")))),(0,r.kt)("p",null,"Run a relay for ",(0,r.kt)("inlineCode",{parentName:"p"},"network2")," as follows (",(0,r.kt)("em",{parentName:"p"},"do this only if you have launched both Fabric networks ",(0,r.kt)("inlineCode",{parentName:"em"},"network1")," and ",(0,r.kt)("inlineCode",{parentName:"em"},"network2")," and wish to test interoperation between them"),")"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"core/relay")," folder."),(0,r.kt)("li",{parentName:"ul"},"To launch the server without TLS, leave the configuration file ",(0,r.kt)("inlineCode",{parentName:"li"},"config/Fabric_Relay2.toml")," in its default state. Otherwise, edit it to set TLS flags for this relay and the other relays and drivers it will connect to in this demonstration as follows:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-toml"},'.\n.\ncert_path="credentials/fabric_cert.pem"\nkey_path="credentials/fabric_key"\ntls=true\n.\n.\n[relays]\n[relays.Corda_Relay]\nhostname="localhost"\nport="9081"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n[relays.Corda_Relay2]\nhostname="localhost"\nport="9082"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n[relays.Fabric_Relay]\nhostname="localhost"\nport="9080"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n.\n.\n[drivers]\n[drivers.Fabric]\nhostname="localhost"\nport="9095"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n.\n.\n'))),(0,r.kt)("li",{parentName:"ul"},"To launch the server, simply run the following:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"RELAY_CONFIG=config/Fabric_Relay2.toml cargo run --bin server\n")))),(0,r.kt)("p",null,"For more information, see the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/core/relay"},"relay README"),"."),(0,r.kt)("h3",{id:"fabric-driver"},"Fabric Driver"),(0,r.kt)("p",null,"A driver is a DLT-specific plugin invoked by the relay while conveying external data queries to the local peer network and collecting a response with proofs. The Fabric driver is built as a Fabric client application on the ",(0,r.kt)("inlineCode",{parentName:"p"},"fabric-network")," NPM package.\nThe code for this lies in the ",(0,r.kt)("inlineCode",{parentName:"p"},"core/drivers/fabric-driver")," folder."),(0,r.kt)("h4",{id:"configuring"},"Configuring"),(0,r.kt)("p",null,"In the ",(0,r.kt)("inlineCode",{parentName:"p"},"core/drivers/fabric-driver")," folder, copy ",(0,r.kt)("inlineCode",{parentName:"p"},".env.template")," to ",(0,r.kt)("inlineCode",{parentName:"p"},".env")," and update ",(0,r.kt)("inlineCode",{parentName:"p"},"CONNECTION_PROFILE")," to point to the connection profile of the Fabric network (e.g. ",(0,r.kt)("inlineCode",{parentName:"p"},"<PATH-TO-WEAVER>/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json"),")"),(0,r.kt)("p",null,"Configure ",(0,r.kt)("inlineCode",{parentName:"p"},"fabric-driver")," for ",(0,r.kt)("inlineCode",{parentName:"p"},"network1")," as follows:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"core/drivers/fabric-driver")," folder."),(0,r.kt)("li",{parentName:"ul"},"Create a ",(0,r.kt)("inlineCode",{parentName:"li"},".env")," file by copying ",(0,r.kt)("inlineCode",{parentName:"li"},".env.template")," and setting suitable parameter values:",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"The ",(0,r.kt)("inlineCode",{parentName:"li"},"CONNECTION_PROFILE")," should point to the absolute path of the connection profile for ",(0,r.kt)("inlineCode",{parentName:"li"},"network1"),".",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"For this exercise, specify the path ",(0,r.kt)("inlineCode",{parentName:"li"},"<PATH-TO-WEAVER>/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json")," (",(0,r.kt)("em",{parentName:"li"},"you must specify the full absolute path here"),")."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"<PATH-TO-WEAVER>")," here is the absolute path of the ",(0,r.kt)("inlineCode",{parentName:"li"},"weaver-dlt-interoperability")," clone folder."))),(0,r.kt)("li",{parentName:"ul"},"If you wish to start the driver without TLS, set the following parameter values:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},"RELAY_TLS=false\nRELAY_TLSCA_CERT_PATH=\nDRIVER_TLS=false\nDRIVER_TLS_CERT_PATH=\nDRIVER_TLS_KEY_PATH=\n")),"Otherwise, if you wish to start the driver with TLS enabled, set the following parameter values (replace ",(0,r.kt)("inlineCode",{parentName:"li"},"<PATH-TO-WEAVER>")," with the absolute path of the ",(0,r.kt)("inlineCode",{parentName:"li"},"weaver-dlt-interoperability")," clone folder):",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},"RELAY_TLS=true\nRELAY_TLSCA_CERT_PATH=<PATH-TO-WEAVER>/core/relay/credentials/fabric_ca_cert.pem\nDRIVER_TLS=true\nDRIVER_TLS_CERT_PATH=<PATH-TO-WEAVER>/core/relay/credentials/fabric_cert.pem\nDRIVER_TLS_KEY_PATH=<PATH-TO-WEAVER>/core/relay/credentials/fabric_key\n"))),(0,r.kt)("li",{parentName:"ul"},"Leave the default values unchanged for the other parameters. The relay and driver endpoints as well as the network name are already specified.")))),(0,r.kt)("h4",{id:"building-1"},"Building"),(0,r.kt)("p",null,"Build the Fabric driver module as follows:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"core/drivers/fabric-driver")," folder."),(0,r.kt)("li",{parentName:"ul"},"Create ",(0,r.kt)("inlineCode",{parentName:"li"},".npmrc")," from template ",(0,r.kt)("inlineCode",{parentName:"li"},".npmrc.template"),", by replacing ",(0,r.kt)("inlineCode",{parentName:"li"},"<personal-access-token>")," with yours created above."),(0,r.kt)("li",{parentName:"ul"},"Run the following:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make build\n")))),(0,r.kt)("h4",{id:"running"},"Running"),(0,r.kt)("p",null,"Run a Fabric driver for ",(0,r.kt)("inlineCode",{parentName:"p"},"network1")," as follows:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"core/drivers/fabric-driver")," folder."),(0,r.kt)("li",{parentName:"ul"},"Run the following:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"npm run dev\n")))),(0,r.kt)("p",null,"Run a Fabric driver for ",(0,r.kt)("inlineCode",{parentName:"p"},"network2")," as follows (",(0,r.kt)("em",{parentName:"p"},"do this only if you wish to test interoperation between the two Fabric networks ",(0,r.kt)("inlineCode",{parentName:"em"},"network1")," and ",(0,r.kt)("inlineCode",{parentName:"em"},"network2")),")"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"core/drivers/fabric-driver")," folder."),(0,r.kt)("li",{parentName:"ul"},"Run the following:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"CONNECTION_PROFILE=<PATH-TO-WEAVER>/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/connection-org1.json NETWORK_NAME=network2 RELAY_ENDPOINT=localhost:9083 DRIVER_ENDPOINT=localhost:9095 npm run dev\n")))),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:"left"},"The variables we specified earlier in the ",(0,r.kt)("inlineCode",{parentName:"td"},".env")," for ",(0,r.kt)("inlineCode",{parentName:"td"},"network1")," are now passed in the command line. Alternatively, you can make a copy of the ",(0,r.kt)("inlineCode",{parentName:"td"},"fabric-driver")," folder with a different name and create a separate ",(0,r.kt)("inlineCode",{parentName:"td"},".env")," file within it that contains links to the connection profile, relay, and driver for ",(0,r.kt)("inlineCode",{parentName:"td"},"network2"),".")))),(0,r.kt)("h3",{id:"fabric-iin-agent"},"Fabric IIN Agent"),(0,r.kt)("p",null,"IIN Agent is a client of a member of a DLT network or security domain with special permissions to update security domain identities and configurations on the ledger via the network's interoperation module. The code for this lies in the ",(0,r.kt)("inlineCode",{parentName:"p"},"core/identity-management/iin-agent")," folder. Navigate to the ",(0,r.kt)("inlineCode",{parentName:"p"},"core/identity-management/iin-agent")," folder."),(0,r.kt)("h4",{id:"building-2"},"Building"),(0,r.kt)("p",null,"To build the IIN Agent, run:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make build-local\n")),(0,r.kt)("h4",{id:"configuration"},"Configuration"),(0,r.kt)("p",null,"Ledger config file specifies ledger specific IIN Agent details such as identity and which network and organization to connect to."),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"To create config file for ",(0,r.kt)("inlineCode",{parentName:"p"},"Org1MSP"),"'s Fabric IIN Agent of ",(0,r.kt)("inlineCode",{parentName:"p"},"network1"),", follow the steps:"),(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"Create copy of template config file for Fabric IIN Agent: ",(0,r.kt)("inlineCode",{parentName:"li"},"src/fabric-ledger/config.json.template"),", say to location ",(0,r.kt)("inlineCode",{parentName:"li"},"src/fabric-ledger/config-n1-org1.json"),"."),(0,r.kt)("li",{parentName:"ul"},"Replace ",(0,r.kt)("inlineCode",{parentName:"li"},"<path-to-connection-profile>")," with ",(0,r.kt)("inlineCode",{parentName:"li"},"<PATH-TO-WEAVER>/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json"),", where replace ",(0,r.kt)("inlineCode",{parentName:"li"},"<PATH-TO-WEAVER>")," with the location of your clone of Weaver."),(0,r.kt)("li",{parentName:"ul"},"Set ",(0,r.kt)("inlineCode",{parentName:"li"},"mspId")," as ",(0,r.kt)("inlineCode",{parentName:"li"},"Org1MSP"),"."),(0,r.kt)("li",{parentName:"ul"},"Set ",(0,r.kt)("inlineCode",{parentName:"li"},"agent.affiliation")," as ",(0,r.kt)("inlineCode",{parentName:"li"},"org1.department1"),"."))),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"To create config file for ",(0,r.kt)("inlineCode",{parentName:"p"},"Org2MSP"),"'s Fabric IIN Agent of ",(0,r.kt)("inlineCode",{parentName:"p"},"network1"),", repeat ",(0,r.kt)("inlineCode",{parentName:"p"},"Step 1")," with different name for config file, say ",(0,r.kt)("inlineCode",{parentName:"p"},"src/fabric-ledger/config-n1-org2.json"),", and replace ",(0,r.kt)("inlineCode",{parentName:"p"},"org1")," with ",(0,r.kt)("inlineCode",{parentName:"p"},"org2")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"Org1MSP")," with ",(0,r.kt)("inlineCode",{parentName:"p"},"Org2MSP"),".")),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"To create config file for ",(0,r.kt)("inlineCode",{parentName:"p"},"Org1MSP"),"'s Fabric IIN Agent of ",(0,r.kt)("inlineCode",{parentName:"p"},"network2"),", repeat ",(0,r.kt)("inlineCode",{parentName:"p"},"Step 1")," with different name for config file, say ",(0,r.kt)("inlineCode",{parentName:"p"},"src/fabric-ledger/config-n2-org1.json"),", and replace ",(0,r.kt)("inlineCode",{parentName:"p"},"network1")," with ",(0,r.kt)("inlineCode",{parentName:"p"},"network2"),".")),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"To create config file for ",(0,r.kt)("inlineCode",{parentName:"p"},"Org2MSP"),"'s Fabric IIN Agent of ",(0,r.kt)("inlineCode",{parentName:"p"},"network2"),", repeat ",(0,r.kt)("inlineCode",{parentName:"p"},"Step 1")," with different name for config file, say ",(0,r.kt)("inlineCode",{parentName:"p"},"src/fabric-ledger/config-n2-org2.json"),", and replace ",(0,r.kt)("inlineCode",{parentName:"p"},"network1")," with ",(0,r.kt)("inlineCode",{parentName:"p"},"network2"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"org1")," with ",(0,r.kt)("inlineCode",{parentName:"p"},"org2")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"Org1MSP")," with ",(0,r.kt)("inlineCode",{parentName:"p"},"Org2MSP"),"."))),(0,r.kt)("h4",{id:"security-domain-configuration"},"Security Domain Configuration"),(0,r.kt)("p",null,"Security Domain config file specifies the scope of security domain, which can be a channel in Fabric networks or list of nodes. File ",(0,r.kt)("inlineCode",{parentName:"p"},"docker-testnet/configs/security-domain-config.json")," can be used for Weaver testnets."),(0,r.kt)("h4",{id:"dns-configuration"},"DNS Configuration"),(0,r.kt)("p",null,"To allow an IIN Agent's to be able to discover other IIN Agents, a config file for DNS is required. Create one ",(0,r.kt)("inlineCode",{parentName:"p"},"dnsconfig.json")," by creating a copy of template ",(0,r.kt)("inlineCode",{parentName:"p"},"dnsconfig.json.template"),", and replace the values with:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"If Fabric networks are started with 1 org, and IIN Agent are to be started without TLS, use following values:")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json"},'{\n "network1": {\n "Org1MSP": {\n "endpoint": "localhost:9500",\n "tls": false,\n "tlsCACertPath": ""\n }\n },\n "network2": {\n "Org1MSP": {\n "endpoint": "localhost:9501",\n "tls": false,\n "tlsCACertPath": ""\n }\n }\n}\n')),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"If Fabric networks are started with 1 org, and IIN Agent are to be started with TLS, use following values:")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json"},'{\n "network1": {\n "Org1MSP": {\n "endpoint": "localhost:9500",\n "tls": true,\n "tlsCACertPath": "../../relay/credentials/fabric_ca_cert.pem"\n }\n },\n "network2": {\n "Org1MSP": {\n "endpoint": "localhost:9501",\n "tls": true,\n "tlsCACertPath": "../../relay/credentials/fabric_ca_cert.pem"\n }\n }\n}\n')),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"If Fabric networks are started with 2 orgs, and IIN Agent are to be started without TLS, use following values:")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json"},'{\n "network1": {\n "Org1MSP": {\n "endpoint": "localhost:9500",\n "tls": false,\n "tlsCACertPath": ""\n },\n "Org2MSP": {\n "endpoint": "localhost:9510",\n "tls": false,\n "tlsCACertPath": ""\n }\n },\n "network2": {\n "Org1MSP": {\n "endpoint": "localhost:9501",\n "tls": false,\n "tlsCACertPath": ""\n },\n "Org2MSP": {\n "endpoint": "localhost:9511",\n "tls": false,\n "tlsCACertPath": ""\n }\n }\n}\n')),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"If Fabric networks are started with 2 orgs, and IIN Agent are to be started with TLS, use following values:")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json"},'{\n "network1": {\n "Org1MSP": {\n "endpoint": "localhost:9500",\n "tls": true,\n "tlsCACertPath": "../../relay/credentials/fabric_ca_cert.pem"\n },\n "Org2MSP": {\n "endpoint": "localhost:9510",\n "tls": true,\n "tlsCACertPath": "../../relay/credentials/fabric_ca_cert.pem"\n }\n },\n "network2": {\n "Org1MSP": {\n "endpoint": "localhost:9501",\n "tls": true,\n "tlsCACertPath": "../../relay/credentials/fabric_ca_cert.pem"\n },\n "Org2MSP": {\n "endpoint": "localhost:9511",\n "tls": true,\n "tlsCACertPath": "../../relay/credentials/fabric_ca_cert.pem"\n }\n }\n}\n')),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:"left"},"The variables we specified earlier in the ",(0,r.kt)("inlineCode",{parentName:"td"},".env")," for ",(0,r.kt)("inlineCode",{parentName:"td"},"network1")," are now passed in the command line. Alternatively, you can make a copy of the ",(0,r.kt)("inlineCode",{parentName:"td"},"fabric-driver")," folder with a different name and create a separate ",(0,r.kt)("inlineCode",{parentName:"td"},".env")," file within it that contains links to the connection profile, relay, and driver for ",(0,r.kt)("inlineCode",{parentName:"td"},"network2"),".")))),(0,r.kt)("h4",{id:"environment-variables"},"Environment Variables"),(0,r.kt)("p",null,"To configure environment variables for ",(0,r.kt)("inlineCode",{parentName:"p"},"Org1MSP"),"'s Fabric IIN Agent of ",(0,r.kt)("inlineCode",{parentName:"p"},"network1"),", follow the steps:"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},"Create a copy of ",(0,r.kt)("inlineCode",{parentName:"li"},".env.template")," as ",(0,r.kt)("inlineCode",{parentName:"li"},".env"),", and update following values based on previous configuration file paths:")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"IIN_AGENT_ENDPOINT=localhost:9500\nMEMBER_ID=Org1MSP\nSECURITY_DOMAIN=network1\nDLT_TYPE=fabric\nCONFIG_PATH=./src/fabric-ledger/config-n1-org1.json\nDNS_CONFIG_PATH=./dnsconfig.json\nSECURITY_DOMAIN_CONFIG_PATH=./docker-testnet/configs/security-domain-config.json\nWEAVER_CONTRACT_ID=interop\nAUTO_SYNC=true\n")),(0,r.kt)("ol",{start:2},(0,r.kt)("li",{parentName:"ol"},"If IIN Agent has to be started with TLS enabled, also update following values:")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"IIN_AGENT_TLS=false\nIIN_AGENT_TLS_CERT_PATH=../../relay/credentials/fabric_cert.pem\nIIN_AGENT_TLS_KEY_PATH=../../relay/credentials/fabric_key\n")),(0,r.kt)("h4",{id:"deployment-1"},"Deployment"),(0,r.kt)("p",null,"Use the following steps to run Fabric IIN Agents in host machine:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"To start IIN Agent for ",(0,r.kt)("inlineCode",{parentName:"li"},"Org1MSP")," of ",(0,r.kt)("inlineCode",{parentName:"li"},"network1"),", run:")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"npm run dev\n")),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"To start IIN Agent for ",(0,r.kt)("inlineCode",{parentName:"li"},"Org2MSP")," of ",(0,r.kt)("inlineCode",{parentName:"li"},"network1")," (",(0,r.kt)("em",{parentName:"li"},"only required if Fabric network was started with 2 orgs"),"), run:")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"IIN_AGENT_ENDPOINT=localhost:9510 MEMBER_ID=Org2MSP CONFIG_PATH=./src/fabric-ledger/config-n1-org2.json npm run dev\n")),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"To start IIN Agent for ",(0,r.kt)("inlineCode",{parentName:"li"},"Org1MSP")," of ",(0,r.kt)("inlineCode",{parentName:"li"},"network2"),", run:")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"IIN_AGENT_ENDPOINT=localhost:9501 SECURITY_DOMAIN=network2 CONFIG_PATH=./src/fabric-ledger/config-n2-org1.json npm run dev\n")),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"To start IIN Agent for ",(0,r.kt)("inlineCode",{parentName:"li"},"Org2MSP")," of ",(0,r.kt)("inlineCode",{parentName:"li"},"network2")," (",(0,r.kt)("em",{parentName:"li"},"only required if Fabric network was started with 2 orgs"),"), run:")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"IIN_AGENT_ENDPOINT=localhost:9511 MEMBER_ID=Org2MSP SECURITY_DOMAIN=network2 CONFIG_PATH=./src/fabric-ledger/config-n2-org2.json npm run dev\n")),(0,r.kt)("h2",{id:"corda-components"},"Corda Components"),(0,r.kt)("p",null,"Using the sequence of instructions below, you can start a Corda network and run an application CorDapp on it. You can also run an interoperation CorDapp, a relay and a ",(0,r.kt)("em",{parentName:"p"},"driver")," acting on behalf of the network. You can initialize the network's vault with access control policies, foreign networks' security groups (i.e., membership providers' certificate chains), and some sample state values that can be shared during subsequent interoperation flows."),(0,r.kt)("h3",{id:"corda-network"},"Corda Network"),(0,r.kt)("p",null,"The Corda networks' code lies in the ",(0,r.kt)("inlineCode",{parentName:"p"},"tests/network-setups/corda")," folder. You can launch two separate Corda networks, namely ",(0,r.kt)("inlineCode",{parentName:"p"},"Corda_Network")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"Corda_Network2"),". Each network runs the ",(0,r.kt)("inlineCode",{parentName:"p"},"samples/corda/corda-simple-application")," CorDapp by default, which maintains a state named ",(0,r.kt)("inlineCode",{parentName:"p"},"SimpleState")," containing a set of key-value pairs (of strings)."),(0,r.kt)("p",null,"The following steps will, in addition to launching the network, build the CorDapp and a Corda client in ",(0,r.kt)("inlineCode",{parentName:"p"},"samples/corda/corda-simple-application/client"),"."),(0,r.kt)("h4",{id:"running-with-interoperation-cordapp-from-github-packages"},"Running with Interoperation CorDapp from Github Packages"),(0,r.kt)("p",null,"Follow the instructions below to build and launch the network:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"tests/network-setups/corda")," folder."),(0,r.kt)("li",{parentName:"ul"},"Create a copy of ",(0,r.kt)("inlineCode",{parentName:"li"},"github.properties.template")," as ",(0,r.kt)("inlineCode",{parentName:"li"},"github.properties"),"."),(0,r.kt)("li",{parentName:"ul"},"Replace ",(0,r.kt)("inlineCode",{parentName:"li"},"<GITHUB email>")," with your github email, and ",(0,r.kt)("inlineCode",{parentName:"li"},"<GITHUB Personal Access Token>")," with the access token created ",(0,r.kt)("a",{parentName:"li",href:"#package-access-token"},"above"),"."),(0,r.kt)("li",{parentName:"ul"},"To spin up the Corda networks with the Interoperation CorDapps:",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"Each consisting of 1 node and a notary (for data-transfer), run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make start\n"))),(0,r.kt)("li",{parentName:"ul"},"Each consisting of 2 nodes and a notary (for asset-exchange/transfer), run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'make start PROFILE="2-nodes"\n'))),(0,r.kt)("li",{parentName:"ul"},"Each consisting of 3 nodes and a notary (for asset-exchange/transfer), run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'make start PROFILE="3-nodes"\n')))))),(0,r.kt)("p",null,"You should see the following message in the terminal:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"Waiting for network node services to start\n")),(0,r.kt)("p",null,"The Corda nodes and notary may take a while (several minutes on memory-constrained systems) to start. If they start up successfully, you should something like the following for each network, though the number of node entries will depend on the profile you used to start the network with (replace ",(0,r.kt)("inlineCode",{parentName:"p"},"<network-name>")," with ",(0,r.kt)("inlineCode",{parentName:"p"},"Corda_Network")," or ",(0,r.kt)("inlineCode",{parentName:"p"},"Corda_Network2"),"):"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"PartyA node services started for network <network-name>\nPartyB node services started for network <network-name>\nPartyC node services started for network <network-name>\nNotary node services started for network <network-name>\n")),(0,r.kt)("h3",{id:"corda-relay"},"Corda Relay"),(0,r.kt)("p",null,"The relay was built earlier, so you just need to use a different configuration file to start a relay for the Corda network."),(0,r.kt)("p",null,"Run a relay for ",(0,r.kt)("inlineCode",{parentName:"p"},"Corda_Network")," as follows:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"p"},"core/relay")," folder.")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"(Make sure you've already built the relay by running ",(0,r.kt)("inlineCode",{parentName:"p"},"make"),".)")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"To launch the server without TLS, leave the configuration file ",(0,r.kt)("inlineCode",{parentName:"p"},"config/Corda_Relay.toml")," in its default state. Otherwise, edit it to set TLS flags for this relay and the other relays and drivers it will connect to in this demonstration as follows:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-toml"},'.\n.\ncert_path="credentials/fabric_cert.pem"\nkey_path="credentials/fabric_key"\ntls=true\n.\n.\n[relays]\n[relays.Fabric_Relay]\nhostname="localhost"\nport="9080"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n[relays.Fabric_Relay2]\nhostname="localhost"\nport="9083"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n[relays.Corda_Relay2]\nhostname="localhost"\nport="9082"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n.\n.\n[drivers]\n[drivers.Corda]\nhostname="localhost"\nport="9099"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n.\n.\n'))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"To launch the server, simply run the following:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"RELAY_CONFIG=config/Corda_Relay.toml cargo run --bin server\n")),(0,r.kt)("p",{parentName:"li"},"If the relay starts up successfully, the following will be logged on your terminal:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},'Relay Name: "Corda_Relay"\nRelayServer listening on [::1]:9081\n')))),(0,r.kt)("p",null,"Run a relay for ",(0,r.kt)("inlineCode",{parentName:"p"},"Corda_Network2")," as follows (",(0,r.kt)("em",{parentName:"p"},"do this only if you have launched both Corda networks ",(0,r.kt)("inlineCode",{parentName:"em"},"Corda_Network")," and ",(0,r.kt)("inlineCode",{parentName:"em"},"Corda_Network2")," and wish to test interoperation between them"),")"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"p"},"core/relay")," folder.")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"To launch the server without TLS, leave the configuration file ",(0,r.kt)("inlineCode",{parentName:"p"},"config/Corda_Relay2.toml")," in its default state. Otherwise, edit it to set TLS flags for this relay and the other relays and drivers it will connect to in this demonstration as follows:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-toml"},'.\n.\ncert_path="credentials/fabric_cert.pem"\nkey_path="credentials/fabric_key"\ntls=true\n.\n.\n[relays]\n[relays.Fabric_Relay]\nhostname="localhost"\nport="9080"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n[relays.Fabric_Relay2]\nhostname="localhost"\nport="9083"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n[relays.Corda_Relay]\nhostname="localhost"\nport="9081"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n.\n.\n[drivers]\n[drivers.Corda]\nhostname="localhost"\nport="9098"\ntls=true\ntlsca_cert_path="credentials/fabric_ca_cert.pem"\n.\n.\n'))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"To launch the server, simply run the following:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"RELAY_CONFIG=config/Corda_Relay2.toml cargo run --bin server\n")),(0,r.kt)("p",{parentName:"li"},"If the relay starts up successfully, the following will be logged on your terminal:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},'Relay Name: "Corda2_Relay"\nRelayServer listening on [::1]:9082\n')))),(0,r.kt)("h3",{id:"corda-driver"},"Corda Driver"),(0,r.kt)("p",null,"The code for this lies in the ",(0,r.kt)("inlineCode",{parentName:"p"},"core/drivers/corda-driver")," folder."),(0,r.kt)("h4",{id:"building-corda-driver"},"Building Corda Driver"),(0,r.kt)("p",null,"Build the Corda driver module as follows:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"core/drivers/corda-driver")," folder."),(0,r.kt)("li",{parentName:"ul"},"Create a copy of ",(0,r.kt)("inlineCode",{parentName:"li"},"github.properties.template")," as ",(0,r.kt)("inlineCode",{parentName:"li"},"github.properties"),"."),(0,r.kt)("li",{parentName:"ul"},"Replace ",(0,r.kt)("inlineCode",{parentName:"li"},"<GITHUB email>")," with your github email, and ",(0,r.kt)("inlineCode",{parentName:"li"},"<GITHUB Personal Access Token>")," with the access token created ",(0,r.kt)("a",{parentName:"li",href:"#package-access-token"},"above"),"."),(0,r.kt)("li",{parentName:"ul"},"Run the following:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make build\n")))),(0,r.kt)("h4",{id:"configuring-1"},"Configuring"),(0,r.kt)("p",null,"Configure the drivers as follows (you can skip this if you wish to run the drivers without TLS):"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"core/drivers/corda-driver")," folder and create a ",(0,r.kt)("inlineCode",{parentName:"li"},".env")," file."),(0,r.kt)("li",{parentName:"ul"},"To run the drivers without TLS, set the following default values:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},"RELAY_TLS=false\nRELAY_TLSCA_TRUST_STORE=\nRELAY_TLSCA_TRUST_STORE_PASSWORD=\nRELAY_TLSCA_CERT_PATHS=\n"))),(0,r.kt)("li",{parentName:"ul"},"To run the drivers with TLS, set the following values (replace ",(0,r.kt)("inlineCode",{parentName:"li"},"<PATH-TO-WEAVER>")," with the absolute path of the ",(0,r.kt)("inlineCode",{parentName:"li"},"weaver-dlt-interoperability")," clone folder):",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},"RELAY_TLS=true\nRELAY_TLSCA_TRUST_STORE=<PATH-TO-WEAVER>/core/relay/credentials/fabric_trust_store.jks\nRELAY_TLSCA_TRUST_STORE_PASSWORD=trelay\nRELAY_TLSCA_CERT_PATHS=<PATH-TO-WEAVER>/core/relay/credentials/fabric_ca_cert.pem\n")))),(0,r.kt)("h4",{id:"running-1"},"Running"),(0,r.kt)("p",null,"Run a Corda driver as follows:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"core/drivers/corda-driver")," folder."),(0,r.kt)("li",{parentName:"ul"},"Run the following to start Corda driver for ",(0,r.kt)("inlineCode",{parentName:"li"},"Corda_Network"),":",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"./build/install/corda-driver/bin/corda-driver\n")),"If the driver starts successfully, it should log the following message on your terminal:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},"Corda driver gRPC server started. Listening on port 9099\n"))),(0,r.kt)("li",{parentName:"ul"},"Run the following to start Corda driver for ",(0,r.kt)("inlineCode",{parentName:"li"},"Corda_Network2"),":",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"DRIVER_PORT=9098 ./build/install/corda-driver/bin/corda-driver\n")),"If the driver starts successfully, it should log the following message on your terminal:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},"Corda driver gRPC server started. Listening on port 9098\n")))),(0,r.kt)("h2",{id:"tear-down-the-setup"},"Tear Down the Setup"),(0,r.kt)("p",null,"Bring down the test network's components as follows:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Simply terminate the various relays and drivers, which are running in the foreground in different terminals"),(0,r.kt)("li",{parentName:"ul"},"To bring down the running Corda network:",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"tests/network-setups/corda")," folder."),(0,r.kt)("li",{parentName:"ul"},"Run the following:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make clean\n"))))),(0,r.kt)("li",{parentName:"ul"},"To bring down all the running Fabric networks:",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"tests/network-setups/fabric/dev")," folder."),(0,r.kt)("li",{parentName:"ul"},"Run the following:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make clean\n")))))))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/935bcf2a.121fffff.js b/assets/js/935bcf2a.121fffff.js deleted file mode 100644 index 84a0dba32..000000000 --- a/assets/js/935bcf2a.121fffff.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[3283],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>u});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,a,r=function(e,t){if(null==e)return{};var n,a,r={},i=Object.keys(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=a.createContext({}),d=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},c=function(e){var t=d(e.components);return a.createElement(s.Provider,{value:t},e.children)},p="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},k=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),p=d(n),k=r,u=p["".concat(s,".").concat(k)]||p[k]||m[k]||i;return n?a.createElement(u,o(o({ref:t},c),{},{components:n})):a.createElement(u,o({ref:t},c))}));function u(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,o=new Array(i);o[0]=k;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[p]="string"==typeof e?e:r,o[1]=l;for(var d=2;d<i;d++)o[d]=n[d];return a.createElement.apply(null,o)}return a.createElement.apply(null,n)}k.displayName="MDXCreateElement"},3444:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>m,frontMatter:()=>i,metadata:()=>l,toc:()=>d});var a=n(7462),r=(n(7294),n(3905));const i={id:"corda-corda",title:"Asset Exchange: Corda with Corda",sidebar_label:"Corda with Corda",pagination_label:"Corda with Corda",pagination_prev:"external/getting-started/interop/asset-exchange/overview"},o=void 0,l={unversionedId:"external/getting-started/interop/asset-exchange/corda-corda",id:"external/getting-started/interop/asset-exchange/corda-corda",title:"Asset Exchange: Corda with Corda",description:"We will demonstrate asset exchange of a tokens in CordaNetwork with tokens on CordaNetwork2. Here PartyA (CORDAPORT=10006) and PartyB (CORDAPORT=10009) in CordaNetwork correspond to PartyA (CORDAPORT=30006) and PartyB (CORDAPORT=30009) in CordaNetwork2 respectively. Following are the step-by-step asset exchange process:",source:"@site/docs/external/getting-started/interop/asset-exchange/corda-corda.md",sourceDirName:"external/getting-started/interop/asset-exchange",slug:"/external/getting-started/interop/asset-exchange/corda-corda",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/corda-corda",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/getting-started/interop/asset-exchange/corda-corda.md",tags:[],version:"current",frontMatter:{id:"corda-corda",title:"Asset Exchange: Corda with Corda",sidebar_label:"Corda with Corda",pagination_label:"Corda with Corda",pagination_prev:"external/getting-started/interop/asset-exchange/overview"},sidebar:"Documentation",previous:{title:"Asset Exchange",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview"},next:{title:"Corda with Besu",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/corda-besu"}},s={},d=[],c={toc:d},p="wrapper";function m(e){let{components:t,...n}=e;return(0,r.kt)(p,(0,a.Z)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"We will demonstrate asset exchange of a tokens in ",(0,r.kt)("inlineCode",{parentName:"p"},"Corda_Network")," with tokens on ",(0,r.kt)("inlineCode",{parentName:"p"},"Corda_Network2"),". Here ",(0,r.kt)("inlineCode",{parentName:"p"},"PartyA")," (",(0,r.kt)("inlineCode",{parentName:"p"},"CORDA_PORT=10006"),") and ",(0,r.kt)("inlineCode",{parentName:"p"},"PartyB")," (",(0,r.kt)("inlineCode",{parentName:"p"},"CORDA_PORT=10009"),") in ",(0,r.kt)("inlineCode",{parentName:"p"},"Corda_Network")," correspond to ",(0,r.kt)("inlineCode",{parentName:"p"},"PartyA")," (",(0,r.kt)("inlineCode",{parentName:"p"},"CORDA_PORT=30006"),") and ",(0,r.kt)("inlineCode",{parentName:"p"},"PartyB")," (",(0,r.kt)("inlineCode",{parentName:"p"},"CORDA_PORT=30009"),") in ",(0,r.kt)("inlineCode",{parentName:"p"},"Corda_Network2")," respectively. Following are the step-by-step asset exchange process:"),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:"left"},"The hash used in following steps can be replaced by any valid ",(0,r.kt)("inlineCode",{parentName:"td"},"SHA256")," hash.")))),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to ",(0,r.kt)("inlineCode",{parentName:"li"},"samples/corda/corda-simple-application")," folder. "),(0,r.kt)("li",{parentName:"ul"},"Run the following to verify the status of the tokens owned by ",(0,r.kt)("inlineCode",{parentName:"li"},"PartyA")," and ",(0,r.kt)("inlineCode",{parentName:"li"},"PartyB")," in the ",(0,r.kt)("inlineCode",{parentName:"li"},"Corda_Network")," and ",(0,r.kt)("inlineCode",{parentName:"li"},"Corda_Network2"),":",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"./scripts/getAssetStatus.sh 2\n"))),(0,r.kt)("li",{parentName:"ul"},"Generate Secret-Hash Pair using following command (prints hash in base64):",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},"./clients/build/install/clients/bin/clients utils hash --hash-fn=SHA256 -s secrettext\n"))),(0,r.kt)("li",{parentName:"ul"},"Run the following to trigger ",(0,r.kt)("inlineCode",{parentName:"li"},"PartyA")," locking ",(0,r.kt)("inlineCode",{parentName:"li"},"30")," units of token type ",(0,r.kt)("inlineCode",{parentName:"li"},"t1")," for ",(0,r.kt)("inlineCode",{parentName:"li"},"PartyB")," in ",(0,r.kt)("inlineCode",{parentName:"li"},"Corda_Network")," for 60 mins:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'CORDA_PORT=10006 ./clients/build/install/clients/bin/clients lock-asset --fungible --hashBase64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs= --timeout=3600 --recipient="O=PartyB,L=London,C=GB" --param=t1:30\n')),"Note the ",(0,r.kt)("inlineCode",{parentName:"li"},"contract-id")," displayed after successful execution of the command, will be used in next steps. The output containing ",(0,r.kt)("inlineCode",{parentName:"li"},"contract-id")," would like this:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"HTLC Lock State created with contract ID Right(b=10448674_80d2bee7-5a5d-45df-b14e-60bac4ba1bf3).\n")),(0,r.kt)("inlineCode",{parentName:"li"},"contract-id")," is the alphanumeric text (with underscore and hyphens) after ",(0,r.kt)("inlineCode",{parentName:"li"},"b=")," within parenthesis. Let's denote it ",(0,r.kt)("inlineCode",{parentName:"li"},"<contract-id-1>"),"."),(0,r.kt)("li",{parentName:"ul"},"Run the following to verify ",(0,r.kt)("inlineCode",{parentName:"li"},"PartyA"),"'s lock (can be verified by both parties):",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"CORDA_PORT=10009 ./clients/build/install/clients/bin/clients is-asset-locked --contract-id=<contract-id-1>\n"))),(0,r.kt)("li",{parentName:"ul"},"Run the following to trigger ",(0,r.kt)("inlineCode",{parentName:"li"},"PartyB")," locking ",(0,r.kt)("inlineCode",{parentName:"li"},"50")," units of token type ",(0,r.kt)("inlineCode",{parentName:"li"},"t2")," for ",(0,r.kt)("inlineCode",{parentName:"li"},"PartyA")," in ",(0,r.kt)("inlineCode",{parentName:"li"},"Corda_Network2")," for 30 mins:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'CORDA_PORT=30009 ./clients/build/install/clients/bin/clients lock-asset --fungible --hashBase64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs= --timeout=1800 --recipient="O=PartyA,L=London,C=GB" --param=t2:50\n')),"Note the ",(0,r.kt)("inlineCode",{parentName:"li"},"contract-id")," displayed after successful execution of the command, will be used in next steps. Let's denote it ",(0,r.kt)("inlineCode",{parentName:"li"},"<contract-id-2>"),"."),(0,r.kt)("li",{parentName:"ul"},"Run the following to verify ",(0,r.kt)("inlineCode",{parentName:"li"},"PartyB"),"'s lock (can be verified by both parties):",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"CORDA_PORT=30006 ./clients/build/install/clients/bin/clients is-asset-locked --contract-id=<contract-id-2>\n"))),(0,r.kt)("li",{parentName:"ul"},"Run the following to trigger ",(0,r.kt)("inlineCode",{parentName:"li"},"PartyA"),"'s claim for ",(0,r.kt)("inlineCode",{parentName:"li"},"50")," units of token type ",(0,r.kt)("inlineCode",{parentName:"li"},"t2")," locked by ",(0,r.kt)("inlineCode",{parentName:"li"},"PartyB")," in ",(0,r.kt)("inlineCode",{parentName:"li"},"Corda_Network2"),":",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"CORDA_PORT=30006 ./clients/build/install/clients/bin/clients claim-asset --secret=secrettext --contract-id=<contract-id-2>\n")),(0,r.kt)("inlineCode",{parentName:"li"},"PartyB")," can see its node's logs to get the revealed hash preimage, and use it to claim the bond in the Fabric network."),(0,r.kt)("li",{parentName:"ul"},"Run the following to trigger ",(0,r.kt)("inlineCode",{parentName:"li"},"PartyB"),"'s claim for ",(0,r.kt)("inlineCode",{parentName:"li"},"30")," units of token type ",(0,r.kt)("inlineCode",{parentName:"li"},"t1")," locked by ",(0,r.kt)("inlineCode",{parentName:"li"},"PartyA")," in ",(0,r.kt)("inlineCode",{parentName:"li"},"Corda_Network"),":",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"CORDA_PORT=10009 ./clients/build/install/clients/bin/clients claim-asset --secret=secrettext --contract-id=<contract-id-1>\n"))),(0,r.kt)("li",{parentName:"ul"},"Run the following to verify the status of the tokens owned by ",(0,r.kt)("inlineCode",{parentName:"li"},"PartyA")," and ",(0,r.kt)("inlineCode",{parentName:"li"},"PartyB")," in the ",(0,r.kt)("inlineCode",{parentName:"li"},"Corda_Network")," and ",(0,r.kt)("inlineCode",{parentName:"li"},"Corda_Network2"),":",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"./scripts/getAssetStatus.sh 2\n")))),(0,r.kt)("p",null,"The above steps complete a successful asset exchange between two Corda networks.\nIn addition to the above commands, following commands can be run if specified timeout has expired and the locked asset remains unclaimed."),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"If ",(0,r.kt)("inlineCode",{parentName:"li"},"PartyA")," wants to unlock the token ",(0,r.kt)("inlineCode",{parentName:"li"},"t1:30")," asset, run the following to trigger ",(0,r.kt)("inlineCode",{parentName:"li"},"PartyA"),"'s re-claim in ",(0,r.kt)("inlineCode",{parentName:"li"},"Corda_Network"),":",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"CORDA_PORT=10006 ./clients/build/install/clients/bin/clients unlock-asset --contract-id=<contract-id-1>\n"))),(0,r.kt)("li",{parentName:"ul"},"If ",(0,r.kt)("inlineCode",{parentName:"li"},"PartyB")," wants to unlock the token ",(0,r.kt)("inlineCode",{parentName:"li"},"t2:50")," asset, run the following to trigger ",(0,r.kt)("inlineCode",{parentName:"li"},"PartyB"),"'s re-claim in ",(0,r.kt)("inlineCode",{parentName:"li"},"Corda_Network2"),":",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"CORDA_PORT=30009 ./clients/build/install/clients/bin/clients unlock-asset --contract-id=<contract-id-2>\n")))))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/935bcf2a.6f888297.js b/assets/js/935bcf2a.6f888297.js new file mode 100644 index 000000000..38fb84d7f --- /dev/null +++ b/assets/js/935bcf2a.6f888297.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[5914],{5680:(e,t,n)=>{n.d(t,{xA:()=>c,yg:()=>m});var a=n(6540);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,a,r=function(e,t){if(null==e)return{};var n,a,r={},i=Object.keys(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=a.createContext({}),d=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},c=function(e){var t=d(e.components);return a.createElement(s.Provider,{value:t},e.children)},p="mdxType",g={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},y=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),p=d(n),y=r,m=p["".concat(s,".").concat(y)]||p[y]||g[y]||i;return n?a.createElement(m,o(o({ref:t},c),{},{components:n})):a.createElement(m,o({ref:t},c))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,o=new Array(i);o[0]=y;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[p]="string"==typeof e?e:r,o[1]=l;for(var d=2;d<i;d++)o[d]=n[d];return a.createElement.apply(null,o)}return a.createElement.apply(null,n)}y.displayName="MDXCreateElement"},6997:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>g,frontMatter:()=>i,metadata:()=>l,toc:()=>d});var a=n(8168),r=(n(6540),n(5680));const i={id:"corda-corda",title:"Asset Exchange: Corda with Corda",sidebar_label:"Corda with Corda",pagination_label:"Corda with Corda",pagination_prev:"external/getting-started/interop/asset-exchange/overview"},o=void 0,l={unversionedId:"external/getting-started/interop/asset-exchange/corda-corda",id:"external/getting-started/interop/asset-exchange/corda-corda",title:"Asset Exchange: Corda with Corda",description:"We will demonstrate asset exchange of a tokens in CordaNetwork with tokens on CordaNetwork2. Here PartyA (CORDAPORT=10006) and PartyB (CORDAPORT=10009) in CordaNetwork correspond to PartyA (CORDAPORT=30006) and PartyB (CORDAPORT=30009) in CordaNetwork2 respectively. Following are the step-by-step asset exchange process:",source:"@site/docs/external/getting-started/interop/asset-exchange/corda-corda.md",sourceDirName:"external/getting-started/interop/asset-exchange",slug:"/external/getting-started/interop/asset-exchange/corda-corda",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/corda-corda",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/getting-started/interop/asset-exchange/corda-corda.md",tags:[],version:"current",frontMatter:{id:"corda-corda",title:"Asset Exchange: Corda with Corda",sidebar_label:"Corda with Corda",pagination_label:"Corda with Corda",pagination_prev:"external/getting-started/interop/asset-exchange/overview"},sidebar:"Documentation",previous:{title:"Asset Exchange",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview"},next:{title:"Corda with Besu",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/corda-besu"}},s={},d=[],c={toc:d},p="wrapper";function g(e){let{components:t,...n}=e;return(0,r.yg)(p,(0,a.A)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,r.yg)("p",null,"We will demonstrate asset exchange of a tokens in ",(0,r.yg)("inlineCode",{parentName:"p"},"Corda_Network")," with tokens on ",(0,r.yg)("inlineCode",{parentName:"p"},"Corda_Network2"),". Here ",(0,r.yg)("inlineCode",{parentName:"p"},"PartyA")," (",(0,r.yg)("inlineCode",{parentName:"p"},"CORDA_PORT=10006"),") and ",(0,r.yg)("inlineCode",{parentName:"p"},"PartyB")," (",(0,r.yg)("inlineCode",{parentName:"p"},"CORDA_PORT=10009"),") in ",(0,r.yg)("inlineCode",{parentName:"p"},"Corda_Network")," correspond to ",(0,r.yg)("inlineCode",{parentName:"p"},"PartyA")," (",(0,r.yg)("inlineCode",{parentName:"p"},"CORDA_PORT=30006"),") and ",(0,r.yg)("inlineCode",{parentName:"p"},"PartyB")," (",(0,r.yg)("inlineCode",{parentName:"p"},"CORDA_PORT=30009"),") in ",(0,r.yg)("inlineCode",{parentName:"p"},"Corda_Network2")," respectively. Following are the step-by-step asset exchange process:"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:"left"},"The hash used in following steps can be replaced by any valid ",(0,r.yg)("inlineCode",{parentName:"td"},"SHA256")," hash.")))),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"samples/corda/corda-simple-application")," folder in your clone of the Weaver repository."),(0,r.yg)("li",{parentName:"ul"},"Run the following to verify the status of the tokens owned by ",(0,r.yg)("inlineCode",{parentName:"li"},"PartyA")," and ",(0,r.yg)("inlineCode",{parentName:"li"},"PartyB")," in the ",(0,r.yg)("inlineCode",{parentName:"li"},"Corda_Network")," and ",(0,r.yg)("inlineCode",{parentName:"li"},"Corda_Network2"),":",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"./scripts/getAssetStatus.sh 2\n"))),(0,r.yg)("li",{parentName:"ul"},"Generate Secret-Hash Pair using following command (prints hash in base64):",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre"},"./clients/build/install/clients/bin/clients utils hash --hash-fn=SHA256 -s secrettext\n"))),(0,r.yg)("li",{parentName:"ul"},"Run the following to trigger ",(0,r.yg)("inlineCode",{parentName:"li"},"PartyA")," locking ",(0,r.yg)("inlineCode",{parentName:"li"},"30")," units of token type ",(0,r.yg)("inlineCode",{parentName:"li"},"t1")," for ",(0,r.yg)("inlineCode",{parentName:"li"},"PartyB")," in ",(0,r.yg)("inlineCode",{parentName:"li"},"Corda_Network")," for 60 mins:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},'CORDA_PORT=10006 ./clients/build/install/clients/bin/clients lock-asset --fungible --hashBase64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs= --timeout=3600 --recipient="O=PartyB,L=London,C=GB" --param=t1:30\n')),"Note the ",(0,r.yg)("inlineCode",{parentName:"li"},"contract-id")," displayed after successful execution of the command, will be used in next steps. The output containing ",(0,r.yg)("inlineCode",{parentName:"li"},"contract-id")," would like this:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"HTLC Lock State created with contract ID Right(b=10448674_80d2bee7-5a5d-45df-b14e-60bac4ba1bf3).\n")),(0,r.yg)("inlineCode",{parentName:"li"},"contract-id")," is the alphanumeric text (with underscore and hyphens) after ",(0,r.yg)("inlineCode",{parentName:"li"},"b=")," within parenthesis. Let's denote it ",(0,r.yg)("inlineCode",{parentName:"li"},"<contract-id-1>"),"."),(0,r.yg)("li",{parentName:"ul"},"Run the following to verify ",(0,r.yg)("inlineCode",{parentName:"li"},"PartyA"),"'s lock (can be verified by both parties):",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"CORDA_PORT=10009 ./clients/build/install/clients/bin/clients is-asset-locked --contract-id=<contract-id-1>\n"))),(0,r.yg)("li",{parentName:"ul"},"Run the following to trigger ",(0,r.yg)("inlineCode",{parentName:"li"},"PartyB")," locking ",(0,r.yg)("inlineCode",{parentName:"li"},"50")," units of token type ",(0,r.yg)("inlineCode",{parentName:"li"},"t2")," for ",(0,r.yg)("inlineCode",{parentName:"li"},"PartyA")," in ",(0,r.yg)("inlineCode",{parentName:"li"},"Corda_Network2")," for 30 mins:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},'CORDA_PORT=30009 ./clients/build/install/clients/bin/clients lock-asset --fungible --hashBase64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs= --timeout=1800 --recipient="O=PartyA,L=London,C=GB" --param=t2:50\n')),"Note the ",(0,r.yg)("inlineCode",{parentName:"li"},"contract-id")," displayed after successful execution of the command, will be used in next steps. Let's denote it ",(0,r.yg)("inlineCode",{parentName:"li"},"<contract-id-2>"),"."),(0,r.yg)("li",{parentName:"ul"},"Run the following to verify ",(0,r.yg)("inlineCode",{parentName:"li"},"PartyB"),"'s lock (can be verified by both parties):",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"CORDA_PORT=30006 ./clients/build/install/clients/bin/clients is-asset-locked --contract-id=<contract-id-2>\n"))),(0,r.yg)("li",{parentName:"ul"},"Run the following to trigger ",(0,r.yg)("inlineCode",{parentName:"li"},"PartyA"),"'s claim for ",(0,r.yg)("inlineCode",{parentName:"li"},"50")," units of token type ",(0,r.yg)("inlineCode",{parentName:"li"},"t2")," locked by ",(0,r.yg)("inlineCode",{parentName:"li"},"PartyB")," in ",(0,r.yg)("inlineCode",{parentName:"li"},"Corda_Network2"),":",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"CORDA_PORT=30006 ./clients/build/install/clients/bin/clients claim-asset --secret=secrettext --contract-id=<contract-id-2>\n")),(0,r.yg)("inlineCode",{parentName:"li"},"PartyB")," can see its node's logs to get the revealed hash preimage, and use it to claim the bond in the Fabric network."),(0,r.yg)("li",{parentName:"ul"},"Run the following to trigger ",(0,r.yg)("inlineCode",{parentName:"li"},"PartyB"),"'s claim for ",(0,r.yg)("inlineCode",{parentName:"li"},"30")," units of token type ",(0,r.yg)("inlineCode",{parentName:"li"},"t1")," locked by ",(0,r.yg)("inlineCode",{parentName:"li"},"PartyA")," in ",(0,r.yg)("inlineCode",{parentName:"li"},"Corda_Network"),":",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"CORDA_PORT=10009 ./clients/build/install/clients/bin/clients claim-asset --secret=secrettext --contract-id=<contract-id-1>\n"))),(0,r.yg)("li",{parentName:"ul"},"Run the following to verify the status of the tokens owned by ",(0,r.yg)("inlineCode",{parentName:"li"},"PartyA")," and ",(0,r.yg)("inlineCode",{parentName:"li"},"PartyB")," in the ",(0,r.yg)("inlineCode",{parentName:"li"},"Corda_Network")," and ",(0,r.yg)("inlineCode",{parentName:"li"},"Corda_Network2"),":",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"./scripts/getAssetStatus.sh 2\n")))),(0,r.yg)("p",null,"The above steps complete a successful asset exchange between two Corda networks.\nIn addition to the above commands, following commands can be run if specified timeout has expired and the locked asset remains unclaimed."),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"If ",(0,r.yg)("inlineCode",{parentName:"li"},"PartyA")," wants to unlock the token ",(0,r.yg)("inlineCode",{parentName:"li"},"t1:30")," asset, run the following to trigger ",(0,r.yg)("inlineCode",{parentName:"li"},"PartyA"),"'s re-claim in ",(0,r.yg)("inlineCode",{parentName:"li"},"Corda_Network"),":",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"CORDA_PORT=10006 ./clients/build/install/clients/bin/clients unlock-asset --contract-id=<contract-id-1>\n"))),(0,r.yg)("li",{parentName:"ul"},"If ",(0,r.yg)("inlineCode",{parentName:"li"},"PartyB")," wants to unlock the token ",(0,r.yg)("inlineCode",{parentName:"li"},"t2:50")," asset, run the following to trigger ",(0,r.yg)("inlineCode",{parentName:"li"},"PartyB"),"'s re-claim in ",(0,r.yg)("inlineCode",{parentName:"li"},"Corda_Network2"),":",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"CORDA_PORT=30009 ./clients/build/install/clients/bin/clients unlock-asset --contract-id=<contract-id-2>\n")))))}g.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/935f2afb.1a177595.js b/assets/js/935f2afb.1a177595.js deleted file mode 100644 index e25bb1f7b..000000000 --- a/assets/js/935f2afb.1a177595.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[53],{1109:e=>{e.exports=JSON.parse('{"pluginId":"default","version":"current","label":"Next","banner":null,"badge":false,"noIndex":false,"className":"docs-version-current","isLast":true,"docsSidebars":{"Documentation":[{"type":"link","label":"Weaver Framework","href":"/weaver-dlt-interoperability/docs/external/introduction","docId":"external/introduction"},{"type":"category","label":"Getting Started","items":[{"type":"link","label":"Using Weaver","href":"/weaver-dlt-interoperability/docs/external/getting-started/guide","docId":"external/getting-started/guide"},{"type":"category","label":"Launching a Test Network","items":[{"type":"link","label":"Component Overview","href":"/weaver-dlt-interoperability/docs/external/getting-started/test-network/overview","docId":"external/getting-started/test-network/overview"},{"type":"link","label":"Setup with Locally Built Weaver Components","href":"/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-local","docId":"external/getting-started/test-network/setup-local"},{"type":"link","label":"Setup with Locally Built Dockerized Weaver Components","href":"/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-local-docker","docId":"external/getting-started/test-network/setup-local-docker"},{"type":"link","label":"Setup with Imported Weaver Components","href":"/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-packages","docId":"external/getting-started/test-network/setup-packages"},{"type":"link","label":"Setup with Imported Dockerized Weaver Components","href":"/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-packages-docker","docId":"external/getting-started/test-network/setup-packages-docker"},{"type":"link","label":"Ledger Initialization","href":"/weaver-dlt-interoperability/docs/external/getting-started/test-network/ledger-initialization","docId":"external/getting-started/test-network/ledger-initialization"},{"type":"link","label":"Advanced Configuration","href":"/weaver-dlt-interoperability/docs/external/getting-started/test-network/advanced-configuration","docId":"external/getting-started/test-network/advanced-configuration"}],"collapsed":true,"collapsible":true},{"type":"category","label":"Testing Interoperation Modes","items":[{"type":"link","label":"Overview","href":"/weaver-dlt-interoperability/docs/external/getting-started/interop/overview","docId":"external/getting-started/interop/overview"},{"type":"link","label":"Data Sharing","href":"/weaver-dlt-interoperability/docs/external/getting-started/interop/data-sharing","docId":"external/getting-started/interop/data-sharing"},{"type":"category","label":"Asset Exchange","items":[{"type":"link","label":"Overview","href":"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview","docId":"external/getting-started/interop/asset-exchange/overview"},{"type":"link","label":"Fabric with Fabric","href":"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-fabric","docId":"external/getting-started/interop/asset-exchange/fabric-fabric"},{"type":"link","label":"Fabric with Corda","href":"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-corda","docId":"external/getting-started/interop/asset-exchange/fabric-corda"},{"type":"link","label":"Fabric with Besu","href":"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-besu","docId":"external/getting-started/interop/asset-exchange/fabric-besu"},{"type":"link","label":"Corda with Corda","href":"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/corda-corda","docId":"external/getting-started/interop/asset-exchange/corda-corda"},{"type":"link","label":"Corda with Besu","href":"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/corda-besu","docId":"external/getting-started/interop/asset-exchange/corda-besu"},{"type":"link","label":"Besu with Besu","href":"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/besu-besu","docId":"external/getting-started/interop/asset-exchange/besu-besu"}],"collapsed":true,"collapsible":true},{"type":"link","label":"Asset Transfer","href":"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-transfer","docId":"external/getting-started/interop/asset-transfer"}],"collapsed":true,"collapsible":true},{"type":"category","label":"Enabling Weaver in your Network and Application","items":[{"type":"link","label":"Overview","href":"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/overview","docId":"external/getting-started/enabling-weaver-network/overview"},{"type":"link","label":"Hyperledger Fabric","href":"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/fabric","docId":"external/getting-started/enabling-weaver-network/fabric"},{"type":"link","label":"Corda","href":"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/corda","docId":"external/getting-started/enabling-weaver-network/corda"},{"type":"link","label":"Hyperledger Besu","href":"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/besu","docId":"external/getting-started/enabling-weaver-network/besu"}],"collapsed":true,"collapsible":true}],"collapsed":true,"collapsible":true},{"type":"category","label":"What is Interoperability?","items":[{"type":"link","label":"Understanding Interoperability","href":"/weaver-dlt-interoperability/docs/external/what-is-interoperability/understanding-interoperability","docId":"external/what-is-interoperability/understanding-interoperability"},{"type":"link","label":"Levels of Interoperability","href":"/weaver-dlt-interoperability/docs/external/what-is-interoperability/levels-of-interoperability","docId":"external/what-is-interoperability/levels-of-interoperability"},{"type":"link","label":"Integration Patterns","href":"/weaver-dlt-interoperability/docs/external/what-is-interoperability/integration-patterns","docId":"external/what-is-interoperability/integration-patterns"}],"collapsed":true,"collapsible":true},{"type":"link","label":"Interoperability Modes","href":"/weaver-dlt-interoperability/docs/external/interoperability-modes","docId":"external/interoperability-modes"},{"type":"link","label":"Design Principles","href":"/weaver-dlt-interoperability/docs/external/design-principles","docId":"external/design-principles"},{"type":"category","label":"User Stories","items":[{"type":"link","label":"Overview","href":"/weaver-dlt-interoperability/docs/external/user-stories/overview","docId":"external/user-stories/overview"},{"type":"link","label":"Global Trade","href":"/weaver-dlt-interoperability/docs/external/user-stories/global-trade","docId":"external/user-stories/global-trade"},{"type":"link","label":"DvP in Financial Markets","href":"/weaver-dlt-interoperability/docs/external/user-stories/financial-markets","docId":"external/user-stories/financial-markets"},{"type":"link","label":"Legacy Integration","href":"/weaver-dlt-interoperability/docs/external/user-stories/legacy-integration","docId":"external/user-stories/legacy-integration"}],"collapsed":true,"collapsible":true},{"type":"category","label":"Architecture and Design","items":[{"type":"link","label":"Overview","href":"/weaver-dlt-interoperability/docs/external/architecture-and-design/overview","docId":"external/architecture-and-design/overview"},{"type":"link","label":"Relay","href":"/weaver-dlt-interoperability/docs/external/architecture-and-design/relay","docId":"external/architecture-and-design/relay"},{"type":"link","label":"Drivers","href":"/weaver-dlt-interoperability/docs/external/architecture-and-design/drivers","docId":"external/architecture-and-design/drivers"},{"type":"link","label":"Weaver Dapps","href":"/weaver-dlt-interoperability/docs/external/architecture-and-design/weaver-dapps","docId":"external/architecture-and-design/weaver-dapps"},{"type":"link","label":"Decentralized Identity","href":"/weaver-dlt-interoperability/docs/external/architecture-and-design/decentralized-identity","docId":"external/architecture-and-design/decentralized-identity"}],"collapsed":true,"collapsible":true},{"type":"category","label":"Security Model","items":[{"type":"link","label":"Authentication","href":"/weaver-dlt-interoperability/docs/external/security-model/authentication","docId":"external/security-model/authentication"},{"type":"link","label":"Access Control","href":"/weaver-dlt-interoperability/docs/external/security-model/access-control","docId":"external/security-model/access-control"},{"type":"link","label":"Proofs and Verification","href":"/weaver-dlt-interoperability/docs/external/security-model/proofs-and-verification","docId":"external/security-model/proofs-and-verification"},{"type":"link","label":"End-to-End Security","href":"/weaver-dlt-interoperability/docs/external/security-model/end-to-end-security","docId":"external/security-model/end-to-end-security"}],"collapsed":true,"collapsible":true},{"type":"category","label":"Deployment Considerations","items":[{"type":"link","label":"Deployment Patterns","href":"/weaver-dlt-interoperability/docs/external/deployment-considerations/deployment-patterns","docId":"external/deployment-considerations/deployment-patterns"},{"type":"link","label":"Governance and Policies","href":"/weaver-dlt-interoperability/docs/external/deployment-considerations/governance-and-policies","docId":"external/deployment-considerations/governance-and-policies"},{"type":"link","label":"Legal and Regulation","href":"/weaver-dlt-interoperability/docs/external/deployment-considerations/legal-and-regulation","docId":"external/deployment-considerations/legal-and-regulation"}],"collapsed":true,"collapsible":true},{"type":"link","label":"Specifications","href":"/weaver-dlt-interoperability/docs/external/specifications","docId":"external/specifications"},{"type":"link","label":"Roadmap","href":"/weaver-dlt-interoperability/docs/external/roadmap","docId":"external/roadmap"},{"type":"link","label":"Publications","href":"/weaver-dlt-interoperability/docs/external/publications","docId":"external/publications"}]},"docs":{"external/architecture-and-design/decentralized-identity":{"id":"external/architecture-and-design/decentralized-identity","title":"Decentralized Identity","description":"\x3c!--","sidebar":"Documentation"},"external/architecture-and-design/drivers":{"id":"external/architecture-and-design/drivers","title":"Drivers","description":"\x3c!--","sidebar":"Documentation"},"external/architecture-and-design/overview":{"id":"external/architecture-and-design/overview","title":"Overview","description":"\x3c!--","sidebar":"Documentation"},"external/architecture-and-design/relay":{"id":"external/architecture-and-design/relay","title":"Relay","description":"\x3c!--","sidebar":"Documentation"},"external/architecture-and-design/weaver-dapps":{"id":"external/architecture-and-design/weaver-dapps","title":"Weaver Dapps","description":"\x3c!--","sidebar":"Documentation"},"external/deployment-considerations/deployment-patterns":{"id":"external/deployment-considerations/deployment-patterns","title":"Deployment Patterns","description":"\x3c!--","sidebar":"Documentation"},"external/deployment-considerations/governance-and-policies":{"id":"external/deployment-considerations/governance-and-policies","title":"Governance and Policies","description":"\x3c!--","sidebar":"Documentation"},"external/deployment-considerations/legal-and-regulation":{"id":"external/deployment-considerations/legal-and-regulation","title":"Legal and Regulation","description":"\x3c!--","sidebar":"Documentation"},"external/design-principles":{"id":"external/design-principles","title":"Design Principles","description":"\x3c!--","sidebar":"Documentation"},"external/getting-started/enabling-weaver-network/besu":{"id":"external/getting-started/enabling-weaver-network/besu","title":"Hyperledger Besu","description":"\x3c!--","sidebar":"Documentation"},"external/getting-started/enabling-weaver-network/corda":{"id":"external/getting-started/enabling-weaver-network/corda","title":"Corda","description":"\x3c!--","sidebar":"Documentation"},"external/getting-started/enabling-weaver-network/fabric":{"id":"external/getting-started/enabling-weaver-network/fabric","title":"Hyperledger Fabric","description":"\x3c!--","sidebar":"Documentation"},"external/getting-started/enabling-weaver-network/overview":{"id":"external/getting-started/enabling-weaver-network/overview","title":"Enabling Weaver in Existing DLT Applications Overview","description":"\x3c!--","sidebar":"Documentation"},"external/getting-started/guide":{"id":"external/getting-started/guide","title":"Using Weaver","description":"\x3c!--","sidebar":"Documentation"},"external/getting-started/interop/asset-exchange":{"id":"external/getting-started/interop/asset-exchange","title":"Asset Exchange","description":"\x3c!--"},"external/getting-started/interop/asset-exchange/besu-besu":{"id":"external/getting-started/interop/asset-exchange/besu-besu","title":"Asset Exchange: Besu with Besu","description":"We divide this page into two sections, if you used default configuration in ledger initialization step, then go to section AliceERC721 with BobERC20, otherwise if you used hybrid tokens in network, then go to section AliceERC1155 with BobERC20","sidebar":"Documentation"},"external/getting-started/interop/asset-exchange/corda-besu":{"id":"external/getting-started/interop/asset-exchange/corda-besu","title":"Asset Exchange: Corda with Besu","description":"We will demonstrate asset exchange of an AliceERC721 NFT in Besu network1 with 10 tokens on Corda_Network.","sidebar":"Documentation"},"external/getting-started/interop/asset-exchange/corda-corda":{"id":"external/getting-started/interop/asset-exchange/corda-corda","title":"Asset Exchange: Corda with Corda","description":"We will demonstrate asset exchange of a tokens in CordaNetwork with tokens on CordaNetwork2. Here PartyA (CORDAPORT=10006) and PartyB (CORDAPORT=10009) in CordaNetwork correspond to PartyA (CORDAPORT=30006) and PartyB (CORDAPORT=30009) in CordaNetwork2 respectively. Following are the step-by-step asset exchange process:","sidebar":"Documentation"},"external/getting-started/interop/asset-exchange/fabric-besu":{"id":"external/getting-started/interop/asset-exchange/fabric-besu","title":"Asset Exchange: Fabric with Besu","description":"We will demonstrate asset exchange of a bond in Fabric network1 with 10 BobERC20 tokens on Besu network2.","sidebar":"Documentation"},"external/getting-started/interop/asset-exchange/fabric-corda":{"id":"external/getting-started/interop/asset-exchange/fabric-corda","title":"Asset Exchange: Fabric with Corda","description":"We will demonstrate asset exchange of a bond in Fabric network1 with tokens on Corda_Network.","sidebar":"Documentation"},"external/getting-started/interop/asset-exchange/fabric-fabric":{"id":"external/getting-started/interop/asset-exchange/fabric-fabric","title":"Asset Exchange: Fabric with Fabric","description":"One Fabric network transfers a bond from Alice to Bob in exchange for a transfer of tokens from Bob to Alice in the other network","sidebar":"Documentation"},"external/getting-started/interop/asset-exchange/overview":{"id":"external/getting-started/interop/asset-exchange/overview","title":"Asset Exchange","description":"\x3c!--","sidebar":"Documentation"},"external/getting-started/interop/asset-transfer":{"id":"external/getting-started/interop/asset-transfer","title":"Asset Transfer","description":"\x3c!--","sidebar":"Documentation"},"external/getting-started/interop/data-sharing":{"id":"external/getting-started/interop/data-sharing","title":"Data Sharing","description":"\x3c!--","sidebar":"Documentation"},"external/getting-started/interop/overview":{"id":"external/getting-started/interop/overview","title":"Testing Interoperation Modes Overview","description":"\x3c!--","sidebar":"Documentation"},"external/getting-started/test-network/advanced-configuration":{"id":"external/getting-started/test-network/advanced-configuration","title":"Advanced Configuration","description":"\x3c!--","sidebar":"Documentation"},"external/getting-started/test-network/ledger-initialization":{"id":"external/getting-started/test-network/ledger-initialization","title":"Ledger Initialization","description":"\x3c!--","sidebar":"Documentation"},"external/getting-started/test-network/overview":{"id":"external/getting-started/test-network/overview","title":"Component Overview","description":"\x3c!--","sidebar":"Documentation"},"external/getting-started/test-network/setup-local":{"id":"external/getting-started/test-network/setup-local","title":"Setup with Locally Built Weaver Components","description":"\x3c!--","sidebar":"Documentation"},"external/getting-started/test-network/setup-local-docker":{"id":"external/getting-started/test-network/setup-local-docker","title":"Setup with Locally Built Dockerized Weaver Components","description":"\x3c!--","sidebar":"Documentation"},"external/getting-started/test-network/setup-packages":{"id":"external/getting-started/test-network/setup-packages","title":"Setup with Imported Weaver Components","description":"\x3c!--","sidebar":"Documentation"},"external/getting-started/test-network/setup-packages-docker":{"id":"external/getting-started/test-network/setup-packages-docker","title":"Setup with Imported Dockerized Weaver Components","description":"\x3c!--","sidebar":"Documentation"},"external/interoperability-modes":{"id":"external/interoperability-modes","title":"Interoperability Modes","description":"\x3c!--","sidebar":"Documentation"},"external/introduction":{"id":"external/introduction","title":"Weaver Framework","description":"\x3c!--","sidebar":"Documentation"},"external/publications":{"id":"external/publications","title":"Publications","description":"\x3c!--","sidebar":"Documentation"},"external/roadmap":{"id":"external/roadmap","title":"Roadmap","description":"\x3c!--","sidebar":"Documentation"},"external/security-model/access-control":{"id":"external/security-model/access-control","title":"Access Control","description":"\x3c!--","sidebar":"Documentation"},"external/security-model/authentication":{"id":"external/security-model/authentication","title":"Authentication","description":"\x3c!--","sidebar":"Documentation"},"external/security-model/end-to-end-security":{"id":"external/security-model/end-to-end-security","title":"End-to-End Security","description":"\x3c!--","sidebar":"Documentation"},"external/security-model/proofs-and-verification":{"id":"external/security-model/proofs-and-verification","title":"Proofs and Verification","description":"\x3c!--","sidebar":"Documentation"},"external/specifications":{"id":"external/specifications","title":"Specifications","description":"\x3c!--","sidebar":"Documentation"},"external/user-stories/financial-markets":{"id":"external/user-stories/financial-markets","title":"DvP in Financial Markets","description":"\x3c!--","sidebar":"Documentation"},"external/user-stories/global-trade":{"id":"external/user-stories/global-trade","title":"Global Trade","description":"\x3c!--","sidebar":"Documentation"},"external/user-stories/legacy-integration":{"id":"external/user-stories/legacy-integration","title":"Legacy Integration","description":"\x3c!--","sidebar":"Documentation"},"external/user-stories/overview":{"id":"external/user-stories/overview","title":"Overview","description":"\x3c!--","sidebar":"Documentation"},"external/what-is-interoperability/integration-patterns":{"id":"external/what-is-interoperability/integration-patterns","title":"Integration Patterns","description":"\x3c!--","sidebar":"Documentation"},"external/what-is-interoperability/levels-of-interoperability":{"id":"external/what-is-interoperability/levels-of-interoperability","title":"Levels of Interoperability","description":"\x3c!--","sidebar":"Documentation"},"external/what-is-interoperability/understanding-interoperability":{"id":"external/what-is-interoperability/understanding-interoperability","title":"Understanding Interoperability","description":"\x3c!--","sidebar":"Documentation"},"internal/activity-plan":{"id":"internal/activity-plan","title":"activity-plan","description":"\x3c!--"},"internal/development/cordapp-interop/cordapp-interop":{"id":"internal/development/cordapp-interop/cordapp-interop","title":"cordapp-interop","description":"\x3c!--"},"internal/development/cordapp-interop/cordapp-interop-api-assets":{"id":"internal/development/cordapp-interop/cordapp-interop-api-assets","title":"cordapp-interop-api-assets","description":"\x3c!--"},"internal/development/cordapp-interop/cordapp-interop-assets":{"id":"internal/development/cordapp-interop/cordapp-interop-assets","title":"cordapp-interop-assets","description":"\x3c!--"},"internal/development/cordapp-interop/cordapp-interop-flows":{"id":"internal/development/cordapp-interop/cordapp-interop-flows","title":"cordapp-interop-flows","description":"\x3c!--"},"internal/development/cordapp-interop/cordapp-interop-rest-api":{"id":"internal/development/cordapp-interop/cordapp-interop-rest-api","title":"cordapp-interop-rest-api","description":"\x3c!--"},"internal/documentation-guidelines":{"id":"internal/documentation-guidelines","title":"documentation-guidelines","description":"\x3c!--"},"internal/team":{"id":"internal/team","title":"team","description":"\x3c!--"}}}')}}]); \ No newline at end of file diff --git a/assets/js/935f2afb.637f96e7.js b/assets/js/935f2afb.637f96e7.js new file mode 100644 index 000000000..39e549247 --- /dev/null +++ b/assets/js/935f2afb.637f96e7.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[8581],{5610:e=>{e.exports=JSON.parse('{"pluginId":"default","version":"current","label":"Next","banner":null,"badge":false,"noIndex":false,"className":"docs-version-current","isLast":true,"docsSidebars":{"Documentation":[{"type":"link","label":"Weaver Framework","href":"/weaver-dlt-interoperability/docs/external/introduction","docId":"external/introduction"},{"type":"category","label":"Getting Started","items":[{"type":"link","label":"Using Weaver","href":"/weaver-dlt-interoperability/docs/external/getting-started/guide","docId":"external/getting-started/guide"},{"type":"category","label":"Launching a Test Network","items":[{"type":"link","label":"Component Overview","href":"/weaver-dlt-interoperability/docs/external/getting-started/test-network/overview","docId":"external/getting-started/test-network/overview"},{"type":"link","label":"Setup with Locally Built Weaver Components","href":"/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-local","docId":"external/getting-started/test-network/setup-local"},{"type":"link","label":"Setup with Locally Built Dockerized Weaver Components","href":"/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-local-docker","docId":"external/getting-started/test-network/setup-local-docker"},{"type":"link","label":"Setup with Imported Weaver Components","href":"/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-packages","docId":"external/getting-started/test-network/setup-packages"},{"type":"link","label":"Setup with Imported Dockerized Weaver Components","href":"/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-packages-docker","docId":"external/getting-started/test-network/setup-packages-docker"},{"type":"link","label":"Ledger Initialization","href":"/weaver-dlt-interoperability/docs/external/getting-started/test-network/ledger-initialization","docId":"external/getting-started/test-network/ledger-initialization"},{"type":"link","label":"Advanced Configuration","href":"/weaver-dlt-interoperability/docs/external/getting-started/test-network/advanced-configuration","docId":"external/getting-started/test-network/advanced-configuration"}],"collapsed":true,"collapsible":true},{"type":"category","label":"Testing Interoperation Modes","items":[{"type":"link","label":"Overview","href":"/weaver-dlt-interoperability/docs/external/getting-started/interop/overview","docId":"external/getting-started/interop/overview"},{"type":"link","label":"Data Sharing","href":"/weaver-dlt-interoperability/docs/external/getting-started/interop/data-sharing","docId":"external/getting-started/interop/data-sharing"},{"type":"category","label":"Asset Exchange","items":[{"type":"link","label":"Overview","href":"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview","docId":"external/getting-started/interop/asset-exchange/overview"},{"type":"link","label":"Fabric with Fabric","href":"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-fabric","docId":"external/getting-started/interop/asset-exchange/fabric-fabric"},{"type":"link","label":"Fabric with Corda","href":"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-corda","docId":"external/getting-started/interop/asset-exchange/fabric-corda"},{"type":"link","label":"Fabric with Besu","href":"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-besu","docId":"external/getting-started/interop/asset-exchange/fabric-besu"},{"type":"link","label":"Corda with Corda","href":"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/corda-corda","docId":"external/getting-started/interop/asset-exchange/corda-corda"},{"type":"link","label":"Corda with Besu","href":"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/corda-besu","docId":"external/getting-started/interop/asset-exchange/corda-besu"},{"type":"link","label":"Besu with Besu","href":"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/besu-besu","docId":"external/getting-started/interop/asset-exchange/besu-besu"}],"collapsed":true,"collapsible":true},{"type":"link","label":"Asset Transfer","href":"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-transfer","docId":"external/getting-started/interop/asset-transfer"}],"collapsed":true,"collapsible":true},{"type":"category","label":"Enabling Weaver in your Network and Application","items":[{"type":"link","label":"Overview","href":"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/overview","docId":"external/getting-started/enabling-weaver-network/overview"},{"type":"link","label":"Hyperledger Fabric","href":"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/fabric","docId":"external/getting-started/enabling-weaver-network/fabric"},{"type":"link","label":"Corda","href":"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/corda","docId":"external/getting-started/enabling-weaver-network/corda"},{"type":"link","label":"Hyperledger Besu","href":"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/besu","docId":"external/getting-started/enabling-weaver-network/besu"}],"collapsed":true,"collapsible":true}],"collapsed":true,"collapsible":true},{"type":"category","label":"What is Interoperability?","items":[{"type":"link","label":"Understanding Interoperability","href":"/weaver-dlt-interoperability/docs/external/what-is-interoperability/understanding-interoperability","docId":"external/what-is-interoperability/understanding-interoperability"},{"type":"link","label":"Levels of Interoperability","href":"/weaver-dlt-interoperability/docs/external/what-is-interoperability/levels-of-interoperability","docId":"external/what-is-interoperability/levels-of-interoperability"},{"type":"link","label":"Integration Patterns","href":"/weaver-dlt-interoperability/docs/external/what-is-interoperability/integration-patterns","docId":"external/what-is-interoperability/integration-patterns"}],"collapsed":true,"collapsible":true},{"type":"link","label":"Interoperability Modes","href":"/weaver-dlt-interoperability/docs/external/interoperability-modes","docId":"external/interoperability-modes"},{"type":"link","label":"Design Principles","href":"/weaver-dlt-interoperability/docs/external/design-principles","docId":"external/design-principles"},{"type":"category","label":"User Stories","items":[{"type":"link","label":"Overview","href":"/weaver-dlt-interoperability/docs/external/user-stories/overview","docId":"external/user-stories/overview"},{"type":"link","label":"Global Trade","href":"/weaver-dlt-interoperability/docs/external/user-stories/global-trade","docId":"external/user-stories/global-trade"},{"type":"link","label":"DvP in Financial Markets","href":"/weaver-dlt-interoperability/docs/external/user-stories/financial-markets","docId":"external/user-stories/financial-markets"},{"type":"link","label":"Legacy Integration","href":"/weaver-dlt-interoperability/docs/external/user-stories/legacy-integration","docId":"external/user-stories/legacy-integration"}],"collapsed":true,"collapsible":true},{"type":"category","label":"Architecture and Design","items":[{"type":"link","label":"Overview","href":"/weaver-dlt-interoperability/docs/external/architecture-and-design/overview","docId":"external/architecture-and-design/overview"},{"type":"link","label":"Relay","href":"/weaver-dlt-interoperability/docs/external/architecture-and-design/relay","docId":"external/architecture-and-design/relay"},{"type":"link","label":"Drivers","href":"/weaver-dlt-interoperability/docs/external/architecture-and-design/drivers","docId":"external/architecture-and-design/drivers"},{"type":"link","label":"Weaver Dapps","href":"/weaver-dlt-interoperability/docs/external/architecture-and-design/weaver-dapps","docId":"external/architecture-and-design/weaver-dapps"},{"type":"link","label":"Decentralized Identity","href":"/weaver-dlt-interoperability/docs/external/architecture-and-design/decentralized-identity","docId":"external/architecture-and-design/decentralized-identity"}],"collapsed":true,"collapsible":true},{"type":"category","label":"Security Model","items":[{"type":"link","label":"Authentication","href":"/weaver-dlt-interoperability/docs/external/security-model/authentication","docId":"external/security-model/authentication"},{"type":"link","label":"Access Control","href":"/weaver-dlt-interoperability/docs/external/security-model/access-control","docId":"external/security-model/access-control"},{"type":"link","label":"Proofs and Verification","href":"/weaver-dlt-interoperability/docs/external/security-model/proofs-and-verification","docId":"external/security-model/proofs-and-verification"},{"type":"link","label":"End-to-End Security","href":"/weaver-dlt-interoperability/docs/external/security-model/end-to-end-security","docId":"external/security-model/end-to-end-security"}],"collapsed":true,"collapsible":true},{"type":"category","label":"Deployment Considerations","items":[{"type":"link","label":"Deployment Patterns","href":"/weaver-dlt-interoperability/docs/external/deployment-considerations/deployment-patterns","docId":"external/deployment-considerations/deployment-patterns"},{"type":"link","label":"Governance and Policies","href":"/weaver-dlt-interoperability/docs/external/deployment-considerations/governance-and-policies","docId":"external/deployment-considerations/governance-and-policies"},{"type":"link","label":"Legal and Regulation","href":"/weaver-dlt-interoperability/docs/external/deployment-considerations/legal-and-regulation","docId":"external/deployment-considerations/legal-and-regulation"}],"collapsed":true,"collapsible":true},{"type":"link","label":"Specifications","href":"/weaver-dlt-interoperability/docs/external/specifications","docId":"external/specifications"},{"type":"link","label":"Roadmap","href":"/weaver-dlt-interoperability/docs/external/roadmap","docId":"external/roadmap"},{"type":"link","label":"Publications","href":"/weaver-dlt-interoperability/docs/external/publications","docId":"external/publications"}]},"docs":{"external/architecture-and-design/decentralized-identity":{"id":"external/architecture-and-design/decentralized-identity","title":"Decentralized Identity","description":"\x3c!--","sidebar":"Documentation"},"external/architecture-and-design/drivers":{"id":"external/architecture-and-design/drivers","title":"Drivers","description":"\x3c!--","sidebar":"Documentation"},"external/architecture-and-design/overview":{"id":"external/architecture-and-design/overview","title":"Overview","description":"\x3c!--","sidebar":"Documentation"},"external/architecture-and-design/relay":{"id":"external/architecture-and-design/relay","title":"Relay","description":"\x3c!--","sidebar":"Documentation"},"external/architecture-and-design/weaver-dapps":{"id":"external/architecture-and-design/weaver-dapps","title":"Weaver Dapps","description":"\x3c!--","sidebar":"Documentation"},"external/deployment-considerations/deployment-patterns":{"id":"external/deployment-considerations/deployment-patterns","title":"Deployment Patterns","description":"\x3c!--","sidebar":"Documentation"},"external/deployment-considerations/governance-and-policies":{"id":"external/deployment-considerations/governance-and-policies","title":"Governance and Policies","description":"\x3c!--","sidebar":"Documentation"},"external/deployment-considerations/legal-and-regulation":{"id":"external/deployment-considerations/legal-and-regulation","title":"Legal and Regulation","description":"\x3c!--","sidebar":"Documentation"},"external/design-principles":{"id":"external/design-principles","title":"Design Principles","description":"\x3c!--","sidebar":"Documentation"},"external/getting-started/enabling-weaver-network/besu":{"id":"external/getting-started/enabling-weaver-network/besu","title":"Hyperledger Besu","description":"\x3c!--","sidebar":"Documentation"},"external/getting-started/enabling-weaver-network/corda":{"id":"external/getting-started/enabling-weaver-network/corda","title":"Corda","description":"\x3c!--","sidebar":"Documentation"},"external/getting-started/enabling-weaver-network/fabric":{"id":"external/getting-started/enabling-weaver-network/fabric","title":"Hyperledger Fabric","description":"\x3c!--","sidebar":"Documentation"},"external/getting-started/enabling-weaver-network/overview":{"id":"external/getting-started/enabling-weaver-network/overview","title":"Enabling Weaver in Existing DLT Applications Overview","description":"\x3c!--","sidebar":"Documentation"},"external/getting-started/guide":{"id":"external/getting-started/guide","title":"Using Weaver","description":"\x3c!--","sidebar":"Documentation"},"external/getting-started/interop/asset-exchange/besu-besu":{"id":"external/getting-started/interop/asset-exchange/besu-besu","title":"Asset Exchange: Besu with Besu","description":"We divide this page into two sections, if you used default configuration in ledger initialization step, then go to section AliceERC721 with BobERC20, otherwise if you used hybrid tokens in network, then go to section AliceERC1155 with BobERC20","sidebar":"Documentation"},"external/getting-started/interop/asset-exchange/corda-besu":{"id":"external/getting-started/interop/asset-exchange/corda-besu","title":"Asset Exchange: Corda with Besu","description":"We will demonstrate asset exchange of an AliceERC721 NFT in Besu network1 with 10 tokens on Corda_Network.","sidebar":"Documentation"},"external/getting-started/interop/asset-exchange/corda-corda":{"id":"external/getting-started/interop/asset-exchange/corda-corda","title":"Asset Exchange: Corda with Corda","description":"We will demonstrate asset exchange of a tokens in CordaNetwork with tokens on CordaNetwork2. Here PartyA (CORDAPORT=10006) and PartyB (CORDAPORT=10009) in CordaNetwork correspond to PartyA (CORDAPORT=30006) and PartyB (CORDAPORT=30009) in CordaNetwork2 respectively. Following are the step-by-step asset exchange process:","sidebar":"Documentation"},"external/getting-started/interop/asset-exchange/fabric-besu":{"id":"external/getting-started/interop/asset-exchange/fabric-besu","title":"Asset Exchange: Fabric with Besu","description":"We will demonstrate asset exchange of a bond in Fabric network1 with 10 BobERC20 tokens on Besu network2.","sidebar":"Documentation"},"external/getting-started/interop/asset-exchange/fabric-corda":{"id":"external/getting-started/interop/asset-exchange/fabric-corda","title":"Asset Exchange: Fabric with Corda","description":"We will demonstrate asset exchange of a bond in Fabric network1 with tokens on Corda_Network.","sidebar":"Documentation"},"external/getting-started/interop/asset-exchange/fabric-fabric":{"id":"external/getting-started/interop/asset-exchange/fabric-fabric","title":"Asset Exchange: Fabric with Fabric","description":"One Fabric network transfers a bond from Alice to Bob in exchange for a transfer of tokens from Bob to Alice in the other network","sidebar":"Documentation"},"external/getting-started/interop/asset-exchange/overview":{"id":"external/getting-started/interop/asset-exchange/overview","title":"Asset Exchange","description":"\x3c!--","sidebar":"Documentation"},"external/getting-started/interop/asset-transfer":{"id":"external/getting-started/interop/asset-transfer","title":"Asset Transfer","description":"\x3c!--","sidebar":"Documentation"},"external/getting-started/interop/data-sharing":{"id":"external/getting-started/interop/data-sharing","title":"Data Sharing","description":"\x3c!--","sidebar":"Documentation"},"external/getting-started/interop/overview":{"id":"external/getting-started/interop/overview","title":"Testing Interoperation Modes Overview","description":"\x3c!--","sidebar":"Documentation"},"external/getting-started/test-network/advanced-configuration":{"id":"external/getting-started/test-network/advanced-configuration","title":"Advanced Configuration","description":"\x3c!--","sidebar":"Documentation"},"external/getting-started/test-network/ledger-initialization":{"id":"external/getting-started/test-network/ledger-initialization","title":"Ledger Initialization","description":"\x3c!--","sidebar":"Documentation"},"external/getting-started/test-network/overview":{"id":"external/getting-started/test-network/overview","title":"Component Overview","description":"\x3c!--","sidebar":"Documentation"},"external/getting-started/test-network/setup-local":{"id":"external/getting-started/test-network/setup-local","title":"Setup with Locally Built Weaver Components","description":"\x3c!--","sidebar":"Documentation"},"external/getting-started/test-network/setup-local-docker":{"id":"external/getting-started/test-network/setup-local-docker","title":"Setup with Locally Built Dockerized Weaver Components","description":"\x3c!--","sidebar":"Documentation"},"external/getting-started/test-network/setup-packages":{"id":"external/getting-started/test-network/setup-packages","title":"Setup with Imported Weaver Components","description":"\x3c!--","sidebar":"Documentation"},"external/getting-started/test-network/setup-packages-docker":{"id":"external/getting-started/test-network/setup-packages-docker","title":"Setup with Imported Dockerized Weaver Components","description":"\x3c!--","sidebar":"Documentation"},"external/interoperability-modes":{"id":"external/interoperability-modes","title":"Interoperability Modes","description":"\x3c!--","sidebar":"Documentation"},"external/introduction":{"id":"external/introduction","title":"Weaver Framework","description":"\x3c!--","sidebar":"Documentation"},"external/publications":{"id":"external/publications","title":"Publications","description":"\x3c!--","sidebar":"Documentation"},"external/roadmap":{"id":"external/roadmap","title":"Roadmap","description":"\x3c!--","sidebar":"Documentation"},"external/security-model/access-control":{"id":"external/security-model/access-control","title":"Access Control","description":"\x3c!--","sidebar":"Documentation"},"external/security-model/authentication":{"id":"external/security-model/authentication","title":"Authentication","description":"\x3c!--","sidebar":"Documentation"},"external/security-model/end-to-end-security":{"id":"external/security-model/end-to-end-security","title":"End-to-End Security","description":"\x3c!--","sidebar":"Documentation"},"external/security-model/proofs-and-verification":{"id":"external/security-model/proofs-and-verification","title":"Proofs and Verification","description":"\x3c!--","sidebar":"Documentation"},"external/specifications":{"id":"external/specifications","title":"Specifications","description":"\x3c!--","sidebar":"Documentation"},"external/user-stories/financial-markets":{"id":"external/user-stories/financial-markets","title":"DvP in Financial Markets","description":"\x3c!--","sidebar":"Documentation"},"external/user-stories/global-trade":{"id":"external/user-stories/global-trade","title":"Global Trade","description":"\x3c!--","sidebar":"Documentation"},"external/user-stories/legacy-integration":{"id":"external/user-stories/legacy-integration","title":"Legacy Integration","description":"\x3c!--","sidebar":"Documentation"},"external/user-stories/overview":{"id":"external/user-stories/overview","title":"Overview","description":"\x3c!--","sidebar":"Documentation"},"external/what-is-interoperability/integration-patterns":{"id":"external/what-is-interoperability/integration-patterns","title":"Integration Patterns","description":"\x3c!--","sidebar":"Documentation"},"external/what-is-interoperability/levels-of-interoperability":{"id":"external/what-is-interoperability/levels-of-interoperability","title":"Levels of Interoperability","description":"\x3c!--","sidebar":"Documentation"},"external/what-is-interoperability/understanding-interoperability":{"id":"external/what-is-interoperability/understanding-interoperability","title":"Understanding Interoperability","description":"\x3c!--","sidebar":"Documentation"}}}')}}]); \ No newline at end of file diff --git a/assets/js/98ecfc99.5108af36.js b/assets/js/98ecfc99.5108af36.js deleted file mode 100644 index 50305411b..000000000 --- a/assets/js/98ecfc99.5108af36.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[3660],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>u});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?r(Object(n),!0).forEach((function(t){i(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):r(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,a,i=function(e,t){if(null==e)return{};var n,a,i={},r=Object.keys(e);for(a=0;a<r.length;a++)n=r[a],t.indexOf(n)>=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a<r.length;a++)n=r[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=a.createContext({}),c=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=c(e.components);return a.createElement(s.Provider,{value:t},e.children)},d="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,r=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),d=c(n),m=i,u=d["".concat(s,".").concat(m)]||d[m]||h[m]||r;return n?a.createElement(u,o(o({ref:t},p),{},{components:n})):a.createElement(u,o({ref:t},p))}));function u(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=n.length,o=new Array(r);o[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[d]="string"==typeof e?e:i,o[1]=l;for(var c=2;c<r;c++)o[c]=n[c];return a.createElement.apply(null,o)}return a.createElement.apply(null,n)}m.displayName="MDXCreateElement"},9981:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>h,frontMatter:()=>r,metadata:()=>l,toc:()=>c});var a=n(7462),i=(n(7294),n(3905));const r={id:"fabric",title:"Hyperledger Fabric"},o=void 0,l={unversionedId:"external/getting-started/enabling-weaver-network/fabric",id:"external/getting-started/enabling-weaver-network/fabric",title:"Hyperledger Fabric",description:"\x3c!--",source:"@site/docs/external/getting-started/enabling-weaver-network/fabric.md",sourceDirName:"external/getting-started/enabling-weaver-network",slug:"/external/getting-started/enabling-weaver-network/fabric",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/fabric",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/getting-started/enabling-weaver-network/fabric.md",tags:[],version:"current",frontMatter:{id:"fabric",title:"Hyperledger Fabric"},sidebar:"Documentation",previous:{title:"Enabling Weaver in Existing DLT Applications",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/overview"},next:{title:"Corda",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/corda"}},s={},c=[{value:"Model",id:"model",level:2},{value:"Procedural Overview",id:"procedural-overview",level:2},{value:"Development Phase",id:"development-phase",level:2},{value:"Chaincode",id:"chaincode",level:3},{value:"For Data Sharing",id:"for-data-sharing",level:4},{value:"For Asset Exchange",id:"for-asset-exchange",level:4},{value:"For Asset Transfer",id:"for-asset-transfer",level:4},{value:"Client (or Layer-2) Applications",id:"client-or-layer-2-applications",level:3},{value:"For Identity Administration",id:"for-identity-administration",level:4},{value:"For Data Sharing",id:"for-data-sharing-1",level:4},{value:"For Asset Exchange",id:"for-asset-exchange-1",level:4},{value:"For Asset Transfer",id:"for-asset-transfer-1",level:4},{value:"Pre-Configuration Phase",id:"pre-configuration-phase",level:2},{value:"Startup and Bootstrap Phase",id:"startup-and-bootstrap-phase",level:2},{value:"For Asset Exchange",id:"for-asset-exchange-2",level:3},{value:"Install the Fabric Interoperation Chaincode",id:"install-the-fabric-interoperation-chaincode",level:4},{value:"For Data Sharing or Asset Transfer",id:"for-data-sharing-or-asset-transfer",level:3},{value:"Install the Fabric Interoperation Chaincode",id:"install-the-fabric-interoperation-chaincode-1",level:4},{value:"Launch Relay",id:"launch-relay",level:4},{value:"Launch Driver",id:"launch-driver",level:4},{value:"Launch IIN Agents",id:"launch-iin-agents",level:4},{value:"Ledger Initialization",id:"ledger-initialization",level:4}],p={toc:c},d="wrapper";function h(e){let{components:t,...r}=e;return(0,i.kt)(d,(0,a.Z)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"After testing the Weaver interoperation mechanisms on ",(0,i.kt)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/overview"},"basic sample networks"),", you may be interested in finding out how you can equip an existing real network, whether in development or in production, to exercise these mechanisms. In this document, we will demonstrate how to equip a Fabric network and application with Weaver components and capabilities."),(0,i.kt)("h2",{id:"model"},"Model"),(0,i.kt)("p",null,"The figure below illustrates a typical Fabric network. The infrastructure consists of a set of peers, ordering service nodes, and CAs that perform the roles of MSPs; each serves a given ",(0,i.kt)("em",{parentName:"p"},"organization")," which is one of the constituent units of the network. On the peers are installed one or more smart contracts (",(0,i.kt)("em",{parentName:"p"},"chaincode"),"), representing shared business logic across the different organizations. Further up lie the so-called Layer-2 (or client) applications that consist of organization-specific business logic and invoke the smart contracts using APIs exposed by the Fabric SDK and with wallet credentials issued by their respective organizations' CAs."),(0,i.kt)("p",null,(0,i.kt)("img",{alt:"alt text",src:n(6269).Z,width:"1107",height:"607"})),(0,i.kt)("p",null,"Such a network equipped with Weaver components and capabilities will look like the figure below. Legacy components are marked in grey and Weaver and bridging components in green."),(0,i.kt)("p",null,(0,i.kt)("img",{alt:"alt text",src:n(1088).Z,width:"1452",height:"632"})),(0,i.kt)("p",null,"The relay and driver are the only additional infrastructure that need to be installed. One or more relays can be installed, as can one or more drivers. The drivers are illustrated in Layer-2 rather than in the bottom layer because, though they are coupled with relays, they exercise contracts using the Fabric SDK and organization-issued credentials just like any Layer-2 application does."),(0,i.kt)("p",null,"Existing chaincode deployed on the network's channels remain undisturbed. All that is required in the smart contracts layer is the deployment of the Fabric Interoperation Chaincode on every channel that needs to offer or consume state from foreign networks."),(0,i.kt)("p",null,"Layer-2, or client, applications will need some additional code and configuration because the decisions to exercise interoperation mechanisms (relay queries for data sharing or atomic asset exchanges) are strictly part of business logic. But Weaver's Fabric Interoperation Node SDK offers various helper functions to ease this process and keep the adaptation to a minimum, as we wil see later in this document. Finally, an ",(0,i.kt)("em",{parentName:"p"},"identity service")," must be offered by the network to expose its CAs' certificate chains to foreign networks, thereby laying the basis for interoperation. This service simply needs to offer a REST endpoint, and can be implemented as a standalone application or (more conveniently) as an augmentation of one or more of the existing Layer-2 applications."),(0,i.kt)("h2",{id:"procedural-overview"},"Procedural Overview"),(0,i.kt)("p",null,"A Hyperledger Fabric network is typically created in phases, in the following sequence:"),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("strong",{parentName:"li"},"Development"),": This involves writing chaincode and Layer-2 applications. The chaincode's deployment name/ID and its transaction API must be designed first, but subsequent development of the two layers of applications can then proceed parallelly."),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("strong",{parentName:"li"},"Pre-Configuration"),": This involves creating a desired specification (as a set of configuration diles) of the network topology and the ledgers it maintains."),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("strong",{parentName:"li"},"Startup and Bootstrap"),": This is the launch phase, in which the network components and applications are started and bootstrapped (i.e., configured with initial state and operating rules).")),(0,i.kt)("p",null,"Assuming that the reader is familiar with this procedure, we will walk through the changes required in each phase to make your network ready for interoperation using Weaver components and code templates. This will involve code addition and adaptation, deployment of additional modules, additional configuration, and creation of additional ledger state records. The requirements and effort will vary with the mode of interoperation you wish to support in your Fabric network."),(0,i.kt)("h2",{id:"development-phase"},"Development Phase"),(0,i.kt)("p",null,"A Fabric distributed application's business logic code spans two layers as illustrated in the network model."),(0,i.kt)("h3",{id:"chaincode"},"Chaincode"),(0,i.kt)("p",null,"These are smart contracts embodied in code, managing business workflow state and digital assets."),(0,i.kt)("h4",{id:"for-data-sharing"},"For Data Sharing"),(0,i.kt)("p",null,"No code changes are required for Weaver enablement, because data sharing involves:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"View packaging (and optionally, encryption) logic and access control logic in a source network, and"),(0,i.kt)("li",{parentName:"ul"},"View validation logic in a destination network")),(0,i.kt)("p",null,"This logic is standard and independent of smart contract, asset, and state, particulars. It is already implemented in the Fabric Interoperation Chaincode offered by Weaver. Hence you just need to deploy that chaincode to exercise data sharing from, or to, your application chaincode. Your application chaincode can be oblivious of the Fabric Interoperation Chaincode's workings and of the view request-response protocol."),(0,i.kt)("h4",{id:"for-asset-exchange"},"For Asset Exchange"),(0,i.kt)("p",null,"To exchange an asset using Weaver, the asset's state on the ledger must be controlled in the following ways:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Locked in favor of a party"),(0,i.kt)("li",{parentName:"ul"},"Claimed by the party to whom the asset is pledged"),(0,i.kt)("li",{parentName:"ul"},"Returned to the original owner if it is not claimed within a given timeframe")),(0,i.kt)("p",null,"In addition, the state of the asset (i.e., whether it is locked), and its current and targeted owners, must be determinable by looking at the ledger records."),(0,i.kt)("p",null,"The bookkeeping logic required to maintain records of locks can be abstracted away from the particulars of a digital asset and its workflow. But as such assets and their properties (including ownership) can be, and are, encoded in an arbitrary number of ways, we cannot provide a one-size-fits all set of functions (like in the data sharing protocol) to exchange any kind of asset. Instead, we must rely on the application contract (chaincode) managing an asset, as it knows precisely what the asset's properties are and how they can be updated and queried on the ledger (channel)."),(0,i.kt)("p",null,"What Weaver offers, therefore, is the following:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Lock management (bookkeeping) logic implemented in the Fabric Interoperation Chaincode that treats each asset as an abstract object and is agnostic of the assets' internals. This logic can be exercised in one of two ways:",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},"Importing the ",(0,i.kt)("a",{parentName:"li",href:"https://pkg.go.dev/github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/libs/assetexchange"},(0,i.kt)("inlineCode",{parentName:"a"},"assetexchange"))," library from the Fabric Interoperation Chaincode into your application chaincode, or"),(0,i.kt)("li",{parentName:"ul"},"Invoking them within the Fabric Interoperation Chaincode using a ",(0,i.kt)("a",{parentName:"li",href:"https://pkg.go.dev/github.com/hyperledger/fabric-chaincode-go/shim#ChaincodeStub.InvokeChaincode"},"chaincode-to-chaincode call"),"."))),(0,i.kt)("li",{parentName:"ul"},"A set of template functions with sample (and extensible) code that must be added to the application chaincode to exercise the above lock management functions.")),(0,i.kt)("p",null,"Below, we list the template functions with sample code that you, as a developer, must use and adapt within your chaincode, in either mode (library import or chaincode invocations)."),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"left"},"The instructions here apply only to chaincode implemented in Go, because Weaver presently offers only a Go version of the Fabric Interoperation Chaincode.")))),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("em",{parentName:"p"},"Using the ",(0,i.kt)("a",{parentName:"em",href:"https://pkg.go.dev/github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/libs/assetexchange"},(0,i.kt)("inlineCode",{parentName:"a"},"assetexchange"))," Library"),": This method doesn't require the ",(0,i.kt)("a",{parentName:"p",href:"https://pkg.go.dev/github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/contracts/interop"},(0,i.kt)("inlineCode",{parentName:"a"},"Fabric Interoperation Chaincode"))," to be installed. In your smart contract's ",(0,i.kt)("inlineCode",{parentName:"p"},"go.mod"),", add the following in the ",(0,i.kt)("inlineCode",{parentName:"p"},"require")," section (the sample below uses the current versions for dependency packages; update them to the latest versions offered by Weaver):"),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-go"},"require(\n ...\n github.com/hyperledger-labs/weaver-dlt-interoperability/common/protos-go v1.5.6\n github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/libs/assetexchange v1.5.3\n ...\n)\n")),(0,i.kt)("p",{parentName:"li"},"The following functions need to be added to your chaincode, and the smart contract class/type used below is called ",(0,i.kt)("inlineCode",{parentName:"p"},"SmartContract")," (",(0,i.kt)("em",{parentName:"p"},"Note"),": the function signature, i.e. the name, arguments, and return values, need to be exactly what is given in the below samples; you can have additional code to manage asset state as per need):"),(0,i.kt)("ol",{parentName:"li"},(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("strong",{parentName:"li"},"LockAsset"),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-go"},'import (\n ...\n "github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/libs/assetexchange"\n)\nfunc (s *SmartContract) LockAsset(ctx contractapi.TransactionContextInterface, assetExchangeAgreementSerializedProto64 string, lockInfoSerializedProto64 string) (string, error) {\n // Add some safety checks before calling LockAsset from library\n // Caller of this chaincode is supposed to be the Locker and the owner of the asset being locked.\n contractId, err := assetexchange.LockAsset(ctx, "", assetExchangeAgreementSerializedProto64, lockInfoSerializedProto64)\n if err != nil {\n return "", logThenErrorf(err.Error())\n }\n // Post proccessing of asset after LockAsset called like change status of the asset so that it can\'t be spent.\n ...\n return contractId, nil\n}\n')),"Here ",(0,i.kt)("inlineCode",{parentName:"li"},"assetExchangeAgreementSerializedProto64")," is a serialized protobuf in Base64 encoded string of ",(0,i.kt)("inlineCode",{parentName:"li"},"AssetExchangeAgreement")," protobuf structure, and can be used to extract details like asset id, type of asset and recipient. Check the structure definition ",(0,i.kt)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/rfcs/formats/assets/exchange.md#representing-two-party-asset-exchange-agreements"},"here"),".\nSimilarly ",(0,i.kt)("inlineCode",{parentName:"li"},"lockInfoSerializedProto64")," is a serialized protobuf in Base64 encoded string of ",(0,i.kt)("inlineCode",{parentName:"li"},"AssetLock")," protobuf structure. Check the structure definition ",(0,i.kt)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/rfcs/formats/assets/exchange.md#representing-locks-on-assets"},"here"),"."),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("strong",{parentName:"li"},"LockFungibleAsset"),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-go"},'func (s *SmartContract) LockFungibleAsset(ctx contractapi.TransactionContextInterface, fungibleAssetExchangeAgreementSerializedProto64 string, lockInfoSerializedProto64 string) (string, error) {\n // Add some safety checks before calling LockFungibleAsset from library\n // Caller of this chaincode is supposed to be the Locker and the owner of the asset being locked.\n contractId, err := assetexchange.LockFungibleAsset(ctx, "", fungibleAssetExchangeAgreementSerializedProto64, lockInfoSerializedProto64)\n if err != nil {\n return "", logThenErrorf(err.Error())\n }\n // Post proccessing of asset after LockFungibleAsset called like reduce the amount of tokens owned by the locker, or mark it locked so that it can\'t be spent.\n ...\n return contractId, nil\n}\n')),"Here ",(0,i.kt)("inlineCode",{parentName:"li"},"fungibleAssetExchangeAgreementSerializedProto64")," is a serialized protobuf in Base64 encoded string of ",(0,i.kt)("inlineCode",{parentName:"li"},"FungibleAssetExchangeAgreement")," protobuf structure, and can be used to extract details like asset quantity, type of asset and recipient. Check the structure definition ",(0,i.kt)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/rfcs/formats/assets/exchange.md#representing-two-party-asset-exchange-agreements"},"here"),"."),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("strong",{parentName:"li"},"IsAssetLockedQueryUsingContractId"),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-go"},"func (s *SmartContract) IsAssetLockedQueryUsingContractId(ctx contractapi.TransactionContextInterface, contractId string) (bool, error) {\n return assetexchange.IsAssetLockedQueryUsingContractId(ctx, contractId)\n}\n"))),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("strong",{parentName:"li"},"ClaimAssetUsingContractId"),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-go"},"func (s *SmartContract) ClaimAssetUsingContractId(ctx contractapi.TransactionContextInterface, contractId, claimInfoSerializedProto64 string) (bool, error) {\n // Note recipient will be the caller for this function\n claimed := false\n err := assetexchange.ClaimAssetUsingContractId(ctx, contractId, claimInfoSerializedProto64)\n if err != nil {\n return false, logThenErrorf(err.Error())\n }\n claimed = true\n // After the above function call, update the owner of the asset with recipeint/caller\n ...\n return claimed, nil\n}\n"))),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("strong",{parentName:"li"},"UnlockAssetUsingContractId"),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-go"},"func (s *SmartContract) UnlockAssetUsingContractId(ctx contractapi.TransactionContextInterface, contractId string) (bool, error) {\n unlocked := false\n err := assetexchange.UnlockAssetUsingContractId(ctx, contractId)\n if err != nil {\n return false, logThenErrorf(err.Error())\n }\n unlocked = true\n ...\n return true, nil\n}\n")))),(0,i.kt)("p",{parentName:"li"},"In addition, you should add the following extra utility functions to enable client applications to query and discover asset state:"),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-go"},"func (s *SmartContract) GetHTLCHashByContractId(ctx contractapi.TransactionContextInterface, contractId string) (string, error) {\n return assetexchange.GetHTLCHashByContractId(ctx, contractId)\n}\nfunc (s *SmartContract) GetHTLCHashPreImageByContractId(ctx contractapi.TransactionContextInterface, contractId string) (string, error) {\n return assetexchange.GetHTLCHashPreImageByContractId(ctx, contractId)\n}\n")),(0,i.kt)("p",{parentName:"li"},"There is an alternative API to implement asset exchange using this library, which doesn't involve contract IDs. For details, see the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/core/network/fabric-interop-cc/libs/assetexchange/README.md#without-contractid"},"Asset Exchange Library README"),".\n")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("em",{parentName:"p"},"Using the ",(0,i.kt)("a",{parentName:"em",href:"https://pkg.go.dev/github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/contracts/interop"},(0,i.kt)("inlineCode",{parentName:"a"},"Fabric Interoperation Chaincode"))),": This method requires the Fabric Interoperation Chaincode to be installed on all peers of the channel, using a special chaincode ID (e.g., ",(0,i.kt)("inlineCode",{parentName:"p"},"interop"),", which is what we will use later in this document). Your application chaincode needs to implement the interface ",(0,i.kt)("inlineCode",{parentName:"p"},"github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/interfaces/asset-mgmt"),".\nIn your smart contract's ",(0,i.kt)("inlineCode",{parentName:"p"},"go.mod"),", add the following in require (update the version according to the latest module version):"),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-go"},"require(\n ...\n github.com/hyperledger-labs/weaver-dlt-interoperability/common/protos-go v1.5.6\n github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/interfaces/asset-mgmt v1.5.3\n ...\n)\n")),(0,i.kt)("p",{parentName:"li"},"In the SmartContract class definition file, add the following code:"),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-go"},'import (\n ...\n am "github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/interfaces/asset-mgmt"\n)\ntype SmartContract struct {\n contractapi.Contract\n amc am.AssetManagementContract\n}\n')),(0,i.kt)("p",{parentName:"li"},"The following functions need to be added to your chaincode (",(0,i.kt)("em",{parentName:"p"},"Note"),": the function signature, i.e. the name, arguments, and return values, need to be exactly what is given in the below samples; you can have additional code to manage asset state as per need):"),(0,i.kt)("ol",{parentName:"li"},(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("strong",{parentName:"li"},"LockAsset"),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-go"},'func (s *SmartContract) LockAsset(ctx contractapi.TransactionContextInterface, assetExchangeAgreementSerializedProto64 string, lockInfoSerializedProto64 string) (string, error) {\n // Add some safety checks before calling LockAsset from library\n // Caller of this chaincode is supposed to be the Locker and the owner of the asset being locked.\n contractId, err := s.amc.LockAsset(ctx, "", assetExchangeAgreementSerializedProto64, lockInfoSerializedProto64)\n if err != nil {\n return "", logThenErrorf(err.Error())\n }\n // Post proccessing of asset after LockAsset called like change status of the asset so that it can\'t be spent.\n ...\n return contractId, nil\n}\n')),"Here ",(0,i.kt)("inlineCode",{parentName:"li"},"assetExchangeAgreementSerializedProto64")," is a serialized protobuf in Base64 encoded string of ",(0,i.kt)("inlineCode",{parentName:"li"},"AssetExchangeAgreement")," protobuf structure, and can be used to extract details like asset id, type of asset and recipient. Check the structure definition ",(0,i.kt)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/rfcs/formats/assets/exchange.md#representing-two-party-asset-exchange-agreements"},"here"),".\nSimilarly ",(0,i.kt)("inlineCode",{parentName:"li"},"lockInfoSerializedProto64")," is a serialized protobuf in Base64 encoded string of ",(0,i.kt)("inlineCode",{parentName:"li"},"AssetLock")," protobuf structure. Check the structure definition ",(0,i.kt)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/rfcs/formats/assets/exchange.md#representing-locks-on-assets"},"here"),"."),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("strong",{parentName:"li"},"LockFungibleAsset"),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-go"},'func (s *SmartContract) LockFungibleAsset(ctx contractapi.TransactionContextInterface, fungibleAssetExchangeAgreementSerializedProto64 string, lockInfoSerializedProto64 string) (string, error) {\n // Add some safety checks before calling LockFungibleAsset from library\n // Caller of this chaincode is supposed to be the Locker and the owner of the asset being locked.\n contractId, err := s.amc.LockFungibleAsset(ctx, "", fungibleAssetExchangeAgreementSerializedProto64, lockInfoSerializedProto64)\n if err != nil {\n return "", logThenErrorf(err.Error())\n }\n // Post proccessing of asset after LockFungibleAsset called like reduce the amount of tokens owned by the locker, or mark it locked so that it can\'t be spent.\n ...\n return contractId, nil\n}\n')),"Here ",(0,i.kt)("inlineCode",{parentName:"li"},"fungibleAssetExchangeAgreementSerializedProto64")," is a serialized protobuf in Base64 encoded string of ",(0,i.kt)("inlineCode",{parentName:"li"},"FungibleAssetExchangeAgreement")," protobuf structure, and can be used to extract details like asset quantity, type of asset and recipient. Check the structure definition ",(0,i.kt)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/rfcs/formats/assets/exchange.md#representing-two-party-asset-exchange-agreements"},"here"),"."),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("strong",{parentName:"li"},"IsAssetLockedQueryUsingContractId"),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-go"},"func (s *SmartContract) IsAssetLockedQueryUsingContractId(ctx contractapi.TransactionContextInterface, contractId string) (bool, error) {\n return s.amc.IsAssetLockedQueryUsingContractId(ctx, contractId)\n}\n"))),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("strong",{parentName:"li"},"ClaimAssetUsingContractId"),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-go"},"func (s *SmartContract) ClaimAssetUsingContractId(ctx contractapi.TransactionContextInterface, contractId, claimInfoSerializedProto64 string) (bool, error) {\n // Note recipient will be the caller for this function\n claimed := false\n err := s.amc.ClaimAssetUsingContractId(ctx, contractId, claimInfoSerializedProto64)\n if err != nil {\n return false, logThenErrorf(err.Error())\n }\n claimed = true\n // After the above function call, update the owner of the asset with recipeint/caller\n ...\n return claimed, nil\n}\n"))),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("strong",{parentName:"li"},"UnlockAssetUsingContractId"),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-go"},"func (s *SmartContract) UnlockAssetUsingContractId(ctx contractapi.TransactionContextInterface, contractId string) (bool, error) {\n unlocked := false\n err := s.amc.UnlockAssetUsingContractId(ctx, contractId)\n if err != nil {\n return false, logThenErrorf(err.Error())\n }\n unlocked = true\n ...\n return true, nil\n}\n")),"In addition, you should add the following extra utility functions to enable client applications to query and discover asset state:")),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-go"},"func (s *SmartContract) GetHTLCHashByContractId(ctx contractapi.TransactionContextInterface, contractId string) (string, error) {\n return s.amc.GetHTLCHashByContractId(ctx, contractId)\n}\nfunc (s *SmartContract) GetHTLCHashPreImageByContractId(ctx contractapi.TransactionContextInterface, contractId string) (string, error) {\n return s.amc.GetHTLCHashPreImageByContractId(ctx, contractId)\n}\n")))),(0,i.kt)("h4",{id:"for-asset-transfer"},"For Asset Transfer"),(0,i.kt)("p",null,(0,i.kt)("em",{parentName:"p"},"TBD")),(0,i.kt)("h3",{id:"client-or-layer-2-applications"},"Client (or Layer-2) Applications"),(0,i.kt)("p",null,"Weaver provides an SDK to help you adapt your applications to exercise the various interoperability modes. These are called out as ",(0,i.kt)("strong",{parentName:"p"},"Interoperation Helpers")," in the network model illustrated earlier. Your Fabric network's Layer-2 applications have business logic embedded in them that, broadly speaking, accept data from users and other external agents and invoke smart contracts using library functions and APIs offered by the Fabric SDK. When you use Weaver for network interoperability, other options can be added, namely requesting and accepting data from foreign networks, and triggering locks and claims for atomic exchanges spanning two networks. Weaver's Fabric Interoperation SDK (currently implemented both in Node.js and Golang) offers a library to exercise these options, supplementing the Fabric SDK. But this will involve modification to the application's business logic."),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"left"},"The instructions here apply to applications implemented in Node.js (JavaScript and TypeScript), using the Weaver Node SDK for Fabric. We will add instructions later for Go applications using the Weaver Go SDK for Fabric.")))),(0,i.kt)("p",null,"To import and use the Weaver SDK, you need to add the following dependency to the ",(0,i.kt)("inlineCode",{parentName:"p"},"dependencies")," section of your Node.js application's ",(0,i.kt)("inlineCode",{parentName:"p"},"package.json")," file:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'"@hyperledger-labs/weaver-fabric-interop-sdk": "latest",\n')),(0,i.kt)("p",null,"(Instead of ",(0,i.kt)("inlineCode",{parentName:"p"},"latest"),", you can select a particular version from the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/packages/888424"},"package website"),".)"),(0,i.kt)("p",null,"Before you run ",(0,i.kt)("inlineCode",{parentName:"p"},"npm install")," to fetch the dependencies, make sure you create a ",(0,i.kt)("a",{parentName:"p",href:"https://docs.github.com/en/github/authenticating-to-github/keeping-your-account-and-data-secure/creating-a-personal-access-token"},"personal access token")," with ",(0,i.kt)("inlineCode",{parentName:"p"},"read:packages")," access in Github. Create an ",(0,i.kt)("inlineCode",{parentName:"p"},".npmrc")," file in the same folder as the ",(0,i.kt)("inlineCode",{parentName:"p"},"package.json")," with the following contents:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"registry=https://npm.pkg.github.com/hyperledger-labs\n//npm.pkg.github.com/:_authToken=<personal-access-token>\n")),(0,i.kt)("p",null,"Replace ",(0,i.kt)("inlineCode",{parentName:"p"},"<personal-access-token>")," in this file with the token you created in Github."),(0,i.kt)("p",null,"First, you must incorporate some code for Weaver's network administration, specifically identity management. Then, using the given sample code and examples, you can adapt your applications for each interoperability mode."),(0,i.kt)("h4",{id:"for-identity-administration"},"For Identity Administration"),(0,i.kt)("p",null,"A Fabric network channel must share its security domain (or membership) configuration, i.e., its organizations' CA certificate chains, with a foreign network with which it seeks to interoperate. Each organization must run an IIN Agent for this purpose. The set of IIN Agents, a.k.a. the ",(0,i.kt)("em",{parentName:"p"},"local membership")," must be recorded in the ledger before those agents can be operational. In your Fabric network application suite, one or more applications will exist for network administration; the following code snippet should be added in at least one of those applications to record local membership as a prerequisite for interoperability:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-typescript"},"import { MembershipManager } from '@hyperledger-labs/weaver-fabric-interop-sdk'\n\nconst gateway = <get-fabric-network-gateway-instance>\n\ntry {\n const response = await MembershipManager.createLocalMembership(\n gateway,\n members, // list of all organization MSPIDs that are part of the channel\n securityDomain, // name of the local network's security domain\n channelName, // Channel Name\n contractName // Fabric Interoperation Chaincode installation ID on the channel\n )\n} catch (e) {\n // On error try updating local membership\n const response = await MembershipManager.updateLocalMembership(gateway, members, securityDomain, channelName, contractName)\n}\n")),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"<get-fabric-network-gateway-instance>")," should be replaced with standard (boilerplate) code to get a handle to your network's gateway. This requires a special wallet identity, namely one with a ",(0,i.kt)("inlineCode",{parentName:"li"},"network-admin")," attribute indicating that the caller is a trusted network administrator who is authorized to record local memberships on the ",(0,i.kt)("inlineCode",{parentName:"li"},"channelName")," channel."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"members")," must consist of the list of organizational MSP IDs for the ",(0,i.kt)("inlineCode",{parentName:"li"},"channelName")," channel.")),(0,i.kt)("h4",{id:"for-data-sharing-1"},"For Data Sharing"),(0,i.kt)("p",null,"Consider a scenario inspired by the ",(0,i.kt)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/external/user-stories/global-trade"},"global trade use case")," where a letter of credit (L/C) management business logic (chaincode ",(0,i.kt)("inlineCode",{parentName:"p"},"letterofcreditcc"),") installed in the ",(0,i.kt)("inlineCode",{parentName:"p"},"tradefinancechannel")," channel in the ",(0,i.kt)("inlineCode",{parentName:"p"},"trade-finance-network")," network supports a transaction ",(0,i.kt)("inlineCode",{parentName:"p"},"RecordBillOfLading"),", which validates and records a bill of lading (B/L) supplied by a user via a UI. Weaver will enable such a B/L to be fetched from a different network ",(0,i.kt)("inlineCode",{parentName:"p"},"trade-logistics-network")," by querying the function ",(0,i.kt)("inlineCode",{parentName:"p"},"GetBillOfLading")," exposed by the chaincode ",(0,i.kt)("inlineCode",{parentName:"p"},"shipmentcc")," installed in the ",(0,i.kt)("inlineCode",{parentName:"p"},"tradelogisticschannel")," channel."),(0,i.kt)("p",null,"(In preparation, a suitable access control policy must be recorded on ",(0,i.kt)("inlineCode",{parentName:"p"},"tradelogisticschannel")," in ",(0,i.kt)("inlineCode",{parentName:"p"},"trade-logistics-network"),", and a suitable verification policy must be recorded on ",(0,i.kt)("inlineCode",{parentName:"p"},"tradefinancechannel")," in ",(0,i.kt)("inlineCode",{parentName:"p"},"trade-finance-network"),'. We will see how to do this in the "Startup and Boostrap" section later.)'),(0,i.kt)("p",null,"You will need to insert some code in the Layer-2 application that accepts a B/L and submits a ",(0,i.kt)("inlineCode",{parentName:"p"},"RecordBillOfLading")," transaction in ",(0,i.kt)("inlineCode",{parentName:"p"},"trade-finance-network"),". (No code changes need to be made in any application in the other network.) The logic to accept a B/L should be replaced (or you can simply add an alternative) by a call to the ",(0,i.kt)("inlineCode",{parentName:"p"},"interopFlow")," function offered by the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/packages/888424"},"weaver-fabric-interop-sdk")," library (there's an ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/releases/tag/sdks%2Ffabric%2Fgo-sdk%2Fv1.2.3-alpha.1"},"equivalent library in Golang")," too). The following code sample illustrates this (the Golang equivalent is left to the reader):"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-js",metastring:"showLineNumbers",showLineNumbers:!0},"const ihelper = require('@hyperledger-labs/weaver-fabric-interop-sdk').InteroperableHelper;\nconst interopcc = <handle-to-fabric-interop-chaincode>; // Use Fabric SDK functions: (new Gateway()).getNetwork(...).getContract(<fabric-interop-chaincode-id>)\nconst keyCert = await ihelper.getKeyAndCertForRemoteRequestbyUserName(<wallet>, <user-id>); // Read key and certificate for <user-id> from wallet (get handle using Fabric SDK Wallets API)\n// Collect view addresses for relay requests in the context of an interop flow\ninteropJSONs.push({\n NetworkID: 'trade-logistics-network',\n RemoteEndpoint: <trade-logistics-relay-url[:<port>], // Replace with remote network's relay address and port\n ChannelID: 'tradelogisticschannel',\n ChaincodeID: 'shipmentcc',\n ChaincodeFunc: 'GetBillOfLading',\n ccArgs: [ <shipment-reference> ], // Replace <shipment-reference> with a value that can be used to look up the right B/L\n Sign: true\n});\nconst indices = [ 1 ];\n// Trigger an end-to-end interoperation (data sharing) protocol\n// Send a request to a foreign network via your relay, receive the response and submit a transaction to a local chaincode\nconst flowResponse = await ihelper.interopFlow(\n interopcc,\n 'trade-finance-network',\n {\n channel: 'tradefinancechannel',\n contractName: 'letterofcreditcc',\n ccFunc: 'RecordBillOfLading',\n ccArgs: [ <shipment-reference> , '' ]\n },\n <org-msp-id>, // Replace with this Layer-2 application's organization's MSP ID\n <trade-finance-relay-url>[:<port>], // Replace with local network's relay address and port\n indices,\n interopJSONs,\n keyCert,\n <endorsingOrgs>, // List of orgs to submit transaction to local i.e. trade logistics network\n false, // Boolean flag to indicate whether return without submit transaction to local i.e. trade logistics network\n false, // Boolean flag indicating no TLS communication with relay\n [], // Keep it empty when TLS is disabled\n <confidential-flag>, // Boolean flag to indicate whether to use to end-to-end encryption\n);\n// List of errors to check for\nif (!flowResponse.views || flowResponse.views.length === 0 || !flowResponse.result || flowResponse.views.length !== argIndices.length) {\n throw <error>;\n}\n")),(0,i.kt)("p",null,"Let us understand this code snippet better. The structure in lines 20-25 specifies the local chaincode transaction that is to be triggered after remote data (view) has been requested and obtained via relays. The function ",(0,i.kt)("inlineCode",{parentName:"p"},"RecordBillOfLading")," expects two arguments as specified in line 24: the first is the common shipment reference that is used by the letter of credit in ",(0,i.kt)("inlineCode",{parentName:"p"},"trade-finance-network")," and the bill of lading in ",(0,i.kt)("inlineCode",{parentName:"p"},"trade-logistics-network"),", and the second is the bill of lading contents. When the ",(0,i.kt)("inlineCode",{parentName:"p"},"interopFlow")," function is called, this argument is left blank because it is supposed to be filled with contents obtained from a view request. The array list ",(0,i.kt)("inlineCode",{parentName:"p"},"indices"),", which is passed as an argument to ",(0,i.kt)("inlineCode",{parentName:"p"},"interopFlow")," therefore contains the index value ",(0,i.kt)("inlineCode",{parentName:"p"},"1")," (line 14), indicating which argument ought to be substituted with view data. The ",(0,i.kt)("inlineCode",{parentName:"p"},"interopJSONs")," array correspondingly contains a list of view addresses that are to be supplied to the relay. The ",(0,i.kt)("inlineCode",{parentName:"p"},"<confidential-flag>")," if set to ",(0,i.kt)("inlineCode",{parentName:"p"},"true")," will enable end-to-end confidentiality, i.e. payload will be encrypted from ",(0,i.kt)("inlineCode",{parentName:"p"},"trade-finance-network"),"'s weaver chaincode, and will be decrypted in SDK (i.e. Layer-2 client application) at ",(0,i.kt)("inlineCode",{parentName:"p"},"trade-logistics-network"),", but relays and drivers in between will not be able to see the payload. By default this flag is set to ",(0,i.kt)("inlineCode",{parentName:"p"},"false"),"."),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"left"},"A local chaincode invocation may require multiple view requests to different networks, which is why ",(0,i.kt)("inlineCode",{parentName:"td"},"indices")," and ",(0,i.kt)("inlineCode",{parentName:"td"},"interopJSONs")," are arrays; they therefore must have the same lengths.")))),(0,i.kt)("p",null,"The rest of the code ought to be self-explanatory. Values are hardcoded for explanation purposes, but you can refactor the above code by reading view addresses corresponding to chaincode invocations from a configuration file."),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Enabling TLS"),":\nBy default, the TLS is set to false in ",(0,i.kt)("inlineCode",{parentName:"p"},"interopFlow"),", i.e. disabled. But if you want to enable TLS, can pass additional parameters to the ",(0,i.kt)("inlineCode",{parentName:"p"},"interopFlow")," function as follows:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-TypeScript"},"const flowResponse = await ihelper.interopFlow(\n interopcc,\n 'trade-finance-network',\n {\n channel: 'tradefinancechannel',\n contractName: 'letterofcreditcc',\n ccFunc: 'RecordBillOfLading',\n ccArgs: [ <shipment-reference> , '' ]\n },\n <org-msp-id>, // Replace with this Layer-2 application's organization's MSP ID\n <trade-finance-relay-url>[:<port>], // Replace with local network's relay address and port\n indices,\n interopJSONs,\n keyCert,\n <endorsingOrgs>, // List of orgs to submit transaction to in trade logistics network\n false, // Boolean flag to indicate whether return without submit transaction to local i.e. trade logistics network\n true, // Boolean indication TLS is enabled.\n <tlsCACertPathsForRelay>, // list of CA certificate file paths\n);\n")),(0,i.kt)("h4",{id:"for-asset-exchange-1"},"For Asset Exchange"),(0,i.kt)("p",null,"Let's take an example of asset exchange between ",(0,i.kt)("inlineCode",{parentName:"p"},"Alice")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"Bob"),", where Bob wants to purchase an asset of type ",(0,i.kt)("inlineCode",{parentName:"p"},"Gold")," with id ",(0,i.kt)("inlineCode",{parentName:"p"},"A123")," from ",(0,i.kt)("inlineCode",{parentName:"p"},"Alice")," in ",(0,i.kt)("inlineCode",{parentName:"p"},"BondNetwork")," in exchange for ",(0,i.kt)("inlineCode",{parentName:"p"},"200")," tokens of type ",(0,i.kt)("inlineCode",{parentName:"p"},"CBDC01")," in ",(0,i.kt)("inlineCode",{parentName:"p"},"TokenNetwork"),"."),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"Alice")," needs to select a secret text (say ",(0,i.kt)("inlineCode",{parentName:"p"},"s"),"), and hash it (say ",(0,i.kt)("inlineCode",{parentName:"p"},"H"),") using say ",(0,i.kt)("inlineCode",{parentName:"p"},"SHA512"),", which will be used to lock her asset in ",(0,i.kt)("inlineCode",{parentName:"p"},"BondNetwork"),". At the place in your application where an asset exchange is to be initiated, you need to add code to enable Alice to lock the non-fungible asset using hash ",(0,i.kt)("inlineCode",{parentName:"p"},"H")," and timeout duration of 10 minutes:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-typescript"},'import { AssetManager, HashFunctions } from \'@hyperledger-labs/weaver-fabric-interop-sdk\'\n\nconst hash = HashFunctions.SHA512(); // Create Hash instance of one of the supported Hash Algorithm\nhash.setSerializedHashBase64(H); // Set the Hash\nconst timeout = Math.floor(Date.now()/1000) + 10 * 60;\n\nconst bondContract = <handle-to-fabric-application-chaincode-in-bond-network>;\n\nconst result = await AssetManager.createHTLC(\n bondContract,\n "Gold", // Asset ID\n "A123", // Asset Type\n bobCertificate, // Certificate of Bob in Bond Network\n hash, // Hash generated by Alice using her secret s\n timeout, // Timeout in epoch for 10 mins from current time\n null // Optional callback function to be called after the asset is locked\n);\nlet bondContractId = result.result; // Unique ID for this asset exchange contract in BondNetwork\n')),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"left"},"Note that 'Alice' and 'Bob' and the asset specifics can be parameterized in the above code, which can be reused for arbitrary asset exchange scenarios in your business workflow. The above code is only meant to be a sample.")))),(0,i.kt)("p",null,"Now ",(0,i.kt)("inlineCode",{parentName:"p"},"Bob")," will lock his tokens in ",(0,i.kt)("inlineCode",{parentName:"p"},"TokenNetwork"),". To lock the fungible asset using same hash ",(0,i.kt)("inlineCode",{parentName:"p"},"H")," and timeout of 5 minutes (half the timeout duration used by Alice in ",(0,i.kt)("inlineCode",{parentName:"p"},"BondNetwork"),"), add the following code snippet in your application:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-typescript"},'const hash = HashFunctions.SHA512(); // Create Hash instance of one of the supported Hash Algorithm\nhash.setSerializedHashBase64(H); // Set the Hash\nconst timeout = Math.floor(Date.now()/1000) + 5 * 60;\n\nconst tokenContract = <handle-to-fabric-application-chaincode-in-token-network>;\nconst result = await AssetManager.createFungibleHTLC(\n tokenContract,\n "CBDC01", // Token ID\n 200, // Token Quantity\n aliceCertificate, // Certificate of Alice in Token Network\n hash, // Hash H used by Alice in Bond Network\n timeout, // Timeout in epoch for 5 mins from current time\n null // Optional callback function to be called after the asset is locked\n)\nconst tokenContractId = result.result // Unique ID for this asset exchange contract in TokenNetwork\n')),(0,i.kt)("p",null,"Wherever the lock status of the asset is required in your application, you should insert a query function call as follows:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-typescript"},"const contract = <handle-to-fabric-application-chaincode>;\n// Below contractId is the ID obtained during lock\nconst isLocked = AssetManager.isAssetLockedInHTLCqueryUsingContractId(contract, contractId)\n")),(0,i.kt)("p",null,"Wherever a participant (either 'Alice' or 'Bob' in this example) needs to claim a locked asset using the secret text (pre-image of hash) ",(0,i.kt)("inlineCode",{parentName:"p"},"s")," in your application, insert the following code snippet (",(0,i.kt)("em",{parentName:"p"},"Note"),": typically one would insert this in event callback functions or in functions that are polling the ledger to monitor whether the asset is locked in favor of a given recipient):"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-typescript"},"const hash = HashFunctions.SHA512(); // Create Hash instance of one of the supported Hash Algorithm\nhash.setPreimage(s) // Set Pre-Image s\nconst contract = <handle-to-fabric-application-chaincode>;\nconst claimSuccess = await AssetManager.claimAssetInHTLCusingContractId(\n contract,\n contractId, // contractId obtained during lock\n hash\n)\n// return value claimSuccess is boolean indicating success or failure of claim\n")),(0,i.kt)("p",null,"Wherever the asset must be unlocked in your application (typically, an event callback function triggered upon the expiration of the time lock), insert the following code snippet:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-typescript"},"const contract = <handle-to-fabric-application-chaincode>;\nconst reclaimSuccess = await AssetManager.reclaimAssetInHTLCusingContractId(\n contract,\n contractId // contractId obtained during lock\n)\n// return value 'reclaimSuccess' is a boolean indicating success or failure of reclaim\n")),(0,i.kt)("h4",{id:"for-asset-transfer-1"},"For Asset Transfer"),(0,i.kt)("p",null,(0,i.kt)("em",{parentName:"p"},"TBD")),(0,i.kt)("h2",{id:"pre-configuration-phase"},"Pre-Configuration Phase"),(0,i.kt)("p",null,"Typically, pre-configuration in a Fabric network involves generating (after creating the channel specifications and policies):"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("em",{parentName:"li"},"Channel artifacts"),": orderer genesis block, channel transaction, and anchor peer configurations from a ",(0,i.kt)("inlineCode",{parentName:"li"},"configtx.yaml")," file (using Fabric's ",(0,i.kt)("inlineCode",{parentName:"li"},"configtxgen")," tool)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("em",{parentName:"li"},"Crypto artifacts"),": keys and certificates for CAs, peers, orderers, and clients from a ",(0,i.kt)("inlineCode",{parentName:"li"},"crypto-config.yaml")," file (using Fabric's ",(0,i.kt)("inlineCode",{parentName:"li"},"cryptogen")," tool)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("em",{parentName:"li"},"Connection profiles"),": one for every network organization, which will be used by the organization's Layer-2 applications to connect to the network's peers and CAs")),(0,i.kt)("p",null,"No changes are required in this process to support any of the three interoperation modes using Weaver. The connection profiles generated above will be used by certain Weaver modules, as we will see later. The only additional step required is to generate special wallet identities for the following:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Network administrator: one or more identities containing the ",(0,i.kt)("inlineCode",{parentName:"li"},"network-admin")," attribute; only a user/application possessing this identity may record special (privileged) information regarding memberships and policies on the channel."),(0,i.kt)("li",{parentName:"ul"},"Fabric Driver: one or more identities (for each deployed driver) containing the ",(0,i.kt)("inlineCode",{parentName:"li"},"relay")," attribute; only a relay-driver combination possessing this identity may run data sharing-related operations on the deployed Fabric Interoperation Chaincode."),(0,i.kt)("li",{parentName:"ul"},"IIN Agent: one or more identities (for each deployed agent) containing the ",(0,i.kt)("inlineCode",{parentName:"li"},"iin-agent")," attribute: only an agent may submit foreign network membership records to the Fabric Interoperation Chaincode.")),(0,i.kt)("p",null,"Later we will see how the components possessing these identities are deployed."),(0,i.kt)("h2",{id:"startup-and-bootstrap-phase"},"Startup and Bootstrap Phase"),(0,i.kt)("p",null,"After writing application code and creating the network configuration files, the components of a Fabric network (peers, CAs, and ordering service) are launched. In this section, we will list the additional tasks you, as a Fabric network administrator, must perform to make your network ready to interoperate."),(0,i.kt)("p",null,"To launch a network using containerized components, you will typically use a Docker Compose or Kubernetes configuration file. No modifications are needed to the peers', orderers', and CAs' configurations. Sample instructions are given below for networks launched using Docker Compose; we leave it to the reader to adapt these to their custom launch processes."),(0,i.kt)("h3",{id:"for-asset-exchange-2"},"For Asset Exchange"),(0,i.kt)("p",null,"The asset exchange mode currently requires only the Fabric Interoperation Chaincode module from Weaver. Relays, drivers, and IIN agents, are not necessary. In the future, we expect to make the asset exchange protocol moe automated using these components; the instructions here will be updated appropriately."),(0,i.kt)("h4",{id:"install-the-fabric-interoperation-chaincode"},"Install the Fabric Interoperation Chaincode"),(0,i.kt)("p",null,"Install the Fabric Interoperation Chaincode in the relevant channel(s), i.e., those that run chaincodes that will be involved in asset exchanges. This is a Go module that can be fetched from ",(0,i.kt)("inlineCode",{parentName:"p"},"github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/contracts/interop"),". Following that, you an install it using the appropriate Fabric process: in Fabric v2, you will need to package, install, approve, and commit this module on the selected channels in your network."),(0,i.kt)("h3",{id:"for-data-sharing-or-asset-transfer"},"For Data Sharing or Asset Transfer"),(0,i.kt)("p",null,"Both the data sharing and asset transfer modes require the Fabric Interoperation Chaincode, relays, drivers, and IIN agents, to be deployed."),(0,i.kt)("h4",{id:"install-the-fabric-interoperation-chaincode-1"},"Install the Fabric Interoperation Chaincode"),(0,i.kt)("p",null,"Install the Fabric Interoperation Chaincode in the relevant channel(s), i.e., those that run chaincodess that will be involved in data sharing (and asset transfers, which require multiple data shares). This is a Go module that can be fetched from ",(0,i.kt)("inlineCode",{parentName:"p"},"github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/contracts/interop"),". Following that, you an install it using the appropriate Fabric process: in Fabric v2, you will need to package, install, approve, and commit this module on the selected channels in your network."),(0,i.kt)("h4",{id:"launch-relay"},"Launch Relay"),(0,i.kt)("p",null,"You need to run one or more relays for network-to-network communication. Here we provide instructions to run one relay running in a Docker container, which is sufficient for data sharing. (Later, we will provide instructions to run multiple relays, which will be useful from a failover perspective.)"),(0,i.kt)("p",null,"Weaver provides a ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/pkgs/container/weaver-relay-server"},"pre-built image")," for the relay. Before launching a container, you just need to customize its configuration for your Fabric network, which you can do by simply creating a folder (let's call it ",(0,i.kt)("inlineCode",{parentName:"p"},"relay_config"),") and configuring the following files in it:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},".env"),": This sets suitable environment variables within the relay container. Copy the ",(0,i.kt)("inlineCode",{parentName:"p"},".env.template")," file ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/core/relay/.env.template"},"from the repository")," and customize it for your purposes, as indicated in the below sample:"),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre"},'PATH_TO_CONFIG=./config.toml\nRELAY_NAME=<"name" in config.toml>\nRELAY_PORT=<relay-server-port/"port" in config.toml>\nEXTERNAL_NETWORK=<docker-bridge-network>\nDOCKER_REGISTRY=ghcr.io/hyperledger-labs\nDOCKER_IMAGE_NAME=weaver-relay\nDOCKER_TAG=1.5.4\n')),(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},"The ",(0,i.kt)("inlineCode",{parentName:"li"},"PATH_TO_CONFIG")," variable should point to the properties file typically named ",(0,i.kt)("inlineCode",{parentName:"li"},"config.toml")," (you can name this whatever you wish). See further below for instructions to write this file."),(0,i.kt)("li",{parentName:"ul"},"The ",(0,i.kt)("inlineCode",{parentName:"li"},"RELAY_NAME")," variable specifies a unique name for this relay. It should match what's specified in the ",(0,i.kt)("inlineCode",{parentName:"li"},"config.toml")," (more on that below)."),(0,i.kt)("li",{parentName:"ul"},"The ",(0,i.kt)("inlineCode",{parentName:"li"},"RELAY_PORT")," variable specifies the port this relay server will listen on. It should match what's specified in the ",(0,i.kt)("inlineCode",{parentName:"li"},"config.toml")," (more on that below)."),(0,i.kt)("li",{parentName:"ul"},"The ",(0,i.kt)("inlineCode",{parentName:"li"},"EXTERNAL_NETWORK")," variable should be set to the ",(0,i.kt)("a",{parentName:"li",href:"https://docs.docker.com/compose/networking/"},"name")," of your Fabric network."),(0,i.kt)("li",{parentName:"ul"},"The ",(0,i.kt)("inlineCode",{parentName:"li"},"DOCKER_*")," variables are used to specify the image on which the container will be built. Make sure you set ",(0,i.kt)("inlineCode",{parentName:"li"},"DOCKER_TAG")," to the latest version you see on ",(0,i.kt)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/pkgs/container/weaver-relay-server"},"Github"),".")),(0,i.kt)("p",{parentName:"li"},"For more details, see the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/core/relay/relay-docker.md"},"Relay Docker README"),' ("Relay Server Image" and "Running With Docker Compose" sections).')),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"config.toml"),": This is the file specified in the ",(0,i.kt)("inlineCode",{parentName:"p"},"PATH_TO_CONFIG")," variable in the ",(0,i.kt)("inlineCode",{parentName:"p"},".env"),". It specifies properties of this relay and the driver(s) it supports. A sample is given below:"),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-toml",metastring:"showLineNumbers",showLineNumbers:!0},'name=<relay-name>\nport=<relay-port>\nhost="0.0.0.0"\ndb_path="db/<relay-name>/requests"\nremote_db_path="db/<relay-name>/remote_request"\n\n# FOR TLS\ncert_path="credentials/fabric_cert.pem"\nkey_path="credentials/fabric_key"\ntls=<true/false>\n\n[networks]\n[networks.<network-name>]\nnetwork="<driver-name>"\n\n[relays]\n[relays.<foreign-relay-name>]\nhostname="<foreign-relay-hostname-or-ip-address>"\nport="<foreign-relay-port>"\n\n[drivers]\n[drivers.<driver-name>]\nhostname="<driver-hostname-or-ip-address>"\nport="<driver-port>"\n')),(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"<relay-name>")," should be a unique ID representing this relay; e.g., ",(0,i.kt)("inlineCode",{parentName:"li"},"my_network_relay"),". It should match the ",(0,i.kt)("inlineCode",{parentName:"li"},"RELAY_NAME")," value in ",(0,i.kt)("inlineCode",{parentName:"li"},".env"),"."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"<relay-port>")," is the port number the relay server will listen on. It should match the ",(0,i.kt)("inlineCode",{parentName:"li"},"RELAY_PORT")," value in ",(0,i.kt)("inlineCode",{parentName:"li"},".env"),"."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"db_path")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"remote_db_path")," are used internally by the relay to store data. Replace ",(0,i.kt)("inlineCode",{parentName:"li"},"<relay-name>")," with the same value set for the ",(0,i.kt)("inlineCode",{parentName:"li"},"name")," parameter. (These can point to any filesystem paths in the relay's container.)"),(0,i.kt)("li",{parentName:"ul"},"If you set ",(0,i.kt)("inlineCode",{parentName:"li"},"tls")," to ",(0,i.kt)("inlineCode",{parentName:"li"},"true"),", the relay will enforce TLS communication. The ",(0,i.kt)("inlineCode",{parentName:"li"},"cert_path")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"key_path")," should point to a Fabric TLS certificate and key respectively, such as those created using the ",(0,i.kt)("inlineCode",{parentName:"li"},"cryptogen")," tool."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"<network-name>")," is a unique identifier for your local network. You can set it to whatever value you wish."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"<driver-name>")," refers to the driver used by this relay to respond to requests. This also refers to one of the drivers's specifications in the ",(0,i.kt)("inlineCode",{parentName:"li"},"drivers")," section further below. In this code snippet, we have defined one driver. (The names in lines 14 and 22 must match.) In lines 23 and 24 respectively, you should specify the hostname and port for the driver (whose configuration we will handle later)."),(0,i.kt)("li",{parentName:"ul"},"The ",(0,i.kt)("inlineCode",{parentName:"li"},"relays")," section specifies all foreign relays this relay can connect to. The ",(0,i.kt)("inlineCode",{parentName:"li"},"<foreign-relay-name>")," value should be a unique ID for a given foreign relay, and this value will be used by your Layer-2 applications when constructing view addresses for data sharing requests. In lines 18 and 19, you should specify the hostname and port for the foreign relay."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"Enabling TLS"),":",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},"You can make your relay accept TLS connections by specifying a TLS certificate file path and private key file path in ",(0,i.kt)("inlineCode",{parentName:"li"},"cert_path")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"key_path")," respectively, and set ",(0,i.kt)("inlineCode",{parentName:"li"},"tls")," to ",(0,i.kt)("inlineCode",{parentName:"li"},"true"),"."),(0,i.kt)("li",{parentName:"ul"},"To communicate with a foreign relay using TLS, specify that relay's TLS CA certificate path in ",(0,i.kt)("inlineCode",{parentName:"li"},"tlsca_cert_path")," (currently only one certificate can be configured) and set ",(0,i.kt)("inlineCode",{parentName:"li"},"tls")," to ",(0,i.kt)("inlineCode",{parentName:"li"},"true")," by extending that relay's section as follows (",(0,i.kt)("em",{parentName:"li"},"Note"),": this CA certificate should match the one specified in the ",(0,i.kt)("inlineCode",{parentName:"li"},"cert_path")," property in the foreign relay's ",(0,i.kt)("inlineCode",{parentName:"li"},"config.toml")," file):",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-toml"},'[relays]\n[relays.<foreign-relay-name>]\nhostname="<foreign-relay-hostname-or-ip-address>"\nport="<foreign-relay-port>"\ntls=<true|false>\ntlsca_cert_path="<relay-tls-ca-certificate-path>"\n'))),(0,i.kt)("li",{parentName:"ul"},"To communicate with a driver using TLS, specify the driver's TLS CA certificate in ",(0,i.kt)("inlineCode",{parentName:"li"},"tlsca_cert_path")," (currently only one certificate can be configured) and set ",(0,i.kt)("inlineCode",{parentName:"li"},"tls")," to ",(0,i.kt)("inlineCode",{parentName:"li"},"true")," by extending that driver's section as follows (",(0,i.kt)("em",{parentName:"li"},"Note"),": this CA certificate must match the certificate used by the driver using the ",(0,i.kt)("inlineCode",{parentName:"li"},"DRIVER_TLS_CERT_PATH")," property in its ",(0,i.kt)("inlineCode",{parentName:"li"},".env")," configuration file, which we will examine later):",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-toml"},'[drivers]\n[drivers.<driver-name>]\nhostname="<driver-hostname-or-ip-address>"\nport="<driver-port>"\ntls=<true|false>\ntlsca_cert_path="<driver-tls-ca-certificate-path>"\n')))))),(0,i.kt)("table",{parentName:"li"},(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"left"},"You can specify more than one foreign relay instance in the ",(0,i.kt)("inlineCode",{parentName:"td"},"relays")," section.")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"left"},"You can specify more than one driver instance in the ",(0,i.kt)("inlineCode",{parentName:"td"},"drivers")," section."))))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"docker-compose.yaml"),": This specifies the properties of the relay container. You can use the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/core/relay/docker-compose.yaml"},"file in the repository")," verbatim."))),(0,i.kt)("p",null,"To start the relay server, navigate to the folder containing the above files and run the following:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"docker-compose up -d relay-server\n")),(0,i.kt)("h4",{id:"launch-driver"},"Launch Driver"),(0,i.kt)("p",null,"You need to run one or more drivers through which your relay can interact with your Fabric network. Here we provide instructions to run one Fabric driver running in a Docker container, which is sufficient for data sharing. (Later, we will provide instructions to run multiple drivers, which will be useful both from a failover perspective and to interact with different subsets of your Fabric network, like private data collections.)"),(0,i.kt)("p",null,"Weaver provides a ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/pkgs/container/weaver-fabric-driver"},"pre-built image")," for the Fabric driver. Before launching a container, you just need to customize its configuration for your Fabric network, which you can do by simply creating a folder (let's call it ",(0,i.kt)("inlineCode",{parentName:"p"},"driver_config"),") and configuring the following files in it:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},".env"),": This sets suitable environment variables within the driver container. Copy the ",(0,i.kt)("inlineCode",{parentName:"p"},".env.template")," file ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/core/drivers/fabric-driver/.env.docker.template"},"from the repository")," and customize it for your purposes, as indicated in the below sample:"),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre"},"CONNECTION_PROFILE=<path_to_connection_profile>\nDRIVER_CONFIG=./config.json\nRELAY_ENDPOINT=<relay-hostname>:<relay-port>\nNETWORK_NAME=<network-name>\nDRIVER_PORT=<driver-server-port>\nINTEROP_CHAINCODE=<interop-chaincode-name>\nEXTERNAL_NETWORK=<docker-bridge-network>\nTLS_CREDENTIALS_DIR=<dir-with-tls-cert-and-key>\nDOCKER_IMAGE_NAME=ghcr.io/hyperledger-labs/weaver-fabric-driver\nDOCKER_TAG=1.5.6\nDRIVER_TLS=<true|false>\nDRIVER_TLS_CERT_PATH=path_to_tls_cert_pem_for_driver\nDRIVER_TLS_KEY_PATH=path_to_tls_key_pem_for_driver\nRELAY_TLS=<true|false>\nRELAY_TLSCA_CERT_PATH=path_to_tls_ca_cert_pem_for_relay\n")),(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"<path_to_connection_profile>"),' should point to the path of a connection profile you generated in the "Pre-Configuration" section. A Fabric driver obtains client credentials from one of the organizations in your network, so pick an organization and point to the right connection profile.'),(0,i.kt)("li",{parentName:"ul"},"The ",(0,i.kt)("inlineCode",{parentName:"li"},"DRIVER_CONFIG")," variable should point to the ",(0,i.kt)("inlineCode",{parentName:"li"},"config.json")," (you can name this whatever you wish) specified below."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"<relay-hostname>")," should be set to the hostname of the relay server machine and ",(0,i.kt)("inlineCode",{parentName:"li"},"<relay-port>")," should match the ",(0,i.kt)("inlineCode",{parentName:"li"},"port")," value in the relay's ",(0,i.kt)("inlineCode",{parentName:"li"},"config.toml")," (see above)."),(0,i.kt)("li",{parentName:"ul"},"The ",(0,i.kt)("inlineCode",{parentName:"li"},"NETWORK_NAME")," variable should be a unique ID referring to the Fabric network. It will be used to distinguish container names and wallet paths. (This setting is relevant in situations where a driver is used to query multiple network channels.)"),(0,i.kt)("li",{parentName:"ul"},"The ",(0,i.kt)("inlineCode",{parentName:"li"},"DRIVER_PORT")," variable should be set to the port this driver will listen on."),(0,i.kt)("li",{parentName:"ul"},"The ",(0,i.kt)("inlineCode",{parentName:"li"},"INTEROP_CHAINCODE")," variable should be set to the ID of the Fabric Interop Chaincode installed on your Fabric network channel."),(0,i.kt)("li",{parentName:"ul"},"The ",(0,i.kt)("inlineCode",{parentName:"li"},"EXTERNAL_NETWORK")," variable should be set to the ",(0,i.kt)("a",{parentName:"li",href:"https://docs.docker.com/compose/networking/"},"name")," of your Fabric network."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"Enabling TLS"),":",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},"You can make your driver accept TLS connections by specifying ",(0,i.kt)("inlineCode",{parentName:"li"},"DRIVER_TLS")," as ",(0,i.kt)("inlineCode",{parentName:"li"},"true")," and specifying a TLS certificate file path and private key file path in ",(0,i.kt)("inlineCode",{parentName:"li"},"DRIVER_TLS_CERT_PATH")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"DRIVER_TLS_KEY_PATH")," respectively. The same certificate should be specified in this driver's definition in the ",(0,i.kt)("inlineCode",{parentName:"li"},"drivers")," section in the ",(0,i.kt)("inlineCode",{parentName:"li"},"config.toml")," file of your relay in the ",(0,i.kt)("inlineCode",{parentName:"li"},"tlsca_cert_path")," property (see the earlier section on relay configuration)."),(0,i.kt)("li",{parentName:"ul"},"To communicate with your network' relay using TLS (i.e., if the relay is TLS-enabled), specify that relay's TLS CA certificate path in ",(0,i.kt)("inlineCode",{parentName:"li"},"RELAY_TLSCA_CERT_PATH")," (currently only one certificate can be configured) and set ",(0,i.kt)("inlineCode",{parentName:"li"},"RELAY_TLS")," to ",(0,i.kt)("inlineCode",{parentName:"li"},"true"),". This CA certificate should match the one specified in the ",(0,i.kt)("inlineCode",{parentName:"li"},"cert_path")," property in the relay's ",(0,i.kt)("inlineCode",{parentName:"li"},"config.toml")," file (see the earlier section on relay configuration):"),(0,i.kt)("li",{parentName:"ul"},"You can point to the folder in your host system containing the certificate and key using the ",(0,i.kt)("inlineCode",{parentName:"li"},"TLS_CREDENTIALS_DIR")," variable. (This folder will be synced to the ",(0,i.kt)("inlineCode",{parentName:"li"},"/fabric-driver/credentials")," folder in the Fabric Driver container as specified in the ",(0,i.kt)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/core/drivers/fabric-driver/docker-compose.yml"},"docker-compose file"),".) Make sure you point to the right certificate and key file paths within the container using the ",(0,i.kt)("inlineCode",{parentName:"li"},"DRIVER_TLS_CERT_PATH"),", ",(0,i.kt)("inlineCode",{parentName:"li"},"DRIVER_TLS_KEY_PATH"),", and ",(0,i.kt)("inlineCode",{parentName:"li"},"RELAY_TLSCA_CERT_PATH")," variables."))))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"config.json"),": This contains settings used to connect to a CA of a Fabric network organization and enroll a client. A sample is given below:"),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "admin":{\n "name":"admin",\n "secret":"adminpw"\n },\n "relay": {\n "name":"relay",\n "affiliation":"<affiliation>",\n "role": "client",\n "attrs": [{ "name": "relay", "value": "true", "ecert": true }]\n },\n "mspId":"<msp-id>",\n "caUrl":"<ca-service-endpoint>"\n}\n')),(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},"As in the ",(0,i.kt)("inlineCode",{parentName:"li"},".env")," configuration, you should pick an organization for the driver to associate with. The ",(0,i.kt)("inlineCode",{parentName:"li"},"admin")," section specifies the registrar name and password (this should be familiar to any Fabric network administrator) used to enroll clients. Default values of ",(0,i.kt)("inlineCode",{parentName:"li"},"admin")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"adminpw")," are specified above as examples, which you should replace with the right values configured in your network organization's CA."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"<affiliation>")," should be what's specified in your organization's Fabric CA server configuration. The default is ",(0,i.kt)("inlineCode",{parentName:"li"},"org1.department1"),", but you should look up the appropriate value from the CA server's configuration file."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"<msp-id>")," should be set to the (or an) MSP ID of the selected organization."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"<ca-service-endpoint>")," should be set to the CA server's endpoint. If you launched your CA server as a container from a docker-compose file, this should be set to the container's service name.")),(0,i.kt)("table",{parentName:"li"},(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"left"},"If your connection profile already contains specifications for a CA server, you can leave the ",(0,i.kt)("inlineCode",{parentName:"td"},"<ca-service-endpoint>")," value as a blank."))))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"docker-compose.yaml"),": This specifies the properties of the driver container. You can use the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/core/drivers/fabric-driver/docker-compose.yml"},"file in the repository")," verbatim."))),(0,i.kt)("p",null,"To start the driver, navigate to the folder containing the above files and run the following:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"docker-compose up -d\n")),(0,i.kt)("h4",{id:"launch-iin-agents"},"Launch IIN Agents"),(0,i.kt)("p",null,"You need to run one IIN Agent for each organization in the Fabric network channel you are enabling Weaver in. This agent runs a protocol with other organizations' agents and with targeted foreign networks' agents to sync and record foreign networks' memberships to the channel ledger."),(0,i.kt)("p",null,"Weaver provides a ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/pkgs/container/weaver-iin-agent"},"pre-built image")," for the IIN Agent. Before launching a container, you just need to customize its configuration for your Fabric network organization, which you can do by simply creating a folder (let's call it ",(0,i.kt)("inlineCode",{parentName:"p"},"iin_agent_config_<orgname>"),") and configuring the following files in it:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"config.json"),": This contains settings used to connect to a Fabric network organization and its CA (part of the organization's MSP). A sample is given below:"),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre"},'{\n "admin":{\n "name":"admin",\n "secret":"adminpw"\n },\n "agent": {\n "name":"iin-agent",\n "affiliation":"<affiliation>",\n "role": "client",\n "attrs": [{ "name": "iin-agent", "value": "true", "ecert": true }]\n },\n "mspId":"<msp-id>",\n "ordererMspIds": [<list-of-orderer-msp-ids>],\n "ccpPath": "<path-to-connection-profile>",\n "walletPath": "",\n "caUrl": "<ca-service-endpoint>",\n "local": "false"\n}\n'))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"dnsconfig.json"),": This specifies the list of known IIN agents of your network (i.e., belonging to other organizations) and of foreign networks. A sample DNS configuration file is given below:"),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre"},'{\n "<securityDomainName1>": {\n "<iin-agent1-name>": {\n "endpoint": "<hostname:port>",\n "tls": <true/false>,\n "tlsCACertPath": "<cacert-path-or-empty-string>"\n },\n "<iin-agent2-name>": {\n "endpoint": "<hostname:port>",\n "tls": <true/false>,\n "tlsCACertPath": "<cacert-path-or-empty-string>"\n }\n },\n "<securityDomainName2>": {\n "<iin-agent1-name>": {\n "endpoint": "<hostname:port>",\n "tls": <true/false>,\n "tlsCACertPath": "<cacert-path-or-empty-string>"\n },\n "<iin-agent2-name>": {\n "endpoint": "<hostname:port>",\n "tls": <true/false>,\n "tlsCACertPath": "<cacert-path-or-empty-string>"\n }\n }\n}\n')),(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},"Each security domain (i.e., unique ledger, like a Fabric channel) scopes a set of JSON objects, each containing specifications of an IIN Agent. The key (",(0,i.kt)("inlineCode",{parentName:"li"},"<iin-agent1-name>")," for example) in each is the IIN Agent's name, which can be the organization's MSP ID (for a Fabric network). The value is another JSON object, containing an ",(0,i.kt)("inlineCode",{parentName:"li"},"endpoint")," with a hostname and port for the agent."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"Enabling TLS"),": To communicate with a given IIN Agent using TLS (i.e., if that agent is TLS-enabled), specify ",(0,i.kt)("inlineCode",{parentName:"li"},"tls")," as ",(0,i.kt)("inlineCode",{parentName:"li"},"true")," and that agent's TLS CA certificate path in ",(0,i.kt)("inlineCode",{parentName:"li"},"tlsCACertPath")," (currently only one certificate can be configured) within the JSON object corresponding to that agent. This CA certificate should match the one specified in that IIN Agent's ",(0,i.kt)("inlineCode",{parentName:"li"},".env")," file, whose configuration we will specify later."))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"security-domain-config.json"),": This config file contains list of security domain defined for the network and its members, i.e. it can be list of organizations or channel name. Sample security domain configuration file:"),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre"},'{\n "<securityDomainName1>": "<channelName>",\n "<securityDomainName2>": [\n "<Org1MSPId>",\n "<Org2MSPId>"\n ]\n}\n'))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},".env"),": This sets suitable environment variables within the driver container. Copy the ",(0,i.kt)("inlineCode",{parentName:"p"},".env.template")," file ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/core/identity-management/iin-agent/.env.docker.template"},"from the repository")," and customize it for your purposes, as indicated in the below sample:"),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre"},"IIN_AGENT_PORT=<iin-agent-server-port>\nIIN_AGENT_TLS=<true/false>\nIIN_AGENT_TLS_CERT_PATH=<path_to_tls_cert_pem_for_iin_agent>\nIIN_AGENT_TLS_KEY_PATH=<path_to_tls_key_pem_for_iin_agent>\nMEMBER_ID=<org-msp-id>\nSECURITY_DOMAIN=network1\nDLT_TYPE=fabric\nCONFIG_PATH=./config.json\nDNS_CONFIG_PATH=./dnsconfig.json\nSECURITY_DOMAIN_CONFIG_PATH=./security-domain-config.json\nWEAVER_CONTRACT_ID=<name-of-weaver-interop-chaincode-installed>\nSYNC_PERIOD=<repeated_auto_sync_interval>\nAUTO_SYNC=<true/false>\nTLS_CREDENTIALS_DIR=<dir-with-tls-cert-and-key>\nDOCKER_IMAGE_NAME=ghcr.io/hyperledger-labs/weaver-iin-agent\nDOCKER_TAG=<iin-agent-docker-image-version>\nEXTERNAL_NETWORK=<docker-bridge-network>\n")),(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"IIN_AGENT_ENDPOINT"),": The endpoint at which IIN Agent server should listen. E.g.: ",(0,i.kt)("inlineCode",{parentName:"li"},"0.0.0.0:9500")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"IIN_AGENT_TLS"),": Set this to ",(0,i.kt)("inlineCode",{parentName:"li"},"true")," to enable TLS on IIN Agent server"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"IIN_AGENT_TLS_CERT_PATH"),": Path to TLS certificate if TLS is enabled"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"IIN_AGENT_TLS_KEY_PATH"),": Path to TLS key if TLS is enabled"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"MEMBER_ID"),": Member Id for this IIN Agent. For fabric network, it should be the Organization's MSP ID"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"SECURITY_DOMAIN"),": Security domain to which this IIN Agent belongs"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"DLT_TYPE"),": To indicate the type of DLT for which this IIN Agent is running. E.g. ",(0,i.kt)("inlineCode",{parentName:"li"},"fabric")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"CONFIG_PATH"),": Path to ledger specific config file (explained in next subsection)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"DNS_CONFIG_PATH"),": Path to DNS config file explained in previous sub sections"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"SECURITY_DOMAIN_CONFIG_PATH"),": Path to security domain config file explained in previous sub sections"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"WEAVER_CONTRACT_ID"),": Contract ID for DLT specific Weaver interoperation module installed on network"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"SYNC_PERIOD"),": Period at which auto synchronization of memberships from other security domains should happen"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"AUTO_SYNC"),": Set this to ",(0,i.kt)("inlineCode",{parentName:"li"},"true")," to enable auto synchronization of memberships from other security domains"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"DOCKER_TAG"),": Set this to the desired version of the Weaver IIN Agent ",(0,i.kt)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/pkgs/container/weaver-iin-agent"},"docker image")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"EXTERNAL_NETWORK"),": Set to the network ",(0,i.kt)("a",{parentName:"li",href:"https://docs.docker.com/compose/networking/"},"name")," of your Fabric network."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"Enabling TLS"),":",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},"Make your IIN Agent accept TLS connections by specifying ",(0,i.kt)("inlineCode",{parentName:"li"},"IIN_AGENT_TLS")," as ",(0,i.kt)("inlineCode",{parentName:"li"},"true")," and specifying a TLS certificate file path and private key file path in ",(0,i.kt)("inlineCode",{parentName:"li"},"IIN_AGENT_TLS_CERT_PATH")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"IIN_AGENT_TLS_KEY_PATH")," respectively. The same certificate should be specified in this agent's JSON object in another agent's ",(0,i.kt)("inlineCode",{parentName:"li"},"dnsconfig.json")," file under the appropriate security domain and IIN Agent ID scope."),(0,i.kt)("li",{parentName:"ul"},"You can point to the folder in your host system containing the certificate and key using the ",(0,i.kt)("inlineCode",{parentName:"li"},"TLS_CREDENTIALS_DIR")," variable. (This folder will be synced to the ",(0,i.kt)("inlineCode",{parentName:"li"},"/opt/iinagent/credentials")," folder in the IIN Agent container as specified in the ",(0,i.kt)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/core/identity-management/iin-agent/docker-compose.yml"},"docker-compose file"),".) Make sure you point to the right certificate and key file paths within the container using the ",(0,i.kt)("inlineCode",{parentName:"li"},"IIN_AGENT_TLS_CERT_PATH")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"IIN_AGENT_TLS_KEY_PATH")," variables respectively."))))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"docker-compose.yaml"),": This specifies the properties of the IIN agent container. You can use the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/core/identity-management/iin-agent/docker-compose.yml"},"file in the repository")," verbatim."))),(0,i.kt)("p",null,"Now to start the IIN agent, navigate to the folder containing the above files and run the following:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"docker-compose up -d\n")),(0,i.kt)("p",null,"Repeat the above steps to launch an IIN Agent for every other organization on your channnel, i.e., create similar configuration files in an organization-specific folder. Make sure you:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Update the organization names in every relevant location in the ",(0,i.kt)("inlineCode",{parentName:"li"},"config.json"),"."),(0,i.kt)("li",{parentName:"ul"},"Update ",(0,i.kt)("inlineCode",{parentName:"li"},"IIN_AGENT_ENDPOINT")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"MEMBER_ID")," in the ",(0,i.kt)("inlineCode",{parentName:"li"},".env"),".")),(0,i.kt)("h4",{id:"ledger-initialization"},"Ledger Initialization"),(0,i.kt)("p",null,"To prepare your network for interoperation with a foreign network, you need to record the following to your network channel through the Fabric Interoperation Chaincode:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},"Access control policies"),":\nLet's take the example of the request made from ",(0,i.kt)("inlineCode",{parentName:"p"},"trade-finance-network")," to ",(0,i.kt)("inlineCode",{parentName:"p"},"trade-logistics-network")," for a B/L earlier in this document. ",(0,i.kt)("inlineCode",{parentName:"p"},"trade-logistics-network")," can have a policy of the following form permitting access to the ",(0,i.kt)("inlineCode",{parentName:"p"},"GetBillOfLading")," function from a client belonging to the ",(0,i.kt)("inlineCode",{parentName:"p"},"Exporter")," organization in ",(0,i.kt)("inlineCode",{parentName:"p"},"trade-finance-network")," as follows:"),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "securityDomain":"trade-finance-network",\n "rules":\n [\n {\n "principal":"ExporterMSP",\n "principalType":"ca",\n "resource":"tradelogisticschannel:shipmentcc:GetBillOfLading:*",\n "read":true\n }\n ]\n}\n')),(0,i.kt)("p",{parentName:"li"},"In this sample, a single rule is specified for requests coming from ",(0,i.kt)("inlineCode",{parentName:"p"},"trade-finance-network"),": it states that a ",(0,i.kt)("inlineCode",{parentName:"p"},"GetBillOfLading")," query made to the ",(0,i.kt)("inlineCode",{parentName:"p"},"shipmentcc")," contract installed on the ",(0,i.kt)("inlineCode",{parentName:"p"},"tradelogisticschannel")," channel is permitted for a requestor possessing credentials certified by an MSP with the ",(0,i.kt)("inlineCode",{parentName:"p"},"ExporterMSP")," identity. The ",(0,i.kt)("inlineCode",{parentName:"p"},"*")," at the end indicates that any arguments passed to the function will pass the access control check."),(0,i.kt)("p",{parentName:"li"},"You need to record this policy rule on your Fabric network's channel by invoking either the ",(0,i.kt)("inlineCode",{parentName:"p"},"CreateAccessControlPolicy")," function or the ",(0,i.kt)("inlineCode",{parentName:"p"},"UpdateAccessControlPolicy")," function on the Fabric Interoperation Chaincode that is already installed on that channel; use the former if you are recording a set of rules for the given ",(0,i.kt)("inlineCode",{parentName:"p"},"securityDomain")," for the first time and the latter to overwrite a set of rules recorded earlier. In either case, the chaincode function will take a single argument, which is the policy in the form of a JSON string (make sure you escape the double quotes before sending the request to avoid parsing errors). You can do this in one of two ways: (1) writing a small piece of code in Layer-2 that invokes the contract using the Fabric SDK Gateway API, or (2) running a ",(0,i.kt)("inlineCode",{parentName:"p"},"peer chaincode invoke")," command from within a Docker container built on the ",(0,i.kt)("inlineCode",{parentName:"p"},"hyperledger/fabric-tools")," image. Either approach should be familiar to a Fabric practitioner.")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},"Verification policies"),":\nTaking the same example as above, an example of a verification policy for a B/L requested by the ",(0,i.kt)("inlineCode",{parentName:"p"},"trade-finance-network")," from the ",(0,i.kt)("inlineCode",{parentName:"p"},"trade-logistics-network")," is as follows:"),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "securityDomain":"trade-logistics-network",\n "identifiers":\n [\n {\n "pattern":"tradelogisticschannel:shipmentcc:GetBillOfLading:*",\n "policy":\n {\n "type":"Signature",\n "criteria":\n [\n "ExporterMSP",\n "CarrierMSP"\n ]\n }\n }\n ]\n}\n')),(0,i.kt)("p",{parentName:"li"},"In this sample, a single verification policy rule is specified for data views coming from ",(0,i.kt)("inlineCode",{parentName:"p"},"trade-logistics-network"),": it states that the data returned by the ",(0,i.kt)("inlineCode",{parentName:"p"},"GetBillOfLading")," query made to the ",(0,i.kt)("inlineCode",{parentName:"p"},"shipmentcc")," chaincode on the ",(0,i.kt)("inlineCode",{parentName:"p"},"tradelogisticschannel")," channel requires as proof two signatures, one from a peer in the organization whose MSP ID is ",(0,i.kt)("inlineCode",{parentName:"p"},"ExporterMSP")," and another from a peer in the organization whose MSP ID is ",(0,i.kt)("inlineCode",{parentName:"p"},"CarrierMSP"),"."),(0,i.kt)("p",{parentName:"li"},"You need to record this policy rule on your Fabric network's channel by invoking either the ",(0,i.kt)("inlineCode",{parentName:"p"},"CreateVerificationPolicy")," function or the ",(0,i.kt)("inlineCode",{parentName:"p"},"UpdateVerificationPolicy")," function on the Fabric Interoperation Chaincode that is already installed on that channel; use the former if you are recording a set of rules for the given ",(0,i.kt)("inlineCode",{parentName:"p"},"securityDomain")," for the first time and the latter to overwrite a set of rules recorded earlier. In either case, the chaincode function will take a single argument, which is the policy in the form of a JSON string (make sure you escape the double quotes before sending the request to avoid parsing errors). As with the access control policy, you can do this in one of two ways: (1) writing a small piece of code in Layer-2 that invokes the contract using the Fabric SDK Gateway API, or (2) running a ",(0,i.kt)("inlineCode",{parentName:"p"},"peer chaincode invoke")," command from within a Docker container built on the ",(0,i.kt)("inlineCode",{parentName:"p"},"hyperledger/fabric-tools")," image. Either approach should be familiar to a Fabric practitioner."),(0,i.kt)("table",{parentName:"li"},(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"left"},"For any cross-network data request, make sure an access control policy is recorded in the ",(0,i.kt)("em",{parentName:"td"},"source network")," (",(0,i.kt)("inlineCode",{parentName:"td"},"trade-logistics-network")," in the above example) and a corresponding verification policy is recorded in the ",(0,i.kt)("em",{parentName:"td"},"destination network")," (",(0,i.kt)("inlineCode",{parentName:"td"},"trade-finance-network")," in the above example) before any relay request is triggered."))))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},"Local network security domain (membership) configuration"),':\nRecall the code snippet added to your application in the "Identity Administration" section. Exercise that code snippet, exposed either through a function API or an HTTP endpoint, to record the initial local membership for the relevant network channels.'))),(0,i.kt)("p",null,"Your Fabric network is now up and running with the necessary Weaver components, and your network's channel's ledger is bootstrapped with the initial configuration necessary for cross-network interactions!"))}h.isMDXComponent=!0},6269:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/fabric-network-model-06abc1e93e9ae75bd416b1f822b7a312.png"},1088:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/fabric-weaver-model-bf28db3b4df0cd0ecd2a364e6886f91e.png"}}]); \ No newline at end of file diff --git a/assets/js/98ecfc99.de12cc9c.js b/assets/js/98ecfc99.de12cc9c.js new file mode 100644 index 000000000..2f9555dd5 --- /dev/null +++ b/assets/js/98ecfc99.de12cc9c.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[31],{5680:(e,n,t)=>{t.d(n,{xA:()=>p,yg:()=>m});var a=t(6540);function i(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function r(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function o(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?r(Object(t),!0).forEach((function(n){i(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):r(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function l(e,n){if(null==e)return{};var t,a,i=function(e,n){if(null==e)return{};var t,a,i={},r=Object.keys(e);for(a=0;a<r.length;a++)t=r[a],n.indexOf(t)>=0||(i[t]=e[t]);return i}(e,n);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a<r.length;a++)t=r[a],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(i[t]=e[t])}return i}var s=a.createContext({}),c=function(e){var n=a.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):o(o({},n),e)),t},p=function(e){var n=c(e.components);return a.createElement(s.Provider,{value:n},e.children)},d="mdxType",g={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},h=a.forwardRef((function(e,n){var t=e.components,i=e.mdxType,r=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),d=c(t),h=i,m=d["".concat(s,".").concat(h)]||d[h]||g[h]||r;return t?a.createElement(m,o(o({ref:n},p),{},{components:t})):a.createElement(m,o({ref:n},p))}));function m(e,n){var t=arguments,i=n&&n.mdxType;if("string"==typeof e||i){var r=t.length,o=new Array(r);o[0]=h;var l={};for(var s in n)hasOwnProperty.call(n,s)&&(l[s]=n[s]);l.originalType=e,l[d]="string"==typeof e?e:i,o[1]=l;for(var c=2;c<r;c++)o[c]=t[c];return a.createElement.apply(null,o)}return a.createElement.apply(null,t)}h.displayName="MDXCreateElement"},2111:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>s,contentTitle:()=>o,default:()=>g,frontMatter:()=>r,metadata:()=>l,toc:()=>c});var a=t(8168),i=(t(6540),t(5680));const r={id:"fabric",title:"Hyperledger Fabric"},o=void 0,l={unversionedId:"external/getting-started/enabling-weaver-network/fabric",id:"external/getting-started/enabling-weaver-network/fabric",title:"Hyperledger Fabric",description:"\x3c!--",source:"@site/docs/external/getting-started/enabling-weaver-network/fabric.md",sourceDirName:"external/getting-started/enabling-weaver-network",slug:"/external/getting-started/enabling-weaver-network/fabric",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/fabric",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/getting-started/enabling-weaver-network/fabric.md",tags:[],version:"current",frontMatter:{id:"fabric",title:"Hyperledger Fabric"},sidebar:"Documentation",previous:{title:"Enabling Weaver in Existing DLT Applications",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/overview"},next:{title:"Corda",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/corda"}},s={},c=[{value:"Model",id:"model",level:2},{value:"Procedural Overview",id:"procedural-overview",level:2},{value:"Development Phase",id:"development-phase",level:2},{value:"Chaincode",id:"chaincode",level:3},{value:"For Data Sharing",id:"for-data-sharing",level:4},{value:"For Asset Exchange",id:"for-asset-exchange",level:4},{value:"For Asset Transfer",id:"for-asset-transfer",level:4},{value:"Client (or Layer-2) Applications",id:"client-or-layer-2-applications",level:3},{value:"For Identity Administration",id:"for-identity-administration",level:4},{value:"For Data Sharing",id:"for-data-sharing-1",level:4},{value:"For Asset Exchange",id:"for-asset-exchange-1",level:4},{value:"For Asset Transfer",id:"for-asset-transfer-1",level:4},{value:"Pre-Configuration Phase",id:"pre-configuration-phase",level:2},{value:"Startup and Bootstrap Phase",id:"startup-and-bootstrap-phase",level:2},{value:"For Asset Exchange",id:"for-asset-exchange-2",level:3},{value:"Install the Fabric Interoperation Chaincode",id:"install-the-fabric-interoperation-chaincode",level:4},{value:"For Data Sharing or Asset Transfer",id:"for-data-sharing-or-asset-transfer",level:3},{value:"Install the Fabric Interoperation Chaincode",id:"install-the-fabric-interoperation-chaincode-1",level:4},{value:"Launch Relay",id:"launch-relay",level:4},{value:"Launch Driver",id:"launch-driver",level:4},{value:"Launch IIN Agents",id:"launch-iin-agents",level:4},{value:"Ledger Initialization",id:"ledger-initialization",level:4}],p={toc:c},d="wrapper";function g(e){let{components:n,...r}=e;return(0,i.yg)(d,(0,a.A)({},p,r,{components:n,mdxType:"MDXLayout"}),(0,i.yg)("p",null,"After testing the Weaver interoperation mechanisms on ",(0,i.yg)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/overview"},"basic sample networks"),", you may be interested in finding out how you can equip an existing real network, whether in development or in production, to exercise these mechanisms. In this document, we will demonstrate how to equip a Fabric network and application with Weaver components and capabilities."),(0,i.yg)("h2",{id:"model"},"Model"),(0,i.yg)("p",null,"The figure below illustrates a typical Fabric network. The infrastructure consists of a set of peers, ordering service nodes, and CAs that perform the roles of MSPs; each serves a given ",(0,i.yg)("em",{parentName:"p"},"organization")," which is one of the constituent units of the network. On the peers are installed one or more smart contracts (",(0,i.yg)("em",{parentName:"p"},"chaincode"),"), representing shared business logic across the different organizations. Further up lie the so-called Layer-2 (or client) applications that consist of organization-specific business logic and invoke the smart contracts using APIs exposed by the Fabric SDK and with wallet credentials issued by their respective organizations' CAs."),(0,i.yg)("p",null,(0,i.yg)("img",{alt:"alt text",src:t(6185).A,width:"1107",height:"607"})),(0,i.yg)("p",null,"Such a network equipped with Weaver components and capabilities will look like the figure below. Legacy components are marked in grey and Weaver and bridging components in green."),(0,i.yg)("p",null,(0,i.yg)("img",{alt:"alt text",src:t(419).A,width:"1452",height:"632"})),(0,i.yg)("p",null,"The relay and driver are the only additional infrastructure that need to be installed. One or more relays can be installed, as can one or more drivers. The drivers are illustrated in Layer-2 rather than in the bottom layer because, though they are coupled with relays, they exercise contracts using the Fabric SDK and organization-issued credentials just like any Layer-2 application does."),(0,i.yg)("p",null,"Existing chaincode deployed on the network's channels remain undisturbed. All that is required in the smart contracts layer is the deployment of the Fabric Interoperation Chaincode on every channel that needs to offer or consume state from foreign networks."),(0,i.yg)("p",null,"Layer-2, or client, applications will need some additional code and configuration because the decisions to exercise interoperation mechanisms (relay queries for data sharing or atomic asset exchanges) are strictly part of business logic. But Weaver's Fabric Interoperation Node SDK offers various helper functions to ease this process and keep the adaptation to a minimum, as we wil see later in this document. Finally, an ",(0,i.yg)("em",{parentName:"p"},"identity service")," must be offered by the network to expose its CAs' certificate chains to foreign networks, thereby laying the basis for interoperation. This service simply needs to offer a REST endpoint, and can be implemented as a standalone application or (more conveniently) as an augmentation of one or more of the existing Layer-2 applications."),(0,i.yg)("h2",{id:"procedural-overview"},"Procedural Overview"),(0,i.yg)("p",null,"A Hyperledger Fabric network is typically created in phases, in the following sequence:"),(0,i.yg)("ol",null,(0,i.yg)("li",{parentName:"ol"},(0,i.yg)("strong",{parentName:"li"},"Development"),": This involves writing chaincode and Layer-2 applications. The chaincode's deployment name/ID and its transaction API must be designed first, but subsequent development of the two layers of applications can then proceed parallelly."),(0,i.yg)("li",{parentName:"ol"},(0,i.yg)("strong",{parentName:"li"},"Pre-Configuration"),": This involves creating a desired specification (as a set of configuration diles) of the network topology and the ledgers it maintains."),(0,i.yg)("li",{parentName:"ol"},(0,i.yg)("strong",{parentName:"li"},"Startup and Bootstrap"),": This is the launch phase, in which the network components and applications are started and bootstrapped (i.e., configured with initial state and operating rules).")),(0,i.yg)("p",null,"Assuming that the reader is familiar with this procedure, we will walk through the changes required in each phase to make your network ready for interoperation using Weaver components and code templates. This will involve code addition and adaptation, deployment of additional modules, additional configuration, and creation of additional ledger state records. The requirements and effort will vary with the mode of interoperation you wish to support in your Fabric network."),(0,i.yg)("h2",{id:"development-phase"},"Development Phase"),(0,i.yg)("p",null,"A Fabric distributed application's business logic code spans two layers as illustrated in the network model."),(0,i.yg)("h3",{id:"chaincode"},"Chaincode"),(0,i.yg)("p",null,"These are smart contracts embodied in code, managing business workflow state and digital assets."),(0,i.yg)("h4",{id:"for-data-sharing"},"For Data Sharing"),(0,i.yg)("p",null,"No code changes are required for Weaver enablement, because data sharing involves:"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},"View packaging (and optionally, encryption) logic and access control logic in a source network, and"),(0,i.yg)("li",{parentName:"ul"},"View validation logic in a destination network")),(0,i.yg)("p",null,"This logic is standard and independent of smart contract, asset, and state, particulars. It is already implemented in the Fabric Interoperation Chaincode offered by Weaver. Hence you just need to deploy that chaincode to exercise data sharing from, or to, your application chaincode. Your application chaincode can be oblivious of the Fabric Interoperation Chaincode's workings and of the view request-response protocol."),(0,i.yg)("h4",{id:"for-asset-exchange"},"For Asset Exchange"),(0,i.yg)("p",null,"To exchange an asset using Weaver, the asset's state on the ledger must be controlled in the following ways:"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},"Locked in favor of a party"),(0,i.yg)("li",{parentName:"ul"},"Claimed by the party to whom the asset is pledged"),(0,i.yg)("li",{parentName:"ul"},"Returned to the original owner if it is not claimed within a given timeframe")),(0,i.yg)("p",null,"In addition, the state of the asset (i.e., whether it is locked), and its current and targeted owners, must be determinable by looking at the ledger records."),(0,i.yg)("p",null,"The bookkeeping logic required to maintain records of locks can be abstracted away from the particulars of a digital asset and its workflow. But as such assets and their properties (including ownership) can be, and are, encoded in an arbitrary number of ways, we cannot provide a one-size-fits all set of functions (like in the data sharing protocol) to exchange any kind of asset. Instead, we must rely on the application contract (chaincode) managing an asset, as it knows precisely what the asset's properties are and how they can be updated and queried on the ledger (channel)."),(0,i.yg)("p",null,"What Weaver offers, therefore, is the following:"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},"Lock management (bookkeeping) logic implemented in the Fabric Interoperation Chaincode that treats each asset as an abstract object and is agnostic of the assets' internals. This logic can be exercised in one of two ways:",(0,i.yg)("ul",{parentName:"li"},(0,i.yg)("li",{parentName:"ul"},"Importing the ",(0,i.yg)("a",{parentName:"li",href:"https://pkg.go.dev/github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/libs/assetexchange"},(0,i.yg)("inlineCode",{parentName:"a"},"assetexchange"))," library from the Fabric Interoperation Chaincode into your application chaincode, or"),(0,i.yg)("li",{parentName:"ul"},"Invoking them within the Fabric Interoperation Chaincode using a ",(0,i.yg)("a",{parentName:"li",href:"https://pkg.go.dev/github.com/hyperledger/fabric-chaincode-go/shim#ChaincodeStub.InvokeChaincode"},"chaincode-to-chaincode call"),"."))),(0,i.yg)("li",{parentName:"ul"},"A set of template functions with sample (and extensible) code that must be added to the application chaincode to exercise the above lock management functions.")),(0,i.yg)("p",null,"Below, we list the template functions with sample code that you, as a developer, must use and adapt within your chaincode, in either mode (library import or chaincode invocations)."),(0,i.yg)("table",null,(0,i.yg)("thead",{parentName:"table"},(0,i.yg)("tr",{parentName:"thead"},(0,i.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,i.yg)("tbody",{parentName:"table"},(0,i.yg)("tr",{parentName:"tbody"},(0,i.yg)("td",{parentName:"tr",align:"left"},"The instructions here apply only to chaincode implemented in Go, because Weaver presently offers only a Go version of the Fabric Interoperation Chaincode.")))),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("p",{parentName:"li"},(0,i.yg)("em",{parentName:"p"},"Using the ",(0,i.yg)("a",{parentName:"em",href:"https://pkg.go.dev/github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/libs/assetexchange"},(0,i.yg)("inlineCode",{parentName:"a"},"assetexchange"))," Library"),": This method doesn't require the ",(0,i.yg)("a",{parentName:"p",href:"https://pkg.go.dev/github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/contracts/interop"},(0,i.yg)("inlineCode",{parentName:"a"},"Fabric Interoperation Chaincode"))," to be installed. In your smart contract's ",(0,i.yg)("inlineCode",{parentName:"p"},"go.mod"),", add the following in the ",(0,i.yg)("inlineCode",{parentName:"p"},"require")," section (the sample below uses the current versions for dependency packages; update them to the latest versions offered by Weaver):"),(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-go"},"require(\n ...\n github.com/hyperledger-labs/weaver-dlt-interoperability/common/protos-go v1.5.6\n github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/libs/assetexchange v1.5.3\n ...\n)\n")),(0,i.yg)("p",{parentName:"li"},"The following functions need to be added to your chaincode, and the smart contract class/type used below is called ",(0,i.yg)("inlineCode",{parentName:"p"},"SmartContract")," (",(0,i.yg)("em",{parentName:"p"},"Note"),": the function signature, i.e. the name, arguments, and return values, need to be exactly what is given in the below samples; you can have additional code to manage asset state as per need):"),(0,i.yg)("ol",{parentName:"li"},(0,i.yg)("li",{parentName:"ol"},(0,i.yg)("strong",{parentName:"li"},"LockAsset"),(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-go"},'import (\n ...\n "github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/libs/assetexchange"\n)\nfunc (s *SmartContract) LockAsset(ctx contractapi.TransactionContextInterface, assetExchangeAgreementSerializedProto64 string, lockInfoSerializedProto64 string) (string, error) {\n // Add some safety checks before calling LockAsset from library\n // Caller of this chaincode is supposed to be the Locker and the owner of the asset being locked.\n contractId, err := assetexchange.LockAsset(ctx, "", assetExchangeAgreementSerializedProto64, lockInfoSerializedProto64)\n if err != nil {\n return "", logThenErrorf(err.Error())\n }\n // Post proccessing of asset after LockAsset called like change status of the asset so that it can\'t be spent.\n ...\n return contractId, nil\n}\n')),"Here ",(0,i.yg)("inlineCode",{parentName:"li"},"assetExchangeAgreementSerializedProto64")," is a serialized protobuf in Base64 encoded string of ",(0,i.yg)("inlineCode",{parentName:"li"},"AssetExchangeAgreement")," protobuf structure, and can be used to extract details like asset id, type of asset and recipient. Check the structure definition ",(0,i.yg)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/rfcs/formats/assets/exchange.md#representing-two-party-asset-exchange-agreements"},"here"),".\nSimilarly ",(0,i.yg)("inlineCode",{parentName:"li"},"lockInfoSerializedProto64")," is a serialized protobuf in Base64 encoded string of ",(0,i.yg)("inlineCode",{parentName:"li"},"AssetLock")," protobuf structure. Check the structure definition ",(0,i.yg)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/rfcs/formats/assets/exchange.md#representing-locks-on-assets"},"here"),"."),(0,i.yg)("li",{parentName:"ol"},(0,i.yg)("strong",{parentName:"li"},"LockFungibleAsset"),(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-go"},'func (s *SmartContract) LockFungibleAsset(ctx contractapi.TransactionContextInterface, fungibleAssetExchangeAgreementSerializedProto64 string, lockInfoSerializedProto64 string) (string, error) {\n // Add some safety checks before calling LockFungibleAsset from library\n // Caller of this chaincode is supposed to be the Locker and the owner of the asset being locked.\n contractId, err := assetexchange.LockFungibleAsset(ctx, "", fungibleAssetExchangeAgreementSerializedProto64, lockInfoSerializedProto64)\n if err != nil {\n return "", logThenErrorf(err.Error())\n }\n // Post proccessing of asset after LockFungibleAsset called like reduce the amount of tokens owned by the locker, or mark it locked so that it can\'t be spent.\n ...\n return contractId, nil\n}\n')),"Here ",(0,i.yg)("inlineCode",{parentName:"li"},"fungibleAssetExchangeAgreementSerializedProto64")," is a serialized protobuf in Base64 encoded string of ",(0,i.yg)("inlineCode",{parentName:"li"},"FungibleAssetExchangeAgreement")," protobuf structure, and can be used to extract details like asset quantity, type of asset and recipient. Check the structure definition ",(0,i.yg)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/rfcs/formats/assets/exchange.md#representing-two-party-asset-exchange-agreements"},"here"),"."),(0,i.yg)("li",{parentName:"ol"},(0,i.yg)("strong",{parentName:"li"},"IsAssetLockedQueryUsingContractId"),(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-go"},"func (s *SmartContract) IsAssetLockedQueryUsingContractId(ctx contractapi.TransactionContextInterface, contractId string) (bool, error) {\n return assetexchange.IsAssetLockedQueryUsingContractId(ctx, contractId)\n}\n"))),(0,i.yg)("li",{parentName:"ol"},(0,i.yg)("strong",{parentName:"li"},"ClaimAssetUsingContractId"),(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-go"},"func (s *SmartContract) ClaimAssetUsingContractId(ctx contractapi.TransactionContextInterface, contractId, claimInfoSerializedProto64 string) (bool, error) {\n // Note recipient will be the caller for this function\n claimed := false\n err := assetexchange.ClaimAssetUsingContractId(ctx, contractId, claimInfoSerializedProto64)\n if err != nil {\n return false, logThenErrorf(err.Error())\n }\n claimed = true\n // After the above function call, update the owner of the asset with recipeint/caller\n ...\n return claimed, nil\n}\n"))),(0,i.yg)("li",{parentName:"ol"},(0,i.yg)("strong",{parentName:"li"},"UnlockAssetUsingContractId"),(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-go"},"func (s *SmartContract) UnlockAssetUsingContractId(ctx contractapi.TransactionContextInterface, contractId string) (bool, error) {\n unlocked := false\n err := assetexchange.UnlockAssetUsingContractId(ctx, contractId)\n if err != nil {\n return false, logThenErrorf(err.Error())\n }\n unlocked = true\n ...\n return true, nil\n}\n")))),(0,i.yg)("p",{parentName:"li"},"In addition, you should add the following extra utility functions to enable client applications to query and discover asset state:"),(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-go"},"func (s *SmartContract) GetHTLCHashByContractId(ctx contractapi.TransactionContextInterface, contractId string) (string, error) {\n return assetexchange.GetHTLCHashByContractId(ctx, contractId)\n}\nfunc (s *SmartContract) GetHTLCHashPreImageByContractId(ctx contractapi.TransactionContextInterface, contractId string) (string, error) {\n return assetexchange.GetHTLCHashPreImageByContractId(ctx, contractId)\n}\n")),(0,i.yg)("p",{parentName:"li"},"There is an alternative API to implement asset exchange using this library, which doesn't involve contract IDs. For details, see the ",(0,i.yg)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/core/network/fabric-interop-cc/libs/assetexchange/README.md#without-contractid"},"Asset Exchange Library README"),".\n")),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("p",{parentName:"li"},(0,i.yg)("em",{parentName:"p"},"Using the ",(0,i.yg)("a",{parentName:"em",href:"https://pkg.go.dev/github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/contracts/interop"},(0,i.yg)("inlineCode",{parentName:"a"},"Fabric Interoperation Chaincode"))),": This method requires the Fabric Interoperation Chaincode to be installed on all peers of the channel, using a special chaincode ID (e.g., ",(0,i.yg)("inlineCode",{parentName:"p"},"interop"),", which is what we will use later in this document). Your application chaincode needs to implement the interface ",(0,i.yg)("inlineCode",{parentName:"p"},"github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/interfaces/asset-mgmt"),".\nIn your smart contract's ",(0,i.yg)("inlineCode",{parentName:"p"},"go.mod"),", add the following in require (update the version according to the latest module version):"),(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-go"},"require(\n ...\n github.com/hyperledger-labs/weaver-dlt-interoperability/common/protos-go v1.5.6\n github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/interfaces/asset-mgmt v1.5.3\n ...\n)\n")),(0,i.yg)("p",{parentName:"li"},"In the SmartContract class definition file, add the following code:"),(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-go"},'import (\n ...\n am "github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/interfaces/asset-mgmt"\n)\ntype SmartContract struct {\n contractapi.Contract\n amc am.AssetManagementContract\n}\n')),(0,i.yg)("p",{parentName:"li"},"The following functions need to be added to your chaincode (",(0,i.yg)("em",{parentName:"p"},"Note"),": the function signature, i.e. the name, arguments, and return values, need to be exactly what is given in the below samples; you can have additional code to manage asset state as per need):"),(0,i.yg)("ol",{parentName:"li"},(0,i.yg)("li",{parentName:"ol"},(0,i.yg)("strong",{parentName:"li"},"LockAsset"),(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-go"},'func (s *SmartContract) LockAsset(ctx contractapi.TransactionContextInterface, assetExchangeAgreementSerializedProto64 string, lockInfoSerializedProto64 string) (string, error) {\n // Add some safety checks before calling LockAsset from library\n // Caller of this chaincode is supposed to be the Locker and the owner of the asset being locked.\n contractId, err := s.amc.LockAsset(ctx, "", assetExchangeAgreementSerializedProto64, lockInfoSerializedProto64)\n if err != nil {\n return "", logThenErrorf(err.Error())\n }\n // Post proccessing of asset after LockAsset called like change status of the asset so that it can\'t be spent.\n ...\n return contractId, nil\n}\n')),"Here ",(0,i.yg)("inlineCode",{parentName:"li"},"assetExchangeAgreementSerializedProto64")," is a serialized protobuf in Base64 encoded string of ",(0,i.yg)("inlineCode",{parentName:"li"},"AssetExchangeAgreement")," protobuf structure, and can be used to extract details like asset id, type of asset and recipient. Check the structure definition ",(0,i.yg)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/rfcs/formats/assets/exchange.md#representing-two-party-asset-exchange-agreements"},"here"),".\nSimilarly ",(0,i.yg)("inlineCode",{parentName:"li"},"lockInfoSerializedProto64")," is a serialized protobuf in Base64 encoded string of ",(0,i.yg)("inlineCode",{parentName:"li"},"AssetLock")," protobuf structure. Check the structure definition ",(0,i.yg)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/rfcs/formats/assets/exchange.md#representing-locks-on-assets"},"here"),"."),(0,i.yg)("li",{parentName:"ol"},(0,i.yg)("strong",{parentName:"li"},"LockFungibleAsset"),(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-go"},'func (s *SmartContract) LockFungibleAsset(ctx contractapi.TransactionContextInterface, fungibleAssetExchangeAgreementSerializedProto64 string, lockInfoSerializedProto64 string) (string, error) {\n // Add some safety checks before calling LockFungibleAsset from library\n // Caller of this chaincode is supposed to be the Locker and the owner of the asset being locked.\n contractId, err := s.amc.LockFungibleAsset(ctx, "", fungibleAssetExchangeAgreementSerializedProto64, lockInfoSerializedProto64)\n if err != nil {\n return "", logThenErrorf(err.Error())\n }\n // Post proccessing of asset after LockFungibleAsset called like reduce the amount of tokens owned by the locker, or mark it locked so that it can\'t be spent.\n ...\n return contractId, nil\n}\n')),"Here ",(0,i.yg)("inlineCode",{parentName:"li"},"fungibleAssetExchangeAgreementSerializedProto64")," is a serialized protobuf in Base64 encoded string of ",(0,i.yg)("inlineCode",{parentName:"li"},"FungibleAssetExchangeAgreement")," protobuf structure, and can be used to extract details like asset quantity, type of asset and recipient. Check the structure definition ",(0,i.yg)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/rfcs/formats/assets/exchange.md#representing-two-party-asset-exchange-agreements"},"here"),"."),(0,i.yg)("li",{parentName:"ol"},(0,i.yg)("strong",{parentName:"li"},"IsAssetLockedQueryUsingContractId"),(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-go"},"func (s *SmartContract) IsAssetLockedQueryUsingContractId(ctx contractapi.TransactionContextInterface, contractId string) (bool, error) {\n return s.amc.IsAssetLockedQueryUsingContractId(ctx, contractId)\n}\n"))),(0,i.yg)("li",{parentName:"ol"},(0,i.yg)("strong",{parentName:"li"},"ClaimAssetUsingContractId"),(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-go"},"func (s *SmartContract) ClaimAssetUsingContractId(ctx contractapi.TransactionContextInterface, contractId, claimInfoSerializedProto64 string) (bool, error) {\n // Note recipient will be the caller for this function\n claimed := false\n err := s.amc.ClaimAssetUsingContractId(ctx, contractId, claimInfoSerializedProto64)\n if err != nil {\n return false, logThenErrorf(err.Error())\n }\n claimed = true\n // After the above function call, update the owner of the asset with recipeint/caller\n ...\n return claimed, nil\n}\n"))),(0,i.yg)("li",{parentName:"ol"},(0,i.yg)("strong",{parentName:"li"},"UnlockAssetUsingContractId"),(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-go"},"func (s *SmartContract) UnlockAssetUsingContractId(ctx contractapi.TransactionContextInterface, contractId string) (bool, error) {\n unlocked := false\n err := s.amc.UnlockAssetUsingContractId(ctx, contractId)\n if err != nil {\n return false, logThenErrorf(err.Error())\n }\n unlocked = true\n ...\n return true, nil\n}\n")),"In addition, you should add the following extra utility functions to enable client applications to query and discover asset state:")),(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-go"},"func (s *SmartContract) GetHTLCHashByContractId(ctx contractapi.TransactionContextInterface, contractId string) (string, error) {\n return s.amc.GetHTLCHashByContractId(ctx, contractId)\n}\nfunc (s *SmartContract) GetHTLCHashPreImageByContractId(ctx contractapi.TransactionContextInterface, contractId string) (string, error) {\n return s.amc.GetHTLCHashPreImageByContractId(ctx, contractId)\n}\n")))),(0,i.yg)("h4",{id:"for-asset-transfer"},"For Asset Transfer"),(0,i.yg)("p",null,(0,i.yg)("em",{parentName:"p"},"TBD")),(0,i.yg)("h3",{id:"client-or-layer-2-applications"},"Client (or Layer-2) Applications"),(0,i.yg)("p",null,"Weaver provides an SDK to help you adapt your applications to exercise the various interoperability modes. These are called out as ",(0,i.yg)("strong",{parentName:"p"},"Interoperation Helpers")," in the network model illustrated earlier. Your Fabric network's Layer-2 applications have business logic embedded in them that, broadly speaking, accept data from users and other external agents and invoke smart contracts using library functions and APIs offered by the Fabric SDK. When you use Weaver for network interoperability, other options can be added, namely requesting and accepting data from foreign networks, and triggering locks and claims for atomic exchanges spanning two networks. Weaver's Fabric Interoperation SDK (currently implemented both in Node.js and Golang) offers a library to exercise these options, supplementing the Fabric SDK. But this will involve modification to the application's business logic."),(0,i.yg)("table",null,(0,i.yg)("thead",{parentName:"table"},(0,i.yg)("tr",{parentName:"thead"},(0,i.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,i.yg)("tbody",{parentName:"table"},(0,i.yg)("tr",{parentName:"tbody"},(0,i.yg)("td",{parentName:"tr",align:"left"},"The instructions here apply to applications implemented in Node.js (JavaScript and TypeScript), using the Weaver Node SDK for Fabric. We will add instructions later for Go applications using the Weaver Go SDK for Fabric.")))),(0,i.yg)("p",null,"To import and use the Weaver SDK, you need to add the following dependency to the ",(0,i.yg)("inlineCode",{parentName:"p"},"dependencies")," section of your Node.js application's ",(0,i.yg)("inlineCode",{parentName:"p"},"package.json")," file:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-json"},'"@hyperledger-labs/weaver-fabric-interop-sdk": "latest",\n')),(0,i.yg)("p",null,"(Instead of ",(0,i.yg)("inlineCode",{parentName:"p"},"latest"),", you can select a particular version from the ",(0,i.yg)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/packages/888424"},"package website"),".)"),(0,i.yg)("p",null,"Before you run ",(0,i.yg)("inlineCode",{parentName:"p"},"npm install")," to fetch the dependencies, make sure you create a ",(0,i.yg)("a",{parentName:"p",href:"https://docs.github.com/en/github/authenticating-to-github/keeping-your-account-and-data-secure/creating-a-personal-access-token"},"personal access token")," with ",(0,i.yg)("inlineCode",{parentName:"p"},"read:packages")," access in GitHub. Create an ",(0,i.yg)("inlineCode",{parentName:"p"},".npmrc")," file in the same folder as the ",(0,i.yg)("inlineCode",{parentName:"p"},"package.json")," with the following contents:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre"},"registry=https://npm.pkg.github.com/hyperledger-labs\n//npm.pkg.github.com/:_authToken=<personal-access-token>\n")),(0,i.yg)("p",null,"Replace ",(0,i.yg)("inlineCode",{parentName:"p"},"<personal-access-token>")," in this file with the token you created in GitHub."),(0,i.yg)("p",null,"First, you must incorporate some code for Weaver's network administration, specifically identity management. Then, using the given sample code and examples, you can adapt your applications for each interoperability mode."),(0,i.yg)("h4",{id:"for-identity-administration"},"For Identity Administration"),(0,i.yg)("p",null,"A Fabric network channel must share its security domain (or membership) configuration, i.e., its organizations' CA certificate chains, with a foreign network with which it seeks to interoperate. Each organization must run an IIN Agent for this purpose. The set of IIN Agents, a.k.a. the ",(0,i.yg)("em",{parentName:"p"},"local membership")," must be recorded in the ledger before those agents can be operational. In your Fabric network application suite, one or more applications will exist for network administration; the following code snippet should be added in at least one of those applications to record local membership as a prerequisite for interoperability:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-typescript"},"import { MembershipManager } from '@hyperledger-labs/weaver-fabric-interop-sdk'\n\nconst gateway = <get-fabric-network-gateway-instance>\n\ntry {\n const response = await MembershipManager.createLocalMembership(\n gateway,\n members, // list of all organization MSPIDs that are part of the channel\n securityDomain, // name of the local network's security domain\n channelName, // Channel Name\n contractName // Fabric Interoperation Chaincode installation ID on the channel\n )\n} catch (e) {\n // On error try updating local membership\n const response = await MembershipManager.updateLocalMembership(gateway, members, securityDomain, channelName, contractName)\n}\n")),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("inlineCode",{parentName:"li"},"<get-fabric-network-gateway-instance>")," should be replaced with standard (boilerplate) code to get a handle to your network's gateway. This requires a special wallet identity, namely one with a ",(0,i.yg)("inlineCode",{parentName:"li"},"network-admin")," attribute indicating that the caller is a trusted network administrator who is authorized to record local memberships on the ",(0,i.yg)("inlineCode",{parentName:"li"},"channelName")," channel."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("inlineCode",{parentName:"li"},"members")," must consist of the list of organizational MSP IDs for the ",(0,i.yg)("inlineCode",{parentName:"li"},"channelName")," channel.")),(0,i.yg)("h4",{id:"for-data-sharing-1"},"For Data Sharing"),(0,i.yg)("p",null,"Consider a scenario inspired by the ",(0,i.yg)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/external/user-stories/global-trade"},"global trade use case")," where a letter of credit (L/C) management business logic (chaincode ",(0,i.yg)("inlineCode",{parentName:"p"},"letterofcreditcc"),") installed in the ",(0,i.yg)("inlineCode",{parentName:"p"},"tradefinancechannel")," channel in the ",(0,i.yg)("inlineCode",{parentName:"p"},"trade-finance-network")," network supports a transaction ",(0,i.yg)("inlineCode",{parentName:"p"},"RecordBillOfLading"),", which validates and records a bill of lading (B/L) supplied by a user via a UI. Weaver will enable such a B/L to be fetched from a different network ",(0,i.yg)("inlineCode",{parentName:"p"},"trade-logistics-network")," by querying the function ",(0,i.yg)("inlineCode",{parentName:"p"},"GetBillOfLading")," exposed by the chaincode ",(0,i.yg)("inlineCode",{parentName:"p"},"shipmentcc")," installed in the ",(0,i.yg)("inlineCode",{parentName:"p"},"tradelogisticschannel")," channel."),(0,i.yg)("p",null,"(In preparation, a suitable access control policy must be recorded on ",(0,i.yg)("inlineCode",{parentName:"p"},"tradelogisticschannel")," in ",(0,i.yg)("inlineCode",{parentName:"p"},"trade-logistics-network"),", and a suitable verification policy must be recorded on ",(0,i.yg)("inlineCode",{parentName:"p"},"tradefinancechannel")," in ",(0,i.yg)("inlineCode",{parentName:"p"},"trade-finance-network"),'. We will see how to do this in the "Startup and Boostrap" section later.)'),(0,i.yg)("p",null,"You will need to insert some code in the Layer-2 application that accepts a B/L and submits a ",(0,i.yg)("inlineCode",{parentName:"p"},"RecordBillOfLading")," transaction in ",(0,i.yg)("inlineCode",{parentName:"p"},"trade-finance-network"),". (No code changes need to be made in any application in the other network.) The logic to accept a B/L should be replaced (or you can simply add an alternative) by a call to the ",(0,i.yg)("inlineCode",{parentName:"p"},"interopFlow")," function offered by the ",(0,i.yg)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/packages/888424"},"weaver-fabric-interop-sdk")," library (there's an ",(0,i.yg)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/releases/tag/sdks%2Ffabric%2Fgo-sdk%2Fv1.2.3-alpha.1"},"equivalent library in Golang")," too). The following code sample illustrates this (the Golang equivalent is left to the reader):"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-js",metastring:"showLineNumbers",showLineNumbers:!0},"const ihelper = require('@hyperledger-labs/weaver-fabric-interop-sdk').InteroperableHelper;\nconst interopcc = <handle-to-fabric-interop-chaincode>; // Use Fabric SDK functions: (new Gateway()).getNetwork(...).getContract(<fabric-interop-chaincode-id>)\nconst keyCert = await ihelper.getKeyAndCertForRemoteRequestbyUserName(<wallet>, <user-id>); // Read key and certificate for <user-id> from wallet (get handle using Fabric SDK Wallets API)\n// Collect view addresses for relay requests in the context of an interop flow\ninteropJSONs.push({\n NetworkID: 'trade-logistics-network',\n RemoteEndpoint: <trade-logistics-relay-url[:<port>], // Replace with remote network's relay address and port\n ChannelID: 'tradelogisticschannel',\n ChaincodeID: 'shipmentcc',\n ChaincodeFunc: 'GetBillOfLading',\n ccArgs: [ <shipment-reference> ], // Replace <shipment-reference> with a value that can be used to look up the right B/L\n Sign: true\n});\nconst indices = [ 1 ];\n// Trigger an end-to-end interoperation (data sharing) protocol\n// Send a request to a foreign network via your relay, receive the response and submit a transaction to a local chaincode\nconst flowResponse = await ihelper.interopFlow(\n interopcc,\n 'trade-finance-network',\n {\n channel: 'tradefinancechannel',\n contractName: 'letterofcreditcc',\n ccFunc: 'RecordBillOfLading',\n ccArgs: [ <shipment-reference> , '' ]\n },\n <org-msp-id>, // Replace with this Layer-2 application's organization's MSP ID\n <trade-finance-relay-url>[:<port>], // Replace with local network's relay address and port\n indices,\n interopJSONs,\n keyCert,\n <endorsingOrgs>, // List of orgs to submit transaction to local i.e. trade logistics network\n false, // Boolean flag to indicate whether return without submit transaction to local i.e. trade logistics network\n false, // Boolean flag indicating no TLS communication with relay\n [], // Keep it empty when TLS is disabled\n <confidential-flag>, // Boolean flag to indicate whether to use to end-to-end encryption\n);\n// List of errors to check for\nif (!flowResponse.views || flowResponse.views.length === 0 || !flowResponse.result || flowResponse.views.length !== argIndices.length) {\n throw <error>;\n}\n")),(0,i.yg)("p",null,"Let us understand this code snippet better. The structure in lines 20-25 specifies the local chaincode transaction that is to be triggered after remote data (view) has been requested and obtained via relays. The function ",(0,i.yg)("inlineCode",{parentName:"p"},"RecordBillOfLading")," expects two arguments as specified in line 24: the first is the common shipment reference that is used by the letter of credit in ",(0,i.yg)("inlineCode",{parentName:"p"},"trade-finance-network")," and the bill of lading in ",(0,i.yg)("inlineCode",{parentName:"p"},"trade-logistics-network"),", and the second is the bill of lading contents. When the ",(0,i.yg)("inlineCode",{parentName:"p"},"interopFlow")," function is called, this argument is left blank because it is supposed to be filled with contents obtained from a view request. The array list ",(0,i.yg)("inlineCode",{parentName:"p"},"indices"),", which is passed as an argument to ",(0,i.yg)("inlineCode",{parentName:"p"},"interopFlow")," therefore contains the index value ",(0,i.yg)("inlineCode",{parentName:"p"},"1")," (line 14), indicating which argument ought to be substituted with view data. The ",(0,i.yg)("inlineCode",{parentName:"p"},"interopJSONs")," array correspondingly contains a list of view addresses that are to be supplied to the relay. The ",(0,i.yg)("inlineCode",{parentName:"p"},"<confidential-flag>")," if set to ",(0,i.yg)("inlineCode",{parentName:"p"},"true")," will enable end-to-end confidentiality, i.e. payload will be encrypted from ",(0,i.yg)("inlineCode",{parentName:"p"},"trade-finance-network"),"'s Weaver chaincode, and will be decrypted in SDK (i.e. Layer-2 client application) at ",(0,i.yg)("inlineCode",{parentName:"p"},"trade-logistics-network"),", but relays and drivers in between will not be able to see the payload. By default this flag is set to ",(0,i.yg)("inlineCode",{parentName:"p"},"false"),"."),(0,i.yg)("table",null,(0,i.yg)("thead",{parentName:"table"},(0,i.yg)("tr",{parentName:"thead"},(0,i.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,i.yg)("tbody",{parentName:"table"},(0,i.yg)("tr",{parentName:"tbody"},(0,i.yg)("td",{parentName:"tr",align:"left"},"A local chaincode invocation may require multiple view requests to different networks, which is why ",(0,i.yg)("inlineCode",{parentName:"td"},"indices")," and ",(0,i.yg)("inlineCode",{parentName:"td"},"interopJSONs")," are arrays; they therefore must have the same lengths.")))),(0,i.yg)("p",null,"The rest of the code ought to be self-explanatory. Values are hardcoded for explanation purposes, but you can refactor the above code by reading view addresses corresponding to chaincode invocations from a configuration file."),(0,i.yg)("p",null,(0,i.yg)("strong",{parentName:"p"},"Enabling TLS"),":\nBy default, the TLS is set to false in ",(0,i.yg)("inlineCode",{parentName:"p"},"interopFlow"),", i.e. disabled. But if you want to enable TLS, can pass additional parameters to the ",(0,i.yg)("inlineCode",{parentName:"p"},"interopFlow")," function as follows:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-TypeScript"},"const flowResponse = await ihelper.interopFlow(\n interopcc,\n 'trade-finance-network',\n {\n channel: 'tradefinancechannel',\n contractName: 'letterofcreditcc',\n ccFunc: 'RecordBillOfLading',\n ccArgs: [ <shipment-reference> , '' ]\n },\n <org-msp-id>, // Replace with this Layer-2 application's organization's MSP ID\n <trade-finance-relay-url>[:<port>], // Replace with local network's relay address and port\n indices,\n interopJSONs,\n keyCert,\n <endorsingOrgs>, // List of orgs to submit transaction to in trade logistics network\n false, // Boolean flag to indicate whether return without submit transaction to local i.e. trade logistics network\n true, // Boolean indication TLS is enabled.\n <tlsCACertPathsForRelay>, // list of CA certificate file paths\n);\n")),(0,i.yg)("h4",{id:"for-asset-exchange-1"},"For Asset Exchange"),(0,i.yg)("p",null,"Let's take an example of asset exchange between ",(0,i.yg)("inlineCode",{parentName:"p"},"Alice")," and ",(0,i.yg)("inlineCode",{parentName:"p"},"Bob"),", where Bob wants to purchase an asset of type ",(0,i.yg)("inlineCode",{parentName:"p"},"Gold")," with id ",(0,i.yg)("inlineCode",{parentName:"p"},"A123")," from ",(0,i.yg)("inlineCode",{parentName:"p"},"Alice")," in ",(0,i.yg)("inlineCode",{parentName:"p"},"BondNetwork")," in exchange for ",(0,i.yg)("inlineCode",{parentName:"p"},"200")," tokens of type ",(0,i.yg)("inlineCode",{parentName:"p"},"CBDC01")," in ",(0,i.yg)("inlineCode",{parentName:"p"},"TokenNetwork"),"."),(0,i.yg)("p",null,(0,i.yg)("inlineCode",{parentName:"p"},"Alice")," needs to select a secret text (say ",(0,i.yg)("inlineCode",{parentName:"p"},"s"),"), and hash it (say ",(0,i.yg)("inlineCode",{parentName:"p"},"H"),") using say ",(0,i.yg)("inlineCode",{parentName:"p"},"SHA512"),", which will be used to lock her asset in ",(0,i.yg)("inlineCode",{parentName:"p"},"BondNetwork"),". At the place in your application where an asset exchange is to be initiated, you need to add code to enable Alice to lock the non-fungible asset using hash ",(0,i.yg)("inlineCode",{parentName:"p"},"H")," and timeout duration of 10 minutes:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-typescript"},'import { AssetManager, HashFunctions } from \'@hyperledger-labs/weaver-fabric-interop-sdk\'\n\nconst hash = HashFunctions.SHA512(); // Create Hash instance of one of the supported Hash Algorithm\nhash.setSerializedHashBase64(H); // Set the Hash\nconst timeout = Math.floor(Date.now()/1000) + 10 * 60;\n\nconst bondContract = <handle-to-fabric-application-chaincode-in-bond-network>;\n\nconst result = await AssetManager.createHTLC(\n bondContract,\n "Gold", // Asset ID\n "A123", // Asset Type\n bobCertificate, // Certificate of Bob in Bond Network\n hash, // Hash generated by Alice using her secret s\n timeout, // Timeout in epoch for 10 mins from current time\n null // Optional callback function to be called after the asset is locked\n);\nlet bondContractId = result.result; // Unique ID for this asset exchange contract in BondNetwork\n')),(0,i.yg)("table",null,(0,i.yg)("thead",{parentName:"table"},(0,i.yg)("tr",{parentName:"thead"},(0,i.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,i.yg)("tbody",{parentName:"table"},(0,i.yg)("tr",{parentName:"tbody"},(0,i.yg)("td",{parentName:"tr",align:"left"},"Note that 'Alice' and 'Bob' and the asset specifics can be parameterized in the above code, which can be reused for arbitrary asset exchange scenarios in your business workflow. The above code is only meant to be a sample.")))),(0,i.yg)("p",null,"Now ",(0,i.yg)("inlineCode",{parentName:"p"},"Bob")," will lock his tokens in ",(0,i.yg)("inlineCode",{parentName:"p"},"TokenNetwork"),". To lock the fungible asset using same hash ",(0,i.yg)("inlineCode",{parentName:"p"},"H")," and timeout of 5 minutes (half the timeout duration used by Alice in ",(0,i.yg)("inlineCode",{parentName:"p"},"BondNetwork"),"), add the following code snippet in your application:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-typescript"},'const hash = HashFunctions.SHA512(); // Create Hash instance of one of the supported Hash Algorithm\nhash.setSerializedHashBase64(H); // Set the Hash\nconst timeout = Math.floor(Date.now()/1000) + 5 * 60;\n\nconst tokenContract = <handle-to-fabric-application-chaincode-in-token-network>;\nconst result = await AssetManager.createFungibleHTLC(\n tokenContract,\n "CBDC01", // Token ID\n 200, // Token Quantity\n aliceCertificate, // Certificate of Alice in Token Network\n hash, // Hash H used by Alice in Bond Network\n timeout, // Timeout in epoch for 5 mins from current time\n null // Optional callback function to be called after the asset is locked\n)\nconst tokenContractId = result.result // Unique ID for this asset exchange contract in TokenNetwork\n')),(0,i.yg)("p",null,"Wherever the lock status of the asset is required in your application, you should insert a query function call as follows:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-typescript"},"const contract = <handle-to-fabric-application-chaincode>;\n// Below contractId is the ID obtained during lock\nconst isLocked = AssetManager.isAssetLockedInHTLCqueryUsingContractId(contract, contractId)\n")),(0,i.yg)("p",null,"Wherever a participant (either 'Alice' or 'Bob' in this example) needs to claim a locked asset using the secret text (pre-image of hash) ",(0,i.yg)("inlineCode",{parentName:"p"},"s")," in your application, insert the following code snippet (",(0,i.yg)("em",{parentName:"p"},"Note"),": typically one would insert this in event callback functions or in functions that are polling the ledger to monitor whether the asset is locked in favor of a given recipient):"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-typescript"},"const hash = HashFunctions.SHA512(); // Create Hash instance of one of the supported Hash Algorithm\nhash.setPreimage(s) // Set Pre-Image s\nconst contract = <handle-to-fabric-application-chaincode>;\nconst claimSuccess = await AssetManager.claimAssetInHTLCusingContractId(\n contract,\n contractId, // contractId obtained during lock\n hash\n)\n// return value claimSuccess is boolean indicating success or failure of claim\n")),(0,i.yg)("p",null,"Wherever the asset must be unlocked in your application (typically, an event callback function triggered upon the expiration of the time lock), insert the following code snippet:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-typescript"},"const contract = <handle-to-fabric-application-chaincode>;\nconst reclaimSuccess = await AssetManager.reclaimAssetInHTLCusingContractId(\n contract,\n contractId // contractId obtained during lock\n)\n// return value 'reclaimSuccess' is a boolean indicating success or failure of reclaim\n")),(0,i.yg)("h4",{id:"for-asset-transfer-1"},"For Asset Transfer"),(0,i.yg)("p",null,(0,i.yg)("em",{parentName:"p"},"TBD")),(0,i.yg)("h2",{id:"pre-configuration-phase"},"Pre-Configuration Phase"),(0,i.yg)("p",null,"Typically, pre-configuration in a Fabric network involves generating (after creating the channel specifications and policies):"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("em",{parentName:"li"},"Channel artifacts"),": orderer genesis block, channel transaction, and anchor peer configurations from a ",(0,i.yg)("inlineCode",{parentName:"li"},"configtx.yaml")," file (using Fabric's ",(0,i.yg)("inlineCode",{parentName:"li"},"configtxgen")," tool)"),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("em",{parentName:"li"},"Crypto artifacts"),": keys and certificates for CAs, peers, orderers, and clients from a ",(0,i.yg)("inlineCode",{parentName:"li"},"crypto-config.yaml")," file (using Fabric's ",(0,i.yg)("inlineCode",{parentName:"li"},"cryptogen")," tool)"),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("em",{parentName:"li"},"Connection profiles"),": one for every network organization, which will be used by the organization's Layer-2 applications to connect to the network's peers and CAs")),(0,i.yg)("p",null,"No changes are required in this process to support any of the three interoperation modes using Weaver. The connection profiles generated above will be used by certain Weaver modules, as we will see later. The only additional step required is to generate special wallet identities for the following:"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},"Network administrator: one or more identities containing the ",(0,i.yg)("inlineCode",{parentName:"li"},"network-admin")," attribute; only a user/application possessing this identity may record special (privileged) information regarding memberships and policies on the channel."),(0,i.yg)("li",{parentName:"ul"},"Fabric Driver: one or more identities (for each deployed driver) containing the ",(0,i.yg)("inlineCode",{parentName:"li"},"relay")," attribute; only a relay-driver combination possessing this identity may run data sharing-related operations on the deployed Fabric Interoperation Chaincode."),(0,i.yg)("li",{parentName:"ul"},"IIN Agent: one or more identities (for each deployed agent) containing the ",(0,i.yg)("inlineCode",{parentName:"li"},"iin-agent")," attribute: only an agent may submit foreign network membership records to the Fabric Interoperation Chaincode.")),(0,i.yg)("p",null,"Later we will see how the components possessing these identities are deployed."),(0,i.yg)("h2",{id:"startup-and-bootstrap-phase"},"Startup and Bootstrap Phase"),(0,i.yg)("p",null,"After writing application code and creating the network configuration files, the components of a Fabric network (peers, CAs, and ordering service) are launched. In this section, we will list the additional tasks you, as a Fabric network administrator, must perform to make your network ready to interoperate."),(0,i.yg)("p",null,"To launch a network using containerized components, you will typically use a Docker Compose or Kubernetes configuration file. No modifications are needed to the peers', orderers', and CAs' configurations. Sample instructions are given below for networks launched using Docker Compose; we leave it to the reader to adapt these to their custom launch processes."),(0,i.yg)("h3",{id:"for-asset-exchange-2"},"For Asset Exchange"),(0,i.yg)("p",null,"The asset exchange mode currently requires only the Fabric Interoperation Chaincode module from Weaver. Relays, drivers, and IIN agents, are not necessary. In the future, we expect to make the asset exchange protocol moe automated using these components; the instructions here will be updated appropriately."),(0,i.yg)("h4",{id:"install-the-fabric-interoperation-chaincode"},"Install the Fabric Interoperation Chaincode"),(0,i.yg)("p",null,"Install the Fabric Interoperation Chaincode in the relevant channel(s), i.e., those that run chaincodes that will be involved in asset exchanges. This is a Go module that can be fetched from ",(0,i.yg)("inlineCode",{parentName:"p"},"github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/contracts/interop"),". Following that, you an install it using the appropriate Fabric process: in Fabric v2, you will need to package, install, approve, and commit this module on the selected channels in your network."),(0,i.yg)("h3",{id:"for-data-sharing-or-asset-transfer"},"For Data Sharing or Asset Transfer"),(0,i.yg)("p",null,"Both the data sharing and asset transfer modes require the Fabric Interoperation Chaincode, relays, drivers, and IIN agents, to be deployed."),(0,i.yg)("h4",{id:"install-the-fabric-interoperation-chaincode-1"},"Install the Fabric Interoperation Chaincode"),(0,i.yg)("p",null,"Install the Fabric Interoperation Chaincode in the relevant channel(s), i.e., those that run chaincodess that will be involved in data sharing (and asset transfers, which require multiple data shares). This is a Go module that can be fetched from ",(0,i.yg)("inlineCode",{parentName:"p"},"github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/contracts/interop"),". Following that, you an install it using the appropriate Fabric process: in Fabric v2, you will need to package, install, approve, and commit this module on the selected channels in your network."),(0,i.yg)("h4",{id:"launch-relay"},"Launch Relay"),(0,i.yg)("p",null,"You need to run one or more relays for network-to-network communication. Here we provide instructions to run one relay running in a Docker container, which is sufficient for data sharing. (Later, we will provide instructions to run multiple relays, which will be useful from a failover perspective.)"),(0,i.yg)("p",null,"Weaver provides a ",(0,i.yg)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/pkgs/container/weaver-relay-server"},"pre-built image")," for the relay. Before launching a container, you just need to customize its configuration for your Fabric network, which you can do by simply creating a folder (let's call it ",(0,i.yg)("inlineCode",{parentName:"p"},"relay_config"),") and configuring the following files in it:"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("p",{parentName:"li"},(0,i.yg)("inlineCode",{parentName:"p"},".env"),": This sets suitable environment variables within the relay container. Copy the ",(0,i.yg)("inlineCode",{parentName:"p"},".env.template")," file ",(0,i.yg)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/core/relay/.env.template"},"from the repository")," and customize it for your purposes, as indicated in the below sample:"),(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre"},'PATH_TO_CONFIG=./config.toml\nRELAY_NAME=<"name" in config.toml>\nRELAY_PORT=<relay-server-port/"port" in config.toml>\nEXTERNAL_NETWORK=<docker-bridge-network>\nDOCKER_REGISTRY=ghcr.io/hyperledger-labs\nDOCKER_IMAGE_NAME=weaver-relay\nDOCKER_TAG=1.5.4\n')),(0,i.yg)("ul",{parentName:"li"},(0,i.yg)("li",{parentName:"ul"},"The ",(0,i.yg)("inlineCode",{parentName:"li"},"PATH_TO_CONFIG")," variable should point to the properties file typically named ",(0,i.yg)("inlineCode",{parentName:"li"},"config.toml")," (you can name this whatever you wish). See further below for instructions to write this file."),(0,i.yg)("li",{parentName:"ul"},"The ",(0,i.yg)("inlineCode",{parentName:"li"},"RELAY_NAME")," variable specifies a unique name for this relay. It should match what's specified in the ",(0,i.yg)("inlineCode",{parentName:"li"},"config.toml")," (more on that below)."),(0,i.yg)("li",{parentName:"ul"},"The ",(0,i.yg)("inlineCode",{parentName:"li"},"RELAY_PORT")," variable specifies the port this relay server will listen on. It should match what's specified in the ",(0,i.yg)("inlineCode",{parentName:"li"},"config.toml")," (more on that below)."),(0,i.yg)("li",{parentName:"ul"},"The ",(0,i.yg)("inlineCode",{parentName:"li"},"EXTERNAL_NETWORK")," variable should be set to the ",(0,i.yg)("a",{parentName:"li",href:"https://docs.docker.com/compose/networking/"},"name")," of your Fabric network."),(0,i.yg)("li",{parentName:"ul"},"The ",(0,i.yg)("inlineCode",{parentName:"li"},"DOCKER_*")," variables are used to specify the image on which the container will be built. Make sure you set ",(0,i.yg)("inlineCode",{parentName:"li"},"DOCKER_TAG")," to the latest version you see on ",(0,i.yg)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/pkgs/container/weaver-relay-server"},"GitHub"),".")),(0,i.yg)("p",{parentName:"li"},"For more details, see the ",(0,i.yg)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/core/relay/relay-docker.md"},"Relay Docker README"),' ("Relay Server Image" and "Running With Docker Compose" sections).')),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("p",{parentName:"li"},(0,i.yg)("inlineCode",{parentName:"p"},"config.toml"),": This is the file specified in the ",(0,i.yg)("inlineCode",{parentName:"p"},"PATH_TO_CONFIG")," variable in the ",(0,i.yg)("inlineCode",{parentName:"p"},".env"),". It specifies properties of this relay and the driver(s) it supports. A sample is given below:"),(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-toml",metastring:"showLineNumbers",showLineNumbers:!0},'name=<relay-name>\nport=<relay-port>\nhost="0.0.0.0"\ndb_path="db/<relay-name>/requests"\nremote_db_path="db/<relay-name>/remote_request"\n\n# FOR TLS\ncert_path="credentials/fabric_cert.pem"\nkey_path="credentials/fabric_key"\ntls=<true/false>\n\n[networks]\n[networks.<network-name>]\nnetwork="<driver-name>"\n\n[relays]\n[relays.<foreign-relay-name>]\nhostname="<foreign-relay-hostname-or-ip-address>"\nport="<foreign-relay-port>"\n\n[drivers]\n[drivers.<driver-name>]\nhostname="<driver-hostname-or-ip-address>"\nport="<driver-port>"\n')),(0,i.yg)("ul",{parentName:"li"},(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("inlineCode",{parentName:"li"},"<relay-name>")," should be a unique ID representing this relay; e.g., ",(0,i.yg)("inlineCode",{parentName:"li"},"my_network_relay"),". It should match the ",(0,i.yg)("inlineCode",{parentName:"li"},"RELAY_NAME")," value in ",(0,i.yg)("inlineCode",{parentName:"li"},".env"),"."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("inlineCode",{parentName:"li"},"<relay-port>")," is the port number the relay server will listen on. It should match the ",(0,i.yg)("inlineCode",{parentName:"li"},"RELAY_PORT")," value in ",(0,i.yg)("inlineCode",{parentName:"li"},".env"),"."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("inlineCode",{parentName:"li"},"db_path")," and ",(0,i.yg)("inlineCode",{parentName:"li"},"remote_db_path")," are used internally by the relay to store data. Replace ",(0,i.yg)("inlineCode",{parentName:"li"},"<relay-name>")," with the same value set for the ",(0,i.yg)("inlineCode",{parentName:"li"},"name")," parameter. (These can point to any filesystem paths in the relay's container.)"),(0,i.yg)("li",{parentName:"ul"},"If you set ",(0,i.yg)("inlineCode",{parentName:"li"},"tls")," to ",(0,i.yg)("inlineCode",{parentName:"li"},"true"),", the relay will enforce TLS communication. The ",(0,i.yg)("inlineCode",{parentName:"li"},"cert_path")," and ",(0,i.yg)("inlineCode",{parentName:"li"},"key_path")," should point to a Fabric TLS certificate and key respectively, such as those created using the ",(0,i.yg)("inlineCode",{parentName:"li"},"cryptogen")," tool."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("inlineCode",{parentName:"li"},"<network-name>")," is a unique identifier for your local network. You can set it to whatever value you wish."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("inlineCode",{parentName:"li"},"<driver-name>")," refers to the driver used by this relay to respond to requests. This also refers to one of the drivers's specifications in the ",(0,i.yg)("inlineCode",{parentName:"li"},"drivers")," section further below. In this code snippet, we have defined one driver. (The names in lines 14 and 22 must match.) In lines 23 and 24 respectively, you should specify the hostname and port for the driver (whose configuration we will handle later)."),(0,i.yg)("li",{parentName:"ul"},"The ",(0,i.yg)("inlineCode",{parentName:"li"},"relays")," section specifies all foreign relays this relay can connect to. The ",(0,i.yg)("inlineCode",{parentName:"li"},"<foreign-relay-name>")," value should be a unique ID for a given foreign relay, and this value will be used by your Layer-2 applications when constructing view addresses for data sharing requests. In lines 18 and 19, you should specify the hostname and port for the foreign relay."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Enabling TLS"),":",(0,i.yg)("ul",{parentName:"li"},(0,i.yg)("li",{parentName:"ul"},"You can make your relay accept TLS connections by specifying a TLS certificate file path and private key file path in ",(0,i.yg)("inlineCode",{parentName:"li"},"cert_path")," and ",(0,i.yg)("inlineCode",{parentName:"li"},"key_path")," respectively, and set ",(0,i.yg)("inlineCode",{parentName:"li"},"tls")," to ",(0,i.yg)("inlineCode",{parentName:"li"},"true"),"."),(0,i.yg)("li",{parentName:"ul"},"To communicate with a foreign relay using TLS, specify that relay's TLS CA certificate path in ",(0,i.yg)("inlineCode",{parentName:"li"},"tlsca_cert_path")," (currently only one certificate can be configured) and set ",(0,i.yg)("inlineCode",{parentName:"li"},"tls")," to ",(0,i.yg)("inlineCode",{parentName:"li"},"true")," by extending that relay's section as follows (",(0,i.yg)("em",{parentName:"li"},"Note"),": this CA certificate should match the one specified in the ",(0,i.yg)("inlineCode",{parentName:"li"},"cert_path")," property in the foreign relay's ",(0,i.yg)("inlineCode",{parentName:"li"},"config.toml")," file):",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-toml"},'[relays]\n[relays.<foreign-relay-name>]\nhostname="<foreign-relay-hostname-or-ip-address>"\nport="<foreign-relay-port>"\ntls=<true|false>\ntlsca_cert_path="<relay-tls-ca-certificate-path>"\n'))),(0,i.yg)("li",{parentName:"ul"},"To communicate with a driver using TLS, specify the driver's TLS CA certificate in ",(0,i.yg)("inlineCode",{parentName:"li"},"tlsca_cert_path")," (currently only one certificate can be configured) and set ",(0,i.yg)("inlineCode",{parentName:"li"},"tls")," to ",(0,i.yg)("inlineCode",{parentName:"li"},"true")," by extending that driver's section as follows (",(0,i.yg)("em",{parentName:"li"},"Note"),": this CA certificate must match the certificate used by the driver using the ",(0,i.yg)("inlineCode",{parentName:"li"},"DRIVER_TLS_CERT_PATH")," property in its ",(0,i.yg)("inlineCode",{parentName:"li"},".env")," configuration file, which we will examine later):",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-toml"},'[drivers]\n[drivers.<driver-name>]\nhostname="<driver-hostname-or-ip-address>"\nport="<driver-port>"\ntls=<true|false>\ntlsca_cert_path="<driver-tls-ca-certificate-path>"\n')))))),(0,i.yg)("table",{parentName:"li"},(0,i.yg)("thead",{parentName:"table"},(0,i.yg)("tr",{parentName:"thead"},(0,i.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,i.yg)("tbody",{parentName:"table"},(0,i.yg)("tr",{parentName:"tbody"},(0,i.yg)("td",{parentName:"tr",align:"left"},"You can specify more than one foreign relay instance in the ",(0,i.yg)("inlineCode",{parentName:"td"},"relays")," section.")),(0,i.yg)("tr",{parentName:"tbody"},(0,i.yg)("td",{parentName:"tr",align:"left"},"You can specify more than one driver instance in the ",(0,i.yg)("inlineCode",{parentName:"td"},"drivers")," section."))))),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("p",{parentName:"li"},(0,i.yg)("inlineCode",{parentName:"p"},"docker-compose.yaml"),": This specifies the properties of the relay container. You can use the ",(0,i.yg)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/core/relay/docker-compose.yaml"},"file in the repository")," verbatim."))),(0,i.yg)("p",null,"To start the relay server, navigate to the folder containing the above files and run the following:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"docker-compose up -d relay-server\n")),(0,i.yg)("h4",{id:"launch-driver"},"Launch Driver"),(0,i.yg)("p",null,"You need to run one or more drivers through which your relay can interact with your Fabric network. Here we provide instructions to run one Fabric driver running in a Docker container, which is sufficient for data sharing. (Later, we will provide instructions to run multiple drivers, which will be useful both from a failover perspective and to interact with different subsets of your Fabric network, like private data collections.)"),(0,i.yg)("p",null,"Weaver provides a ",(0,i.yg)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/pkgs/container/weaver-fabric-driver"},"pre-built image")," for the Fabric driver. Before launching a container, you just need to customize its configuration for your Fabric network, which you can do by simply creating a folder (let's call it ",(0,i.yg)("inlineCode",{parentName:"p"},"driver_config"),") and configuring the following files in it:"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("p",{parentName:"li"},(0,i.yg)("inlineCode",{parentName:"p"},".env"),": This sets suitable environment variables within the driver container. Copy the ",(0,i.yg)("inlineCode",{parentName:"p"},".env.docker.template")," file ",(0,i.yg)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/core/drivers/fabric-driver/.env.docker.template"},"from the repository")," and customize it for your purposes, as indicated in the below sample:"),(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre"},"CONNECTION_PROFILE=<path_to_connection_profile>\nDRIVER_CONFIG=./config.json\nRELAY_ENDPOINT=<relay-hostname>:<relay-port>\nNETWORK_NAME=<network-name>\nDRIVER_PORT=<driver-server-port>\nINTEROP_CHAINCODE=<interop-chaincode-name>\nEXTERNAL_NETWORK=<docker-bridge-network>\nTLS_CREDENTIALS_DIR=<dir-with-tls-cert-and-key>\nDOCKER_IMAGE_NAME=ghcr.io/hyperledger-labs/weaver-fabric-driver\nDOCKER_TAG=1.5.6\nDRIVER_TLS=<true|false>\nDRIVER_TLS_CERT_PATH=path_to_tls_cert_pem_for_driver\nDRIVER_TLS_KEY_PATH=path_to_tls_key_pem_for_driver\nRELAY_TLS=<true|false>\nRELAY_TLSCA_CERT_PATH=path_to_tls_ca_cert_pem_for_relay\n")),(0,i.yg)("ul",{parentName:"li"},(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("inlineCode",{parentName:"li"},"<path_to_connection_profile>"),' should point to the path of a connection profile you generated in the "Pre-Configuration" section. A Fabric driver obtains client credentials from one of the organizations in your network, so pick an organization and point to the right connection profile.'),(0,i.yg)("li",{parentName:"ul"},"The ",(0,i.yg)("inlineCode",{parentName:"li"},"DRIVER_CONFIG")," variable should point to the ",(0,i.yg)("inlineCode",{parentName:"li"},"config.json")," (you can name this whatever you wish) specified below."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("inlineCode",{parentName:"li"},"<relay-hostname>")," should be set to the hostname of the relay server machine and ",(0,i.yg)("inlineCode",{parentName:"li"},"<relay-port>")," should match the ",(0,i.yg)("inlineCode",{parentName:"li"},"port")," value in the relay's ",(0,i.yg)("inlineCode",{parentName:"li"},"config.toml")," (see above)."),(0,i.yg)("li",{parentName:"ul"},"The ",(0,i.yg)("inlineCode",{parentName:"li"},"NETWORK_NAME")," variable should be a unique ID referring to the Fabric network. It will be used to distinguish container names and wallet paths. (This setting is relevant in situations where a driver is used to query multiple network channels.)"),(0,i.yg)("li",{parentName:"ul"},"The ",(0,i.yg)("inlineCode",{parentName:"li"},"DRIVER_PORT")," variable should be set to the port this driver will listen on."),(0,i.yg)("li",{parentName:"ul"},"The ",(0,i.yg)("inlineCode",{parentName:"li"},"INTEROP_CHAINCODE")," variable should be set to the ID of the Fabric Interop Chaincode installed on your Fabric network channel."),(0,i.yg)("li",{parentName:"ul"},"The ",(0,i.yg)("inlineCode",{parentName:"li"},"EXTERNAL_NETWORK")," variable should be set to the ",(0,i.yg)("a",{parentName:"li",href:"https://docs.docker.com/compose/networking/"},"name")," of your Fabric network."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Enabling TLS"),":",(0,i.yg)("ul",{parentName:"li"},(0,i.yg)("li",{parentName:"ul"},"You can make your driver accept TLS connections by specifying ",(0,i.yg)("inlineCode",{parentName:"li"},"DRIVER_TLS")," as ",(0,i.yg)("inlineCode",{parentName:"li"},"true")," and specifying a TLS certificate file path and private key file path in ",(0,i.yg)("inlineCode",{parentName:"li"},"DRIVER_TLS_CERT_PATH")," and ",(0,i.yg)("inlineCode",{parentName:"li"},"DRIVER_TLS_KEY_PATH")," respectively. The same certificate should be specified in this driver's definition in the ",(0,i.yg)("inlineCode",{parentName:"li"},"drivers")," section in the ",(0,i.yg)("inlineCode",{parentName:"li"},"config.toml")," file of your relay in the ",(0,i.yg)("inlineCode",{parentName:"li"},"tlsca_cert_path")," property (see the earlier section on relay configuration)."),(0,i.yg)("li",{parentName:"ul"},"To communicate with your network' relay using TLS (i.e., if the relay is TLS-enabled), specify that relay's TLS CA certificate path in ",(0,i.yg)("inlineCode",{parentName:"li"},"RELAY_TLSCA_CERT_PATH")," (currently only one certificate can be configured) and set ",(0,i.yg)("inlineCode",{parentName:"li"},"RELAY_TLS")," to ",(0,i.yg)("inlineCode",{parentName:"li"},"true"),". This CA certificate should match the one specified in the ",(0,i.yg)("inlineCode",{parentName:"li"},"cert_path")," property in the relay's ",(0,i.yg)("inlineCode",{parentName:"li"},"config.toml")," file (see the earlier section on relay configuration):"),(0,i.yg)("li",{parentName:"ul"},"You can point to the folder in your host system containing the certificate and key using the ",(0,i.yg)("inlineCode",{parentName:"li"},"TLS_CREDENTIALS_DIR")," variable. (This folder will be synced to the ",(0,i.yg)("inlineCode",{parentName:"li"},"/fabric-driver/credentials")," folder in the Fabric Driver container as specified in the ",(0,i.yg)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/core/drivers/fabric-driver/docker-compose.yml"},"docker-compose file"),".) Make sure you point to the right certificate and key file paths within the container using the ",(0,i.yg)("inlineCode",{parentName:"li"},"DRIVER_TLS_CERT_PATH"),", ",(0,i.yg)("inlineCode",{parentName:"li"},"DRIVER_TLS_KEY_PATH"),", and ",(0,i.yg)("inlineCode",{parentName:"li"},"RELAY_TLSCA_CERT_PATH")," variables."))))),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("p",{parentName:"li"},(0,i.yg)("inlineCode",{parentName:"p"},"config.json"),": This contains settings used to connect to a CA of a Fabric network organization and enroll a client. A sample is given below:"),(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-json"},'{\n "admin":{\n "name":"admin",\n "secret":"adminpw"\n },\n "relay": {\n "name":"relay",\n "affiliation":"<affiliation>",\n "role": "client",\n "attrs": [{ "name": "relay", "value": "true", "ecert": true }]\n },\n "mspId":"<msp-id>",\n "caUrl":"<ca-service-endpoint>"\n}\n')),(0,i.yg)("ul",{parentName:"li"},(0,i.yg)("li",{parentName:"ul"},"As in the ",(0,i.yg)("inlineCode",{parentName:"li"},".env")," configuration, you should pick an organization for the driver to associate with. The ",(0,i.yg)("inlineCode",{parentName:"li"},"admin")," section specifies the registrar name and password (this should be familiar to any Fabric network administrator) used to enroll clients. Default values of ",(0,i.yg)("inlineCode",{parentName:"li"},"admin")," and ",(0,i.yg)("inlineCode",{parentName:"li"},"adminpw")," are specified above as examples, which you should replace with the right values configured in your network organization's CA."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("inlineCode",{parentName:"li"},"<affiliation>")," should be what's specified in your organization's Fabric CA server configuration. The default is ",(0,i.yg)("inlineCode",{parentName:"li"},"org1.department1"),", but you should look up the appropriate value from the CA server's configuration file."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("inlineCode",{parentName:"li"},"<msp-id>")," should be set to the (or an) MSP ID of the selected organization."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("inlineCode",{parentName:"li"},"<ca-service-endpoint>")," should be set to the CA server's endpoint. If you launched your CA server as a container from a docker-compose file, this should be set to the container's service name.")),(0,i.yg)("table",{parentName:"li"},(0,i.yg)("thead",{parentName:"table"},(0,i.yg)("tr",{parentName:"thead"},(0,i.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,i.yg)("tbody",{parentName:"table"},(0,i.yg)("tr",{parentName:"tbody"},(0,i.yg)("td",{parentName:"tr",align:"left"},"If your connection profile already contains specifications for a CA server, you can leave the ",(0,i.yg)("inlineCode",{parentName:"td"},"<ca-service-endpoint>")," value as a blank."))))),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("p",{parentName:"li"},(0,i.yg)("inlineCode",{parentName:"p"},"docker-compose.yaml"),": This specifies the properties of the driver container. You can use the ",(0,i.yg)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/core/drivers/fabric-driver/docker-compose.yml"},"file in the repository")," verbatim."))),(0,i.yg)("p",null,"To start the driver, navigate to the folder containing the above files and run the following:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"docker-compose up -d\n")),(0,i.yg)("h4",{id:"launch-iin-agents"},"Launch IIN Agents"),(0,i.yg)("p",null,"You need to run one IIN Agent for each organization in the Fabric network channel you are enabling Weaver in. This agent runs a protocol with other organizations' agents and with targeted foreign networks' agents to sync and record foreign networks' memberships to the channel ledger."),(0,i.yg)("p",null,"Weaver provides a ",(0,i.yg)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/pkgs/container/weaver-iin-agent"},"pre-built image")," for the IIN Agent. Before launching a container, you just need to customize its configuration for your Fabric network organization, which you can do by simply creating a folder (let's call it ",(0,i.yg)("inlineCode",{parentName:"p"},"iin_agent_config_<orgname>"),") and configuring the following files in it:"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("p",{parentName:"li"},(0,i.yg)("inlineCode",{parentName:"p"},"config.json"),": This contains settings used to connect to a Fabric network organization and its CA (part of the organization's MSP). A sample is given below:"),(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre"},'{\n "admin":{\n "name":"admin",\n "secret":"adminpw"\n },\n "agent": {\n "name":"iin-agent",\n "affiliation":"<affiliation>",\n "role": "client",\n "attrs": [{ "name": "iin-agent", "value": "true", "ecert": true }]\n },\n "mspId":"<msp-id>",\n "ordererMspIds": [<list-of-orderer-msp-ids>],\n "ccpPath": "<path-to-connection-profile>",\n "walletPath": "",\n "caUrl": "<ca-service-endpoint>",\n "local": "false"\n}\n'))),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("p",{parentName:"li"},(0,i.yg)("inlineCode",{parentName:"p"},"dnsconfig.json"),": This specifies the list of known IIN agents of your network (i.e., belonging to other organizations) and of foreign networks. A sample DNS configuration file is given below:"),(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre"},'{\n "<securityDomainName1>": {\n "<iin-agent1-name>": {\n "endpoint": "<hostname:port>",\n "tls": <true/false>,\n "tlsCACertPath": "<cacert-path-or-empty-string>"\n },\n "<iin-agent2-name>": {\n "endpoint": "<hostname:port>",\n "tls": <true/false>,\n "tlsCACertPath": "<cacert-path-or-empty-string>"\n }\n },\n "<securityDomainName2>": {\n "<iin-agent1-name>": {\n "endpoint": "<hostname:port>",\n "tls": <true/false>,\n "tlsCACertPath": "<cacert-path-or-empty-string>"\n },\n "<iin-agent2-name>": {\n "endpoint": "<hostname:port>",\n "tls": <true/false>,\n "tlsCACertPath": "<cacert-path-or-empty-string>"\n }\n }\n}\n')),(0,i.yg)("ul",{parentName:"li"},(0,i.yg)("li",{parentName:"ul"},"Each security domain (i.e., unique ledger, like a Fabric channel) scopes a set of JSON objects, each containing specifications of an IIN Agent. The key (",(0,i.yg)("inlineCode",{parentName:"li"},"<iin-agent1-name>")," for example) in each is the IIN Agent's name, which can be the organization's MSP ID (for a Fabric network). The value is another JSON object, containing an ",(0,i.yg)("inlineCode",{parentName:"li"},"endpoint")," with a hostname and port for the agent."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Enabling TLS"),": To communicate with a given IIN Agent using TLS (i.e., if that agent is TLS-enabled), specify ",(0,i.yg)("inlineCode",{parentName:"li"},"tls")," as ",(0,i.yg)("inlineCode",{parentName:"li"},"true")," and that agent's TLS CA certificate path in ",(0,i.yg)("inlineCode",{parentName:"li"},"tlsCACertPath")," (currently only one certificate can be configured) within the JSON object corresponding to that agent. This CA certificate should match the one specified in that IIN Agent's ",(0,i.yg)("inlineCode",{parentName:"li"},".env")," file, whose configuration we will specify later."))),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("p",{parentName:"li"},(0,i.yg)("inlineCode",{parentName:"p"},"security-domain-config.json"),": This config file contains list of security domain defined for the network and its members, i.e. it can be list of organizations or channel name. Sample security domain configuration file:"),(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre"},'{\n "<securityDomainName1>": "<channelName>",\n "<securityDomainName2>": [\n "<Org1MSPId>",\n "<Org2MSPId>"\n ]\n}\n'))),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("p",{parentName:"li"},(0,i.yg)("inlineCode",{parentName:"p"},".env"),": This sets suitable environment variables within the driver container. Copy the ",(0,i.yg)("inlineCode",{parentName:"p"},".env.template")," file ",(0,i.yg)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/core/identity-management/iin-agent/.env.docker.template"},"from the repository")," and customize it for your purposes, as indicated in the below sample:"),(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre"},"IIN_AGENT_PORT=<iin-agent-server-port>\nIIN_AGENT_TLS=<true/false>\nIIN_AGENT_TLS_CERT_PATH=<path_to_tls_cert_pem_for_iin_agent>\nIIN_AGENT_TLS_KEY_PATH=<path_to_tls_key_pem_for_iin_agent>\nMEMBER_ID=<org-msp-id>\nSECURITY_DOMAIN=network1\nDLT_TYPE=fabric\nCONFIG_PATH=./config.json\nDNS_CONFIG_PATH=./dnsconfig.json\nSECURITY_DOMAIN_CONFIG_PATH=./security-domain-config.json\nWEAVER_CONTRACT_ID=<name-of-weaver-interop-chaincode-installed>\nSYNC_PERIOD=<repeated_auto_sync_interval>\nAUTO_SYNC=<true/false>\nTLS_CREDENTIALS_DIR=<dir-with-tls-cert-and-key>\nDOCKER_IMAGE_NAME=ghcr.io/hyperledger-labs/weaver-iin-agent\nDOCKER_TAG=<iin-agent-docker-image-version>\nEXTERNAL_NETWORK=<docker-bridge-network>\n")),(0,i.yg)("ul",{parentName:"li"},(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("inlineCode",{parentName:"li"},"IIN_AGENT_ENDPOINT"),": The endpoint at which IIN Agent server should listen. E.g.: ",(0,i.yg)("inlineCode",{parentName:"li"},"0.0.0.0:9500")),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("inlineCode",{parentName:"li"},"IIN_AGENT_TLS"),": Set this to ",(0,i.yg)("inlineCode",{parentName:"li"},"true")," to enable TLS on IIN Agent server"),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("inlineCode",{parentName:"li"},"IIN_AGENT_TLS_CERT_PATH"),": Path to TLS certificate if TLS is enabled"),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("inlineCode",{parentName:"li"},"IIN_AGENT_TLS_KEY_PATH"),": Path to TLS key if TLS is enabled"),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("inlineCode",{parentName:"li"},"MEMBER_ID"),": Member Id for this IIN Agent. For fabric network, it should be the Organization's MSP ID"),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("inlineCode",{parentName:"li"},"SECURITY_DOMAIN"),": Security domain to which this IIN Agent belongs"),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("inlineCode",{parentName:"li"},"DLT_TYPE"),": To indicate the type of DLT for which this IIN Agent is running. E.g. ",(0,i.yg)("inlineCode",{parentName:"li"},"fabric")),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("inlineCode",{parentName:"li"},"CONFIG_PATH"),": Path to ledger specific config file (explained in next subsection)"),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("inlineCode",{parentName:"li"},"DNS_CONFIG_PATH"),": Path to DNS config file explained in previous sub sections"),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("inlineCode",{parentName:"li"},"SECURITY_DOMAIN_CONFIG_PATH"),": Path to security domain config file explained in previous sub sections"),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("inlineCode",{parentName:"li"},"WEAVER_CONTRACT_ID"),": Contract ID for DLT specific Weaver interoperation module installed on network"),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("inlineCode",{parentName:"li"},"SYNC_PERIOD"),": Period at which auto synchronization of memberships from other security domains should happen"),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("inlineCode",{parentName:"li"},"AUTO_SYNC"),": Set this to ",(0,i.yg)("inlineCode",{parentName:"li"},"true")," to enable auto synchronization of memberships from other security domains"),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("inlineCode",{parentName:"li"},"DOCKER_TAG"),": Set this to the desired version of the Weaver IIN Agent ",(0,i.yg)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/pkgs/container/weaver-iin-agent"},"docker image")),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("inlineCode",{parentName:"li"},"EXTERNAL_NETWORK"),": Set to the network ",(0,i.yg)("a",{parentName:"li",href:"https://docs.docker.com/compose/networking/"},"name")," of your Fabric network."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Enabling TLS"),":",(0,i.yg)("ul",{parentName:"li"},(0,i.yg)("li",{parentName:"ul"},"Make your IIN Agent accept TLS connections by specifying ",(0,i.yg)("inlineCode",{parentName:"li"},"IIN_AGENT_TLS")," as ",(0,i.yg)("inlineCode",{parentName:"li"},"true")," and specifying a TLS certificate file path and private key file path in ",(0,i.yg)("inlineCode",{parentName:"li"},"IIN_AGENT_TLS_CERT_PATH")," and ",(0,i.yg)("inlineCode",{parentName:"li"},"IIN_AGENT_TLS_KEY_PATH")," respectively. The same certificate should be specified in this agent's JSON object in another agent's ",(0,i.yg)("inlineCode",{parentName:"li"},"dnsconfig.json")," file under the appropriate security domain and IIN Agent ID scope."),(0,i.yg)("li",{parentName:"ul"},"You can point to the folder in your host system containing the certificate and key using the ",(0,i.yg)("inlineCode",{parentName:"li"},"TLS_CREDENTIALS_DIR")," variable. (This folder will be synced to the ",(0,i.yg)("inlineCode",{parentName:"li"},"/opt/iinagent/credentials")," folder in the IIN Agent container as specified in the ",(0,i.yg)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/core/identity-management/iin-agent/docker-compose.yml"},"docker-compose file"),".) Make sure you point to the right certificate and key file paths within the container using the ",(0,i.yg)("inlineCode",{parentName:"li"},"IIN_AGENT_TLS_CERT_PATH")," and ",(0,i.yg)("inlineCode",{parentName:"li"},"IIN_AGENT_TLS_KEY_PATH")," variables respectively."))))),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("p",{parentName:"li"},(0,i.yg)("inlineCode",{parentName:"p"},"docker-compose.yaml"),": This specifies the properties of the IIN agent container. You can use the ",(0,i.yg)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/core/identity-management/iin-agent/docker-compose.yml"},"file in the repository")," verbatim."))),(0,i.yg)("p",null,"Now to start the IIN agent, navigate to the folder containing the above files and run the following:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"docker-compose up -d\n")),(0,i.yg)("p",null,"Repeat the above steps to launch an IIN Agent for every other organization on your channnel, i.e., create similar configuration files in an organization-specific folder. Make sure you:"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},"Update the organization names in every relevant location in the ",(0,i.yg)("inlineCode",{parentName:"li"},"config.json"),"."),(0,i.yg)("li",{parentName:"ul"},"Update ",(0,i.yg)("inlineCode",{parentName:"li"},"IIN_AGENT_ENDPOINT")," and ",(0,i.yg)("inlineCode",{parentName:"li"},"MEMBER_ID")," in the ",(0,i.yg)("inlineCode",{parentName:"li"},".env"),".")),(0,i.yg)("h4",{id:"ledger-initialization"},"Ledger Initialization"),(0,i.yg)("p",null,"To prepare your network for interoperation with a foreign network, you need to record the following to your network channel through the Fabric Interoperation Chaincode:"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("p",{parentName:"li"},(0,i.yg)("strong",{parentName:"p"},"Access control policies"),":\nLet's take the example of the request made from ",(0,i.yg)("inlineCode",{parentName:"p"},"trade-finance-network")," to ",(0,i.yg)("inlineCode",{parentName:"p"},"trade-logistics-network")," for a B/L earlier in this document. ",(0,i.yg)("inlineCode",{parentName:"p"},"trade-logistics-network")," can have a policy of the following form permitting access to the ",(0,i.yg)("inlineCode",{parentName:"p"},"GetBillOfLading")," function from a client belonging to the ",(0,i.yg)("inlineCode",{parentName:"p"},"Exporter")," organization in ",(0,i.yg)("inlineCode",{parentName:"p"},"trade-finance-network")," as follows:"),(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-json"},'{\n "securityDomain":"trade-finance-network",\n "rules":\n [\n {\n "principal":"ExporterMSP",\n "principalType":"ca",\n "resource":"tradelogisticschannel:shipmentcc:GetBillOfLading:*",\n "read":true\n }\n ]\n}\n')),(0,i.yg)("p",{parentName:"li"},"In this sample, a single rule is specified for requests coming from ",(0,i.yg)("inlineCode",{parentName:"p"},"trade-finance-network"),": it states that a ",(0,i.yg)("inlineCode",{parentName:"p"},"GetBillOfLading")," query made to the ",(0,i.yg)("inlineCode",{parentName:"p"},"shipmentcc")," contract installed on the ",(0,i.yg)("inlineCode",{parentName:"p"},"tradelogisticschannel")," channel is permitted for a requestor possessing credentials certified by an MSP with the ",(0,i.yg)("inlineCode",{parentName:"p"},"ExporterMSP")," identity. The ",(0,i.yg)("inlineCode",{parentName:"p"},"*")," at the end indicates that any arguments passed to the function will pass the access control check."),(0,i.yg)("p",{parentName:"li"},"You need to record this policy rule on your Fabric network's channel by invoking either the ",(0,i.yg)("inlineCode",{parentName:"p"},"CreateAccessControlPolicy")," function or the ",(0,i.yg)("inlineCode",{parentName:"p"},"UpdateAccessControlPolicy")," function on the Fabric Interoperation Chaincode that is already installed on that channel; use the former if you are recording a set of rules for the given ",(0,i.yg)("inlineCode",{parentName:"p"},"securityDomain")," for the first time and the latter to overwrite a set of rules recorded earlier. In either case, the chaincode function will take a single argument, which is the policy in the form of a JSON string (make sure you escape the double quotes before sending the request to avoid parsing errors). You can do this in one of two ways: (1) writing a small piece of code in Layer-2 that invokes the contract using the Fabric SDK Gateway API, or (2) running a ",(0,i.yg)("inlineCode",{parentName:"p"},"peer chaincode invoke")," command from within a Docker container built on the ",(0,i.yg)("inlineCode",{parentName:"p"},"hyperledger/fabric-tools")," image. Either approach should be familiar to a Fabric practitioner.")),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("p",{parentName:"li"},(0,i.yg)("strong",{parentName:"p"},"Verification policies"),":\nTaking the same example as above, an example of a verification policy for a B/L requested by the ",(0,i.yg)("inlineCode",{parentName:"p"},"trade-finance-network")," from the ",(0,i.yg)("inlineCode",{parentName:"p"},"trade-logistics-network")," is as follows:"),(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-json"},'{\n "securityDomain":"trade-logistics-network",\n "identifiers":\n [\n {\n "pattern":"tradelogisticschannel:shipmentcc:GetBillOfLading:*",\n "policy":\n {\n "type":"Signature",\n "criteria":\n [\n "ExporterMSP",\n "CarrierMSP"\n ]\n }\n }\n ]\n}\n')),(0,i.yg)("p",{parentName:"li"},"In this sample, a single verification policy rule is specified for data views coming from ",(0,i.yg)("inlineCode",{parentName:"p"},"trade-logistics-network"),": it states that the data returned by the ",(0,i.yg)("inlineCode",{parentName:"p"},"GetBillOfLading")," query made to the ",(0,i.yg)("inlineCode",{parentName:"p"},"shipmentcc")," chaincode on the ",(0,i.yg)("inlineCode",{parentName:"p"},"tradelogisticschannel")," channel requires as proof two signatures, one from a peer in the organization whose MSP ID is ",(0,i.yg)("inlineCode",{parentName:"p"},"ExporterMSP")," and another from a peer in the organization whose MSP ID is ",(0,i.yg)("inlineCode",{parentName:"p"},"CarrierMSP"),"."),(0,i.yg)("p",{parentName:"li"},"You need to record this policy rule on your Fabric network's channel by invoking either the ",(0,i.yg)("inlineCode",{parentName:"p"},"CreateVerificationPolicy")," function or the ",(0,i.yg)("inlineCode",{parentName:"p"},"UpdateVerificationPolicy")," function on the Fabric Interoperation Chaincode that is already installed on that channel; use the former if you are recording a set of rules for the given ",(0,i.yg)("inlineCode",{parentName:"p"},"securityDomain")," for the first time and the latter to overwrite a set of rules recorded earlier. In either case, the chaincode function will take a single argument, which is the policy in the form of a JSON string (make sure you escape the double quotes before sending the request to avoid parsing errors). As with the access control policy, you can do this in one of two ways: (1) writing a small piece of code in Layer-2 that invokes the contract using the Fabric SDK Gateway API, or (2) running a ",(0,i.yg)("inlineCode",{parentName:"p"},"peer chaincode invoke")," command from within a Docker container built on the ",(0,i.yg)("inlineCode",{parentName:"p"},"hyperledger/fabric-tools")," image. Either approach should be familiar to a Fabric practitioner."),(0,i.yg)("table",{parentName:"li"},(0,i.yg)("thead",{parentName:"table"},(0,i.yg)("tr",{parentName:"thead"},(0,i.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,i.yg)("tbody",{parentName:"table"},(0,i.yg)("tr",{parentName:"tbody"},(0,i.yg)("td",{parentName:"tr",align:"left"},"For any cross-network data request, make sure an access control policy is recorded in the ",(0,i.yg)("em",{parentName:"td"},"source network")," (",(0,i.yg)("inlineCode",{parentName:"td"},"trade-logistics-network")," in the above example) and a corresponding verification policy is recorded in the ",(0,i.yg)("em",{parentName:"td"},"destination network")," (",(0,i.yg)("inlineCode",{parentName:"td"},"trade-finance-network")," in the above example) before any relay request is triggered."))))),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("p",{parentName:"li"},(0,i.yg)("strong",{parentName:"p"},"Local network security domain (membership) configuration"),':\nRecall the code snippet added to your application in the "Identity Administration" section. Exercise that code snippet, exposed either through a function API or an HTTP endpoint, to record the initial local membership for the relevant network channels.'))),(0,i.yg)("p",null,"Your Fabric network is now up and running with the necessary Weaver components, and your network's channel's ledger is bootstrapped with the initial configuration necessary for cross-network interactions!"))}g.isMDXComponent=!0},6185:(e,n,t)=>{t.d(n,{A:()=>a});const a=t.p+"assets/images/fabric-network-model-06abc1e93e9ae75bd416b1f822b7a312.png"},419:(e,n,t)=>{t.d(n,{A:()=>a});const a=t.p+"assets/images/fabric-weaver-model-bf28db3b4df0cd0ecd2a364e6886f91e.png"}}]); \ No newline at end of file diff --git a/assets/js/99b332c9.1742e64d.js b/assets/js/99b332c9.88c79114.js similarity index 70% rename from assets/js/99b332c9.1742e64d.js rename to assets/js/99b332c9.88c79114.js index f6964b289..3ffba353b 100644 --- a/assets/js/99b332c9.1742e64d.js +++ b/assets/js/99b332c9.88c79114.js @@ -1 +1 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[1939],{3769:e=>{e.exports=JSON.parse('{"name":"docusaurus-plugin-content-docs","id":"default"}')}}]); \ No newline at end of file +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[8003],{1966:e=>{e.exports=JSON.parse('{"name":"docusaurus-plugin-content-docs","id":"default"}')}}]); \ No newline at end of file diff --git a/assets/js/9a814649.976c239d.js b/assets/js/9a814649.976c239d.js deleted file mode 100644 index e8a6b7915..000000000 --- a/assets/js/9a814649.976c239d.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[676],{3905:(e,n,t)=>{t.d(n,{Zo:()=>l,kt:()=>S});var r=t(7294);function i(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function a(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function s(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?a(Object(t),!0).forEach((function(n){i(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):a(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function o(e,n){if(null==e)return{};var t,r,i=function(e,n){if(null==e)return{};var t,r,i={},a=Object.keys(e);for(r=0;r<a.length;r++)t=a[r],n.indexOf(t)>=0||(i[t]=e[t]);return i}(e,n);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)t=a[r],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(i[t]=e[t])}return i}var p=r.createContext({}),c=function(e){var n=r.useContext(p),t=n;return e&&(t="function"==typeof e?e(n):s(s({},n),e)),t},l=function(e){var n=c(e.components);return r.createElement(p.Provider,{value:n},e.children)},d="mdxType",g={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},u=r.forwardRef((function(e,n){var t=e.components,i=e.mdxType,a=e.originalType,p=e.parentName,l=o(e,["components","mdxType","originalType","parentName"]),d=c(t),u=i,S=d["".concat(p,".").concat(u)]||d[u]||g[u]||a;return t?r.createElement(S,s(s({ref:n},l),{},{components:t})):r.createElement(S,s({ref:n},l))}));function S(e,n){var t=arguments,i=n&&n.mdxType;if("string"==typeof e||i){var a=t.length,s=new Array(a);s[0]=u;var o={};for(var p in n)hasOwnProperty.call(n,p)&&(o[p]=n[p]);o.originalType=e,o[d]="string"==typeof e?e:i,s[1]=o;for(var c=2;c<a;c++)s[c]=t[c];return r.createElement.apply(null,s)}return r.createElement.apply(null,t)}u.displayName="MDXCreateElement"},1518:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>p,contentTitle:()=>s,default:()=>g,frontMatter:()=>a,metadata:()=>o,toc:()=>c});var r=t(7462),i=(t(7294),t(3905));const a={},s=void 0,o={unversionedId:"internal/development/cordapp-interop/cordapp-interop-api-assets",id:"internal/development/cordapp-interop/cordapp-interop-api-assets",title:"cordapp-interop-api-assets",description:"\x3c!--",source:"@site/docs/internal/development/cordapp-interop/cordapp-interop-api-assets.md",sourceDirName:"internal/development/cordapp-interop",slug:"/internal/development/cordapp-interop/cordapp-interop-api-assets",permalink:"/weaver-dlt-interoperability/docs/internal/development/cordapp-interop/cordapp-interop-api-assets",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/internal/development/cordapp-interop/cordapp-interop-api-assets.md",tags:[],version:"current",frontMatter:{}},p={},c=[],l={toc:c},d="wrapper";function g(e){let{components:n,...t}=e;return(0,i.kt)(d,(0,r.Z)({},l,t,{components:n,mdxType:"MDXLayout"}),(0,i.kt)("hr",null),(0,i.kt)("p",null,"id: cordapp-interop-api-assets\ntitle: API Assets"),(0,i.kt)("hr",null),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"class AccessControlIssueRequestState(\n linearId: UniqueIdentifier = UniqueIdentifier(),\n externalNetworkId: String,\n externalNetworkCertificates: List<String>,\n requestApprovals: List<DigitalSignature.WithKey>,\n stateLinearId: UniqueIdentifier,\n participants: List<Party>\n) : LinearState\n\nclass FormattedResponse(\n organizationName: String,\n decryptedPayload: String,\n certString: String,\n signatureBytes: ByteArray,\n message: ByteArray,\n publicKey: PublicKey\n)\n\nclass RelayRequestObject(\n operationType: String,\n policy: String,\n function: String,\n arguments: List<String>,\n clientOrganizationId: String,\n clientCertificate: String,\n clientSignature: String\n)\n\nclass RelayResponseObject(\n requestId: String,\n status: String,\n response: List<NodeResponse>?\n)\n\nclass NodeResponse(\n proposal: String,\n proposalResponse: String\n)\n\nclass RelayRequestId(\n requestId: String\n)\n\nclass ExternalStateRequest(\n url: String,\n path: String,\n externalNetworkId: String,\n requestId: String,\n function: String,\n participants: List<String>,\n mock: String?\n)\n\nclass ForeignNetworkMapInformationIntermediateResponse(\n CarrierMSP: FNNode,\n SellerMSP: FNNode\n)\n\nclass FNNode(\n admins: List<String>,\n crypto_config: CryptoConfig,\n fabric_node_ous: String?,\n intermediate_certs: List<String>,\n name: String,\n organizational_unit_identifiers: List<String>,\n revocation_list: List<String>,\n root_certs: List<String>,\n signing_identity: String?,\n tls_intermediate_certs: List<String>,\n tls_root_certs: List<String>\n)\n\nclass CryptoConfig(\n identity_identifier_hash_function: String,\n signature_hash_family: String\n)\n\nclass TxIdResponseObject(\n queryResponse: List<List<StateQueryResponse>?>\n)\n\nclass LinearIdResponseObject(\n queryResponse: List<StateQueryResponse>\n)\n\nclass QueryResponse(\n state: String,\n linearId: String\n)\n\nclass ParsedQueryObject(\n linearId: UniqueIdentifier,\n txId: String?\n)\n\nclass ExternalNetworkRequest(\n externalNetworkId: String,\n organizationName: String,\n requesterCertificate: String,\n requesterSignature: String,\n stateLinearId: String\n)\n\nclass NetworkMapObject(\n networkId: String,\n nodes: List<Node>\n)\n\nclass Node(\n name: String,\n address: String,\n hierarchicalCerts: List<ByteArray>,\n hierarchicalCANames: List<String>\n)\n\nclass ExternalNetworkRequestWithTxId(\n externalNetworkId: String,\n organizationName: String,\n requesterCertificate: String,\n requesterSignature: String,\n txId: String\n)\n\nclass FNIMStateRequest(\n networkId: String,\n topology: List<FNNode>,\n participants: List<String>\n)\n\nclass FNIMStateResponse(\n linearId: UniqueIdentifier,\n networkId: String,\n topology: List<FNNode>,\n participants: List<String>\n)\n\nclass AccessControlIssueRequestStateRequest(\n externalNetworkId: String,\n externalNetworkCertificates: List<String>,\n stateLinearId: String,\n participants: List<String>\n)\n\nclass AccessControlIssueRequestStateResponse(\n linearId: UniqueIdentifier,\n externalNetworkId: String,\n externalNetworkCertificates: List<String>,\n requestApprovals: List<String>,\n stateLinearId: String,\n participants: List<String>\n)\n\nclass AccessControlStateResponse(\n linearId: UniqueIdentifier,\n externalNetworkId: String,\n externalNetworkCertificates: List<String>,\n stateLinearId: String,\n participants: List<String>\n)\n")))}g.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/9e4087bc.8ba881f8.js b/assets/js/9e4087bc.ec92cfc4.js similarity index 56% rename from assets/js/9e4087bc.8ba881f8.js rename to assets/js/9e4087bc.ec92cfc4.js index 377bd91c4..049f78c4e 100644 --- a/assets/js/9e4087bc.8ba881f8.js +++ b/assets/js/9e4087bc.ec92cfc4.js @@ -1 +1 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[3608],{3169:(e,t,a)=>{a.r(t),a.d(t,{default:()=>o});var r=a(7294),l=a(9960),n=a(5999),c=a(1944),i=a(3285);function m(e){let{year:t,posts:a}=e;return r.createElement(r.Fragment,null,r.createElement("h3",null,t),r.createElement("ul",null,a.map((e=>r.createElement("li",{key:e.metadata.date},r.createElement(l.Z,{to:e.metadata.permalink},e.metadata.formattedDate," - ",e.metadata.title))))))}function s(e){let{years:t}=e;return r.createElement("section",{className:"margin-vert--lg"},r.createElement("div",{className:"container"},r.createElement("div",{className:"row"},t.map(((e,t)=>r.createElement("div",{key:t,className:"col col--4 margin-vert--lg"},r.createElement(m,e)))))))}function o(e){let{archive:t}=e;const a=(0,n.I)({id:"theme.blog.archive.title",message:"Archive",description:"The page & hero title of the blog archive page"}),l=(0,n.I)({id:"theme.blog.archive.description",message:"Archive",description:"The page & hero description of the blog archive page"}),m=function(e){const t=e.reduceRight(((e,t)=>{const a=t.metadata.date.split("-")[0],r=e.get(a)??[];return e.set(a,[t,...r])}),new Map);return Array.from(t,(e=>{let[t,a]=e;return{year:t,posts:a}}))}(t.blogPosts);return r.createElement(r.Fragment,null,r.createElement(c.d,{title:a,description:l}),r.createElement(i.Z,null,r.createElement("header",{className:"hero hero--primary"},r.createElement("div",{className:"container"},r.createElement("h1",{className:"hero__title"},a),r.createElement("p",{className:"hero__subtitle"},l))),r.createElement("main",null,m.length>0&&r.createElement(s,{years:m}))))}}}]); \ No newline at end of file +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[2711],{9331:(e,t,a)=>{a.r(t),a.d(t,{default:()=>o});var r=a(6540),l=a(5489),n=a(1312),c=a(1003),i=a(5713);function m(e){let{year:t,posts:a}=e;return r.createElement(r.Fragment,null,r.createElement("h3",null,t),r.createElement("ul",null,a.map((e=>r.createElement("li",{key:e.metadata.date},r.createElement(l.A,{to:e.metadata.permalink},e.metadata.formattedDate," - ",e.metadata.title))))))}function s(e){let{years:t}=e;return r.createElement("section",{className:"margin-vert--lg"},r.createElement("div",{className:"container"},r.createElement("div",{className:"row"},t.map(((e,t)=>r.createElement("div",{key:t,className:"col col--4 margin-vert--lg"},r.createElement(m,e)))))))}function o(e){let{archive:t}=e;const a=(0,n.T)({id:"theme.blog.archive.title",message:"Archive",description:"The page & hero title of the blog archive page"}),l=(0,n.T)({id:"theme.blog.archive.description",message:"Archive",description:"The page & hero description of the blog archive page"}),m=function(e){const t=e.reduceRight(((e,t)=>{const a=t.metadata.date.split("-")[0],r=e.get(a)??[];return e.set(a,[t,...r])}),new Map);return Array.from(t,(e=>{let[t,a]=e;return{year:t,posts:a}}))}(t.blogPosts);return r.createElement(r.Fragment,null,r.createElement(c.be,{title:a,description:l}),r.createElement(i.A,null,r.createElement("header",{className:"hero hero--primary"},r.createElement("div",{className:"container"},r.createElement("h1",{className:"hero__title"},a),r.createElement("p",{className:"hero__subtitle"},l))),r.createElement("main",null,m.length>0&&r.createElement(s,{years:m}))))}}}]); \ No newline at end of file diff --git a/assets/js/9f52c9db.5845363a.js b/assets/js/9f52c9db.ff69c241.js similarity index 89% rename from assets/js/9f52c9db.5845363a.js rename to assets/js/9f52c9db.ff69c241.js index 3842d875d..8703f293d 100644 --- a/assets/js/9f52c9db.5845363a.js +++ b/assets/js/9f52c9db.ff69c241.js @@ -1 +1 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[2435],{3905:(e,t,n)=>{n.d(t,{Zo:()=>s,kt:()=>u});var r=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?a(Object(n),!0).forEach((function(t){o(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):a(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},a=Object.keys(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var p=r.createContext({}),c=function(e){var t=r.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},s=function(e){var t=c(e.components);return r.createElement(p.Provider,{value:t},e.children)},d="mdxType",y={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,p=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),d=c(n),m=o,u=d["".concat(p,".").concat(m)]||d[m]||y[m]||a;return n?r.createElement(u,i(i({ref:t},s),{},{components:n})):r.createElement(u,i({ref:t},s))}));function u(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,i=new Array(a);i[0]=m;var l={};for(var p in t)hasOwnProperty.call(t,p)&&(l[p]=t[p]);l.originalType=e,l[d]="string"==typeof e?e:o,i[1]=l;for(var c=2;c<a;c++)i[c]=n[c];return r.createElement.apply(null,i)}return r.createElement.apply(null,n)}m.displayName="MDXCreateElement"},8540:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>i,default:()=>y,frontMatter:()=>a,metadata:()=>l,toc:()=>c});var r=n(7462),o=(n(7294),n(3905));const a={id:"deployment-patterns",title:"Deployment Patterns"},i=void 0,l={unversionedId:"external/deployment-considerations/deployment-patterns",id:"external/deployment-considerations/deployment-patterns",title:"Deployment Patterns",description:"\x3c!--",source:"@site/docs/external/deployment-considerations/deployment-patterns.md",sourceDirName:"external/deployment-considerations",slug:"/external/deployment-considerations/deployment-patterns",permalink:"/weaver-dlt-interoperability/docs/external/deployment-considerations/deployment-patterns",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/deployment-considerations/deployment-patterns.md",tags:[],version:"current",frontMatter:{id:"deployment-patterns",title:"Deployment Patterns"},sidebar:"Documentation",previous:{title:"End-to-End Security",permalink:"/weaver-dlt-interoperability/docs/external/security-model/end-to-end-security"},next:{title:"Governance and Policies",permalink:"/weaver-dlt-interoperability/docs/external/deployment-considerations/governance-and-policies"}},p={},c=[],s={toc:c},d="wrapper";function y(e){let{components:t,...n}=e;return(0,o.kt)(d,(0,r.Z)({},s,n,{components:t,mdxType:"MDXLayout"}))}y.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[4625],{5680:(e,t,n)=>{n.d(t,{xA:()=>s,yg:()=>u});var r=n(6540);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?a(Object(n),!0).forEach((function(t){o(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):a(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},a=Object.keys(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var p=r.createContext({}),c=function(e){var t=r.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},s=function(e){var t=c(e.components);return r.createElement(p.Provider,{value:t},e.children)},d="mdxType",y={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,p=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),d=c(n),m=o,u=d["".concat(p,".").concat(m)]||d[m]||y[m]||a;return n?r.createElement(u,i(i({ref:t},s),{},{components:n})):r.createElement(u,i({ref:t},s))}));function u(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,i=new Array(a);i[0]=m;var l={};for(var p in t)hasOwnProperty.call(t,p)&&(l[p]=t[p]);l.originalType=e,l[d]="string"==typeof e?e:o,i[1]=l;for(var c=2;c<a;c++)i[c]=n[c];return r.createElement.apply(null,i)}return r.createElement.apply(null,n)}m.displayName="MDXCreateElement"},4585:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>i,default:()=>y,frontMatter:()=>a,metadata:()=>l,toc:()=>c});var r=n(8168),o=(n(6540),n(5680));const a={id:"deployment-patterns",title:"Deployment Patterns"},i=void 0,l={unversionedId:"external/deployment-considerations/deployment-patterns",id:"external/deployment-considerations/deployment-patterns",title:"Deployment Patterns",description:"\x3c!--",source:"@site/docs/external/deployment-considerations/deployment-patterns.md",sourceDirName:"external/deployment-considerations",slug:"/external/deployment-considerations/deployment-patterns",permalink:"/weaver-dlt-interoperability/docs/external/deployment-considerations/deployment-patterns",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/deployment-considerations/deployment-patterns.md",tags:[],version:"current",frontMatter:{id:"deployment-patterns",title:"Deployment Patterns"},sidebar:"Documentation",previous:{title:"End-to-End Security",permalink:"/weaver-dlt-interoperability/docs/external/security-model/end-to-end-security"},next:{title:"Governance and Policies",permalink:"/weaver-dlt-interoperability/docs/external/deployment-considerations/governance-and-policies"}},p={},c=[],s={toc:c},d="wrapper";function y(e){let{components:t,...n}=e;return(0,o.yg)(d,(0,r.A)({},s,n,{components:t,mdxType:"MDXLayout"}))}y.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/a3e47e5c.cdea0430.js b/assets/js/a3e47e5c.cdea0430.js deleted file mode 100644 index d7c463a75..000000000 --- a/assets/js/a3e47e5c.cdea0430.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[8995],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>u});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,a,r=function(e,t){if(null==e)return{};var n,a,r={},i=Object.keys(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=a.createContext({}),h=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},c=function(e){var t=h(e.components);return a.createElement(l.Provider,{value:t},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,l=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),d=h(n),m=r,u=d["".concat(l,".").concat(m)]||d[m]||p[m]||i;return n?a.createElement(u,o(o({ref:t},c),{},{components:n})):a.createElement(u,o({ref:t},c))}));function u(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,o=new Array(i);o[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[d]="string"==typeof e?e:r,o[1]=s;for(var h=2;h<i;h++)o[h]=n[h];return a.createElement.apply(null,o)}return a.createElement.apply(null,n)}m.displayName="MDXCreateElement"},938:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>o,default:()=>p,frontMatter:()=>i,metadata:()=>s,toc:()=>h});var a=n(7462),r=(n(7294),n(3905));const i={id:"global-trade",title:"Global Trade"},o=void 0,s={unversionedId:"external/user-stories/global-trade",id:"external/user-stories/global-trade",title:"Global Trade",description:"\x3c!--",source:"@site/docs/external/user-stories/global-trade.md",sourceDirName:"external/user-stories",slug:"/external/user-stories/global-trade",permalink:"/weaver-dlt-interoperability/docs/external/user-stories/global-trade",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/user-stories/global-trade.md",tags:[],version:"current",frontMatter:{id:"global-trade",title:"Global Trade"},sidebar:"Documentation",previous:{title:"Overview",permalink:"/weaver-dlt-interoperability/docs/external/user-stories/overview"},next:{title:"DvP in Financial Markets",permalink:"/weaver-dlt-interoperability/docs/external/user-stories/financial-markets"}},l={},h=[{value:"Process Overview",id:"process-overview",level:2},{value:"Networks in Isolation",id:"networks-in-isolation",level:2},{value:"Initiating a Trade",id:"initiating-a-trade",level:3},{value:"Trade Logistics Network",id:"trade-logistics-network",level:3},{value:"Trade Finance Network",id:"trade-finance-network",level:3},{value:"Linking Finance with Logistics",id:"linking-finance-with-logistics",level:2},{value:"Extending the Scenario",id:"extending-the-scenario",level:2},{value:"Vision: Network of Networks",id:"vision-network-of-networks",level:2}],c={toc:h},d="wrapper";function p(e){let{components:t,...i}=e;return(0,r.kt)(d,(0,a.Z)({},c,i,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"The examples in this page cover the ",(0,r.kt)("strong",{parentName:"p"},"global trade")," application domain and the ",(0,r.kt)("strong",{parentName:"p"},"data sharing")," pattern."),(0,r.kt)("h2",{id:"process-overview"},"Process Overview"),(0,r.kt)("p",null,"At its simplest, international trade is about a party in one country buying certain goods from a party in another country. Because the goods cross international boundaries, the buyer is called an ",(0,r.kt)("em",{parentName:"p"},"importer")," and the seller is called an ",(0,r.kt)("em",{parentName:"p"},"exporter"),". For the same reason, this process is not as straightforward as, say, purchasing an item from a retailer."),(0,r.kt)("p",null,"The exporting of goods in most countries is governed by a host of regulatory provisions and authorities, making the very act of clearing the sale and getting the goods ready for shipment a complex one. Further, an exporter must rely on one or more ",(0,r.kt)("em",{parentName:"p"},"carriers")," to move the shipment from source to destination while managing all of the risks this entails."),(0,r.kt)("p",null,"But this only covers the shipping logistics. The trading parties, i.e., the exporter and importer, both face what is called ",(0,r.kt)("em",{parentName:"p"},"counterparty risk"),", or the hazard of giving something up without a guarantee of receiving something in return. If the exporter ships the goods first, the importer may renege on the payment. And if the importer mmakes the payment first, the exporter may renege on the shipment. To hedge against this risk, sophisticated process of ",(0,r.kt)("em",{parentName:"p"},"trade finance")," have evolved over centuries, with banks or other financial institutions providing the sorts of guarantees (in exchange for fees) that enable exporters and importers to safely conduct trades."),(0,r.kt)("p",null,"Permissioned blockchains are a great fit to manage such trade scenarios, involving multiple independent entities and no governing authorities, using smart contracts. Let us now see two kinds of processes in action, each of which can be managed in its own restricted network:"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("strong",{parentName:"li"},"Trade logistics"),": preparation, clearance, and export of goods"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("strong",{parentName:"li"},"Trade finance"),": payment guarantees and fulfillment")),(0,r.kt)("h2",{id:"networks-in-isolation"},"Networks in Isolation"),(0,r.kt)("p",null,"There exist real business networks in production that manage trade logistics and finance, but they can be very complex. We will present highly simplified versions of these processes, and focus on the aspects that will motivate the need for data sharing across networks."),(0,r.kt)("p",null,"Also, we will henceforth use the terms ",(0,r.kt)("em",{parentName:"p"},"buyer")," and ",(0,r.kt)("em",{parentName:"p"},"seller")," instead of ",(0,r.kt)("em",{parentName:"p"},"importer")," and ",(0,r.kt)("em",{parentName:"p"},"exporter")," respectively."),(0,r.kt)("h3",{id:"initiating-a-trade"},"Initiating a Trade"),(0,r.kt)("p",null,"Our trade process begins offline, with buyer and seller negotiating and agreeing on the sale of particular goods for given payment. We will assume that a ",(0,r.kt)("em",{parentName:"p"},"purchase order")," is created and contains a unique id we can use as reference in subsequent steps. This is illustrated in the figure below."),(0,r.kt)("p",null,(0,r.kt)("img",{alt:"alt text",src:n(6056).Z,width:"251",height:"484"})),(0,r.kt)("h3",{id:"trade-logistics-network"},"Trade Logistics Network"),(0,r.kt)("p",null,"The figure below represents a trade logistics network consisting of a seller and a carrier, loosely inspired by the TradeLens network built on Hyperledger Fabric. Think of the seller as a coffee plantation owner is Brazil, for example, and the carrier as a prominent shipping company like Maersk."),(0,r.kt)("p",null,(0,r.kt)("img",{alt:"alt text",src:n(8005).Z,width:"886",height:"544"})),(0,r.kt)("p",null,"The seller begins by booking a shipping consignment (associated with the purchase order id) and then registering its creation. It then hands the consignment over to the carrier. In a real life export scenario, this process involves a lot of documentation and approval cycles, but we are going to ignore all of those here. The carrier supplies documents certifying its possession of the consignment and the contents within it. The ",(0,r.kt)("em",{parentName:"p"},"bill of lading")," (B/L for short) is one of these documents, and though there may be others, like a packing list and a shipping manifest, we only need one to motivate interoperability. So we will keep it simple and assume that the carrier simply uploads a B/L. The seller examines and accepts this document, following which the carrier dispatches the consignment."),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Note that, at this point, a valid B/L is recorded on the trade logistics network ledger, a fact we will make use of soon enough.")),(0,r.kt)("h3",{id:"trade-finance-network"},"Trade Finance Network"),(0,r.kt)("p",null,"The figure below represents a trade finance network consisting of a seller, a buyer, and their respective banks. This is loosely inspired by the We.Trade network built on Hyperledger Fabric and the Marco Polo network built on R3 Corda. Think of the seller as our coffee plantation owner in the logistics network, the buyer as Starbucks, and the banks as Bank of America and HSBC Bank, for example."),(0,r.kt)("p",null,(0,r.kt)("img",{alt:"alt text",src:n(6014).Z,width:"879",height:"626"})),(0,r.kt)("p",null,"Traders and banks use a variety of mechanisms to mitigate counterparty risk, one of them being ",(0,r.kt)("em",{parentName:"p"},"open accounting"),", used in networks like We.Trade. We pick the popular ",(0,r.kt)("em",{parentName:"p"},"letter of credit")," (L/C for short) instrument for our trade finance story as this exemplifies the inherent link between logistics and finance (we will see this later). The process begins with the buyer requesting an L/C from its bank for a given trade, referring to the id of the purchase order generated earlier. In simplest terms, an L/C is a promise made by a bank to pay a certain amount to the bearer of certain documents associated with a given export shipment. In our scenario, the buyer's bank issues an L/C promising to pay the seller (through its bank) the amount due to it upon production of a valid B/L. This L/C proposal is recorded on the ledger, and subsequently approved by the seller's bank. After the seller uploads a B/L, the seller's bank is allowed to register a request for payment. This leaves a payment obligation for the buyer's bank on the ledger, which is where we will conclude the scenario, as the actual payment is carried out through a separate process on a different network."),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Note that the seller is supposed to produce and record a valid B/L in Step 4.")),(0,r.kt)("h2",{id:"linking-finance-with-logistics"},"Linking Finance with Logistics"),(0,r.kt)("p",null,"It is obvious that the logistics and finance processes are linked. Both begin with references to a common purchase order id and both involve bills of lading. Let us focus on the B/L, as it exemplifies a common pattern in these kinds of business networks: ",(0,r.kt)("em",{parentName:"p"},"that of being generated in one network and being used in another"),". Because thee are two separate networks, the trade finance network depends on the seller to upload a B/L. But here, we encounter another kind of hazard, one we discussed earlier in the ",(0,r.kt)("a",{parentName:"p",href:"./overview#challenges-to-overcome"},"challenges")," section. The seller has an incentive to produce a fake bill of lading in order to get paid for goods it may not have dispatched and may have no intention of dispatching. In the present setup, the trade finance network as a whole, nor the buyer or its bank, has visibility into the trade logistics network's ledger, and hence have to trust the seller's word."),(0,r.kt)("p",null,"This hazard can be avoided if the networks are interoperable, and can share data with each other. Specifically, if the trade logistics network can share a B/L recorded on its ledger ",(0,r.kt)("em",{parentName:"p"},"institutionally")," with the trade finance network. To see how this works, see the diagram below, which contains both the networks and merges their flows."),(0,r.kt)("p",null,(0,r.kt)("img",{alt:"alt text",src:n(8747).Z,width:"1533",height:"696"})),(0,r.kt)("p",null,"Step 4 in the ",(0,r.kt)("a",{parentName:"p",href:"./global-trade#trade-finance-network"},"isolated trade finance network")," is now replaced with an interoperation step (Step 10) whereby the trade finance network obtains a B/L from the trade logistics network via a data-sharing protocol. This avoids the hazard of having to depend on an unreliable seller to supply a valid B/L. But it is not enough for the trade logistics network to share B/L data. It must also share some ",(0,r.kt)("em",{parentName:"p"},"proof")," or evidence that the B/L is presently on record in its shared ledger."),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Note: in general, an interoperation mechanism for data sharing must communicate data as well as an associated proof that can be ",(0,r.kt)("em",{parentName:"strong"},"independently verified")," by every memebr of the receiving network.")),(0,r.kt)("h2",{id:"extending-the-scenario"},"Extending the Scenario"),(0,r.kt)("p",null,"The above example conforms to how the logistics and finance processes work today. Letters of credit typically specify bills of lading among the lists of documents that must be supplied to claim a payment. But state-of-the-art blockchain technology and permissioned networks can facilitate a lot more process innovation than earlier technology could."),(0,r.kt)("p",null,"The present trade logistics network allows a consignment to be created and dispatched without any knowledge of how the trade will be financed. But in real life, there is a need to track imports and exports carefully to ensure that no regulations are broken, and secondarily, to avoid wasted effort. Therefore, we can envision trade logistics networks requiring some evidence of the financial arrangements of a trade before it allows a seller and a carrier to carry out with the shipping process."),(0,r.kt)("p",null,"The process augmentation is illustrated in the figure below with the insertion of a new Step 6 between the booking and the creation of a shipping consignment."),(0,r.kt)("p",null,(0,r.kt)("img",{alt:"alt text",src:n(693).Z,width:"1533",height:"696"})),(0,r.kt)("p",null,"Like Step 11 (Step 10 in the earlier figure), this is a data-sharing interoperation step where the L/C proposed and accepted on the trade finance network's ledger is copied to the trade logistics network's ledger. (As with the B/L sharing, proof of the L/C ledger record must accompany L/C data.) In this new process, the trade logistics network will not waste time processing shipments that do not have a backing L/C guarantee from the trade finance network."),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Note that in the interoperation steps, the artifact being shared by one network with another (B/L or L/C) does not have to be copied verbatim to the receiving network's ledger. The process incorporates transformations carried out through smart contract transactions occurring through their networks' native consensus mechanisms.")),(0,r.kt)("h2",{id:"vision-network-of-networks"},"Vision: Network of Networks"),(0,r.kt)("p",null,"The promise of blockchain was a more decentralized yet trustworthy internet, but as we saw earlier, networks like Bitcoin and Ethereum may not fulfill that promise, largely because they have technical limitations when it comes to performance and scaling, privacy preservation, and auditability. At the same time, private blockchain networks are here to stay, and they do overcome these technical limitations, albeit at smaller scale. In the longer term, a more sustainable and achievable vision will be to allow private networks to exist while possessing the means to interoperate with other private networks. The interlinking of a trade logistics network with a trade finance network was just a sample. There is more aspects to an international trade scenario: more networks and more cross-network dependencies. But as long as we can institute mechanisms to link two networks directly for data-sharing, we can extrapolate our two-network scenario into a network-of-networks scenario."),(0,r.kt)("p",null,"To show how this will work, we will add two more networks to the mix. Business networks exist to track the quality and health of perishable goods from the production source to the end retailer. These networks complement networks like Trade Lens, which manage the long-distance shipping that occurs in the middle but have no visibiity into the goods before consignment creation or after delivery at the destination by the carrier. To track goods at either ends is the function of networks like IBM Food Trust, which would be ideal for the coffee shipment example we used earlier. A separate aspect of our trade scenario is the actual payment a buyer makes to the seller. Our trade finance network ends by recording a payment obligation, but the transfer of money needs to occur on a separate payment network, like, for example, the Stellar Network."),(0,r.kt)("p",null,"The figure below presents our vision for how cross-network data sharing can help smoothen and simplify all aspects of global trade despite the fact that different sub-processes occur on independent private networks."),(0,r.kt)("p",null,(0,r.kt)("img",{alt:"alt text",src:n(4790).Z,width:"907",height:"1080"})),(0,r.kt)("p",null,"The ",(0,r.kt)("em",{parentName:"p"},"Food Tracking Network")," is loosely inspired by IBM Food Trust and the ",(0,r.kt)("em",{parentName:"p"},"Payments Network")," loosely inspired by Stellar."),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"The seller and buyer, as the trading parties, belong to the food tracking network. The process in this network begins with a registration of a purchase order, following which perishable goods (think coffee seeds, for example) are tracked from farms to a warehouse where a shipping consignment is created. Whenever the carier delivers the shipment, the fact of delivery is recorded as is the condition of the goods within."),(0,r.kt)("li",{parentName:"ul"},"The payment network has the buyer's and seller's bank as members. Action in this network is triggered by the buyer's bank making a payment, or a monetary transfer, to the seller's bank. Both banks have accounts in this network and the payment succeeds or fails depending on available account balance.")),(0,r.kt)("p",null,"There are two parallel timelines starting at Step 17:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},'One involves the trade finance network and the payments network (Steps 17-20). Step 18 contains both "Make Payment" and "Receive Payment" as these actions are supposed to occur atomically within the payments network. These pertain to the fulfilment of the payment promised to the seller by the buyer.'),(0,r.kt)("li",{parentName:"ul"},"Another involves the trade logistics network and the food tracking network (Steps 17-19). These pertain to the tracking of goods after dispatch and confirmation of their subsequent delivery and condition.")),(0,r.kt)("p",null,"You may notice we have augmented the trade logistics and trade finance processes as follows:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Step 17 in the trade logistics network illustrates a sequence of transactions, each recording the location and condition of the goods in transit at periodic intervals. We assume that this information can be procured using sensors deployed with the consignment."),(0,r.kt)("li",{parentName:"ul"},'Step 20 in the trade finance network results in the cancelling of the payment obligation recorded by the seller\'s bank in Step 17 within that network ("Request Payment"), thereby concluding the trade instance associated with the purchase order id generated in Step 1.')),(0,r.kt)("p",null,"The data-sharing interoperation steps are as follows:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("em",{parentName:"li"},"Step 3"),": The trade finance network fetches a purchase order from the food tracking network before permitting an L/C request to be made."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("em",{parentName:"li"},"Step 8"),": The trade logistics network fetches an L/C from the trade finance network before permitting a consignment to be created."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("em",{parentName:"li"},"Step 9"),": The food tracking network fetches a consignment booking record and an associated L/C from the trade logistics network before permitting tracking of goods from the source to the shipping warehouse."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("em",{parentName:"li"},"Step 11"),": The trade logistics network fetches tracking information indicating delivery of goods to the warehouse before permitting a consignment to be created."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("em",{parentName:"li"},"Step 16"),": The trade finance network fetches a B/L from the trade logistics network before permitting the seller's bank to register a payment request."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("em",{parentName:"li"},"Step 18"),": This is a recurring step, in each instance of which the food tracking network fetches location and condition information for a given consignment from the trade logistics network, and does not permit the confirmation of consignment delivery and the integrity of the goods within until the shipment reaches its destination and its condition meets the required standard."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("em",{parentName:"li"},"Step 19"),": The trade finance network gets confirmation of payment (from buyer's account to seller's account) from the payments network.")),(0,r.kt)("p",null,"To summarize, internationally traded goods can be tracked from a farm in one country to a retailer in another, the goods can be exported and shipped with all regulations complied with, financial guarantees can be put in place to safeguard the trading parties, and cross-border payments can be processed seamlessly and in a trustworthy manner. But this requires a combination of private blockchain networks willing to share data with each other and also have the ability to verify the authenticity of received data. We hope this scenario makes the motivation for data-sharing interoperation mechanisms perfectly clear."))}p.isMDXComponent=!0},8747:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/interop-bl-61e5b8dd05231725f6666d5667563007.png"},4790:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/interop-four-networks-trade-9e5a4615ea47ce67292302870464b738.png"},693:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/interop-lc-bl-da719caad248b680b46abede62a6834d.png"},6056:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/purchase-order-fac77f11aad1814b20900891ed81dbfd.png"},6014:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/trade-finance-network-981f58ce5df21470e516376dc6a2b2f5.png"},8005:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/trade-logistics-network-4a6d8a24e627f1aa0fcbe6af00c58986.png"}}]); \ No newline at end of file diff --git a/assets/js/a3e47e5c.db70941b.js b/assets/js/a3e47e5c.db70941b.js new file mode 100644 index 000000000..eff45d88f --- /dev/null +++ b/assets/js/a3e47e5c.db70941b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[576],{5680:(e,t,n)=>{n.d(t,{xA:()=>c,yg:()=>m});var a=n(6540);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,a,r=function(e,t){if(null==e)return{};var n,a,r={},i=Object.keys(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=a.createContext({}),h=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},c=function(e){var t=h(e.components);return a.createElement(l.Provider,{value:t},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},g=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,l=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),d=h(n),g=r,m=d["".concat(l,".").concat(g)]||d[g]||p[g]||i;return n?a.createElement(m,o(o({ref:t},c),{},{components:n})):a.createElement(m,o({ref:t},c))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,o=new Array(i);o[0]=g;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[d]="string"==typeof e?e:r,o[1]=s;for(var h=2;h<i;h++)o[h]=n[h];return a.createElement.apply(null,o)}return a.createElement.apply(null,n)}g.displayName="MDXCreateElement"},6460:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>o,default:()=>p,frontMatter:()=>i,metadata:()=>s,toc:()=>h});var a=n(8168),r=(n(6540),n(5680));const i={id:"global-trade",title:"Global Trade"},o=void 0,s={unversionedId:"external/user-stories/global-trade",id:"external/user-stories/global-trade",title:"Global Trade",description:"\x3c!--",source:"@site/docs/external/user-stories/global-trade.md",sourceDirName:"external/user-stories",slug:"/external/user-stories/global-trade",permalink:"/weaver-dlt-interoperability/docs/external/user-stories/global-trade",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/user-stories/global-trade.md",tags:[],version:"current",frontMatter:{id:"global-trade",title:"Global Trade"},sidebar:"Documentation",previous:{title:"Overview",permalink:"/weaver-dlt-interoperability/docs/external/user-stories/overview"},next:{title:"DvP in Financial Markets",permalink:"/weaver-dlt-interoperability/docs/external/user-stories/financial-markets"}},l={},h=[{value:"Process Overview",id:"process-overview",level:2},{value:"Networks in Isolation",id:"networks-in-isolation",level:2},{value:"Initiating a Trade",id:"initiating-a-trade",level:3},{value:"Trade Logistics Network",id:"trade-logistics-network",level:3},{value:"Trade Finance Network",id:"trade-finance-network",level:3},{value:"Linking Finance with Logistics",id:"linking-finance-with-logistics",level:2},{value:"Extending the Scenario",id:"extending-the-scenario",level:2},{value:"Vision: Network of Networks",id:"vision-network-of-networks",level:2}],c={toc:h},d="wrapper";function p(e){let{components:t,...i}=e;return(0,r.yg)(d,(0,a.A)({},c,i,{components:t,mdxType:"MDXLayout"}),(0,r.yg)("p",null,"The examples in this page cover the ",(0,r.yg)("strong",{parentName:"p"},"global trade")," application domain and the ",(0,r.yg)("strong",{parentName:"p"},"data sharing")," pattern."),(0,r.yg)("h2",{id:"process-overview"},"Process Overview"),(0,r.yg)("p",null,"At its simplest, international trade is about a party in one country buying certain goods from a party in another country. Because the goods cross international boundaries, the buyer is called an ",(0,r.yg)("em",{parentName:"p"},"importer")," and the seller is called an ",(0,r.yg)("em",{parentName:"p"},"exporter"),". For the same reason, this process is not as straightforward as, say, purchasing an item from a retailer."),(0,r.yg)("p",null,"The exporting of goods in most countries is governed by a host of regulatory provisions and authorities, making the very act of clearing the sale and getting the goods ready for shipment a complex one. Further, an exporter must rely on one or more ",(0,r.yg)("em",{parentName:"p"},"carriers")," to move the shipment from source to destination while managing all of the risks this entails."),(0,r.yg)("p",null,"But this only covers the shipping logistics. The trading parties, i.e., the exporter and importer, both face what is called ",(0,r.yg)("em",{parentName:"p"},"counterparty risk"),", or the hazard of giving something up without a guarantee of receiving something in return. If the exporter ships the goods first, the importer may renege on the payment. And if the importer mmakes the payment first, the exporter may renege on the shipment. To hedge against this risk, sophisticated process of ",(0,r.yg)("em",{parentName:"p"},"trade finance")," have evolved over centuries, with banks or other financial institutions providing the sorts of guarantees (in exchange for fees) that enable exporters and importers to safely conduct trades."),(0,r.yg)("p",null,"Permissioned blockchains are a great fit to manage such trade scenarios, involving multiple independent entities and no governing authorities, using smart contracts. Let us now see two kinds of processes in action, each of which can be managed in its own restricted network:"),(0,r.yg)("ol",null,(0,r.yg)("li",{parentName:"ol"},(0,r.yg)("strong",{parentName:"li"},"Trade logistics"),": preparation, clearance, and export of goods"),(0,r.yg)("li",{parentName:"ol"},(0,r.yg)("strong",{parentName:"li"},"Trade finance"),": payment guarantees and fulfillment")),(0,r.yg)("h2",{id:"networks-in-isolation"},"Networks in Isolation"),(0,r.yg)("p",null,"There exist real business networks in production that manage trade logistics and finance, but they can be very complex. We will present highly simplified versions of these processes, and focus on the aspects that will motivate the need for data sharing across networks."),(0,r.yg)("p",null,"Also, we will henceforth use the terms ",(0,r.yg)("em",{parentName:"p"},"buyer")," and ",(0,r.yg)("em",{parentName:"p"},"seller")," instead of ",(0,r.yg)("em",{parentName:"p"},"importer")," and ",(0,r.yg)("em",{parentName:"p"},"exporter")," respectively."),(0,r.yg)("h3",{id:"initiating-a-trade"},"Initiating a Trade"),(0,r.yg)("p",null,"Our trade process begins offline, with buyer and seller negotiating and agreeing on the sale of particular goods for given payment. We will assume that a ",(0,r.yg)("em",{parentName:"p"},"purchase order")," is created and contains a unique id we can use as reference in subsequent steps. This is illustrated in the figure below."),(0,r.yg)("p",null,(0,r.yg)("img",{alt:"alt text",src:n(6565).A,width:"251",height:"484"})),(0,r.yg)("h3",{id:"trade-logistics-network"},"Trade Logistics Network"),(0,r.yg)("p",null,"The figure below represents a trade logistics network consisting of a seller and a carrier, loosely inspired by the TradeLens network built on Hyperledger Fabric. Think of the seller as a coffee plantation owner is Brazil, for example, and the carrier as a prominent shipping company like Maersk."),(0,r.yg)("p",null,(0,r.yg)("img",{alt:"alt text",src:n(5898).A,width:"886",height:"544"})),(0,r.yg)("p",null,"The seller begins by booking a shipping consignment (associated with the purchase order id) and then registering its creation. It then hands the consignment over to the carrier. In a real life export scenario, this process involves a lot of documentation and approval cycles, but we are going to ignore all of those here. The carrier supplies documents certifying its possession of the consignment and the contents within it. The ",(0,r.yg)("em",{parentName:"p"},"bill of lading")," (B/L for short) is one of these documents, and though there may be others, like a packing list and a shipping manifest, we only need one to motivate interoperability. So we will keep it simple and assume that the carrier simply uploads a B/L. The seller examines and accepts this document, following which the carrier dispatches the consignment."),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},"Note that, at this point, a valid B/L is recorded on the trade logistics network ledger, a fact we will make use of soon enough.")),(0,r.yg)("h3",{id:"trade-finance-network"},"Trade Finance Network"),(0,r.yg)("p",null,"The figure below represents a trade finance network consisting of a seller, a buyer, and their respective banks. This is loosely inspired by the We.Trade network built on Hyperledger Fabric and the Marco Polo network built on R3 Corda. Think of the seller as our coffee plantation owner in the logistics network, the buyer as Starbucks, and the banks as Bank of America and HSBC Bank, for example."),(0,r.yg)("p",null,(0,r.yg)("img",{alt:"alt text",src:n(9013).A,width:"879",height:"626"})),(0,r.yg)("p",null,"Traders and banks use a variety of mechanisms to mitigate counterparty risk, one of them being ",(0,r.yg)("em",{parentName:"p"},"open accounting"),", used in networks like We.Trade. We pick the popular ",(0,r.yg)("em",{parentName:"p"},"letter of credit")," (L/C for short) instrument for our trade finance story as this exemplifies the inherent link between logistics and finance (we will see this later). The process begins with the buyer requesting an L/C from its bank for a given trade, referring to the id of the purchase order generated earlier. In simplest terms, an L/C is a promise made by a bank to pay a certain amount to the bearer of certain documents associated with a given export shipment. In our scenario, the buyer's bank issues an L/C promising to pay the seller (through its bank) the amount due to it upon production of a valid B/L. This L/C proposal is recorded on the ledger, and subsequently approved by the seller's bank. After the seller uploads a B/L, the seller's bank is allowed to register a request for payment. This leaves a payment obligation for the buyer's bank on the ledger, which is where we will conclude the scenario, as the actual payment is carried out through a separate process on a different network."),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},"Note that the seller is supposed to produce and record a valid B/L in Step 4.")),(0,r.yg)("h2",{id:"linking-finance-with-logistics"},"Linking Finance with Logistics"),(0,r.yg)("p",null,"It is obvious that the logistics and finance processes are linked. Both begin with references to a common purchase order id and both involve bills of lading. Let us focus on the B/L, as it exemplifies a common pattern in these kinds of business networks: ",(0,r.yg)("em",{parentName:"p"},"that of being generated in one network and being used in another"),". Because thee are two separate networks, the trade finance network depends on the seller to upload a B/L. But here, we encounter another kind of hazard, one we discussed earlier in the ",(0,r.yg)("a",{parentName:"p",href:"./overview#challenges-to-overcome"},"challenges")," section. The seller has an incentive to produce a fake bill of lading in order to get paid for goods it may not have dispatched and may have no intention of dispatching. In the present setup, the trade finance network as a whole, nor the buyer or its bank, has visibility into the trade logistics network's ledger, and hence have to trust the seller's word."),(0,r.yg)("p",null,"This hazard can be avoided if the networks are interoperable, and can share data with each other. Specifically, if the trade logistics network can share a B/L recorded on its ledger ",(0,r.yg)("em",{parentName:"p"},"institutionally")," with the trade finance network. To see how this works, see the diagram below, which contains both the networks and merges their flows."),(0,r.yg)("p",null,(0,r.yg)("img",{alt:"alt text",src:n(4489).A,width:"1533",height:"696"})),(0,r.yg)("p",null,"Step 4 in the ",(0,r.yg)("a",{parentName:"p",href:"./global-trade#trade-finance-network"},"isolated trade finance network")," is now replaced with an interoperation step (Step 10) whereby the trade finance network obtains a B/L from the trade logistics network via a data-sharing protocol. This avoids the hazard of having to depend on an unreliable seller to supply a valid B/L. But it is not enough for the trade logistics network to share B/L data. It must also share some ",(0,r.yg)("em",{parentName:"p"},"proof")," or evidence that the B/L is presently on record in its shared ledger."),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},"Note: in general, an interoperation mechanism for data sharing must communicate data as well as an associated proof that can be ",(0,r.yg)("em",{parentName:"strong"},"independently verified")," by every memebr of the receiving network.")),(0,r.yg)("h2",{id:"extending-the-scenario"},"Extending the Scenario"),(0,r.yg)("p",null,"The above example conforms to how the logistics and finance processes work today. Letters of credit typically specify bills of lading among the lists of documents that must be supplied to claim a payment. But state-of-the-art blockchain technology and permissioned networks can facilitate a lot more process innovation than earlier technology could."),(0,r.yg)("p",null,"The present trade logistics network allows a consignment to be created and dispatched without any knowledge of how the trade will be financed. But in real life, there is a need to track imports and exports carefully to ensure that no regulations are broken, and secondarily, to avoid wasted effort. Therefore, we can envision trade logistics networks requiring some evidence of the financial arrangements of a trade before it allows a seller and a carrier to carry out with the shipping process."),(0,r.yg)("p",null,"The process augmentation is illustrated in the figure below with the insertion of a new Step 6 between the booking and the creation of a shipping consignment."),(0,r.yg)("p",null,(0,r.yg)("img",{alt:"alt text",src:n(5241).A,width:"1533",height:"696"})),(0,r.yg)("p",null,"Like Step 11 (Step 10 in the earlier figure), this is a data-sharing interoperation step where the L/C proposed and accepted on the trade finance network's ledger is copied to the trade logistics network's ledger. (As with the B/L sharing, proof of the L/C ledger record must accompany L/C data.) In this new process, the trade logistics network will not waste time processing shipments that do not have a backing L/C guarantee from the trade finance network."),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},"Note that in the interoperation steps, the artifact being shared by one network with another (B/L or L/C) does not have to be copied verbatim to the receiving network's ledger. The process incorporates transformations carried out through smart contract transactions occurring through their networks' native consensus mechanisms.")),(0,r.yg)("h2",{id:"vision-network-of-networks"},"Vision: Network of Networks"),(0,r.yg)("p",null,"The promise of blockchain was a more decentralized yet trustworthy internet, but as we saw earlier, networks like Bitcoin and Ethereum may not fulfill that promise, largely because they have technical limitations when it comes to performance and scaling, privacy preservation, and auditability. At the same time, private blockchain networks are here to stay, and they do overcome these technical limitations, albeit at smaller scale. In the longer term, a more sustainable and achievable vision will be to allow private networks to exist while possessing the means to interoperate with other private networks. The interlinking of a trade logistics network with a trade finance network was just a sample. There is more aspects to an international trade scenario: more networks and more cross-network dependencies. But as long as we can institute mechanisms to link two networks directly for data-sharing, we can extrapolate our two-network scenario into a network-of-networks scenario."),(0,r.yg)("p",null,"To show how this will work, we will add two more networks to the mix. Business networks exist to track the quality and health of perishable goods from the production source to the end retailer. These networks complement networks like Trade Lens, which manage the long-distance shipping that occurs in the middle but have no visibiity into the goods before consignment creation or after delivery at the destination by the carrier. To track goods at either ends is the function of networks like IBM Food Trust, which would be ideal for the coffee shipment example we used earlier. A separate aspect of our trade scenario is the actual payment a buyer makes to the seller. Our trade finance network ends by recording a payment obligation, but the transfer of money needs to occur on a separate payment network, like, for example, the Stellar Network."),(0,r.yg)("p",null,"The figure below presents our vision for how cross-network data sharing can help smoothen and simplify all aspects of global trade despite the fact that different sub-processes occur on independent private networks."),(0,r.yg)("p",null,(0,r.yg)("img",{alt:"alt text",src:n(1762).A,width:"907",height:"1080"})),(0,r.yg)("p",null,"The ",(0,r.yg)("em",{parentName:"p"},"Food Tracking Network")," is loosely inspired by IBM Food Trust and the ",(0,r.yg)("em",{parentName:"p"},"Payments Network")," loosely inspired by Stellar."),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"The seller and buyer, as the trading parties, belong to the food tracking network. The process in this network begins with a registration of a purchase order, following which perishable goods (think coffee seeds, for example) are tracked from farms to a warehouse where a shipping consignment is created. Whenever the carier delivers the shipment, the fact of delivery is recorded as is the condition of the goods within."),(0,r.yg)("li",{parentName:"ul"},"The payment network has the buyer's and seller's bank as members. Action in this network is triggered by the buyer's bank making a payment, or a monetary transfer, to the seller's bank. Both banks have accounts in this network and the payment succeeds or fails depending on available account balance.")),(0,r.yg)("p",null,"There are two parallel timelines starting at Step 17:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},'One involves the trade finance network and the payments network (Steps 17-20). Step 18 contains both "Make Payment" and "Receive Payment" as these actions are supposed to occur atomically within the payments network. These pertain to the fulfilment of the payment promised to the seller by the buyer.'),(0,r.yg)("li",{parentName:"ul"},"Another involves the trade logistics network and the food tracking network (Steps 17-19). These pertain to the tracking of goods after dispatch and confirmation of their subsequent delivery and condition.")),(0,r.yg)("p",null,"You may notice we have augmented the trade logistics and trade finance processes as follows:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Step 17 in the trade logistics network illustrates a sequence of transactions, each recording the location and condition of the goods in transit at periodic intervals. We assume that this information can be procured using sensors deployed with the consignment."),(0,r.yg)("li",{parentName:"ul"},'Step 20 in the trade finance network results in the cancelling of the payment obligation recorded by the seller\'s bank in Step 17 within that network ("Request Payment"), thereby concluding the trade instance associated with the purchase order id generated in Step 1.')),(0,r.yg)("p",null,"The data-sharing interoperation steps are as follows:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("em",{parentName:"li"},"Step 3"),": The trade finance network fetches a purchase order from the food tracking network before permitting an L/C request to be made."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("em",{parentName:"li"},"Step 8"),": The trade logistics network fetches an L/C from the trade finance network before permitting a consignment to be created."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("em",{parentName:"li"},"Step 9"),": The food tracking network fetches a consignment booking record and an associated L/C from the trade logistics network before permitting tracking of goods from the source to the shipping warehouse."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("em",{parentName:"li"},"Step 11"),": The trade logistics network fetches tracking information indicating delivery of goods to the warehouse before permitting a consignment to be created."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("em",{parentName:"li"},"Step 16"),": The trade finance network fetches a B/L from the trade logistics network before permitting the seller's bank to register a payment request."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("em",{parentName:"li"},"Step 18"),": This is a recurring step, in each instance of which the food tracking network fetches location and condition information for a given consignment from the trade logistics network, and does not permit the confirmation of consignment delivery and the integrity of the goods within until the shipment reaches its destination and its condition meets the required standard."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("em",{parentName:"li"},"Step 19"),": The trade finance network gets confirmation of payment (from buyer's account to seller's account) from the payments network.")),(0,r.yg)("p",null,"To summarize, internationally traded goods can be tracked from a farm in one country to a retailer in another, the goods can be exported and shipped with all regulations complied with, financial guarantees can be put in place to safeguard the trading parties, and cross-border payments can be processed seamlessly and in a trustworthy manner. But this requires a combination of private blockchain networks willing to share data with each other and also have the ability to verify the authenticity of received data. We hope this scenario makes the motivation for data-sharing interoperation mechanisms perfectly clear."))}p.isMDXComponent=!0},4489:(e,t,n)=>{n.d(t,{A:()=>a});const a=n.p+"assets/images/interop-bl-61e5b8dd05231725f6666d5667563007.png"},1762:(e,t,n)=>{n.d(t,{A:()=>a});const a=n.p+"assets/images/interop-four-networks-trade-9e5a4615ea47ce67292302870464b738.png"},5241:(e,t,n)=>{n.d(t,{A:()=>a});const a=n.p+"assets/images/interop-lc-bl-da719caad248b680b46abede62a6834d.png"},6565:(e,t,n)=>{n.d(t,{A:()=>a});const a=n.p+"assets/images/purchase-order-fac77f11aad1814b20900891ed81dbfd.png"},9013:(e,t,n)=>{n.d(t,{A:()=>a});const a=n.p+"assets/images/trade-finance-network-981f58ce5df21470e516376dc6a2b2f5.png"},5898:(e,t,n)=>{n.d(t,{A:()=>a});const a=n.p+"assets/images/trade-logistics-network-4a6d8a24e627f1aa0fcbe6af00c58986.png"}}]); \ No newline at end of file diff --git a/assets/js/a50a7707.1c991886.js b/assets/js/a50a7707.1c991886.js new file mode 100644 index 000000000..b972aecda --- /dev/null +++ b/assets/js/a50a7707.1c991886.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[429],{5680:(e,t,a)=>{a.d(t,{xA:()=>g,yg:()=>y});var n=a(6540);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function i(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function o(e){for(var t=1;t<arguments.length;t++){var a=null!=arguments[t]?arguments[t]:{};t%2?i(Object(a),!0).forEach((function(t){r(e,t,a[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(a)):i(Object(a)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(a,t))}))}return e}function s(e,t){if(null==e)return{};var a,n,r=function(e,t){if(null==e)return{};var a,n,r={},i=Object.keys(e);for(n=0;n<i.length;n++)a=i[n],t.indexOf(a)>=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)a=i[n],t.indexOf(a)>=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var l=n.createContext({}),c=function(e){var t=n.useContext(l),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},g=function(e){var t=c(e.components);return n.createElement(l.Provider,{value:t},e.children)},p="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,i=e.originalType,l=e.parentName,g=s(e,["components","mdxType","originalType","parentName"]),p=c(a),d=r,y=p["".concat(l,".").concat(d)]||p[d]||u[d]||i;return a?n.createElement(y,o(o({ref:t},g),{},{components:a})):n.createElement(y,o({ref:t},g))}));function y(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=a.length,o=new Array(i);o[0]=d;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[p]="string"==typeof e?e:r,o[1]=s;for(var c=2;c<i;c++)o[c]=a[c];return n.createElement.apply(null,o)}return n.createElement.apply(null,a)}d.displayName="MDXCreateElement"},1001:(e,t,a)=>{a.r(t),a.d(t,{assets:()=>l,contentTitle:()=>o,default:()=>u,frontMatter:()=>i,metadata:()=>s,toc:()=>c});var n=a(8168),r=(a(6540),a(5680));const i={id:"end-to-end-security",title:"End-to-End Security"},o=void 0,s={unversionedId:"external/security-model/end-to-end-security",id:"external/security-model/end-to-end-security",title:"End-to-End Security",description:"\x3c!--",source:"@site/docs/external/security-model/end-to-end-security.md",sourceDirName:"external/security-model",slug:"/external/security-model/end-to-end-security",permalink:"/weaver-dlt-interoperability/docs/external/security-model/end-to-end-security",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/security-model/end-to-end-security.md",tags:[],version:"current",frontMatter:{id:"end-to-end-security",title:"End-to-End Security"},sidebar:"Documentation",previous:{title:"Proofs and Verification",permalink:"/weaver-dlt-interoperability/docs/external/security-model/proofs-and-verification"},next:{title:"Deployment Patterns",permalink:"/weaver-dlt-interoperability/docs/external/deployment-considerations/deployment-patterns"}},l={},c=[{value:"Relay Security Model",id:"relay-security-model",level:2},{value:"A Relayer of Cryptographic Proofs",id:"a-relayer-of-cryptographic-proofs",level:2},{value:"Deployment Configurations and Security Implications",id:"deployment-configurations-and-security-implications",level:2},{value:"1. Confidential Message Exchange Between Groups of Parties",id:"1-confidential-message-exchange-between-groups-of-parties",level:3},{value:"2. Private Message Exchange Between Networks",id:"2-private-message-exchange-between-networks",level:3},{value:"3. Public Message Exchange Between Networks",id:"3-public-message-exchange-between-networks",level:3},{value:"Nonces and Replay Attacks",id:"nonces-and-replay-attacks",level:2}],g={toc:c},p="wrapper";function u(e){let{components:t,...i}=e;return(0,r.yg)(p,(0,n.A)({},g,i,{components:t,mdxType:"MDXLayout"}),(0,r.yg)("h2",{id:"relay-security-model"},"Relay Security Model"),(0,r.yg)("h2",{id:"a-relayer-of-cryptographic-proofs"},"A Relayer of Cryptographic Proofs"),(0,r.yg)("p",null,"The primary function of the relay is to orchestrate the flow of cyrptographic messages between networks enabling a variety of interoperability modes:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Transfer of data between networks"),(0,r.yg)("li",{parentName:"ul"},"Transfer of assets between networks"),(0,r.yg)("li",{parentName:"ul"},"Exchange of value between networks")),(0,r.yg)("p",null,"These cryptographic messages represent valid state in a distributed ledger and are generated using a range of cryptographic approaches, such as attestation by a set of authoritative nodes, a non-interactive proof of PoW, or a zero-knowledge proof (proof of computational integrity). The mechanisms for deriving such proofs rely on the model of trust provided by the underlying network of nodes. The relay thus plays no direct role in the generation of proofs, removing the need for remote agents (decentralized networks, applications or users) to trust the relay for proof veracity."),(0,r.yg)("p",null,"The relay's message exchange protocol is in a state of development with a view towards supporting multiple interoperability modes. The current implementation however is limited to the transfer of data between networks. Future versions will enable asset and value transfers protocols."),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},"NOTE:")," The security models examined below is limited to the transfer of data where remote queries are initiated by applications."),(0,r.yg)("h2",{id:"deployment-configurations-and-security-implications"},"Deployment Configurations and Security Implications"),(0,r.yg)("p",null,"The relay acts as a gateway between networks for enabling cross-chain communication and supports flexible deployment configurations. "),(0,r.yg)("p",null,"The configuration in any deployment must statisfy the goals of the parties involved in the message exchange. These goals inform the security policy and the adversarial assumptions. The mechanisms for threat mitigation is based on these assumptions. "),(0,r.yg)("p",null,"The configurations described below assume that:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"A small fraction of the parties (e.g. f < n - m, where 'm' is the minimum threshold required for agreement) in a group or network might be byzantine. "),(0,r.yg)("li",{parentName:"ul"},"The threat imposed by a byzantine party with priviledges to construct a valid proof is no worse if the party is also in control of a relay."),(0,r.yg)("li",{parentName:"ul"},"A valid proof is one that satisfies a consumer's proof critieria (policy).")),(0,r.yg)("h3",{id:"1-confidential-message-exchange-between-groups-of-parties"},"1. Confidential Message Exchange Between Groups of Parties"),(0,r.yg)("p",null,(0,r.yg)("img",{alt:"Confidential Message Exchange",src:a(5353).A,title:"Confidential Message Exchange",width:"980",height:"437"})),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},"Goals")," "),(0,r.yg)("p",null,"A group of parties sharing confidential data agree to share a view of their data to remote group. The system configuration will provide the following properties:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Preserve confidentiality of messages exchanged between the groups involved."),(0,r.yg)("li",{parentName:"ul"},"Preserve integrity of messages exchanged across the groups."),(0,r.yg)("li",{parentName:"ul"},"The system must be available for servicing requests.")),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},"Threat Assumptions")),(0,r.yg)("p",null,"An adversary in this configuration might seek to:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Gain access to the confidential data."),(0,r.yg)("li",{parentName:"ul"},"Tamper with the integrity of the messages exchanged."),(0,r.yg)("li",{parentName:"ul"},"Censor messages."),(0,r.yg)("li",{parentName:"ul"},"Deny service.")),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},"Mechanisms for Threat Mitigation")),(0,r.yg)("p",null,"A suitable deployment configuration that addresses these threat assumptions:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Relays will only be deployed and operated by organizations with access to the confidential data and privileges to construct valid proofs."),(0,r.yg)("li",{parentName:"ul"},"A secure channel (mutual TLS) between the relays prevents external adversaries from evesdropping on the communication."),(0,r.yg)("li",{parentName:"ul"},"The inclusion of a nonce in the proof enables replays of past messages to be detected."),(0,r.yg)("li",{parentName:"ul"},"The deployment of multiple relays ensures availability and resistance to censorship.")),(0,r.yg)("p",null,"In the following configuration, a group in one network maintains confidential data and have similar goals as above. The data in the providing network is private but visible to all organizations. The relay in the providing network can be operated by any organization with access to the data (the implications of this are examined next)."),(0,r.yg)("p",null,(0,r.yg)("img",{alt:"Confidential Message Exchange",src:a(2639).A,title:"Confidential Message Exchange",width:"980",height:"437"})),(0,r.yg)("h3",{id:"2-private-message-exchange-between-networks"},"2. Private Message Exchange Between Networks"),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},"Goals")),(0,r.yg)("p",null,"In the following configuration, the data is private to both networks but not confidential to any subset of the members. The system configuration must provide the following properties:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Preserve confidentiality of messages exchanged between the networks."),(0,r.yg)("li",{parentName:"ul"},"Preserve integrity of messages exchanged across the networks."),(0,r.yg)("li",{parentName:"ul"},"The system must be available for servicing requests.")),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},"Threat Assumptions")),(0,r.yg)("p",null,"An adversary in this configuration might seek to:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Gain access to the private data."),(0,r.yg)("li",{parentName:"ul"},"Tamper with the integrity of the messages exchanged."),(0,r.yg)("li",{parentName:"ul"},"Censor messages."),(0,r.yg)("li",{parentName:"ul"},"Deny service.")),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},"Mechanisms for Threat Mitigation")),(0,r.yg)("p",null,"A suitable deployment configuration that addresses the threat assumptions:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Relays will be deployed and operated by organizations that are members of the network with access to the shared private data and privileges to construct valid proofs."),(0,r.yg)("li",{parentName:"ul"},"A secure channel (mutual TLS) between the relays prevents external adversaries from evesdropping on the communication."),(0,r.yg)("li",{parentName:"ul"},"The inclusion of a nonce in the proof enables replays of past messages to be detected."),(0,r.yg)("li",{parentName:"ul"},"The deployment of multiple relays ensures availability and resistance to censorship.")),(0,r.yg)("p",null,(0,r.yg)("img",{alt:"Private Message Exchange",src:a(360).A,title:"Private Message Exchange",width:"980",height:"437"})),(0,r.yg)("h3",{id:"3-public-message-exchange-between-networks"},"3. Public Message Exchange Between Networks"),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},"Goals")),(0,r.yg)("p",null,"A private network consumes data from a public permissionless network. The system configuration must provide the following properties:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Preserve confidentiality of messages exchanged between the networks."),(0,r.yg)("li",{parentName:"ul"},"Preserve integrity of messages exchanged across the networks."),(0,r.yg)("li",{parentName:"ul"},"The system must be available for servicing requests.")),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},"Threat Assumptions")),(0,r.yg)("p",null,"An adversary in this configuration might seek to:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Monitor data accessed by the private network."),(0,r.yg)("li",{parentName:"ul"},"Tamper with the integrity of the messages exchanged."),(0,r.yg)("li",{parentName:"ul"},"Censor messages."),(0,r.yg)("li",{parentName:"ul"},"Deny service.")),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},"Mechanisms for Threat Mitigation")),(0,r.yg)("p",null,"A suitable deployment configuration that addresses the threat assumptions:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Nodes (clients) of the public ledger will be deployed and operated by multiple organizations in the private network (a sufficient distribution to accomodate 'f' faulty nodes)",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},"Nodes modified to sign responses with a valid identity certificate (e.g. Hyperledger Besu as Ethereum mainnet client)."))),(0,r.yg)("li",{parentName:"ul"},"Relays to private and public nodes will be deployed and operated by organizations within the network."),(0,r.yg)("li",{parentName:"ul"},"The inclusion of a nonce in the proof enables replays of past messages to be detected."),(0,r.yg)("li",{parentName:"ul"},"The deployment of multiple relays ensures availability and resistance to censorship.")),(0,r.yg)("p",null,(0,r.yg)("img",{alt:"Private Public Data Exchange",src:a(1400).A,title:"Private-Public Message Exchange",width:"894",height:"437"})),(0,r.yg)("p",null,"The following alternate configuration allows for a public node to be operated by a single organization. The oracle provides trusted meta-data to ensure proofs can be validated correctly (E.g. current validator set used for signing blocks in PoS/BFT sysmtems and block height to verify currency of state. A formal study on mechanisms for proof construction and their short-commings has been deferred)."),(0,r.yg)("p",null,(0,r.yg)("img",{alt:"Private Public Data Exchange",src:a(4392).A,title:"Private-Public Message Exchange",width:"878",height:"437"})),(0,r.yg)("p",null,"In the following configuration an external notary acts as an authoritative source for public ledger data. A secure channel (mutual TLS) between the relays prevents external adversaries from evesdropping on the communication."),(0,r.yg)("p",null,(0,r.yg)("img",{alt:"Private Public Data Exchange",src:a(9009).A,title:"Private-Public Message Exchange",width:"878",height:"437"})),(0,r.yg)("h2",{id:"nonces-and-replay-attacks"},"Nonces and Replay Attacks"))}u.isMDXComponent=!0},5353:(e,t,a)=>{a.d(t,{A:()=>n});const n=a.p+"assets/images/confidential-message-exchange-464a9dd7ced8b637e79114f0a5a5ea7f.png"},2639:(e,t,a)=>{a.d(t,{A:()=>n});const n=a.p+"assets/images/confidential-message-exchange2-66fcb64e5ccf9f3c67f8515bbaf949eb.png"},360:(e,t,a)=>{a.d(t,{A:()=>n});const n=a.p+"assets/images/private-message-exchange-e152ae2c623b0b2e22a10aa8c1ab4303.png"},1400:(e,t,a)=>{a.d(t,{A:()=>n});const n=a.p+"assets/images/private-public-message-exchange-154e73e46c6a606c4d8fe0ed016f5672.png"},4392:(e,t,a)=>{a.d(t,{A:()=>n});const n=a.p+"assets/images/private-public-message-exchange2-c7dcb3f4a8faaaecec32928569aa29dc.png"},9009:(e,t,a)=>{a.d(t,{A:()=>n});const n=a.p+"assets/images/private-public-message-exchange3-07fb1f5baf8ad3c32448493bdecd23a7.png"}}]); \ No newline at end of file diff --git a/assets/js/a50a7707.bcb02034.js b/assets/js/a50a7707.bcb02034.js deleted file mode 100644 index 922360d3a..000000000 --- a/assets/js/a50a7707.bcb02034.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[7195],{3905:(e,t,a)=>{a.d(t,{Zo:()=>p,kt:()=>h});var n=a(7294);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function i(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function o(e){for(var t=1;t<arguments.length;t++){var a=null!=arguments[t]?arguments[t]:{};t%2?i(Object(a),!0).forEach((function(t){r(e,t,a[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(a)):i(Object(a)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(a,t))}))}return e}function s(e,t){if(null==e)return{};var a,n,r=function(e,t){if(null==e)return{};var a,n,r={},i=Object.keys(e);for(n=0;n<i.length;n++)a=i[n],t.indexOf(a)>=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)a=i[n],t.indexOf(a)>=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var l=n.createContext({}),c=function(e){var t=n.useContext(l),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},p=function(e){var t=c(e.components);return n.createElement(l.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,i=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=c(a),m=r,h=u["".concat(l,".").concat(m)]||u[m]||d[m]||i;return a?n.createElement(h,o(o({ref:t},p),{},{components:a})):n.createElement(h,o({ref:t},p))}));function h(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=a.length,o=new Array(i);o[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[u]="string"==typeof e?e:r,o[1]=s;for(var c=2;c<i;c++)o[c]=a[c];return n.createElement.apply(null,o)}return n.createElement.apply(null,a)}m.displayName="MDXCreateElement"},7644:(e,t,a)=>{a.r(t),a.d(t,{assets:()=>l,contentTitle:()=>o,default:()=>d,frontMatter:()=>i,metadata:()=>s,toc:()=>c});var n=a(7462),r=(a(7294),a(3905));const i={id:"end-to-end-security",title:"End-to-End Security"},o=void 0,s={unversionedId:"external/security-model/end-to-end-security",id:"external/security-model/end-to-end-security",title:"End-to-End Security",description:"\x3c!--",source:"@site/docs/external/security-model/end-to-end-security.md",sourceDirName:"external/security-model",slug:"/external/security-model/end-to-end-security",permalink:"/weaver-dlt-interoperability/docs/external/security-model/end-to-end-security",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/security-model/end-to-end-security.md",tags:[],version:"current",frontMatter:{id:"end-to-end-security",title:"End-to-End Security"},sidebar:"Documentation",previous:{title:"Proofs and Verification",permalink:"/weaver-dlt-interoperability/docs/external/security-model/proofs-and-verification"},next:{title:"Deployment Patterns",permalink:"/weaver-dlt-interoperability/docs/external/deployment-considerations/deployment-patterns"}},l={},c=[{value:"Relay Security Model",id:"relay-security-model",level:2},{value:"A Relayer of Cryptographic Proofs",id:"a-relayer-of-cryptographic-proofs",level:2},{value:"Deployment Configurations and Security Implications",id:"deployment-configurations-and-security-implications",level:2},{value:"1. Confidential Message Exchange Between Groups of Parties",id:"1-confidential-message-exchange-between-groups-of-parties",level:3},{value:"2. Private Message Exchange Between Networks",id:"2-private-message-exchange-between-networks",level:3},{value:"3. Public Message Exchange Between Networks",id:"3-public-message-exchange-between-networks",level:3},{value:"Nonces and Replay Attacks",id:"nonces-and-replay-attacks",level:2}],p={toc:c},u="wrapper";function d(e){let{components:t,...i}=e;return(0,r.kt)(u,(0,n.Z)({},p,i,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h2",{id:"relay-security-model"},"Relay Security Model"),(0,r.kt)("h2",{id:"a-relayer-of-cryptographic-proofs"},"A Relayer of Cryptographic Proofs"),(0,r.kt)("p",null,"The primary function of the relay is to orchestrate the flow of cyrptographic messages between networks enabling a variety of interoperability modes:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Transfer of data between networks"),(0,r.kt)("li",{parentName:"ul"},"Transfer of assets between networks"),(0,r.kt)("li",{parentName:"ul"},"Exchange of value between networks")),(0,r.kt)("p",null,"These cryptographic messages represent valid state in a distributed ledger and are generated using a range of cryptographic approaches, such as attestation by a set of authoritative nodes, a non-interactive proof of PoW, or a zero-knowledge proof (proof of computational integrity). The mechanisms for deriving such proofs rely on the model of trust provided by the underlying network of nodes. The relay thus plays no direct role in the generation of proofs, removing the need for remote agents (decentralized networks, applications or users) to trust the relay for proof veracity."),(0,r.kt)("p",null,"The relay's message exchange protocol is in a state of development with a view towards supporting multiple interoperability modes. The current implementation however is limited to the transfer of data between networks. Future versions will enable asset and value transfers protocols."),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"NOTE:")," The security models examined below is limited to the transfer of data where remote queries are initiated by applications."),(0,r.kt)("h2",{id:"deployment-configurations-and-security-implications"},"Deployment Configurations and Security Implications"),(0,r.kt)("p",null,"The relay acts as a gateway between networks for enabling cross-chain communication and supports flexible deployment configurations. "),(0,r.kt)("p",null,"The configuration in any deployment must statisfy the goals of the parties involved in the message exchange. These goals inform the security policy and the adversarial assumptions. The mechanisms for threat mitigation is based on these assumptions. "),(0,r.kt)("p",null,"The configurations described below assume that:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"A small fraction of the parties (e.g. f < n - m, where 'm' is the minimum threshold required for agreement) in a group or network might be byzantine. "),(0,r.kt)("li",{parentName:"ul"},"The threat imposed by a byzantine party with priviledges to construct a valid proof is no worse if the party is also in control of a relay."),(0,r.kt)("li",{parentName:"ul"},"A valid proof is one that satisfies a consumer's proof critieria (policy).")),(0,r.kt)("h3",{id:"1-confidential-message-exchange-between-groups-of-parties"},"1. Confidential Message Exchange Between Groups of Parties"),(0,r.kt)("p",null,(0,r.kt)("img",{alt:"Confidential Message Exchange",src:a(7999).Z,title:"Confidential Message Exchange",width:"980",height:"437"})),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Goals")," "),(0,r.kt)("p",null,"A group of parties sharing confidential data agree to share a view of their data to remote group. The system configuration will provide the following properties:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Preserve confidentiality of messages exchanged between the groups involved."),(0,r.kt)("li",{parentName:"ul"},"Preserve integrity of messages exchanged across the groups."),(0,r.kt)("li",{parentName:"ul"},"The system must be available for servicing requests.")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Threat Assumptions")),(0,r.kt)("p",null,"An adversary in this configuration might seek to:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Gain access to the confidential data."),(0,r.kt)("li",{parentName:"ul"},"Tamper with the integrity of the messages exchanged."),(0,r.kt)("li",{parentName:"ul"},"Censor messages."),(0,r.kt)("li",{parentName:"ul"},"Deny service.")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Mechanisms for Threat Mitigation")),(0,r.kt)("p",null,"A suitable deployment configuration that addresses these threat assumptions:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Relays will only be deployed and operated by organizations with access to the confidential data and privileges to construct valid proofs."),(0,r.kt)("li",{parentName:"ul"},"A secure channel (mutual TLS) between the relays prevents external adversaries from evesdropping on the communication."),(0,r.kt)("li",{parentName:"ul"},"The inclusion of a nonce in the proof enables replays of past messages to be detected."),(0,r.kt)("li",{parentName:"ul"},"The deployment of multiple relays ensures availability and resistance to censorship.")),(0,r.kt)("p",null,"In the following configuration, a group in one network maintains confidential data and have similar goals as above. The data in the providing network is private but visible to all organizations. The relay in the providing network can be operated by any organization with access to the data (the implications of this are examined next)."),(0,r.kt)("p",null,(0,r.kt)("img",{alt:"Confidential Message Exchange",src:a(6433).Z,title:"Confidential Message Exchange",width:"980",height:"437"})),(0,r.kt)("h3",{id:"2-private-message-exchange-between-networks"},"2. Private Message Exchange Between Networks"),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Goals")),(0,r.kt)("p",null,"In the following configuration, the data is private to both networks but not confidential to any subset of the members. The system configuration must provide the following properties:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Preserve confidentiality of messages exchanged between the networks."),(0,r.kt)("li",{parentName:"ul"},"Preserve integrity of messages exchanged across the networks."),(0,r.kt)("li",{parentName:"ul"},"The system must be available for servicing requests.")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Threat Assumptions")),(0,r.kt)("p",null,"An adversary in this configuration might seek to:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Gain access to the private data."),(0,r.kt)("li",{parentName:"ul"},"Tamper with the integrity of the messages exchanged."),(0,r.kt)("li",{parentName:"ul"},"Censor messages."),(0,r.kt)("li",{parentName:"ul"},"Deny service.")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Mechanisms for Threat Mitigation")),(0,r.kt)("p",null,"A suitable deployment configuration that addresses the threat assumptions:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Relays will be deployed and operated by organizations that are members of the network with access to the shared private data and privileges to construct valid proofs."),(0,r.kt)("li",{parentName:"ul"},"A secure channel (mutual TLS) between the relays prevents external adversaries from evesdropping on the communication."),(0,r.kt)("li",{parentName:"ul"},"The inclusion of a nonce in the proof enables replays of past messages to be detected."),(0,r.kt)("li",{parentName:"ul"},"The deployment of multiple relays ensures availability and resistance to censorship.")),(0,r.kt)("p",null,(0,r.kt)("img",{alt:"Private Message Exchange",src:a(9796).Z,title:"Private Message Exchange",width:"980",height:"437"})),(0,r.kt)("h3",{id:"3-public-message-exchange-between-networks"},"3. Public Message Exchange Between Networks"),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Goals")),(0,r.kt)("p",null,"A private network consumes data from a public permissionless network. The system configuration must provide the following properties:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Preserve confidentiality of messages exchanged between the networks."),(0,r.kt)("li",{parentName:"ul"},"Preserve integrity of messages exchanged across the networks."),(0,r.kt)("li",{parentName:"ul"},"The system must be available for servicing requests.")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Threat Assumptions")),(0,r.kt)("p",null,"An adversary in this configuration might seek to:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Monitor data accessed by the private network."),(0,r.kt)("li",{parentName:"ul"},"Tamper with the integrity of the messages exchanged."),(0,r.kt)("li",{parentName:"ul"},"Censor messages."),(0,r.kt)("li",{parentName:"ul"},"Deny service.")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Mechanisms for Threat Mitigation")),(0,r.kt)("p",null,"A suitable deployment configuration that addresses the threat assumptions:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Nodes (clients) of the public ledger will be deployed and operated by multiple organizations in the private network (a sufficient distribution to accomodate 'f' faulty nodes)",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"Nodes modified to sign responses with a valid identity certificate (e.g. Hyperledger Besu as Ethereum mainnet client)."))),(0,r.kt)("li",{parentName:"ul"},"Relays to private and public nodes will be deployed and operated by organizations within the network."),(0,r.kt)("li",{parentName:"ul"},"The inclusion of a nonce in the proof enables replays of past messages to be detected."),(0,r.kt)("li",{parentName:"ul"},"The deployment of multiple relays ensures availability and resistance to censorship.")),(0,r.kt)("p",null,(0,r.kt)("img",{alt:"Private Public Data Exchange",src:a(8732).Z,title:"Private-Public Message Exchange",width:"894",height:"437"})),(0,r.kt)("p",null,"The following alternate configuration allows for a public node to be operated by a single organization. The oracle provides trusted meta-data to ensure proofs can be validated correctly (E.g. current validator set used for signing blocks in PoS/BFT sysmtems and block height to verify currency of state. A formal study on mechanisms for proof construction and their short-commings has been deferred)."),(0,r.kt)("p",null,(0,r.kt)("img",{alt:"Private Public Data Exchange",src:a(6888).Z,title:"Private-Public Message Exchange",width:"878",height:"437"})),(0,r.kt)("p",null,"In the following configuration an external notary acts as an authoritative source for public ledger data. A secure channel (mutual TLS) between the relays prevents external adversaries from evesdropping on the communication."),(0,r.kt)("p",null,(0,r.kt)("img",{alt:"Private Public Data Exchange",src:a(8675).Z,title:"Private-Public Message Exchange",width:"878",height:"437"})),(0,r.kt)("h2",{id:"nonces-and-replay-attacks"},"Nonces and Replay Attacks"))}d.isMDXComponent=!0},7999:(e,t,a)=>{a.d(t,{Z:()=>n});const n=a.p+"assets/images/confidential-message-exchange-464a9dd7ced8b637e79114f0a5a5ea7f.png"},6433:(e,t,a)=>{a.d(t,{Z:()=>n});const n=a.p+"assets/images/confidential-message-exchange2-66fcb64e5ccf9f3c67f8515bbaf949eb.png"},9796:(e,t,a)=>{a.d(t,{Z:()=>n});const n=a.p+"assets/images/private-message-exchange-e152ae2c623b0b2e22a10aa8c1ab4303.png"},8732:(e,t,a)=>{a.d(t,{Z:()=>n});const n=a.p+"assets/images/private-public-message-exchange-154e73e46c6a606c4d8fe0ed016f5672.png"},6888:(e,t,a)=>{a.d(t,{Z:()=>n});const n=a.p+"assets/images/private-public-message-exchange2-c7dcb3f4a8faaaecec32928569aa29dc.png"},8675:(e,t,a)=>{a.d(t,{Z:()=>n});const n=a.p+"assets/images/private-public-message-exchange3-07fb1f5baf8ad3c32448493bdecd23a7.png"}}]); \ No newline at end of file diff --git a/assets/js/a6aa9e1f.4986bb6c.js b/assets/js/a6aa9e1f.4986bb6c.js deleted file mode 100644 index 888a774db..000000000 --- a/assets/js/a6aa9e1f.4986bb6c.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[3089],{3269:(e,t,a)=>{a.r(t),a.d(t,{default:()=>v});var n=a(7294),r=a(6010),l=a(2263),i=a(1944),o=a(5281),s=a(9058),m=a(5999),c=a(2244);function g(e){const{metadata:t}=e,{previousPage:a,nextPage:r}=t;return n.createElement("nav",{className:"pagination-nav","aria-label":(0,m.I)({id:"theme.blog.paginator.navAriaLabel",message:"Blog list page navigation",description:"The ARIA label for the blog pagination"})},a&&n.createElement(c.Z,{permalink:a,title:n.createElement(m.Z,{id:"theme.blog.paginator.newerEntries",description:"The label used to navigate to the newer blog posts page (previous page)"},"Newer Entries")}),r&&n.createElement(c.Z,{permalink:r,title:n.createElement(m.Z,{id:"theme.blog.paginator.olderEntries",description:"The label used to navigate to the older blog posts page (next page)"},"Older Entries"),isNext:!0}))}var p=a(197),d=a(9460),u=a(756);function b(e){let{items:t,component:a=u.Z}=e;return n.createElement(n.Fragment,null,t.map((e=>{let{content:t}=e;return n.createElement(d.n,{key:t.metadata.permalink,content:t},n.createElement(a,null,n.createElement(t,null)))})))}function E(e){const{metadata:t}=e,{siteConfig:{title:a}}=(0,l.Z)(),{blogDescription:r,blogTitle:o,permalink:s}=t,m="/"===s?a:o;return n.createElement(n.Fragment,null,n.createElement(i.d,{title:m,description:r}),n.createElement(p.Z,{tag:"blog_posts_list"}))}function h(e){const{metadata:t,items:a,sidebar:r}=e;return n.createElement(s.Z,{sidebar:r},n.createElement(b,{items:a}),n.createElement(g,{metadata:t}))}function v(e){return n.createElement(i.FG,{className:(0,r.Z)(o.k.wrapper.blogPages,o.k.page.blogListPage)},n.createElement(E,e),n.createElement(h,e))}}}]); \ No newline at end of file diff --git a/assets/js/a6aa9e1f.f65ef972.js b/assets/js/a6aa9e1f.f65ef972.js new file mode 100644 index 000000000..6ef2cd307 --- /dev/null +++ b/assets/js/a6aa9e1f.f65ef972.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[7643],{2667:(e,t,a)=>{a.r(t),a.d(t,{default:()=>v});var n=a(6540),r=a(53),l=a(4586),i=a(1003),o=a(7559),s=a(6669),m=a(1312),c=a(9022);function g(e){const{metadata:t}=e,{previousPage:a,nextPage:r}=t;return n.createElement("nav",{className:"pagination-nav","aria-label":(0,m.T)({id:"theme.blog.paginator.navAriaLabel",message:"Blog list page navigation",description:"The ARIA label for the blog pagination"})},a&&n.createElement(c.A,{permalink:a,title:n.createElement(m.A,{id:"theme.blog.paginator.newerEntries",description:"The label used to navigate to the newer blog posts page (previous page)"},"Newer Entries")}),r&&n.createElement(c.A,{permalink:r,title:n.createElement(m.A,{id:"theme.blog.paginator.olderEntries",description:"The label used to navigate to the older blog posts page (next page)"},"Older Entries"),isNext:!0}))}var p=a(1463),u=a(7131),b=a(5623);function d(e){let{items:t,component:a=b.A}=e;return n.createElement(n.Fragment,null,t.map((e=>{let{content:t}=e;return n.createElement(u.i,{key:t.metadata.permalink,content:t},n.createElement(a,null,n.createElement(t,null)))})))}function E(e){const{metadata:t}=e,{siteConfig:{title:a}}=(0,l.A)(),{blogDescription:r,blogTitle:o,permalink:s}=t,m="/"===s?a:o;return n.createElement(n.Fragment,null,n.createElement(i.be,{title:m,description:r}),n.createElement(p.A,{tag:"blog_posts_list"}))}function h(e){const{metadata:t,items:a,sidebar:r}=e;return n.createElement(s.A,{sidebar:r},n.createElement(d,{items:a}),n.createElement(g,{metadata:t}))}function v(e){return n.createElement(i.e3,{className:(0,r.A)(o.G.wrapper.blogPages,o.G.page.blogListPage)},n.createElement(E,e),n.createElement(h,e))}}}]); \ No newline at end of file diff --git a/assets/js/a6da3080.fa7ff818.js b/assets/js/a6da3080.fa7ff818.js deleted file mode 100644 index a54a0f494..000000000 --- a/assets/js/a6da3080.fa7ff818.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[3145],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>N});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function l(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?r(Object(n),!0).forEach((function(t){i(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):r(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function o(e,t){if(null==e)return{};var n,a,i=function(e,t){if(null==e)return{};var n,a,i={},r=Object.keys(e);for(a=0;a<r.length;a++)n=r[a],t.indexOf(n)>=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a<r.length;a++)n=r[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=a.createContext({}),p=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},c=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},d="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},k=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,r=e.originalType,s=e.parentName,c=o(e,["components","mdxType","originalType","parentName"]),d=p(n),k=i,N=d["".concat(s,".").concat(k)]||d[k]||m[k]||r;return n?a.createElement(N,l(l({ref:t},c),{},{components:n})):a.createElement(N,l({ref:t},c))}));function N(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=n.length,l=new Array(r);l[0]=k;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[d]="string"==typeof e?e:i,l[1]=o;for(var p=2;p<r;p++)l[p]=n[p];return a.createElement.apply(null,l)}return a.createElement.apply(null,n)}k.displayName="MDXCreateElement"},474:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>m,frontMatter:()=>r,metadata:()=>o,toc:()=>p});var a=n(7462),i=(n(7294),n(3905));const r={id:"asset-exchange",title:"Asset Exchange",pagination_prev:"external/getting-started/interop/overview",pagination_next:"external/getting-started/enabling-weaver-network/overview"},l=void 0,o={unversionedId:"external/getting-started/interop/asset-exchange",id:"external/getting-started/interop/asset-exchange",title:"Asset Exchange",description:"\x3c!--",source:"@site/docs/external/getting-started/interop/asset-exchange.md",sourceDirName:"external/getting-started/interop",slug:"/external/getting-started/interop/asset-exchange",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/getting-started/interop/asset-exchange.md",tags:[],version:"current",frontMatter:{id:"asset-exchange",title:"Asset Exchange",pagination_prev:"external/getting-started/interop/overview",pagination_next:"external/getting-started/enabling-weaver-network/overview"},previous:{title:"Testing Interoperation Modes",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/overview"},next:{title:"Enabling Weaver in Existing DLT Applications",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/overview"}},s={},p=[{value:"Fabric with Fabric",id:"fabric-with-fabric",level:2},{value:"Fabric with Corda",id:"fabric-with-corda",level:2},{value:"Corda with Corda",id:"corda-with-corda",level:2}],c={toc:p},d="wrapper";function m(e){let{components:t,...n}=e;return(0,i.kt)(d,(0,a.Z)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"This document lists sample ways in which you can exercise the asset-exchange interoperation protocol on the test network ",(0,i.kt)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/overview"},"launched earlier"),"."),(0,i.kt)("p",null,"For this scenario, you only need the networks to be running with the appropriate contracts deployed and the ledgers bootstrapped. You do not need to run relays and drivers. You can run the following combinations of exchanges (",(0,i.kt)("em",{parentName:"p"},"other combinations of DLTs will be supported soon"),")."),(0,i.kt)("h2",{id:"fabric-with-fabric"},"Fabric with Fabric"),(0,i.kt)("p",null,"One Fabric network transfers a bond from Alice to Bob in exchange for a transfer of tokens from Bob to Alice in the other network\nEnsure that one of the following chaincodes have been deployed in both networks:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"simpleasset")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"simpleassetandinterop")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"simpleassettransfer"))),(0,i.kt)("p",null,"Run the following steps:"),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"left"},"The hash used in following steps can be replaced by any valid ",(0,i.kt)("inlineCode",{parentName:"td"},"SHA256")," hash.")))),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},"Navigate to either the ",(0,i.kt)("inlineCode",{parentName:"li"},"samples/fabric/fabric-cli")," folder or the ",(0,i.kt)("inlineCode",{parentName:"li"},"samples/fabric/go-cli")," folder in your clone of the Weaver repository."),(0,i.kt)("li",{parentName:"ol"},"Run the following to verify the status of the assets owned by ",(0,i.kt)("inlineCode",{parentName:"li"},"alice")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"bob")," in the two networks:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./scripts/getAssetStatus.sh 2\n"))),(0,i.kt)("li",{parentName:"ol"},"Complete the asset exchange in either of the two different ways:",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},"Using a single command:",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},"Run the following to trigger exchange of bond ",(0,i.kt)("inlineCode",{parentName:"li"},"bond01:a03")," owned by ",(0,i.kt)("inlineCode",{parentName:"li"},"alice")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"network1")," with ",(0,i.kt)("inlineCode",{parentName:"li"},"100")," units of tokens ",(0,i.kt)("inlineCode",{parentName:"li"},"token1")," owned by ",(0,i.kt)("inlineCode",{parentName:"li"},"bob")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"network2"),":",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset exchange-all --network1=network1 --network2=network2 --secret=secrettext --timeout-duration=100 alice:bond01:a03:bob:token1:100\n"))),(0,i.kt)("li",{parentName:"ul"},"To verify that ",(0,i.kt)("inlineCode",{parentName:"li"},"bob")," now owns a bond in exchange for ",(0,i.kt)("inlineCode",{parentName:"li"},"alice")," owning some tokens, run the following:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./scripts/getAssetStatus.sh 2\n"))))),(0,i.kt)("li",{parentName:"ul"},"Using step-by-step commands:",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},"Generate Secret-Hash Pair using following command (prints hash in base64):",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre"},"./bin/fabric-cli hash --hash_fn=SHA256 secrettext\n"))),(0,i.kt)("li",{parentName:"ul"},"Run the following to trigger ",(0,i.kt)("inlineCode",{parentName:"li"},"alice")," locking ",(0,i.kt)("inlineCode",{parentName:"li"},"bond01:a03")," for ",(0,i.kt)("inlineCode",{parentName:"li"},"bob")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"network1"),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset exchange lock --timeout-duration=3600 --locker=alice --recipient=bob --hashBase64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs= --target-network=network1 --param=bond01:a03\n"))),(0,i.kt)("li",{parentName:"ul"},"Run the following to verify ",(0,i.kt)("inlineCode",{parentName:"li"},"alice"),"'s lock:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset exchange is-locked --locker=alice --recipient=bob --target-network=network1 --param=bond01:a03\n"))),(0,i.kt)("li",{parentName:"ul"},"Run the following to trigger ",(0,i.kt)("inlineCode",{parentName:"li"},"bob")," locking ",(0,i.kt)("inlineCode",{parentName:"li"},"100")," units of ",(0,i.kt)("inlineCode",{parentName:"li"},"token1")," for ",(0,i.kt)("inlineCode",{parentName:"li"},"alice")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"network2"),":",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset exchange lock --fungible --timeout-duration=1800 --locker=bob --recipient=alice --hashBase64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs= --target-network=network2 --param=token1:100\n")),"Note the ",(0,i.kt)("inlineCode",{parentName:"li"},"contract-id")," printed as output in above command. The output line containing ",(0,i.kt)("inlineCode",{parentName:"li"},"contract-id")," (text in base64 after ",(0,i.kt)("inlineCode",{parentName:"li"},"Contract Id:"),") would like this:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"\u2139 Fungible Asset Locked with Contract Id: E0JZq8Z+eS//2Bt4WU0pU210MvNgDC2hdUT1RgszOq0=, preimage: null, hashvalue: ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs=\n"))),(0,i.kt)("li",{parentName:"ul"},"Run the following to verify ",(0,i.kt)("inlineCode",{parentName:"li"},"bob"),"'s lock:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset exchange is-locked --fungible --locker=bob --recipient=alice --target-network=network2 --contract-id=<contract-id>\n"))),(0,i.kt)("li",{parentName:"ul"},"Run the following to trigger ",(0,i.kt)("inlineCode",{parentName:"li"},"alice"),"'s claim for ",(0,i.kt)("inlineCode",{parentName:"li"},"100")," units of ",(0,i.kt)("inlineCode",{parentName:"li"},"token1")," locked by ",(0,i.kt)("inlineCode",{parentName:"li"},"bob")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"network2"),":",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset exchange claim --fungible --recipient=alice --target-network=network2 --contract-id=<contract-id> --secret=<hash-pre-image>\n"))),(0,i.kt)("li",{parentName:"ul"},"Run the following to trigger ",(0,i.kt)("inlineCode",{parentName:"li"},"bob"),"'s claim for ",(0,i.kt)("inlineCode",{parentName:"li"},"bond01:a03")," locked by ",(0,i.kt)("inlineCode",{parentName:"li"},"alice")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"network1"),":",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset exchange claim --recipient=bob --locker=alice --target-network=network1 --param=bond01:a03 --secret=<hash-pre-image>\n")))),"The above steps complete a successful asset exchange between two Fabric networks.\nIn addition to the above commands, following commands can be run if specified timeout has expired and the locked asset remains unclaimed.",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},"If ",(0,i.kt)("inlineCode",{parentName:"li"},"alice")," wants to unlock the bond asset, run the following to trigger ",(0,i.kt)("inlineCode",{parentName:"li"},"alice"),"'s re-claim for ",(0,i.kt)("inlineCode",{parentName:"li"},"bond01:a03")," locked in ",(0,i.kt)("inlineCode",{parentName:"li"},"network1"),":",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset exchange unlock --locker=alice --recipient=bob --target-network=network1 --param=bond01:a03\n"))),(0,i.kt)("li",{parentName:"ul"},"If ",(0,i.kt)("inlineCode",{parentName:"li"},"bob")," wants to unlock the token asset, run the following to trigger ",(0,i.kt)("inlineCode",{parentName:"li"},"bob"),"'s re-claim for ",(0,i.kt)("inlineCode",{parentName:"li"},"token1:100")," locked in ",(0,i.kt)("inlineCode",{parentName:"li"},"network2"),":",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset exchange unlock --fungible --locker=bob --target-network=network2 --contract-id=<contract-id>\n")))))))),(0,i.kt)("h2",{id:"fabric-with-corda"},"Fabric with Corda"),(0,i.kt)("p",null,"We will demonstrate asset exchange of a bond in Fabric ",(0,i.kt)("inlineCode",{parentName:"p"},"network1")," with tokens on ",(0,i.kt)("inlineCode",{parentName:"p"},"Corda_Network"),".\nFor Fabric commands, run from ",(0,i.kt)("inlineCode",{parentName:"p"},"samples/fabric/fabric-cli")," folder, and for Corda commands, run from ",(0,i.kt)("inlineCode",{parentName:"p"},"samples/corda/corda-simple-application")," folder. Here ",(0,i.kt)("inlineCode",{parentName:"p"},"Alice")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"Bob")," in Fabric ",(0,i.kt)("inlineCode",{parentName:"p"},"network1")," correspond to ",(0,i.kt)("inlineCode",{parentName:"p"},"PartyA")," (",(0,i.kt)("inlineCode",{parentName:"p"},"CORDA_PORT=10006"),") and ",(0,i.kt)("inlineCode",{parentName:"p"},"PartyB")," (",(0,i.kt)("inlineCode",{parentName:"p"},"CORDA_PORT=10009"),") in ",(0,i.kt)("inlineCode",{parentName:"p"},"Corda_Network")," respectively. Following are the step-by-step asset exchange process:"),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"left"},"The hash used in following steps can be replaced by any valid ",(0,i.kt)("inlineCode",{parentName:"td"},"SHA256")," hash.")))),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Run the following to verify the status of the bond assets owned by ",(0,i.kt)("inlineCode",{parentName:"li"},"alice")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"bob")," in the Fabric network ",(0,i.kt)("inlineCode",{parentName:"li"},"network1")," from ",(0,i.kt)("inlineCode",{parentName:"li"},"samples/fabric/fabric-cli")," folder:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./scripts/getAssetStatus.sh\n"))),(0,i.kt)("li",{parentName:"ul"},"Run the following to verify the status of the assets owned by ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyA")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyB")," in the ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network")," from ",(0,i.kt)("inlineCode",{parentName:"li"},"samples/corda/corda-simple-application")," folder:")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./scripts/getAssetStatus.sh\n")),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Generate Secret-Hash Pair using following command (prints hash in base64):",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre"},"./bin/fabric-cli hash --hash_fn=SHA256 secrettext\n"))),(0,i.kt)("li",{parentName:"ul"},"Run the following to trigger ",(0,i.kt)("inlineCode",{parentName:"li"},"alice")," locking ",(0,i.kt)("inlineCode",{parentName:"li"},"bond01:a03")," for ",(0,i.kt)("inlineCode",{parentName:"li"},"bob")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"network1")," for 60 mins:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset exchange lock --timeout-duration=3600 --locker=alice --recipient=bob --hashBase64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs= --target-network=network1 --param=bond01:a03\n"))),(0,i.kt)("li",{parentName:"ul"},"Run the following to verify ",(0,i.kt)("inlineCode",{parentName:"li"},"alice"),"'s lock:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset exchange is-locked --locker=alice --recipient=bob --target-network=network1 --param=bond01:a03\n"))),(0,i.kt)("li",{parentName:"ul"},"Run the following to trigger ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyB")," locking ",(0,i.kt)("inlineCode",{parentName:"li"},"50")," units of token type ",(0,i.kt)("inlineCode",{parentName:"li"},"t1")," for ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyA")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network")," for 30 mins:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},'CORDA_PORT=10009 ./clients/build/install/clients/bin/clients lock-asset --fungible --hashBase64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs= --timeout=1800 --recipient="O=PartyA,L=London,C=GB" --param=t1:50\n')),"Note the ",(0,i.kt)("inlineCode",{parentName:"li"},"contract-id")," displayed after successful execution of the command, will be used in next steps. The output containing ",(0,i.kt)("inlineCode",{parentName:"li"},"contract-id")," would like this:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"HTLC Lock State created with contract ID Right(b=10448674_80d2bee7-5a5d-45df-b14e-60bac4ba1bf3).\n")),(0,i.kt)("inlineCode",{parentName:"li"},"contract-id")," is the alphanumeric text (with underscore and hyphens) after ",(0,i.kt)("inlineCode",{parentName:"li"},"b=")," within parenthesis."),(0,i.kt)("li",{parentName:"ul"},"Run the following to verify ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyB"),"'s lock (can be verified by both parties):",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"CORDA_PORT=10006 ./clients/build/install/clients/bin/clients is-asset-locked --contract-id=<contract-id>\n"))),(0,i.kt)("li",{parentName:"ul"},"Run the following to trigger ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyA"),"'s claim for ",(0,i.kt)("inlineCode",{parentName:"li"},"50")," units of token type ",(0,i.kt)("inlineCode",{parentName:"li"},"t1")," locked by ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyB")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network"),":",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"CORDA_PORT=10006 ./clients/build/install/clients/bin/clients claim-asset --secret=secrettext --contract-id=<contract-id>\n")),(0,i.kt)("inlineCode",{parentName:"li"},"PartyB")," can see its node's logs to get the revealed hash preimage, and use it to claim the bond in the Fabric network."),(0,i.kt)("li",{parentName:"ul"},"Run the following to trigger ",(0,i.kt)("inlineCode",{parentName:"li"},"bob"),"'s claim for ",(0,i.kt)("inlineCode",{parentName:"li"},"bond01:a03")," locked by ",(0,i.kt)("inlineCode",{parentName:"li"},"alice")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"network1"),":",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset exchange claim --recipient=bob --locker=alice --target-network=network1 --param=bond01:a03 --secret=secrettext\n"))),(0,i.kt)("li",{parentName:"ul"},"Run the following to verify the status of the bond assets owned by ",(0,i.kt)("inlineCode",{parentName:"li"},"alice")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"bob")," in the Fabric network ",(0,i.kt)("inlineCode",{parentName:"li"},"network1")," from ",(0,i.kt)("inlineCode",{parentName:"li"},"samples/fabric/fabric-cli")," folder:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./scripts/getAssetStatus.sh\n"))),(0,i.kt)("li",{parentName:"ul"},"Run the following to verify the status of the assets owned by ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyA")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyB")," in the ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network")," from ",(0,i.kt)("inlineCode",{parentName:"li"},"samples/corda/corda-simple-application")," folder:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./scripts/getAssetStatus.sh\n")))),(0,i.kt)("p",null,"The above steps complete a successful asset exchange between Fabric and Corda networks.\nIn addition to the above commands, following commands can be run if specified timeout has expired and the locked asset remains unclaimed."),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"If ",(0,i.kt)("inlineCode",{parentName:"li"},"alice")," wants to unlock the bond asset, run the following to trigger ",(0,i.kt)("inlineCode",{parentName:"li"},"alice"),"'s re-claim for ",(0,i.kt)("inlineCode",{parentName:"li"},"bond01:a03")," locked in ",(0,i.kt)("inlineCode",{parentName:"li"},"network1"),":",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset exchange unlock --locker=alice --recipient=bob --target-network=network1 --param=bond01:a03\n"))),(0,i.kt)("li",{parentName:"ul"},"If ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyB")," wants to unlock the token asset, run the following to trigger unlock for ",(0,i.kt)("inlineCode",{parentName:"li"},"t1:50")," locked in ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network"),":",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"CORDA_PORT=10009 ./clients/build/install/clients/bin/clients unlock-asset --contract-id=<contract-id>\n")))),(0,i.kt)("h2",{id:"corda-with-corda"},"Corda with Corda"),(0,i.kt)("p",null,"We will demonstrate asset exchange of a tokens in ",(0,i.kt)("inlineCode",{parentName:"p"},"Corda_Network")," with tokens on ",(0,i.kt)("inlineCode",{parentName:"p"},"Corda_Network2"),". Here ",(0,i.kt)("inlineCode",{parentName:"p"},"PartyA")," (",(0,i.kt)("inlineCode",{parentName:"p"},"CORDA_PORT=10006"),") and ",(0,i.kt)("inlineCode",{parentName:"p"},"PartyB")," (",(0,i.kt)("inlineCode",{parentName:"p"},"CORDA_PORT=10009"),") in ",(0,i.kt)("inlineCode",{parentName:"p"},"Corda_Network")," correspond to ",(0,i.kt)("inlineCode",{parentName:"p"},"PartyA")," (",(0,i.kt)("inlineCode",{parentName:"p"},"CORDA_PORT=30006"),") and ",(0,i.kt)("inlineCode",{parentName:"p"},"PartyB")," (",(0,i.kt)("inlineCode",{parentName:"p"},"CORDA_PORT=30009"),") in ",(0,i.kt)("inlineCode",{parentName:"p"},"Corda_Network2")," respectively. Following are the step-by-step asset exchange process:"),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"left"},"The hash used in following steps can be replaced by any valid ",(0,i.kt)("inlineCode",{parentName:"td"},"SHA256")," hash.")))),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Navigate to ",(0,i.kt)("inlineCode",{parentName:"li"},"samples/corda/corda-simple-application")," folder. "),(0,i.kt)("li",{parentName:"ul"},"Run the following to verify the status of the tokens owned by ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyA")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyB")," in the ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network2"),":",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./scripts/getAssetStatus.sh 2\n"))),(0,i.kt)("li",{parentName:"ul"},"Generate Secret-Hash Pair using following command (prints hash in base64):")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"./clients/build/install/clients/bin/clients utils hash --hash-fn=SHA256 -s secrettext\n")),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Run the following to trigger ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyA")," locking ",(0,i.kt)("inlineCode",{parentName:"li"},"30")," units of token type ",(0,i.kt)("inlineCode",{parentName:"li"},"t1")," for ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyB")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network")," for 60 mins:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},'CORDA_PORT=10006 ./clients/build/install/clients/bin/clients lock-asset --fungible --hashBase64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs= --timeout=3600 --recipient="O=PartyB,L=London,C=GB" --param=t1:30\n')),"Note the ",(0,i.kt)("inlineCode",{parentName:"li"},"contract-id")," displayed after successful execution of the command, will be used in next steps. The output containing ",(0,i.kt)("inlineCode",{parentName:"li"},"contract-id")," would like this:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"HTLC Lock State created with contract ID Right(b=10448674_80d2bee7-5a5d-45df-b14e-60bac4ba1bf3).\n")),(0,i.kt)("inlineCode",{parentName:"li"},"contract-id")," is the alphanumeric text (with underscore and hyphens) after ",(0,i.kt)("inlineCode",{parentName:"li"},"b=")," within parenthesis. Let's denote it ",(0,i.kt)("inlineCode",{parentName:"li"},"<contract-id-1>"),"."),(0,i.kt)("li",{parentName:"ul"},"Run the following to verify ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyA"),"'s lock (can be verified by both parties):",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"CORDA_PORT=10009 ./clients/build/install/clients/bin/clients is-asset-locked --contract-id=<contract-id-1>\n"))),(0,i.kt)("li",{parentName:"ul"},"Run the following to trigger ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyB")," locking ",(0,i.kt)("inlineCode",{parentName:"li"},"50")," units of token type ",(0,i.kt)("inlineCode",{parentName:"li"},"t2")," for ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyA")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network2")," for 30 mins:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},'CORDA_PORT=30009 ./clients/build/install/clients/bin/clients lock-asset --fungible --hashBase64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs= --timeout=1800 --recipient="O=PartyA,L=London,C=GB" --param=t2:50\n')),"Note the ",(0,i.kt)("inlineCode",{parentName:"li"},"contract-id")," displayed after successful execution of the command, will be used in next steps. Let's denote it ",(0,i.kt)("inlineCode",{parentName:"li"},"<contract-id-2>"),"."),(0,i.kt)("li",{parentName:"ul"},"Run the following to verify ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyB"),"'s lock (can be verified by both parties):",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"CORDA_PORT=30006 ./clients/build/install/clients/bin/clients is-asset-locked --contract-id=<contract-id-2>\n"))),(0,i.kt)("li",{parentName:"ul"},"Run the following to trigger ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyA"),"'s claim for ",(0,i.kt)("inlineCode",{parentName:"li"},"50")," units of token type ",(0,i.kt)("inlineCode",{parentName:"li"},"t2")," locked by ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyB")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network2"),":",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"CORDA_PORT=30006 ./clients/build/install/clients/bin/clients claim-asset --secret=secrettext --contract-id=<contract-id-2>\n")),(0,i.kt)("inlineCode",{parentName:"li"},"PartyB")," can see its node's logs to get the revealed hash preimage, and use it to claim the bond in the Fabric network."),(0,i.kt)("li",{parentName:"ul"},"Run the following to trigger ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyB"),"'s claim for ",(0,i.kt)("inlineCode",{parentName:"li"},"30")," units of token type ",(0,i.kt)("inlineCode",{parentName:"li"},"t1")," locked by ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyA")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network"),":",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"CORDA_PORT=10009 ./clients/build/install/clients/bin/clients claim-asset --secret=secrettext --contract-id=<contract-id-1>\n"))),(0,i.kt)("li",{parentName:"ul"},"Run the following to verify the status of the tokens owned by ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyA")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyB")," in the ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network2"),":",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./scripts/getAssetStatus.sh 2\n")))),(0,i.kt)("p",null,"The above steps complete a successful asset exchange between two Corda networks.\nIn addition to the above commands, following commands can be run if specified timeout has expired and the locked asset remains unclaimed."),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"If ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyA")," wants to unlock the token ",(0,i.kt)("inlineCode",{parentName:"li"},"t1:30")," asset, run the following to trigger ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyA"),"'s re-claim in ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network"),":",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"CORDA_PORT=10006 ./clients/build/install/clients/bin/clients unlock-asset --contract-id=<contract-id-1>\n"))),(0,i.kt)("li",{parentName:"ul"},"If ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyB")," wants to unlock the token ",(0,i.kt)("inlineCode",{parentName:"li"},"t2:50")," asset, run the following to trigger ",(0,i.kt)("inlineCode",{parentName:"li"},"PartyB"),"'s re-claim in ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network2"),":",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"CORDA_PORT=30009 ./clients/build/install/clients/bin/clients unlock-asset --contract-id=<contract-id-2>\n")))))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/a92192c3.01c6e0bd.js b/assets/js/a92192c3.01c6e0bd.js deleted file mode 100644 index beac5fa07..000000000 --- a/assets/js/a92192c3.01c6e0bd.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[87],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>m});var n=r(7294);function i(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function a(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?o(Object(r),!0).forEach((function(t){i(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):o(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function c(e,t){if(null==e)return{};var r,n,i=function(e,t){if(null==e)return{};var r,n,i={},o=Object.keys(e);for(n=0;n<o.length;n++)r=o[n],t.indexOf(r)>=0||(i[r]=e[r]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n<o.length;n++)r=o[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(i[r]=e[r])}return i}var l=n.createContext({}),u=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},p=function(e){var t=u(e.components);return n.createElement(l.Provider,{value:t},e.children)},s="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},y=n.forwardRef((function(e,t){var r=e.components,i=e.mdxType,o=e.originalType,l=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),s=u(r),y=i,m=s["".concat(l,".").concat(y)]||s[y]||d[y]||o;return r?n.createElement(m,a(a({ref:t},p),{},{components:r})):n.createElement(m,a({ref:t},p))}));function m(e,t){var r=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=r.length,a=new Array(o);a[0]=y;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c[s]="string"==typeof e?e:i,a[1]=c;for(var u=2;u<o;u++)a[u]=r[u];return n.createElement.apply(null,a)}return n.createElement.apply(null,r)}y.displayName="MDXCreateElement"},9673:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>a,default:()=>d,frontMatter:()=>o,metadata:()=>c,toc:()=>u});var n=r(7462),i=(r(7294),r(3905));const o={id:"authentication",title:"Authentication"},a=void 0,c={unversionedId:"external/security-model/authentication",id:"external/security-model/authentication",title:"Authentication",description:"\x3c!--",source:"@site/docs/external/security-model/authentication.md",sourceDirName:"external/security-model",slug:"/external/security-model/authentication",permalink:"/weaver-dlt-interoperability/docs/external/security-model/authentication",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/security-model/authentication.md",tags:[],version:"current",frontMatter:{id:"authentication",title:"Authentication"},sidebar:"Documentation",previous:{title:"Decentralized Identity",permalink:"/weaver-dlt-interoperability/docs/external/architecture-and-design/decentralized-identity"},next:{title:"Access Control",permalink:"/weaver-dlt-interoperability/docs/external/security-model/access-control"}},l={},u=[],p={toc:u},s="wrapper";function d(e){let{components:t,...r}=e;return(0,i.kt)(s,(0,n.Z)({},p,r,{components:t,mdxType:"MDXLayout"}))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/a92192c3.31d579b2.js b/assets/js/a92192c3.31d579b2.js new file mode 100644 index 000000000..d0332049e --- /dev/null +++ b/assets/js/a92192c3.31d579b2.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[4085],{5680:(e,t,r)=>{r.d(t,{xA:()=>p,yg:()=>m});var n=r(6540);function i(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function a(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?o(Object(r),!0).forEach((function(t){i(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):o(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function c(e,t){if(null==e)return{};var r,n,i=function(e,t){if(null==e)return{};var r,n,i={},o=Object.keys(e);for(n=0;n<o.length;n++)r=o[n],t.indexOf(r)>=0||(i[r]=e[r]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n<o.length;n++)r=o[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(i[r]=e[r])}return i}var l=n.createContext({}),u=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},p=function(e){var t=u(e.components);return n.createElement(l.Provider,{value:t},e.children)},s="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},y=n.forwardRef((function(e,t){var r=e.components,i=e.mdxType,o=e.originalType,l=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),s=u(r),y=i,m=s["".concat(l,".").concat(y)]||s[y]||d[y]||o;return r?n.createElement(m,a(a({ref:t},p),{},{components:r})):n.createElement(m,a({ref:t},p))}));function m(e,t){var r=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=r.length,a=new Array(o);a[0]=y;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c[s]="string"==typeof e?e:i,a[1]=c;for(var u=2;u<o;u++)a[u]=r[u];return n.createElement.apply(null,a)}return n.createElement.apply(null,r)}y.displayName="MDXCreateElement"},139:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>a,default:()=>d,frontMatter:()=>o,metadata:()=>c,toc:()=>u});var n=r(8168),i=(r(6540),r(5680));const o={id:"authentication",title:"Authentication"},a=void 0,c={unversionedId:"external/security-model/authentication",id:"external/security-model/authentication",title:"Authentication",description:"\x3c!--",source:"@site/docs/external/security-model/authentication.md",sourceDirName:"external/security-model",slug:"/external/security-model/authentication",permalink:"/weaver-dlt-interoperability/docs/external/security-model/authentication",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/security-model/authentication.md",tags:[],version:"current",frontMatter:{id:"authentication",title:"Authentication"},sidebar:"Documentation",previous:{title:"Decentralized Identity",permalink:"/weaver-dlt-interoperability/docs/external/architecture-and-design/decentralized-identity"},next:{title:"Access Control",permalink:"/weaver-dlt-interoperability/docs/external/security-model/access-control"}},l={},u=[],p={toc:u},s="wrapper";function d(e){let{components:t,...r}=e;return(0,i.yg)(s,(0,n.A)({},p,r,{components:t,mdxType:"MDXLayout"}))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/abd77f53.5609b353.js b/assets/js/abd77f53.5609b353.js deleted file mode 100644 index 9c3c2aabe..000000000 --- a/assets/js/abd77f53.5609b353.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[3214],{3905:(e,t,r)=>{r.d(t,{Zo:()=>s,kt:()=>m});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?o(Object(r),!0).forEach((function(t){a(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):o(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function p(e,t){if(null==e)return{};var r,n,a=function(e,t){if(null==e)return{};var r,n,a={},o=Object.keys(e);for(n=0;n<o.length;n++)r=o[n],t.indexOf(r)>=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n<o.length;n++)r=o[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var c=n.createContext({}),l=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},s=function(e){var t=l(e.components);return n.createElement(c.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},f=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,s=p(e,["components","mdxType","originalType","parentName"]),d=l(r),f=a,m=d["".concat(c,".").concat(f)]||d[f]||u[f]||o;return r?n.createElement(m,i(i({ref:t},s),{},{components:r})):n.createElement(m,i({ref:t},s))}));function m(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,i=new Array(o);i[0]=f;var p={};for(var c in t)hasOwnProperty.call(t,c)&&(p[c]=t[c]);p.originalType=e,p[d]="string"==typeof e?e:a,i[1]=p;for(var l=2;l<o;l++)i[l]=r[l];return n.createElement.apply(null,i)}return n.createElement.apply(null,r)}f.displayName="MDXCreateElement"},9879:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>u,frontMatter:()=>o,metadata:()=>p,toc:()=>l});var n=r(7462),a=(r(7294),r(3905));const o={},i=void 0,p={unversionedId:"internal/development/cordapp-interop/cordapp-interop-assets",id:"internal/development/cordapp-interop/cordapp-interop-assets",title:"cordapp-interop-assets",description:"\x3c!--",source:"@site/docs/internal/development/cordapp-interop/cordapp-interop-assets.md",sourceDirName:"internal/development/cordapp-interop",slug:"/internal/development/cordapp-interop/cordapp-interop-assets",permalink:"/weaver-dlt-interoperability/docs/internal/development/cordapp-interop/cordapp-interop-assets",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/internal/development/cordapp-interop/cordapp-interop-assets.md",tags:[],version:"current",frontMatter:{}},c={},l=[],s={toc:l},d="wrapper";function u(e){let{components:t,...r}=e;return(0,a.kt)(d,(0,n.Z)({},s,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("hr",null),(0,a.kt)("p",null,"id: cordapp-interop-assets\ntitle: CorDapp Assets"),(0,a.kt)("hr",null),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"class AccessControlState(\n linearId: UniqueIdentifier = UniqueIdentifier(),\n externalNetworkId: String,\n externalNetworkCertificates: List<String>,\n stateLinearId: UniqueIdentifier,\n participants: List<Party>\n) : LinearState\n\nclass ExternalStateObjectState(\n linearId: UniqueIdentifier = UniqueIdentifier(),\n participants: List<Party>,\n externalState: String,\n externalNetworkId: String,\n responseObject: List<FormattedResponse>\n) : LinearState\n\nclass ForeignNetworkInformationManagementState(\n linearId: UniqueIdentifier = UniqueIdentifier(),\n participants: List<Party>,\n networkId: String,\n topology: List<FNNode>\n) : LinearState\n")))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/ac36c4b6.8a0f9722.js b/assets/js/ac36c4b6.9319c158.js similarity index 90% rename from assets/js/ac36c4b6.8a0f9722.js rename to assets/js/ac36c4b6.9319c158.js index 63a5c2024..fe7ad50d9 100644 --- a/assets/js/ac36c4b6.8a0f9722.js +++ b/assets/js/ac36c4b6.9319c158.js @@ -1 +1 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[5622],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>f});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?o(Object(r),!0).forEach((function(t){a(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):o(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function l(e,t){if(null==e)return{};var r,n,a=function(e,t){if(null==e)return{};var r,n,a={},o=Object.keys(e);for(n=0;n<o.length;n++)r=o[n],t.indexOf(r)>=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n<o.length;n++)r=o[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var c=n.createContext({}),p=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},u=function(e){var t=p(e.components);return n.createElement(c.Provider,{value:t},e.children)},s="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),s=p(r),m=a,f=s["".concat(c,".").concat(m)]||s[m]||d[m]||o;return r?n.createElement(f,i(i({ref:t},u),{},{components:r})):n.createElement(f,i({ref:t},u))}));function f(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,i=new Array(o);i[0]=m;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l[s]="string"==typeof e?e:a,i[1]=l;for(var p=2;p<o;p++)i[p]=r[p];return n.createElement.apply(null,i)}return n.createElement.apply(null,r)}m.displayName="MDXCreateElement"},6277:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>d,frontMatter:()=>o,metadata:()=>l,toc:()=>p});var n=r(7462),a=(r(7294),r(3905));const o={id:"roadmap",title:"Roadmap"},i=void 0,l={unversionedId:"external/roadmap",id:"external/roadmap",title:"Roadmap",description:"\x3c!--",source:"@site/docs/external/roadmap.md",sourceDirName:"external",slug:"/external/roadmap",permalink:"/weaver-dlt-interoperability/docs/external/roadmap",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/roadmap.md",tags:[],version:"current",frontMatter:{id:"roadmap",title:"Roadmap"},sidebar:"Documentation",previous:{title:"Specifications",permalink:"/weaver-dlt-interoperability/docs/external/specifications"},next:{title:"Publications",permalink:"/weaver-dlt-interoperability/docs/external/publications"}},c={},p=[],u={toc:p},s="wrapper";function d(e){let{components:t,...r}=e;return(0,a.kt)(s,(0,n.Z)({},u,r,{components:t,mdxType:"MDXLayout"}))}d.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[3885],{5680:(e,t,r)=>{r.d(t,{xA:()=>u,yg:()=>f});var n=r(6540);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?o(Object(r),!0).forEach((function(t){a(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):o(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function l(e,t){if(null==e)return{};var r,n,a=function(e,t){if(null==e)return{};var r,n,a={},o=Object.keys(e);for(n=0;n<o.length;n++)r=o[n],t.indexOf(r)>=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n<o.length;n++)r=o[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var c=n.createContext({}),p=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},u=function(e){var t=p(e.components);return n.createElement(c.Provider,{value:t},e.children)},s="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),s=p(r),m=a,f=s["".concat(c,".").concat(m)]||s[m]||d[m]||o;return r?n.createElement(f,i(i({ref:t},u),{},{components:r})):n.createElement(f,i({ref:t},u))}));function f(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,i=new Array(o);i[0]=m;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l[s]="string"==typeof e?e:a,i[1]=l;for(var p=2;p<o;p++)i[p]=r[p];return n.createElement.apply(null,i)}return n.createElement.apply(null,r)}m.displayName="MDXCreateElement"},3940:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>d,frontMatter:()=>o,metadata:()=>l,toc:()=>p});var n=r(8168),a=(r(6540),r(5680));const o={id:"roadmap",title:"Roadmap"},i=void 0,l={unversionedId:"external/roadmap",id:"external/roadmap",title:"Roadmap",description:"\x3c!--",source:"@site/docs/external/roadmap.md",sourceDirName:"external",slug:"/external/roadmap",permalink:"/weaver-dlt-interoperability/docs/external/roadmap",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/roadmap.md",tags:[],version:"current",frontMatter:{id:"roadmap",title:"Roadmap"},sidebar:"Documentation",previous:{title:"Specifications",permalink:"/weaver-dlt-interoperability/docs/external/specifications"},next:{title:"Publications",permalink:"/weaver-dlt-interoperability/docs/external/publications"}},c={},p=[],u={toc:p},s="wrapper";function d(e){let{components:t,...r}=e;return(0,a.yg)(s,(0,n.A)({},u,r,{components:t,mdxType:"MDXLayout"}))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/b0f8195e.2ae97f7f.js b/assets/js/b0f8195e.2ae97f7f.js deleted file mode 100644 index 7e41cf239..000000000 --- a/assets/js/b0f8195e.2ae97f7f.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[5398],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>u});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?r(Object(n),!0).forEach((function(t){i(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):r(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,a,i=function(e,t){if(null==e)return{};var n,a,i={},r=Object.keys(e);for(a=0;a<r.length;a++)n=r[a],t.indexOf(n)>=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a<r.length;a++)n=r[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var p=a.createContext({}),s=function(e){var t=a.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},d=function(e){var t=s(e.components);return a.createElement(p.Provider,{value:t},e.children)},k="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,r=e.originalType,p=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),k=s(n),m=i,u=k["".concat(p,".").concat(m)]||k[m]||c[m]||r;return n?a.createElement(u,o(o({ref:t},d),{},{components:n})):a.createElement(u,o({ref:t},d))}));function u(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=n.length,o=new Array(r);o[0]=m;var l={};for(var p in t)hasOwnProperty.call(t,p)&&(l[p]=t[p]);l.originalType=e,l[k]="string"==typeof e?e:i,o[1]=l;for(var s=2;s<r;s++)o[s]=n[s];return a.createElement.apply(null,o)}return a.createElement.apply(null,n)}m.displayName="MDXCreateElement"},2674:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>o,default:()=>c,frontMatter:()=>r,metadata:()=>l,toc:()=>s});var a=n(7462),i=(n(7294),n(3905));const r={id:"ledger-initialization",title:"Ledger Initialization",pagination_prev:"external/getting-started/test-network/overview",pagination_next:"external/getting-started/interop/overview"},o=void 0,l={unversionedId:"external/getting-started/test-network/ledger-initialization",id:"external/getting-started/test-network/ledger-initialization",title:"Ledger Initialization",description:"\x3c!--",source:"@site/docs/external/getting-started/test-network/ledger-initialization.md",sourceDirName:"external/getting-started/test-network",slug:"/external/getting-started/test-network/ledger-initialization",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/ledger-initialization",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/getting-started/test-network/ledger-initialization.md",tags:[],version:"current",frontMatter:{id:"ledger-initialization",title:"Ledger Initialization",pagination_prev:"external/getting-started/test-network/overview",pagination_next:"external/getting-started/interop/overview"},sidebar:"Documentation",previous:{title:"Component Overview",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/overview"},next:{title:"Testing Interoperation Modes",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/overview"}},p={},s=[{value:"Preparation for Data Sharing",id:"preparation-for-data-sharing",level:2},{value:"Initializing the Fabric Networks",id:"initializing-the-fabric-networks",level:3},{value:"Configuring the Fabric CLI",id:"configuring-the-fabric-cli",level:4},{value:"Bootstrapping Network and Application State",id:"bootstrapping-network-and-application-state",level:4},{value:"Initializing the Corda Networks",id:"initializing-the-corda-networks",level:3},{value:"Bootstrapping Networks and Application States",id:"bootstrapping-networks-and-application-states",level:4},{value:"Next Steps",id:"next-steps",level:3},{value:"Preparation for Asset Exchange",id:"preparation-for-asset-exchange",level:2},{value:"Initializing the Fabric Networks",id:"initializing-the-fabric-networks-1",level:3},{value:"Configuring the Fabric CLI",id:"configuring-the-fabric-cli-1",level:4},{value:"Bootstrapping Network and Application State",id:"bootstrapping-network-and-application-state-1",level:4},{value:"Initializing the Corda Networks",id:"initializing-the-corda-networks-1",level:3},{value:"Initializing the Besu Networks",id:"initializing-the-besu-networks",level:3},{value:"Configuring the Besu-CLI",id:"configuring-the-besu-cli",level:4},{value:"Bootstrapping Network and Application State",id:"bootstrapping-network-and-application-state-2",level:4},{value:"Next Steps",id:"next-steps-1",level:3},{value:"Preparation for Asset Transfer",id:"preparation-for-asset-transfer",level:2},{value:"Initializing the Fabric Networks",id:"initializing-the-fabric-networks-2",level:3},{value:"Configuring the Fabric CLI",id:"configuring-the-fabric-cli-2",level:4},{value:"Bootstrapping Network and Application State",id:"bootstrapping-network-and-application-state-3",level:4},{value:"Initializing the Corda Networks",id:"initializing-the-corda-networks-2",level:3},{value:"Bootstrapping Networks and Application States",id:"bootstrapping-networks-and-application-states-1",level:4},{value:"Next Steps",id:"next-steps-2",level:3}],d={toc:s},k="wrapper";function c(e){let{components:t,...n}=e;return(0,i.kt)(k,(0,a.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"Once the two Fabric networks and the Corda network are up and running along with their associated relays and drivers, we must initialize states in those networks to prepare them for interoperation. For the Fabric networks, this involves recording state in the channel ledgers, and for the Corda network, in the nodes' vaults. The configuration and bootstrapping takes different form depending on what ",(0,i.kt)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/external/interoperability-modes"},"interoperability mode")," you wish to test."),(0,i.kt)("h2",{id:"preparation-for-data-sharing"},"Preparation for Data Sharing"),(0,i.kt)("p",null,"Follow the below instructions to prepare your networks for data sharing tests."),(0,i.kt)("h3",{id:"initializing-the-fabric-networks"},"Initializing the Fabric Networks"),(0,i.kt)("p",null,"We use the Fabric CLI (",(0,i.kt)("inlineCode",{parentName:"p"},"fabric-cli"),") built earlier (in ",(0,i.kt)("inlineCode",{parentName:"p"},"samples/fabric/fabric-cli")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"samples/fabric/go-cli"),") for this purpose."),(0,i.kt)("h4",{id:"configuring-the-fabric-cli"},"Configuring the Fabric CLI"),(0,i.kt)("p",null,"During bootstrap, the ledgers in both ",(0,i.kt)("inlineCode",{parentName:"p"},"network1")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"network2")," must be populated with the following information scoped by the interoperation chaincode:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Access control policies governing requests from foreign networks"),(0,i.kt)("li",{parentName:"ul"},"Security group info for foreign networks (i.e., identities of network units and their membership providers' certificate chains)"),(0,i.kt)("li",{parentName:"ul"},"Verification policies for proofs supplied by foreign networks\nKnowledge of foreign networks that must be configured in this stage is as follows:"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"network1")," has policies and security group info for ",(0,i.kt)("inlineCode",{parentName:"li"},"network2")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"network2")," has policies and security group info for ",(0,i.kt)("inlineCode",{parentName:"li"},"network1")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network"),"\n(",(0,i.kt)("em",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"em"},"Corda_Network")," will be launched later."),")\nThe ledgers must also be populated with sample key-value pairs for testing interoperation flows, scoped by the sample application chaincode.")),(0,i.kt)("p",null,"Prepare ",(0,i.kt)("inlineCode",{parentName:"p"},"fabric-cli")," for configuration suitably as follows."),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Navigate to the ",(0,i.kt)("inlineCode",{parentName:"li"},"samples/fabric/fabric-cli")," (for the Node.js version) or the ",(0,i.kt)("inlineCode",{parentName:"li"},"samples/fabric/go-cli")," (for the Golang version) folder."),(0,i.kt)("li",{parentName:"ul"},"Create a ",(0,i.kt)("inlineCode",{parentName:"li"},"config.json")," file by copying the ",(0,i.kt)("inlineCode",{parentName:"li"},"config.template.json")," and setting (or adding or removing) suitable values:",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},"For each network, the relay port and connection profile paths are specified using the keys ",(0,i.kt)("inlineCode",{parentName:"li"},"relayPort")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"connProfilePath")," respectively.",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},"Replace ",(0,i.kt)("inlineCode",{parentName:"li"},"<PATH-TO-WEAVER>")," with the absolute path location of the ",(0,i.kt)("inlineCode",{parentName:"li"},"weaver-dlt-interoperability")," clone folder."),(0,i.kt)("li",{parentName:"ul"},"Otherwise, leave the default values unchanged."))))),(0,i.kt)("li",{parentName:"ul"},"Create a ",(0,i.kt)("inlineCode",{parentName:"li"},"chaincode.json")," file by copying the ",(0,i.kt)("inlineCode",{parentName:"li"},"chaincode.json.template")," and leaving the default values unchanged. This file specified the arguments of the transaction to be locally invoked after fetching a remote view."),(0,i.kt)("li",{parentName:"ul"},"Create a ",(0,i.kt)("inlineCode",{parentName:"li"},".env")," file by copying ",(0,i.kt)("inlineCode",{parentName:"li"},".env.template")," and setting the following parameter values:",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},"If Relays and Drivers are deployed in the host machine:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre"},"MEMBER_CREDENTIAL_FOLDER=<PATH-TO-WEAVER>/samples/fabric/fabric-cli/src/data/credentials\nDEFAULT_APPLICATION_CHAINCODE=<chaincode-name>\nDEFAULT_APPLICATION_FUNC=<function-name>\nCONFIG_PATH=./config.json\nCHAINCODE_PATH=./chaincode.json\n"))),(0,i.kt)("li",{parentName:"ul"},"If Relays and Drivers are deployed in the Docker containers:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre"},"MEMBER_CREDENTIAL_FOLDER=<PATH-TO-WEAVER>/samples/fabric/fabric-cli/src/data/credentials_docker\nDEFAULT_APPLICATION_CHAINCODE=<chaincode-name>\nDEFAULT_APPLICATION_FUNC=<function-name>\nCONFIG_PATH=./config.json\nCHAINCODE_PATH=./chaincode.json\n"))),(0,i.kt)("li",{parentName:"ul"},"In each case, replace ",(0,i.kt)("inlineCode",{parentName:"li"},"<PATH-TO-WEAVER>")," with the location of your clone of Weaver and ",(0,i.kt)("inlineCode",{parentName:"li"},"<chaincode-name>")," with the name of the deployed chaincode, either ",(0,i.kt)("inlineCode",{parentName:"li"},"simplestate")," or ",(0,i.kt)("inlineCode",{parentName:"li"},"simplestatewithacl"),"."),(0,i.kt)("li",{parentName:"ul"},"If ",(0,i.kt)("inlineCode",{parentName:"li"},"simplestate")," is deployed, set ",(0,i.kt)("inlineCode",{parentName:"li"},"<function-name>")," to ",(0,i.kt)("inlineCode",{parentName:"li"},"Create"),", and if ",(0,i.kt)("inlineCode",{parentName:"li"},"simplestatewithacl")," if deployed, set ",(0,i.kt)("inlineCode",{parentName:"li"},"<function-name>")," to ",(0,i.kt)("inlineCode",{parentName:"li"},"CreateFromRemote"),"."),(0,i.kt)("li",{parentName:"ul"},"Leave the default values unchanged for the other parameters."))),(0,i.kt)("li",{parentName:"ul"},"Run the following command:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli env set-file ./.env\n")),(0,i.kt)("table",{parentName:"li"},(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"left"},"If the ",(0,i.kt)("inlineCode",{parentName:"td"},"CONFIG_PATH")," environment variable is omitted from ",(0,i.kt)("inlineCode",{parentName:"td"},".env"),", then you must also run:",(0,i.kt)("br",null),(0,i.kt)("inlineCode",{parentName:"td"},"./bin/fabric-cli config set-file ./config.json"))))))),(0,i.kt)("h4",{id:"bootstrapping-network-and-application-state"},"Bootstrapping Network and Application State"),(0,i.kt)("p",null,"Finally, to prepare both ",(0,i.kt)("inlineCode",{parentName:"p"},"network1")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"network2")," for interoperation, run:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli configure all network1 network2\n")),(0,i.kt)("p",null,"If Fabric networks were launched with 2 organizations, run:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli configure all network1 network2 --num-orgs=2\n")),(0,i.kt)("p",null,"Instead, if you launched only one of the two Fabric networks, run the following after replacing ",(0,i.kt)("inlineCode",{parentName:"p"},"<network-id>")," with either ",(0,i.kt)("inlineCode",{parentName:"p"},"network1")," or ",(0,i.kt)("inlineCode",{parentName:"p"},"network2"),", and ",(0,i.kt)("inlineCode",{parentName:"p"},"<1/2>")," with number of organizations in the network:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli configure all <network-id> --num-orgs=<1/2>\n")),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Wait for at least 5 minutes before moving on to the next step (testing interoperability modes) to allow the networks' IIN Agents to sync their respective memberships (which occur after every 5 minutes by default).")),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Optionally"),", fabric-cli can be used to trigger sync manually by running following command: "),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli configure membership --local-network=network1 --target-network=network2 --iin-agent-endpoint=localhost:9500\n")),(0,i.kt)("p",null,"This command syncs ",(0,i.kt)("inlineCode",{parentName:"p"},"network2"),"'s membership (target-network) in ",(0,i.kt)("inlineCode",{parentName:"p"},"network1")," (local-network) using IIN Agent of ",(0,i.kt)("inlineCode",{parentName:"p"},"Org1MSP")," as initiator. Similarly ",(0,i.kt)("inlineCode",{parentName:"p"},"network1"),"'s membership can be synced to ",(0,i.kt)("inlineCode",{parentName:"p"},"network2"),"'s ledger by running:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli configure membership --local-network=network2 --target-network=network1 --iin-agent-endpoint=localhost:9501\n")),(0,i.kt)("p",null,"Wait for 20-30 seconds after above commands to allow IIN Agents to finish the sync."),(0,i.kt)("h3",{id:"initializing-the-corda-networks"},"Initializing the Corda Networks"),(0,i.kt)("p",null,"Once the Corda networks are launched, the client applications (built earlier) needs to be exercised to generate network (ledger) state in preparation to test interoperation flows."),(0,i.kt)("h4",{id:"bootstrapping-networks-and-application-states"},"Bootstrapping Networks and Application States"),(0,i.kt)("p",null,"Just as we did for either Fabric network, the Corda network ledger (or ",(0,i.kt)("em",{parentName:"p"},"vault")," on each node) must be initialized with access control policies, verification policies, and security group information for the two Fabric networks. Further, sample key-value pairs need to be recorded so we can later share them with a Fabric network via an interoperation flow."),(0,i.kt)("p",null,"Bootstrap the Corda networks and application states as follows (",(0,i.kt)("em",{parentName:"p"},"the following instructions will initialize either or both Corda networks, depending on which of those are up and running"),"):"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Navigate to the ",(0,i.kt)("inlineCode",{parentName:"li"},"samples/corda/corda-simple-application")," folder."),(0,i.kt)("li",{parentName:"ul"},"Run the following: ",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},"If Relays and Drivers are deployed in the host machine:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"make initialise-vault\n"))),(0,i.kt)("li",{parentName:"ul"},"If Relays and Drivers are deployed in the Docker containers:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"make initialise-vault-docker\n")))))),(0,i.kt)("h3",{id:"next-steps"},"Next Steps"),(0,i.kt)("p",null,"The test networks are now configured and their ledgers are initialized. You can now run the ",(0,i.kt)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/data-sharing"},"data sharing flows"),"."),(0,i.kt)("h2",{id:"preparation-for-asset-exchange"},"Preparation for Asset Exchange"),(0,i.kt)("p",null,"Follow the below instructions to prepare your networks for asset exchange tests."),(0,i.kt)("h3",{id:"initializing-the-fabric-networks-1"},"Initializing the Fabric Networks"),(0,i.kt)("p",null,"We use the Fabric CLI (",(0,i.kt)("inlineCode",{parentName:"p"},"fabric-cli"),") built earlier (in ",(0,i.kt)("inlineCode",{parentName:"p"},"samples/fabric/fabric-cli")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"samples/fabric/go-cli"),") for this purpose."),(0,i.kt)("h4",{id:"configuring-the-fabric-cli-1"},"Configuring the Fabric CLI"),(0,i.kt)("p",null,"The ledgers must be populated with sample key-value pairs for testing interoperation flows, scoped by the sample application chaincode."),(0,i.kt)("p",null,"Prepare ",(0,i.kt)("inlineCode",{parentName:"p"},"fabric-cli")," for configuration suitably as follows."),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Navigate to the ",(0,i.kt)("inlineCode",{parentName:"li"},"samples/fabric/fabric-cli")," (for the Node.js version) or the ",(0,i.kt)("inlineCode",{parentName:"li"},"samples/fabric/go-cli")," (for the Golang version) folder."),(0,i.kt)("li",{parentName:"ul"},"Create a ",(0,i.kt)("inlineCode",{parentName:"li"},"config.json")," file by copying the ",(0,i.kt)("inlineCode",{parentName:"li"},"config.template.json")," and setting (or adding or removing) suitable values:",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},"For each network, the relay port and connection profile paths are specified using the keys ",(0,i.kt)("inlineCode",{parentName:"li"},"relayPort")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"connProfilePath")," respectively.",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},"Replace ",(0,i.kt)("inlineCode",{parentName:"li"},"<PATH-TO-WEAVER>")," with the absolute path location of the ",(0,i.kt)("inlineCode",{parentName:"li"},"weaver-dlt-interoperability")," clone folder."),(0,i.kt)("li",{parentName:"ul"},"Set the ",(0,i.kt)("inlineCode",{parentName:"li"},"chaincode")," attribute in each network to the deployed chaincode name (",(0,i.kt)("inlineCode",{parentName:"li"},"simpleasset")," or ",(0,i.kt)("inlineCode",{parentName:"li"},"simpleassetandinterop")," or ",(0,i.kt)("inlineCode",{parentName:"li"},"simpleassettransfer"),")."),(0,i.kt)("li",{parentName:"ul"},"Otherwise, leave the default values unchanged."))))),(0,i.kt)("li",{parentName:"ul"},"Create a ",(0,i.kt)("inlineCode",{parentName:"li"},".env")," file by copying ",(0,i.kt)("inlineCode",{parentName:"li"},".env.template")," and setting following parameter values:",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},"If Relays and Drivers are deployed in the host machine:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre"},"MEMBER_CREDENTIAL_FOLDER=<PATH-TO-WEAVER>/samples/fabric/fabric-cli/src/data/credentials\nCONFIG_PATH=./config.json\n"))),(0,i.kt)("li",{parentName:"ul"},"If Relays and Drivers are deployed in the Docker containers:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre"},"MEMBER_CREDENTIAL_FOLDER=<PATH-TO-WEAVER>/samples/fabric/fabric-cli/src/data/credentials_docker\nCONFIG_PATH=./config.json\n"))),(0,i.kt)("li",{parentName:"ul"},"In each case, replace ",(0,i.kt)("inlineCode",{parentName:"li"},"<PATH-TO-WEAVER>")," with the location of your clone of Weaver."),(0,i.kt)("li",{parentName:"ul"},"Leave the default values unchanged for the other parameters."))),(0,i.kt)("li",{parentName:"ul"},"Run the following command:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli env set-file ./.env\n")),(0,i.kt)("table",{parentName:"li"},(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"left"},"If the ",(0,i.kt)("inlineCode",{parentName:"td"},"CONFIG_PATH")," environment variable is omitted from ",(0,i.kt)("inlineCode",{parentName:"td"},".env"),", then you must also run:",(0,i.kt)("br",null),(0,i.kt)("inlineCode",{parentName:"td"},"./bin/fabric-cli config set-file ./config.json"))))))),(0,i.kt)("h4",{id:"bootstrapping-network-and-application-state-1"},"Bootstrapping Network and Application State"),(0,i.kt)("p",null,"Finally, to prepare both ",(0,i.kt)("inlineCode",{parentName:"p"},"network1")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"network2")," for interoperation, run:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./scripts/initAsset.sh\n")),(0,i.kt)("h3",{id:"initializing-the-corda-networks-1"},"Initializing the Corda Networks"),(0,i.kt)("p",null,"Corda Network needs to be initialized with assets for asset-exchange to be performed:\nBootstrap the Corda network and application states as follows:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Navigate to the ",(0,i.kt)("inlineCode",{parentName:"li"},"samples/corda/corda-simple-application")," folder."),(0,i.kt)("li",{parentName:"ul"},"Run the following: ",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},"For ",(0,i.kt)("inlineCode",{parentName:"li"},"cordaSimpleApplication")," app, run:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre"},"./scripts/initAsset.sh\n")))))),(0,i.kt)("h3",{id:"initializing-the-besu-networks"},"Initializing the Besu Networks"),(0,i.kt)("p",null,"Let's assume that ",(0,i.kt)("inlineCode",{parentName:"p"},"network1")," can either manage NFT ",(0,i.kt)("inlineCode",{parentName:"p"},"AliceERC721")," or Hybrid ",(0,i.kt)("inlineCode",{parentName:"p"},"AliceERC1155")," tokens, while ",(0,i.kt)("inlineCode",{parentName:"p"},"network2")," manages fungible ",(0,i.kt)("inlineCode",{parentName:"p"},"BobERC20")," tokens. Here we use account ",(0,i.kt)("inlineCode",{parentName:"p"},"1")," for Alice and account ",(0,i.kt)("inlineCode",{parentName:"p"},"2")," for Bob in both neworks. To prepare Besu networks for asset exchange, navigate to the ",(0,i.kt)("inlineCode",{parentName:"p"},"samples/besu/besu-cli")," and then follow the steps in next subsections."),(0,i.kt)("h4",{id:"configuring-the-besu-cli"},"Configuring the Besu-CLI"),(0,i.kt)("p",null,"Create a ",(0,i.kt)("inlineCode",{parentName:"p"},"config.json")," file by copying the ",(0,i.kt)("inlineCode",{parentName:"p"},"config.template.json"),", keep the default values for managing ",(0,i.kt)("inlineCode",{parentName:"p"},"AliceERC721")," tokens in ",(0,i.kt)("inlineCode",{parentName:"p"},"network1")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"BobERC20")," tokens in ",(0,i.kt)("inlineCode",{parentName:"p"},"network2"),".\nIf you want to change the token type used in the ",(0,i.kt)("inlineCode",{parentName:"p"},"network1")," to Hybrid ",(0,i.kt)("inlineCode",{parentName:"p"},"AliceERC1155")," tokens, in ",(0,i.kt)("inlineCode",{parentName:"p"},"config.json")," update ",(0,i.kt)("inlineCode",{parentName:"p"},"tokenContract")," field with value ",(0,i.kt)("inlineCode",{parentName:"p"},'"../simpleasset/build/contracts/AliceERC1155.json".')),(0,i.kt)("h4",{id:"bootstrapping-network-and-application-state-2"},"Bootstrapping Network and Application State"),(0,i.kt)("p",null,"Finally, to prepare both ",(0,i.kt)("inlineCode",{parentName:"p"},"network1")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"network2")," for interoperation, run:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"If you wish to test the default exchange (ERC-20 tokens for ERC-721 tokens), run::",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./scripts/initAsset.sh\n")),"This will issue ",(0,i.kt)("inlineCode",{parentName:"li"},"100 BobERC20")," tokens to each account in ",(0,i.kt)("inlineCode",{parentName:"li"},"network2")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"AliceERC721")," token with id ",(0,i.kt)("inlineCode",{parentName:"li"},"0")," to ",(0,i.kt)("inlineCode",{parentName:"li"},"Alice")," and id ",(0,i.kt)("inlineCode",{parentName:"li"},"1")," to ",(0,i.kt)("inlineCode",{parentName:"li"},"Bob")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"network1"),"."),(0,i.kt)("li",{parentName:"ul"},"Instead, if you wish to test Alice's exchange of ERC-1155 tokens for Bob's ERC-20 tokens, run:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./scripts/initAsset.sh hybrid\n")),"This will issue ",(0,i.kt)("inlineCode",{parentName:"li"},"100 BobERC20")," tokens to each account in ",(0,i.kt)("inlineCode",{parentName:"li"},"network2")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"100 AliceERC1155")," tokens with id ",(0,i.kt)("inlineCode",{parentName:"li"},"0")," to ",(0,i.kt)("inlineCode",{parentName:"li"},"Alice")," and id ",(0,i.kt)("inlineCode",{parentName:"li"},"1")," to ",(0,i.kt)("inlineCode",{parentName:"li"},"Bob")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"network1"),".")),(0,i.kt)("h3",{id:"next-steps-1"},"Next Steps"),(0,i.kt)("p",null,"The test networks are now configured and their ledgers are initialized. You can now run the ",(0,i.kt)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview"},"asset exchange flows"),"."),(0,i.kt)("h2",{id:"preparation-for-asset-transfer"},"Preparation for Asset Transfer"),(0,i.kt)("p",null,"Follow the below instructions to prepare your networks for asset transfer tests."),(0,i.kt)("h3",{id:"initializing-the-fabric-networks-2"},"Initializing the Fabric Networks"),(0,i.kt)("p",null,"We use the Fabric CLI (",(0,i.kt)("inlineCode",{parentName:"p"},"fabric-cli"),") built earlier (in ",(0,i.kt)("inlineCode",{parentName:"p"},"samples/fabric/fabric-cli")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"samples/fabric/go-cli"),") for this purpose."),(0,i.kt)("h4",{id:"configuring-the-fabric-cli-2"},"Configuring the Fabric CLI"),(0,i.kt)("p",null,"During bootstrap, the ledgers in both ",(0,i.kt)("inlineCode",{parentName:"p"},"network1")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"network2")," must be populated with the following information scoped by the interoperation chaincode:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Access control policies governing requests from foreign networks"),(0,i.kt)("li",{parentName:"ul"},"Security group info for foreign networks (i.e., identities of network units and their membership providers' certificate chains)"),(0,i.kt)("li",{parentName:"ul"},"Verification policies for proofs supplied by foreign networks\nKnowledge of foreign networks that must be configured in this stage is as follows:"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"network1")," has policies and security group info for ",(0,i.kt)("inlineCode",{parentName:"li"},"network2")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"network2")," has policies and security group info for ",(0,i.kt)("inlineCode",{parentName:"li"},"network1")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network"),"\n(",(0,i.kt)("em",{parentName:"li"},"The Corda sample application doesn't support asset transfer yet, but there is no harm in including it above."),")\nThe ledgers must also be populated with sample key-value pairs for testing interoperation flows, scoped by the sample application chaincode.")),(0,i.kt)("p",null,"Prepare ",(0,i.kt)("inlineCode",{parentName:"p"},"fabric-cli")," for configuration suitably as follows."),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Navigate to the ",(0,i.kt)("inlineCode",{parentName:"li"},"samples/fabric/fabric-cli")," folder (",(0,i.kt)("em",{parentName:"li"},"the Go CLI doesn't support asset transfer yet"),")."),(0,i.kt)("li",{parentName:"ul"},"Create a ",(0,i.kt)("inlineCode",{parentName:"li"},"config.json")," file by copying the ",(0,i.kt)("inlineCode",{parentName:"li"},"config.template.json")," and setting (or adding or removing) suitable values:",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},"For each network, the relay port and connection profile paths are specified using the keys ",(0,i.kt)("inlineCode",{parentName:"li"},"relayPort")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"connProfilePath")," respectively.",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},"Replace ",(0,i.kt)("inlineCode",{parentName:"li"},"<PATH-TO-WEAVER>")," with the absolute path location of the ",(0,i.kt)("inlineCode",{parentName:"li"},"weaver-dlt-interoperability")," clone folder."),(0,i.kt)("li",{parentName:"ul"},"Set the ",(0,i.kt)("inlineCode",{parentName:"li"},"chaincode")," attribute in each network to ",(0,i.kt)("inlineCode",{parentName:"li"},"simpleassettransfer"),"."),(0,i.kt)("li",{parentName:"ul"},"Set the ",(0,i.kt)("inlineCode",{parentName:"li"},"aclPolicyPrincipalType")," attribute in ",(0,i.kt)("inlineCode",{parentName:"li"},"network2")," to ",(0,i.kt)("inlineCode",{parentName:"li"},"ca"),"."),(0,i.kt)("li",{parentName:"ul"},"Otherwise, leave the default values unchanged."))))),(0,i.kt)("li",{parentName:"ul"},"Create ",(0,i.kt)("inlineCode",{parentName:"li"},"remote-network-config.json")," file by copying ",(0,i.kt)("inlineCode",{parentName:"li"},"remote-network-config.json.template"),". Use default values if relays and drivers are deployed in the host machine; else if they are deployed in Docker, update as follows:",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},"Update value for ",(0,i.kt)("inlineCode",{parentName:"li"},"relayEndpoint")," for ",(0,i.kt)("inlineCode",{parentName:"li"},"network1")," as ",(0,i.kt)("inlineCode",{parentName:"li"},"relay-network1:9080"),"."),(0,i.kt)("li",{parentName:"ul"},"Update value for ",(0,i.kt)("inlineCode",{parentName:"li"},"relayEndpoint")," for ",(0,i.kt)("inlineCode",{parentName:"li"},"network2")," as ",(0,i.kt)("inlineCode",{parentName:"li"},"relay-network2:9083"),"."),(0,i.kt)("li",{parentName:"ul"},"Update value for ",(0,i.kt)("inlineCode",{parentName:"li"},"relayEndpoint")," for ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network")," as ",(0,i.kt)("inlineCode",{parentName:"li"},"relay-corda:9081"),"."),(0,i.kt)("li",{parentName:"ul"},"Update value for ",(0,i.kt)("inlineCode",{parentName:"li"},"relayEndpoint")," for ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network2")," as ",(0,i.kt)("inlineCode",{parentName:"li"},"relay-corda2:9082"),"."),(0,i.kt)("li",{parentName:"ul"},"Update value for ",(0,i.kt)("inlineCode",{parentName:"li"},"partyEndPoint")," for ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network")," as ",(0,i.kt)("inlineCode",{parentName:"li"},"corda_partya_1:10003"),"."),(0,i.kt)("li",{parentName:"ul"},"Update value for ",(0,i.kt)("inlineCode",{parentName:"li"},"partyEndPoint")," for ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network2")," as ",(0,i.kt)("inlineCode",{parentName:"li"},"corda_network2_partya_1:10003"),"."))),(0,i.kt)("li",{parentName:"ul"},"Create ",(0,i.kt)("inlineCode",{parentName:"li"},"chaincode.json")," file by copying ",(0,i.kt)("inlineCode",{parentName:"li"},"chaincode.json.template"),". Keep the default values unchanged."),(0,i.kt)("li",{parentName:"ul"},"Create a ",(0,i.kt)("inlineCode",{parentName:"li"},".env")," file by copying ",(0,i.kt)("inlineCode",{parentName:"li"},".env.template")," and setting the following parameter values:",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},"If Relays and Drivers are deployed in the host machine:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre"},"MEMBER_CREDENTIAL_FOLDER=<PATH-TO-WEAVER>/samples/fabric/fabric-cli/src/data/credentials\nDEFAULT_APPLICATION_CHAINCODE=simpleassettransfer\nCONFIG_PATH=./config.json\nREMOTE_CONFIG_PATH=./remote-network-config.json\nCHAINCODE_PATH=./chaincode.json\n"))),(0,i.kt)("li",{parentName:"ul"},"If Relays and Drivers are deployed in the Docker containers:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre"},"MEMBER_CREDENTIAL_FOLDER=<PATH-TO-WEAVER>/samples/fabric/fabric-cli/src/data/credentials_docker\nDEFAULT_APPLICATION_CHAINCODE=simpleassettransfer\nCONFIG_PATH=./config.json\nREMOTE_CONFIG_PATH=./remote-network-config.json\nCHAINCODE_PATH=./chaincode.json\n"))),(0,i.kt)("li",{parentName:"ul"},"In each case, replace ",(0,i.kt)("inlineCode",{parentName:"li"},"<PATH-TO-WEAVER>")," with the location of your clone of Weaver."),(0,i.kt)("li",{parentName:"ul"},"Leave the default values unchanged for the other parameters."))),(0,i.kt)("li",{parentName:"ul"},"Run the following command:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre"},"./bin/fabric-cli env set-file ./.env\n")),(0,i.kt)("table",{parentName:"li"},(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"left"},"If the ",(0,i.kt)("inlineCode",{parentName:"td"},"CONFIG_PATH")," environment variable is omitted from ",(0,i.kt)("inlineCode",{parentName:"td"},".env"),", then you must also run:",(0,i.kt)("br",null),(0,i.kt)("inlineCode",{parentName:"td"},"./bin/fabric-cli config set-file ./config.json"))))))),(0,i.kt)("h4",{id:"bootstrapping-network-and-application-state-3"},"Bootstrapping Network and Application State"),(0,i.kt)("p",null,"Create appropriate access control and verification policies for ",(0,i.kt)("inlineCode",{parentName:"p"},"network1")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"network2")," by running:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli configure create all --local-network=network1\n./bin/fabric-cli configure create all --local-network=network2\n")),(0,i.kt)("p",null,"Load access control and verification policies onto the ledgers of ",(0,i.kt)("inlineCode",{parentName:"p"},"network1")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"network2")," by running (replace ",(0,i.kt)("inlineCode",{parentName:"p"},"<1/2>")," with number of organizations in the network):"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli configure network --local-network=network1 --num-orgs=<1/2>\n./bin/fabric-cli configure network --local-network=network2 --num-orgs=<1/2>\n")),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Wait for at least 5 minutes before moving on to the next step (testing interoperability modes) to allow the networks' IIN Agents to sync their respective memberships (which occur after every 5 minutes by default).")),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Optionally"),", fabric-cli can be used to trigger sync manually by running following command: "),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli configure membership --local-network=network1 --target-network=network2 --iin-agent-endpoint=localhost:9500\n")),(0,i.kt)("p",null,"This command syncs ",(0,i.kt)("inlineCode",{parentName:"p"},"network2"),"'s membership (target-network) in ",(0,i.kt)("inlineCode",{parentName:"p"},"network1")," (local-network) using IIN Agent of ",(0,i.kt)("inlineCode",{parentName:"p"},"Org1MSP")," as initiator. Similarly ",(0,i.kt)("inlineCode",{parentName:"p"},"network1"),"'s membership can be synced to ",(0,i.kt)("inlineCode",{parentName:"p"},"network2"),"'s ledger by running:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli configure membership --local-network=network2 --target-network=network1 --iin-agent-endpoint=localhost:9501\n")),(0,i.kt)("p",null,"Wait for 20-30 seconds after above commands to allow IIN Agents to finish the sync."),(0,i.kt)("p",null,"Initialize bond and token asset states and ownerships on the ",(0,i.kt)("inlineCode",{parentName:"p"},"network1")," ledger by running the following (this step will also create a user ",(0,i.kt)("inlineCode",{parentName:"p"},"alice")," in ",(0,i.kt)("inlineCode",{parentName:"p"},"network1")," and a user ",(0,i.kt)("inlineCode",{parentName:"p"},"bob")," in ",(0,i.kt)("inlineCode",{parentName:"p"},"network2"),"):"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./scripts/initAssetsForTransfer.sh\n")),(0,i.kt)("h3",{id:"initializing-the-corda-networks-2"},"Initializing the Corda Networks"),(0,i.kt)("p",null,"Once the Corda networks (",(0,i.kt)("inlineCode",{parentName:"p"},"Corda_Network")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"Corda_Network2"),") are launched, the client applications (built earlier) needs to be exercised to generate ledger state in both exporting/source and importing/destination networks in preparation to test asset transfer interoperation flows."),(0,i.kt)("h4",{id:"bootstrapping-networks-and-application-states-1"},"Bootstrapping Networks and Application States"),(0,i.kt)("p",null,"The Corda network ledger (or ",(0,i.kt)("em",{parentName:"p"},"vault")," on each node) must be initialized with access control policies, verification policies, and security group information for the other networks (two Fabric networks and other Corda network)."),(0,i.kt)("p",null,"Bootstrap the Corda networks and application states as follows (",(0,i.kt)("em",{parentName:"p"},"the following instructions will initialize either or both Corda networks, depending on which of those are up and running"),"):"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Navigate to the ",(0,i.kt)("inlineCode",{parentName:"li"},"samples/corda/corda-simple-application")," folder."),(0,i.kt)("li",{parentName:"ul"},"Run the following:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"cp clients/src/main/resources/config/remote-network-config.json.template clients/src/main/resources/config/remote-network-config.json\n")),"Use default values in ",(0,i.kt)("inlineCode",{parentName:"li"},"remote-network-config.json")," if relays and drivers are deployed in the host machine; else if they are deployed in Docker, update as follows:",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},"Update value for ",(0,i.kt)("inlineCode",{parentName:"li"},"relayEndpoint")," for ",(0,i.kt)("inlineCode",{parentName:"li"},"network1")," as ",(0,i.kt)("inlineCode",{parentName:"li"},"relay-network1:9080"),"."),(0,i.kt)("li",{parentName:"ul"},"Update value for ",(0,i.kt)("inlineCode",{parentName:"li"},"relayEndpoint")," for ",(0,i.kt)("inlineCode",{parentName:"li"},"network2")," as ",(0,i.kt)("inlineCode",{parentName:"li"},"relay-network2:9083"),"."),(0,i.kt)("li",{parentName:"ul"},"Update value for ",(0,i.kt)("inlineCode",{parentName:"li"},"relayEndpoint")," for ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network")," as ",(0,i.kt)("inlineCode",{parentName:"li"},"relay-corda:9081"),"."),(0,i.kt)("li",{parentName:"ul"},"Update value for ",(0,i.kt)("inlineCode",{parentName:"li"},"relayEndpoint")," for ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network2")," as ",(0,i.kt)("inlineCode",{parentName:"li"},"relay-corda2:9082"),"."),(0,i.kt)("li",{parentName:"ul"},"Update value for ",(0,i.kt)("inlineCode",{parentName:"li"},"partyEndPoint")," for ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network")," as ",(0,i.kt)("inlineCode",{parentName:"li"},"corda_partya_1:10003"),"."),(0,i.kt)("li",{parentName:"ul"},"Update value for ",(0,i.kt)("inlineCode",{parentName:"li"},"partyEndPoint")," for ",(0,i.kt)("inlineCode",{parentName:"li"},"Corda_Network2")," as ",(0,i.kt)("inlineCode",{parentName:"li"},"corda_network2_partya_1:10003"),"."))),(0,i.kt)("li",{parentName:"ul"},"Run the following: ",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},"If Relays and Drivers are deployed in the host machine:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"make initialise-vault-asset-transfer\n"))),(0,i.kt)("li",{parentName:"ul"},"If Relays and Drivers are deployed in the Docker containers:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"make initialise-vault-asset-transfer-docker\n")))))),(0,i.kt)("h3",{id:"next-steps-2"},"Next Steps"),(0,i.kt)("p",null,"The test networks are now configured and their ledgers are initialized. You can now run the ",(0,i.kt)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-transfer"},"asset transfer flows"),"."))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/b0f8195e.8a884969.js b/assets/js/b0f8195e.8a884969.js new file mode 100644 index 000000000..dab09dddb --- /dev/null +++ b/assets/js/b0f8195e.8a884969.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[7695],{5680:(e,n,a)=>{a.d(n,{xA:()=>g,yg:()=>m});var t=a(6540);function i(e,n,a){return n in e?Object.defineProperty(e,n,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[n]=a,e}function r(e,n){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var t=Object.getOwnPropertySymbols(e);n&&(t=t.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),a.push.apply(a,t)}return a}function o(e){for(var n=1;n<arguments.length;n++){var a=null!=arguments[n]?arguments[n]:{};n%2?r(Object(a),!0).forEach((function(n){i(e,n,a[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(a)):r(Object(a)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(a,n))}))}return e}function l(e,n){if(null==e)return{};var a,t,i=function(e,n){if(null==e)return{};var a,t,i={},r=Object.keys(e);for(t=0;t<r.length;t++)a=r[t],n.indexOf(a)>=0||(i[a]=e[a]);return i}(e,n);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(t=0;t<r.length;t++)a=r[t],n.indexOf(a)>=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(i[a]=e[a])}return i}var p=t.createContext({}),s=function(e){var n=t.useContext(p),a=n;return e&&(a="function"==typeof e?e(n):o(o({},n),e)),a},g=function(e){var n=s(e.components);return t.createElement(p.Provider,{value:n},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var n=e.children;return t.createElement(t.Fragment,{},n)}},y=t.forwardRef((function(e,n){var a=e.components,i=e.mdxType,r=e.originalType,p=e.parentName,g=l(e,["components","mdxType","originalType","parentName"]),d=s(a),y=i,m=d["".concat(p,".").concat(y)]||d[y]||c[y]||r;return a?t.createElement(m,o(o({ref:n},g),{},{components:a})):t.createElement(m,o({ref:n},g))}));function m(e,n){var a=arguments,i=n&&n.mdxType;if("string"==typeof e||i){var r=a.length,o=new Array(r);o[0]=y;var l={};for(var p in n)hasOwnProperty.call(n,p)&&(l[p]=n[p]);l.originalType=e,l[d]="string"==typeof e?e:i,o[1]=l;for(var s=2;s<r;s++)o[s]=a[s];return t.createElement.apply(null,o)}return t.createElement.apply(null,a)}y.displayName="MDXCreateElement"},2039:(e,n,a)=>{a.r(n),a.d(n,{assets:()=>p,contentTitle:()=>o,default:()=>c,frontMatter:()=>r,metadata:()=>l,toc:()=>s});var t=a(8168),i=(a(6540),a(5680));const r={id:"ledger-initialization",title:"Ledger Initialization",pagination_prev:"external/getting-started/test-network/overview",pagination_next:"external/getting-started/interop/overview"},o=void 0,l={unversionedId:"external/getting-started/test-network/ledger-initialization",id:"external/getting-started/test-network/ledger-initialization",title:"Ledger Initialization",description:"\x3c!--",source:"@site/docs/external/getting-started/test-network/ledger-initialization.md",sourceDirName:"external/getting-started/test-network",slug:"/external/getting-started/test-network/ledger-initialization",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/ledger-initialization",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/getting-started/test-network/ledger-initialization.md",tags:[],version:"current",frontMatter:{id:"ledger-initialization",title:"Ledger Initialization",pagination_prev:"external/getting-started/test-network/overview",pagination_next:"external/getting-started/interop/overview"},sidebar:"Documentation",previous:{title:"Component Overview",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/overview"},next:{title:"Testing Interoperation Modes",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/overview"}},p={},s=[{value:"Preparation for Data Sharing",id:"preparation-for-data-sharing",level:2},{value:"Initializing the Fabric Networks",id:"initializing-the-fabric-networks",level:3},{value:"Configuring the Fabric CLI",id:"configuring-the-fabric-cli",level:4},{value:"Bootstrapping Network and Application State",id:"bootstrapping-network-and-application-state",level:4},{value:"Initializing the Corda Networks",id:"initializing-the-corda-networks",level:3},{value:"Bootstrapping Networks and Application States",id:"bootstrapping-networks-and-application-states",level:4},{value:"Next Steps",id:"next-steps",level:3},{value:"Preparation for Asset Exchange",id:"preparation-for-asset-exchange",level:2},{value:"Initializing the Fabric Networks",id:"initializing-the-fabric-networks-1",level:3},{value:"Configuring the Fabric CLI",id:"configuring-the-fabric-cli-1",level:4},{value:"Bootstrapping Network and Application State",id:"bootstrapping-network-and-application-state-1",level:4},{value:"Initializing the Corda Networks",id:"initializing-the-corda-networks-1",level:3},{value:"Initializing the Besu Networks",id:"initializing-the-besu-networks",level:3},{value:"Configuring the Besu-CLI",id:"configuring-the-besu-cli",level:4},{value:"Bootstrapping Network and Application State",id:"bootstrapping-network-and-application-state-2",level:4},{value:"Next Steps",id:"next-steps-1",level:3},{value:"Preparation for Asset Transfer",id:"preparation-for-asset-transfer",level:2},{value:"Initializing the Fabric Networks",id:"initializing-the-fabric-networks-2",level:3},{value:"Configuring the Fabric CLI",id:"configuring-the-fabric-cli-2",level:4},{value:"Bootstrapping Network and Application State",id:"bootstrapping-network-and-application-state-3",level:4},{value:"Initializing the Corda Networks",id:"initializing-the-corda-networks-2",level:3},{value:"Bootstrapping Networks and Application States",id:"bootstrapping-networks-and-application-states-1",level:4},{value:"Next Steps",id:"next-steps-2",level:3}],g={toc:s},d="wrapper";function c(e){let{components:n,...a}=e;return(0,i.yg)(d,(0,t.A)({},g,a,{components:n,mdxType:"MDXLayout"}),(0,i.yg)("p",null,"Once the two Fabric networks and the Corda network are up and running along with their associated relays and drivers, we must initialize states in those networks to prepare them for interoperation. For the Fabric networks, this involves recording state in the channel ledgers, and for the Corda network, in the nodes' vaults. The configuration and bootstrapping takes different form depending on what ",(0,i.yg)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/external/interoperability-modes"},"interoperability mode")," you wish to test."),(0,i.yg)("h2",{id:"preparation-for-data-sharing"},"Preparation for Data Sharing"),(0,i.yg)("p",null,"Follow the below instructions to prepare your networks for data sharing tests."),(0,i.yg)("h3",{id:"initializing-the-fabric-networks"},"Initializing the Fabric Networks"),(0,i.yg)("p",null,"We use the Fabric CLI (",(0,i.yg)("inlineCode",{parentName:"p"},"fabric-cli"),") built earlier (in ",(0,i.yg)("inlineCode",{parentName:"p"},"samples/fabric/fabric-cli")," for the Node.js version and ",(0,i.yg)("inlineCode",{parentName:"p"},"samples/fabric/go-cli")," for the Golang version) for this purpose."),(0,i.yg)("h4",{id:"configuring-the-fabric-cli"},"Configuring the Fabric CLI"),(0,i.yg)("p",null,"During bootstrap, the ledgers in both ",(0,i.yg)("inlineCode",{parentName:"p"},"network1")," and ",(0,i.yg)("inlineCode",{parentName:"p"},"network2")," must be populated with the following information scoped by the interoperation chaincode:"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},"Access control policies governing requests from foreign networks"),(0,i.yg)("li",{parentName:"ul"},"Security group info for foreign networks (i.e., identities of network units and their membership providers' certificate chains)"),(0,i.yg)("li",{parentName:"ul"},"Verification policies for proofs supplied by foreign networks\nKnowledge of foreign networks that must be configured in this stage is as follows:"),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("inlineCode",{parentName:"li"},"network1")," has policies and security group info for ",(0,i.yg)("inlineCode",{parentName:"li"},"network2")," and ",(0,i.yg)("inlineCode",{parentName:"li"},"Corda_Network")),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("inlineCode",{parentName:"li"},"network2")," has policies and security group info for ",(0,i.yg)("inlineCode",{parentName:"li"},"network1")," and ",(0,i.yg)("inlineCode",{parentName:"li"},"Corda_Network"),"\n(",(0,i.yg)("em",{parentName:"li"},(0,i.yg)("inlineCode",{parentName:"em"},"Corda_Network")," will be launched later."),")\nThe ledgers must also be populated with sample key-value pairs for testing interoperation flows, scoped by the sample application chaincode.")),(0,i.yg)("p",null,"Prepare ",(0,i.yg)("inlineCode",{parentName:"p"},"fabric-cli")," for configuration suitably as follows."),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},"Navigate to the ",(0,i.yg)("inlineCode",{parentName:"li"},"samples/fabric/fabric-cli")," (for the Node.js version) or the ",(0,i.yg)("inlineCode",{parentName:"li"},"samples/fabric/go-cli")," (for the Golang version) folder."),(0,i.yg)("li",{parentName:"ul"},"Create a ",(0,i.yg)("inlineCode",{parentName:"li"},"config.json")," file by copying the ",(0,i.yg)("inlineCode",{parentName:"li"},"config.template.json")," and setting (or adding or removing) suitable values:",(0,i.yg)("ul",{parentName:"li"},(0,i.yg)("li",{parentName:"ul"},"For each network, the relay port and connection profile paths are specified using the keys ",(0,i.yg)("inlineCode",{parentName:"li"},"relayPort")," and ",(0,i.yg)("inlineCode",{parentName:"li"},"connProfilePath")," respectively.",(0,i.yg)("ul",{parentName:"li"},(0,i.yg)("li",{parentName:"ul"},"Replace ",(0,i.yg)("inlineCode",{parentName:"li"},"<PATH-TO-WEAVER>")," with the absolute path location of the ",(0,i.yg)("inlineCode",{parentName:"li"},"weaver-dlt-interoperability")," clone folder."),(0,i.yg)("li",{parentName:"ul"},"Otherwise, leave the default values unchanged."))))),(0,i.yg)("li",{parentName:"ul"},"Create a ",(0,i.yg)("inlineCode",{parentName:"li"},"chaincode.json")," file by copying the ",(0,i.yg)("inlineCode",{parentName:"li"},"chaincode.json.template")," and leaving the default values unchanged. This file specified the arguments of the transaction to be locally invoked after fetching a remote view."),(0,i.yg)("li",{parentName:"ul"},"Create a ",(0,i.yg)("inlineCode",{parentName:"li"},".env")," file by copying ",(0,i.yg)("inlineCode",{parentName:"li"},".env.template")," and setting the following parameter values:",(0,i.yg)("ul",{parentName:"li"},(0,i.yg)("li",{parentName:"ul"},"If Relays and Drivers are deployed in the host machine:",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre"},"MEMBER_CREDENTIAL_FOLDER=<PATH-TO-WEAVER>/samples/fabric/fabric-cli/src/data/credentials\nDEFAULT_APPLICATION_CHAINCODE=<chaincode-name>\nDEFAULT_APPLICATION_FUNC=<function-name>\nCONFIG_PATH=./config.json\nCHAINCODE_PATH=./chaincode.json\n"))),(0,i.yg)("li",{parentName:"ul"},"If Relays and Drivers are deployed in the Docker containers:",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre"},"MEMBER_CREDENTIAL_FOLDER=<PATH-TO-WEAVER>/samples/fabric/fabric-cli/src/data/credentials_docker\nDEFAULT_APPLICATION_CHAINCODE=<chaincode-name>\nDEFAULT_APPLICATION_FUNC=<function-name>\nCONFIG_PATH=./config.json\nCHAINCODE_PATH=./chaincode.json\n"))),(0,i.yg)("li",{parentName:"ul"},"In each case, replace ",(0,i.yg)("inlineCode",{parentName:"li"},"<PATH-TO-WEAVER>")," with the absolute path location of your clone of Weaver and ",(0,i.yg)("inlineCode",{parentName:"li"},"<chaincode-name>")," with the name of the deployed chaincode, either ",(0,i.yg)("inlineCode",{parentName:"li"},"simplestate")," or ",(0,i.yg)("inlineCode",{parentName:"li"},"simplestatewithacl"),"."),(0,i.yg)("li",{parentName:"ul"},"If ",(0,i.yg)("inlineCode",{parentName:"li"},"simplestate")," is deployed, set ",(0,i.yg)("inlineCode",{parentName:"li"},"<function-name>")," to ",(0,i.yg)("inlineCode",{parentName:"li"},"Create"),", and if ",(0,i.yg)("inlineCode",{parentName:"li"},"simplestatewithacl")," if deployed, set ",(0,i.yg)("inlineCode",{parentName:"li"},"<function-name>")," to ",(0,i.yg)("inlineCode",{parentName:"li"},"CreateFromRemote"),"."),(0,i.yg)("li",{parentName:"ul"},"Leave the default values unchanged for the other parameters."))),(0,i.yg)("li",{parentName:"ul"},"Run the following command:",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli env set-file ./.env\n")))),(0,i.yg)("table",null,(0,i.yg)("thead",{parentName:"table"},(0,i.yg)("tr",{parentName:"thead"},(0,i.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,i.yg)("tbody",{parentName:"table"},(0,i.yg)("tr",{parentName:"tbody"},(0,i.yg)("td",{parentName:"tr",align:"left"},"If the ",(0,i.yg)("inlineCode",{parentName:"td"},"CONFIG_PATH")," environment variable is omitted from ",(0,i.yg)("inlineCode",{parentName:"td"},".env"),", then you must also run:",(0,i.yg)("br",null),(0,i.yg)("inlineCode",{parentName:"td"},"./bin/fabric-cli config set-file ./config.json"))))),(0,i.yg)("h4",{id:"bootstrapping-network-and-application-state"},"Bootstrapping Network and Application State"),(0,i.yg)("p",null,"Finally, to prepare both ",(0,i.yg)("inlineCode",{parentName:"p"},"network1")," and ",(0,i.yg)("inlineCode",{parentName:"p"},"network2")," for interoperation, run:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli configure all network1 network2\n")),(0,i.yg)("p",null,"If Fabric networks were launched with 2 organizations, run:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli configure all network1 network2 --num-orgs=2\n")),(0,i.yg)("p",null,"Instead, if you launched only one of the two Fabric networks, run the following after replacing ",(0,i.yg)("inlineCode",{parentName:"p"},"<network-id>")," with either ",(0,i.yg)("inlineCode",{parentName:"p"},"network1")," or ",(0,i.yg)("inlineCode",{parentName:"p"},"network2"),", and ",(0,i.yg)("inlineCode",{parentName:"p"},"<1/2>")," with number of organizations in the network:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli configure all <network-id> --num-orgs=<1/2>\n")),(0,i.yg)("p",null,(0,i.yg)("strong",{parentName:"p"},"Wait for at least 5 minutes before moving on to the next step (testing interoperability modes) to allow the networks' IIN Agents to sync their respective memberships (which occur after every 5 minutes by default).")),(0,i.yg)("p",null,(0,i.yg)("strong",{parentName:"p"},"Optionally"),", fabric-cli can be used to trigger sync manually by running following command: "),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli configure membership --local-network=network1 --target-network=network2 --iin-agent-endpoint=localhost:9500\n")),(0,i.yg)("p",null,"This command syncs ",(0,i.yg)("inlineCode",{parentName:"p"},"network2"),"'s membership (target-network) in ",(0,i.yg)("inlineCode",{parentName:"p"},"network1")," (local-network) using IIN Agent of ",(0,i.yg)("inlineCode",{parentName:"p"},"Org1MSP")," as initiator. Similarly ",(0,i.yg)("inlineCode",{parentName:"p"},"network1"),"'s membership can be synced to ",(0,i.yg)("inlineCode",{parentName:"p"},"network2"),"'s ledger by running:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli configure membership --local-network=network2 --target-network=network1 --iin-agent-endpoint=localhost:9501\n")),(0,i.yg)("p",null,"Wait for 20-30 seconds after above commands to allow IIN Agents to finish the sync."),(0,i.yg)("h3",{id:"initializing-the-corda-networks"},"Initializing the Corda Networks"),(0,i.yg)("p",null,"Once the Corda networks are launched, the client applications (built earlier) needs to be exercised to generate network (ledger) state in preparation to test interoperation flows."),(0,i.yg)("h4",{id:"bootstrapping-networks-and-application-states"},"Bootstrapping Networks and Application States"),(0,i.yg)("p",null,"Just as we did for either Fabric network, the Corda network ledger (or ",(0,i.yg)("em",{parentName:"p"},"vault")," on each node) must be initialized with access control policies, verification policies, and security group information for the two Fabric networks. Further, sample key-value pairs need to be recorded so we can later share them with a Fabric network via an interoperation flow."),(0,i.yg)("p",null,"Bootstrap the Corda networks and application states as follows (",(0,i.yg)("em",{parentName:"p"},"the following instructions will initialize either or both Corda networks, depending on which of those are up and running"),"):"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},"Navigate to the ",(0,i.yg)("inlineCode",{parentName:"li"},"samples/corda/corda-simple-application")," folder."),(0,i.yg)("li",{parentName:"ul"},"Run the following: ",(0,i.yg)("ul",{parentName:"li"},(0,i.yg)("li",{parentName:"ul"},"If Relays and Drivers are deployed in the host machine:",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"make initialise-vault\n"))),(0,i.yg)("li",{parentName:"ul"},"If Relays and Drivers are deployed in the Docker containers:",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"make initialise-vault-docker\n")),"Even upon successful execution (as indicated by the console output), you may see errors of the following form:")),(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre"},"[ERROR] 07:51:17.206 [epollEventLoopGroup-19-1] client.exceptionCaught - AMQ214015: Failed to execute connection life cycle listener\njava.util.concurrent.RejectedExecutionException: Task org.apache.activemq.artemis.utils.actors.ProcessorBase$$Lambda$34/681158875@666df796 rejected from java.util.concurrent.ThreadPoolExecutor@236f653f[Terminated, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 6]\n at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063) ~[?:1.8.0_402]\n..........\n")),"You can ignore these as they are transient errors that don't impact the operations.")),(0,i.yg)("h3",{id:"next-steps"},"Next Steps"),(0,i.yg)("p",null,"The test networks are now configured and their ledgers are initialized. You can now run the ",(0,i.yg)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/data-sharing"},"data sharing flows"),"."),(0,i.yg)("h2",{id:"preparation-for-asset-exchange"},"Preparation for Asset Exchange"),(0,i.yg)("p",null,"Follow the below instructions to prepare your networks for asset exchange tests."),(0,i.yg)("h3",{id:"initializing-the-fabric-networks-1"},"Initializing the Fabric Networks"),(0,i.yg)("p",null,"We use the Fabric CLI (",(0,i.yg)("inlineCode",{parentName:"p"},"fabric-cli"),") built earlier (in ",(0,i.yg)("inlineCode",{parentName:"p"},"samples/fabric/fabric-cli")," for the Node.js version and ",(0,i.yg)("inlineCode",{parentName:"p"},"samples/fabric/go-cli")," for the Golang version) for this purpose."),(0,i.yg)("h4",{id:"configuring-the-fabric-cli-1"},"Configuring the Fabric CLI"),(0,i.yg)("p",null,"The ledgers must be populated with sample key-value pairs for testing interoperation flows, scoped by the sample application chaincode."),(0,i.yg)("p",null,"Prepare ",(0,i.yg)("inlineCode",{parentName:"p"},"fabric-cli")," for configuration suitably as follows."),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},"Navigate to the ",(0,i.yg)("inlineCode",{parentName:"li"},"samples/fabric/fabric-cli")," (for the Node.js version) or the ",(0,i.yg)("inlineCode",{parentName:"li"},"samples/fabric/go-cli")," (for the Golang version) folder."),(0,i.yg)("li",{parentName:"ul"},"Create a ",(0,i.yg)("inlineCode",{parentName:"li"},"config.json")," file by copying the ",(0,i.yg)("inlineCode",{parentName:"li"},"config.template.json")," and setting (or adding or removing) suitable values:",(0,i.yg)("ul",{parentName:"li"},(0,i.yg)("li",{parentName:"ul"},"For each network, the relay port and connection profile paths are specified using the keys ",(0,i.yg)("inlineCode",{parentName:"li"},"relayPort")," and ",(0,i.yg)("inlineCode",{parentName:"li"},"connProfilePath")," respectively.",(0,i.yg)("ul",{parentName:"li"},(0,i.yg)("li",{parentName:"ul"},"Replace ",(0,i.yg)("inlineCode",{parentName:"li"},"<PATH-TO-WEAVER>")," with the absolute path location of the ",(0,i.yg)("inlineCode",{parentName:"li"},"weaver-dlt-interoperability")," clone folder."),(0,i.yg)("li",{parentName:"ul"},"Set the ",(0,i.yg)("inlineCode",{parentName:"li"},"chaincode")," attribute in each network to the deployed chaincode name (",(0,i.yg)("inlineCode",{parentName:"li"},"simpleasset")," or ",(0,i.yg)("inlineCode",{parentName:"li"},"simpleassetandinterop")," or ",(0,i.yg)("inlineCode",{parentName:"li"},"simpleassettransfer"),")."),(0,i.yg)("li",{parentName:"ul"},"Otherwise, leave the default values unchanged."))))),(0,i.yg)("li",{parentName:"ul"},"Create a ",(0,i.yg)("inlineCode",{parentName:"li"},".env")," file by copying ",(0,i.yg)("inlineCode",{parentName:"li"},".env.template")," and setting following parameter values:",(0,i.yg)("ul",{parentName:"li"},(0,i.yg)("li",{parentName:"ul"},"If Relays and Drivers are deployed in the host machine:",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre"},"MEMBER_CREDENTIAL_FOLDER=<PATH-TO-WEAVER>/samples/fabric/fabric-cli/src/data/credentials\nCONFIG_PATH=./config.json\n"))),(0,i.yg)("li",{parentName:"ul"},"If Relays and Drivers are deployed in the Docker containers:",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre"},"MEMBER_CREDENTIAL_FOLDER=<PATH-TO-WEAVER>/samples/fabric/fabric-cli/src/data/credentials_docker\nCONFIG_PATH=./config.json\n"))),(0,i.yg)("li",{parentName:"ul"},"In each case, replace ",(0,i.yg)("inlineCode",{parentName:"li"},"<PATH-TO-WEAVER>")," with the absolute path location of your clone of Weaver."),(0,i.yg)("li",{parentName:"ul"},"Leave the default values unchanged for the other parameters."))),(0,i.yg)("li",{parentName:"ul"},"Run the following command:",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli env set-file ./.env\n")))),(0,i.yg)("table",null,(0,i.yg)("thead",{parentName:"table"},(0,i.yg)("tr",{parentName:"thead"},(0,i.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,i.yg)("tbody",{parentName:"table"},(0,i.yg)("tr",{parentName:"tbody"},(0,i.yg)("td",{parentName:"tr",align:"left"},"If the ",(0,i.yg)("inlineCode",{parentName:"td"},"CONFIG_PATH")," environment variable is omitted from ",(0,i.yg)("inlineCode",{parentName:"td"},".env"),", then you must also run:",(0,i.yg)("br",null),(0,i.yg)("inlineCode",{parentName:"td"},"./bin/fabric-cli config set-file ./config.json"))))),(0,i.yg)("h4",{id:"bootstrapping-network-and-application-state-1"},"Bootstrapping Network and Application State"),(0,i.yg)("p",null,"Finally, to prepare both ",(0,i.yg)("inlineCode",{parentName:"p"},"network1")," and ",(0,i.yg)("inlineCode",{parentName:"p"},"network2")," for interoperation, run:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./scripts/initAsset.sh\n")),(0,i.yg)("h3",{id:"initializing-the-corda-networks-1"},"Initializing the Corda Networks"),(0,i.yg)("p",null,"Corda Network needs to be initialized with assets for asset-exchange to be performed:\nBootstrap the Corda network and application states as follows:"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},"Navigate to the ",(0,i.yg)("inlineCode",{parentName:"li"},"samples/corda/corda-simple-application")," folder."),(0,i.yg)("li",{parentName:"ul"},"Run the following: ",(0,i.yg)("ul",{parentName:"li"},(0,i.yg)("li",{parentName:"ul"},"For ",(0,i.yg)("inlineCode",{parentName:"li"},"cordaSimpleApplication")," app, run:",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre"},"./scripts/initAsset.sh\n")))))),(0,i.yg)("h3",{id:"initializing-the-besu-networks"},"Initializing the Besu Networks"),(0,i.yg)("p",null,"Let's assume that ",(0,i.yg)("inlineCode",{parentName:"p"},"network1")," can either manage NFT ",(0,i.yg)("inlineCode",{parentName:"p"},"AliceERC721")," or Hybrid ",(0,i.yg)("inlineCode",{parentName:"p"},"AliceERC1155")," tokens, while ",(0,i.yg)("inlineCode",{parentName:"p"},"network2")," manages fungible ",(0,i.yg)("inlineCode",{parentName:"p"},"BobERC20")," tokens. Here we use account ",(0,i.yg)("inlineCode",{parentName:"p"},"1")," for Alice and account ",(0,i.yg)("inlineCode",{parentName:"p"},"2")," for Bob in both neworks. To prepare Besu networks for asset exchange, navigate to the ",(0,i.yg)("inlineCode",{parentName:"p"},"samples/besu/besu-cli")," and then follow the steps in next subsections."),(0,i.yg)("h4",{id:"configuring-the-besu-cli"},"Configuring the Besu-CLI"),(0,i.yg)("p",null,"Create a ",(0,i.yg)("inlineCode",{parentName:"p"},"config.json")," file by copying the ",(0,i.yg)("inlineCode",{parentName:"p"},"config.template.json"),", keep the default values for managing ",(0,i.yg)("inlineCode",{parentName:"p"},"AliceERC721")," tokens in ",(0,i.yg)("inlineCode",{parentName:"p"},"network1")," and ",(0,i.yg)("inlineCode",{parentName:"p"},"BobERC20")," tokens in ",(0,i.yg)("inlineCode",{parentName:"p"},"network2"),".\nIf you want to change the token type used in the ",(0,i.yg)("inlineCode",{parentName:"p"},"network1")," to Hybrid ",(0,i.yg)("inlineCode",{parentName:"p"},"AliceERC1155")," tokens, in ",(0,i.yg)("inlineCode",{parentName:"p"},"config.json")," update ",(0,i.yg)("inlineCode",{parentName:"p"},"tokenContract")," field with value ",(0,i.yg)("inlineCode",{parentName:"p"},'"../simpleasset/build/contracts/AliceERC1155.json".')),(0,i.yg)("h4",{id:"bootstrapping-network-and-application-state-2"},"Bootstrapping Network and Application State"),(0,i.yg)("p",null,"Finally, to prepare both ",(0,i.yg)("inlineCode",{parentName:"p"},"network1")," and ",(0,i.yg)("inlineCode",{parentName:"p"},"network2")," for interoperation, run:"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},"If you wish to test the default exchange (ERC-20 tokens for ERC-721 tokens), run::",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./scripts/initAsset.sh\n")),"This will issue ",(0,i.yg)("inlineCode",{parentName:"li"},"100 BobERC20")," tokens to each account in ",(0,i.yg)("inlineCode",{parentName:"li"},"network2")," and ",(0,i.yg)("inlineCode",{parentName:"li"},"AliceERC721")," token with id ",(0,i.yg)("inlineCode",{parentName:"li"},"0")," to ",(0,i.yg)("inlineCode",{parentName:"li"},"Alice")," and id ",(0,i.yg)("inlineCode",{parentName:"li"},"1")," to ",(0,i.yg)("inlineCode",{parentName:"li"},"Bob")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"network1"),"."),(0,i.yg)("li",{parentName:"ul"},"Instead, if you wish to test Alice's exchange of ERC-1155 tokens for Bob's ERC-20 tokens, run:",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./scripts/initAsset.sh hybrid\n")),"This will issue ",(0,i.yg)("inlineCode",{parentName:"li"},"100 BobERC20")," tokens to each account in ",(0,i.yg)("inlineCode",{parentName:"li"},"network2")," and ",(0,i.yg)("inlineCode",{parentName:"li"},"100 AliceERC1155")," tokens with id ",(0,i.yg)("inlineCode",{parentName:"li"},"0")," to ",(0,i.yg)("inlineCode",{parentName:"li"},"Alice")," and id ",(0,i.yg)("inlineCode",{parentName:"li"},"1")," to ",(0,i.yg)("inlineCode",{parentName:"li"},"Bob")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"network1"),".")),(0,i.yg)("h3",{id:"next-steps-1"},"Next Steps"),(0,i.yg)("p",null,"The test networks are now configured and their ledgers are initialized. You can now run the ",(0,i.yg)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview"},"asset exchange flows"),"."),(0,i.yg)("h2",{id:"preparation-for-asset-transfer"},"Preparation for Asset Transfer"),(0,i.yg)("p",null,"Follow the below instructions to prepare your networks for asset transfer tests."),(0,i.yg)("h3",{id:"initializing-the-fabric-networks-2"},"Initializing the Fabric Networks"),(0,i.yg)("p",null,"We use the Fabric CLI (",(0,i.yg)("inlineCode",{parentName:"p"},"fabric-cli"),") built earlier (in ",(0,i.yg)("inlineCode",{parentName:"p"},"samples/fabric/fabric-cli")," for the Node.js version and ",(0,i.yg)("inlineCode",{parentName:"p"},"samples/fabric/go-cli")," for the Golang version) for this purpose."),(0,i.yg)("h4",{id:"configuring-the-fabric-cli-2"},"Configuring the Fabric CLI"),(0,i.yg)("p",null,"During bootstrap, the ledgers in both ",(0,i.yg)("inlineCode",{parentName:"p"},"network1")," and ",(0,i.yg)("inlineCode",{parentName:"p"},"network2")," must be populated with the following information scoped by the interoperation chaincode:"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},"Access control policies governing requests from foreign networks"),(0,i.yg)("li",{parentName:"ul"},"Security group info for foreign networks (i.e., identities of network units and their membership providers' certificate chains)"),(0,i.yg)("li",{parentName:"ul"},"Verification policies for proofs supplied by foreign networks\nKnowledge of foreign networks that must be configured in this stage is as follows:"),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("inlineCode",{parentName:"li"},"network1")," has policies and security group info for ",(0,i.yg)("inlineCode",{parentName:"li"},"network2")," and ",(0,i.yg)("inlineCode",{parentName:"li"},"Corda_Network")),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("inlineCode",{parentName:"li"},"network2")," has policies and security group info for ",(0,i.yg)("inlineCode",{parentName:"li"},"network1")," and ",(0,i.yg)("inlineCode",{parentName:"li"},"Corda_Network"),"\n(",(0,i.yg)("em",{parentName:"li"},"The Corda sample application doesn't support asset transfer yet, but there is no harm in including it above."),")\nThe ledgers must also be populated with sample key-value pairs for testing interoperation flows, scoped by the sample application chaincode.")),(0,i.yg)("p",null,"Prepare ",(0,i.yg)("inlineCode",{parentName:"p"},"fabric-cli")," for configuration suitably as follows."),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},"Navigate to the ",(0,i.yg)("inlineCode",{parentName:"li"},"samples/fabric/fabric-cli")," folder (",(0,i.yg)("em",{parentName:"li"},"the Go CLI doesn't support asset transfer yet"),")."),(0,i.yg)("li",{parentName:"ul"},"Create a ",(0,i.yg)("inlineCode",{parentName:"li"},"config.json")," file by copying the ",(0,i.yg)("inlineCode",{parentName:"li"},"config.template.json")," and setting (or adding or removing) suitable values:",(0,i.yg)("ul",{parentName:"li"},(0,i.yg)("li",{parentName:"ul"},"For each network, the relay port and connection profile paths are specified using the keys ",(0,i.yg)("inlineCode",{parentName:"li"},"relayPort")," and ",(0,i.yg)("inlineCode",{parentName:"li"},"connProfilePath")," respectively.",(0,i.yg)("ul",{parentName:"li"},(0,i.yg)("li",{parentName:"ul"},"Replace ",(0,i.yg)("inlineCode",{parentName:"li"},"<PATH-TO-WEAVER>")," with the absolute path location of the ",(0,i.yg)("inlineCode",{parentName:"li"},"weaver-dlt-interoperability")," clone folder."),(0,i.yg)("li",{parentName:"ul"},"Set the ",(0,i.yg)("inlineCode",{parentName:"li"},"chaincode")," attribute in each network to ",(0,i.yg)("inlineCode",{parentName:"li"},"simpleassettransfer"),"."),(0,i.yg)("li",{parentName:"ul"},"Set the ",(0,i.yg)("inlineCode",{parentName:"li"},"aclPolicyPrincipalType")," attribute in ",(0,i.yg)("inlineCode",{parentName:"li"},"network2")," to ",(0,i.yg)("inlineCode",{parentName:"li"},"ca"),"."),(0,i.yg)("li",{parentName:"ul"},"Otherwise, leave the default values unchanged."))))),(0,i.yg)("li",{parentName:"ul"},"Create ",(0,i.yg)("inlineCode",{parentName:"li"},"remote-network-config.json")," file by copying ",(0,i.yg)("inlineCode",{parentName:"li"},"remote-network-config.json.template"),". Use default values if relays and drivers are deployed in the host machine; else if they are deployed in Docker, update as follows:",(0,i.yg)("ul",{parentName:"li"},(0,i.yg)("li",{parentName:"ul"},"Update value for ",(0,i.yg)("inlineCode",{parentName:"li"},"relayEndpoint")," for ",(0,i.yg)("inlineCode",{parentName:"li"},"network1")," as ",(0,i.yg)("inlineCode",{parentName:"li"},"relay-network1:9080"),"."),(0,i.yg)("li",{parentName:"ul"},"Update value for ",(0,i.yg)("inlineCode",{parentName:"li"},"relayEndpoint")," for ",(0,i.yg)("inlineCode",{parentName:"li"},"network2")," as ",(0,i.yg)("inlineCode",{parentName:"li"},"relay-network2:9083"),"."),(0,i.yg)("li",{parentName:"ul"},"Update value for ",(0,i.yg)("inlineCode",{parentName:"li"},"relayEndpoint")," for ",(0,i.yg)("inlineCode",{parentName:"li"},"Corda_Network")," as ",(0,i.yg)("inlineCode",{parentName:"li"},"relay-corda:9081"),"."),(0,i.yg)("li",{parentName:"ul"},"Update value for ",(0,i.yg)("inlineCode",{parentName:"li"},"relayEndpoint")," for ",(0,i.yg)("inlineCode",{parentName:"li"},"Corda_Network2")," as ",(0,i.yg)("inlineCode",{parentName:"li"},"relay-corda2:9082"),"."),(0,i.yg)("li",{parentName:"ul"},"Update value for ",(0,i.yg)("inlineCode",{parentName:"li"},"partyEndPoint")," for ",(0,i.yg)("inlineCode",{parentName:"li"},"Corda_Network")," as ",(0,i.yg)("inlineCode",{parentName:"li"},"corda_partya_1:10003"),"."),(0,i.yg)("li",{parentName:"ul"},"Update value for ",(0,i.yg)("inlineCode",{parentName:"li"},"partyEndPoint")," for ",(0,i.yg)("inlineCode",{parentName:"li"},"Corda_Network2")," as ",(0,i.yg)("inlineCode",{parentName:"li"},"corda_network2_partya_1:10003"),"."))),(0,i.yg)("li",{parentName:"ul"},"Create ",(0,i.yg)("inlineCode",{parentName:"li"},"chaincode.json")," file by copying ",(0,i.yg)("inlineCode",{parentName:"li"},"chaincode.json.template"),". Keep the default values unchanged."),(0,i.yg)("li",{parentName:"ul"},"Create a ",(0,i.yg)("inlineCode",{parentName:"li"},".env")," file by copying ",(0,i.yg)("inlineCode",{parentName:"li"},".env.template")," and setting the following parameter values:",(0,i.yg)("ul",{parentName:"li"},(0,i.yg)("li",{parentName:"ul"},"If Relays and Drivers are deployed in the host machine:",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre"},"MEMBER_CREDENTIAL_FOLDER=<PATH-TO-WEAVER>/samples/fabric/fabric-cli/src/data/credentials\nDEFAULT_APPLICATION_CHAINCODE=simpleassettransfer\nCONFIG_PATH=./config.json\nREMOTE_CONFIG_PATH=./remote-network-config.json\nCHAINCODE_PATH=./chaincode.json\n"))),(0,i.yg)("li",{parentName:"ul"},"If Relays and Drivers are deployed in the Docker containers:",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre"},"MEMBER_CREDENTIAL_FOLDER=<PATH-TO-WEAVER>/samples/fabric/fabric-cli/src/data/credentials_docker\nDEFAULT_APPLICATION_CHAINCODE=simpleassettransfer\nCONFIG_PATH=./config.json\nREMOTE_CONFIG_PATH=./remote-network-config.json\nCHAINCODE_PATH=./chaincode.json\n"))),(0,i.yg)("li",{parentName:"ul"},"In each case, replace ",(0,i.yg)("inlineCode",{parentName:"li"},"<PATH-TO-WEAVER>")," with the absolute path location of your clone of Weaver."),(0,i.yg)("li",{parentName:"ul"},"Leave the default values unchanged for the other parameters."))),(0,i.yg)("li",{parentName:"ul"},"Run the following command:",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre"},"./bin/fabric-cli env set-file ./.env\n")))),(0,i.yg)("table",null,(0,i.yg)("thead",{parentName:"table"},(0,i.yg)("tr",{parentName:"thead"},(0,i.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,i.yg)("tbody",{parentName:"table"},(0,i.yg)("tr",{parentName:"tbody"},(0,i.yg)("td",{parentName:"tr",align:"left"},"If the ",(0,i.yg)("inlineCode",{parentName:"td"},"CONFIG_PATH")," environment variable is omitted from ",(0,i.yg)("inlineCode",{parentName:"td"},".env"),", then you must also run:",(0,i.yg)("br",null),(0,i.yg)("inlineCode",{parentName:"td"},"./bin/fabric-cli config set-file ./config.json"))))),(0,i.yg)("h4",{id:"bootstrapping-network-and-application-state-3"},"Bootstrapping Network and Application State"),(0,i.yg)("p",null,"Create appropriate access control and verification policies for ",(0,i.yg)("inlineCode",{parentName:"p"},"network1")," and ",(0,i.yg)("inlineCode",{parentName:"p"},"network2")," by running:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli configure create all --local-network=network1\n./bin/fabric-cli configure create all --local-network=network2\n")),(0,i.yg)("p",null,"Load access control and verification policies onto the ledgers of ",(0,i.yg)("inlineCode",{parentName:"p"},"network1")," and ",(0,i.yg)("inlineCode",{parentName:"p"},"network2")," by running (replace ",(0,i.yg)("inlineCode",{parentName:"p"},"<1/2>")," with number of organizations in the network):"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli configure network --local-network=network1 --num-orgs=<1/2>\n./bin/fabric-cli configure network --local-network=network2 --num-orgs=<1/2>\n")),(0,i.yg)("p",null,(0,i.yg)("strong",{parentName:"p"},"Wait for at least 5 minutes before moving on to the next step (testing interoperability modes) to allow the networks' IIN Agents to sync their respective memberships (which occur after every 5 minutes by default).")),(0,i.yg)("p",null,(0,i.yg)("strong",{parentName:"p"},"Optionally"),", fabric-cli can be used to trigger sync manually by running following command: "),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli configure membership --local-network=network1 --target-network=network2 --iin-agent-endpoint=localhost:9500\n")),(0,i.yg)("p",null,"This command syncs ",(0,i.yg)("inlineCode",{parentName:"p"},"network2"),"'s membership (target-network) in ",(0,i.yg)("inlineCode",{parentName:"p"},"network1")," (local-network) using IIN Agent of ",(0,i.yg)("inlineCode",{parentName:"p"},"Org1MSP")," as initiator. Similarly ",(0,i.yg)("inlineCode",{parentName:"p"},"network1"),"'s membership can be synced to ",(0,i.yg)("inlineCode",{parentName:"p"},"network2"),"'s ledger by running:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli configure membership --local-network=network2 --target-network=network1 --iin-agent-endpoint=localhost:9501\n")),(0,i.yg)("p",null,"Wait for 20-30 seconds after above commands to allow IIN Agents to finish the sync."),(0,i.yg)("p",null,"Initialize bond and token asset states and ownerships on the ",(0,i.yg)("inlineCode",{parentName:"p"},"network1")," ledger by running the following (this step will also create a user ",(0,i.yg)("inlineCode",{parentName:"p"},"alice")," in ",(0,i.yg)("inlineCode",{parentName:"p"},"network1")," and a user ",(0,i.yg)("inlineCode",{parentName:"p"},"bob")," in ",(0,i.yg)("inlineCode",{parentName:"p"},"network2"),"):"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./scripts/initAssetsForTransfer.sh\n")),(0,i.yg)("h3",{id:"initializing-the-corda-networks-2"},"Initializing the Corda Networks"),(0,i.yg)("p",null,"Once the Corda networks (",(0,i.yg)("inlineCode",{parentName:"p"},"Corda_Network")," and ",(0,i.yg)("inlineCode",{parentName:"p"},"Corda_Network2"),") are launched, the client applications (built earlier) needs to be exercised to generate ledger state in both exporting/source and importing/destination networks in preparation to test asset transfer interoperation flows."),(0,i.yg)("h4",{id:"bootstrapping-networks-and-application-states-1"},"Bootstrapping Networks and Application States"),(0,i.yg)("p",null,"The Corda network ledger (or ",(0,i.yg)("em",{parentName:"p"},"vault")," on each node) must be initialized with access control policies, verification policies, and security group information for the other networks (two Fabric networks and other Corda network)."),(0,i.yg)("p",null,"Bootstrap the Corda networks and application states as follows (",(0,i.yg)("em",{parentName:"p"},"the following instructions will initialize either or both Corda networks, depending on which of those are up and running"),"):"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},"Navigate to the ",(0,i.yg)("inlineCode",{parentName:"li"},"samples/corda/corda-simple-application")," folder."),(0,i.yg)("li",{parentName:"ul"},"Run the following:",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"cp clients/src/main/resources/config/remote-network-config.json.template clients/src/main/resources/config/remote-network-config.json\n")),"Use default values in ",(0,i.yg)("inlineCode",{parentName:"li"},"remote-network-config.json")," if relays and drivers are deployed in the host machine; else if they are deployed in Docker, update as follows:",(0,i.yg)("ul",{parentName:"li"},(0,i.yg)("li",{parentName:"ul"},"Update value for ",(0,i.yg)("inlineCode",{parentName:"li"},"relayEndpoint")," for ",(0,i.yg)("inlineCode",{parentName:"li"},"network1")," as ",(0,i.yg)("inlineCode",{parentName:"li"},"relay-network1:9080"),"."),(0,i.yg)("li",{parentName:"ul"},"Update value for ",(0,i.yg)("inlineCode",{parentName:"li"},"relayEndpoint")," for ",(0,i.yg)("inlineCode",{parentName:"li"},"network2")," as ",(0,i.yg)("inlineCode",{parentName:"li"},"relay-network2:9083"),"."),(0,i.yg)("li",{parentName:"ul"},"Update value for ",(0,i.yg)("inlineCode",{parentName:"li"},"relayEndpoint")," for ",(0,i.yg)("inlineCode",{parentName:"li"},"Corda_Network")," as ",(0,i.yg)("inlineCode",{parentName:"li"},"relay-corda:9081"),"."),(0,i.yg)("li",{parentName:"ul"},"Update value for ",(0,i.yg)("inlineCode",{parentName:"li"},"relayEndpoint")," for ",(0,i.yg)("inlineCode",{parentName:"li"},"Corda_Network2")," as ",(0,i.yg)("inlineCode",{parentName:"li"},"relay-corda2:9082"),"."),(0,i.yg)("li",{parentName:"ul"},"Update value for ",(0,i.yg)("inlineCode",{parentName:"li"},"partyEndPoint")," for ",(0,i.yg)("inlineCode",{parentName:"li"},"Corda_Network")," as ",(0,i.yg)("inlineCode",{parentName:"li"},"corda_partya_1:10003"),"."),(0,i.yg)("li",{parentName:"ul"},"Update value for ",(0,i.yg)("inlineCode",{parentName:"li"},"partyEndPoint")," for ",(0,i.yg)("inlineCode",{parentName:"li"},"Corda_Network2")," as ",(0,i.yg)("inlineCode",{parentName:"li"},"corda_network2_partya_1:10003"),"."))),(0,i.yg)("li",{parentName:"ul"},"Run the following: ",(0,i.yg)("ul",{parentName:"li"},(0,i.yg)("li",{parentName:"ul"},"If Relays and Drivers are deployed in the host machine:",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"make initialise-vault-asset-transfer\n"))),(0,i.yg)("li",{parentName:"ul"},"If Relays and Drivers are deployed in the Docker containers:",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"make initialise-vault-asset-transfer-docker\n")),"Even upon successful execution (as indicated by the console output), you may see errors of the following form:")),(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre"},"[ERROR] 07:51:17.206 [epollEventLoopGroup-19-1] client.exceptionCaught - AMQ214015: Failed to execute connection life cycle listener\njava.util.concurrent.RejectedExecutionException: Task org.apache.activemq.artemis.utils.actors.ProcessorBase$$Lambda$34/681158875@666df796 rejected from java.util.concurrent.ThreadPoolExecutor@236f653f[Terminated, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 6]\n at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063) ~[?:1.8.0_402]\n..........\n")),"You can ignore these as they are transient errors that don't impact the operations.")),(0,i.yg)("h3",{id:"next-steps-2"},"Next Steps"),(0,i.yg)("p",null,"The test networks are now configured and their ledgers are initialized. You can now run the ",(0,i.yg)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-transfer"},"asset transfer flows"),"."))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/b379f194.15c4c4e5.js b/assets/js/b379f194.d678cc4c.js similarity index 79% rename from assets/js/b379f194.15c4c4e5.js rename to assets/js/b379f194.d678cc4c.js index 277d26dbb..d8f4bb94c 100644 --- a/assets/js/b379f194.15c4c4e5.js +++ b/assets/js/b379f194.d678cc4c.js @@ -1 +1 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[2136],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>p});var n=r(7294);function i(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function o(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?a(Object(r),!0).forEach((function(t){i(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):a(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function s(e,t){if(null==e)return{};var r,n,i=function(e,t){if(null==e)return{};var r,n,i={},a=Object.keys(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||(i[r]=e[r]);return i}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(i[r]=e[r])}return i}var c=n.createContext({}),l=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},u=function(e){var t=l(e.components);return n.createElement(c.Provider,{value:t},e.children)},d="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},h=n.forwardRef((function(e,t){var r=e.components,i=e.mdxType,a=e.originalType,c=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),d=l(r),h=i,p=d["".concat(c,".").concat(h)]||d[h]||m[h]||a;return r?n.createElement(p,o(o({ref:t},u),{},{components:r})):n.createElement(p,o({ref:t},u))}));function p(e,t){var r=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var a=r.length,o=new Array(a);o[0]=h;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[d]="string"==typeof e?e:i,o[1]=s;for(var l=2;l<a;l++)o[l]=r[l];return n.createElement.apply(null,o)}return n.createElement.apply(null,r)}h.displayName="MDXCreateElement"},2895:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>m,frontMatter:()=>a,metadata:()=>s,toc:()=>l});var n=r(7462),i=(r(7294),r(3905));const a={id:"overview",title:"Overview"},o=void 0,s={unversionedId:"external/architecture-and-design/overview",id:"external/architecture-and-design/overview",title:"Overview",description:"\x3c!--",source:"@site/docs/external/architecture-and-design/overview.md",sourceDirName:"external/architecture-and-design",slug:"/external/architecture-and-design/overview",permalink:"/weaver-dlt-interoperability/docs/external/architecture-and-design/overview",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/architecture-and-design/overview.md",tags:[],version:"current",frontMatter:{id:"overview",title:"Overview"},sidebar:"Documentation",previous:{title:"Legacy Integration",permalink:"/weaver-dlt-interoperability/docs/external/user-stories/legacy-integration"},next:{title:"Relay",permalink:"/weaver-dlt-interoperability/docs/external/architecture-and-design/relay"}},c={},l=[{value:"Network",id:"network",level:2},{value:"Relay",id:"relay",level:2},{value:"Synchronous vs Asynchronous message communication",id:"synchronous-vs-asynchronous-message-communication",level:2},{value:"Message vs connection oriented communication",id:"message-vs-connection-oriented-communication",level:2}],u={toc:l},d="wrapper";function m(e){let{components:t,...a}=e;return(0,i.kt)(d,(0,n.Z)({},u,a,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"The below diagram shows a high level architecture diagram of the Weaver framework."),(0,i.kt)("p",null,(0,i.kt)("img",{src:r(5266).Z,width:"1572",height:"941"})),(0,i.kt)("h2",{id:"network"},"Network"),(0,i.kt)("p",null,"The networks in the system can be made up of various heterogenious technologies, including Hyperledger Fabric and Corda. Each network in the system needs to contain an interoperability (IOP) module that enables them to communicate with the relays."),(0,i.kt)("h2",{id:"relay"},"Relay"),(0,i.kt)("p",null,"The relays act as a conduit to facilitate communication of protocols between networks (e.g. data transfer, asset exchange etc). The roles of the relays are described in more detail in ",(0,i.kt)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/external/architecture-and-design/relay"},"relay"),"."),(0,i.kt)("h1",{id:"design-decisions"},"Design Decisions"),(0,i.kt)("p",null,"The high level design decisions that were made for the system are outlined here."),(0,i.kt)("h2",{id:"synchronous-vs-asynchronous-message-communication"},"Synchronous vs Asynchronous message communication"),(0,i.kt)("p",null,"We decided to go with an asynchronous message architecture. The primary reason for this is because requests can take an arbitary amount of time to respond, it is not practical for a synchronous message to wait that long for a reply. For example, obtaining a 12 block confirmation on the Bitcoin network can take about 2 hours."),(0,i.kt)("h2",{id:"message-vs-connection-oriented-communication"},"Message vs connection oriented communication"),(0,i.kt)("p",null,"We decided to go with a message oriented architecture. The primary reason for this is because it makes the system more fault tolerant. With a message oriented architecture the requester and responder don't need to be alive at the same time. For example, if the requestor crashes while the responder is processing the request, the communication is not interrupted since the responder will just send a message when it has finished processing the request. The design choice also enables the systen to be made more fault tolerant in the future by implementing message queues between components in the system."))}m.isMDXComponent=!0},5266:(e,t,r)=>{r.d(t,{Z:()=>n});const n=r.p+"assets/images/architecture_overview-7b33025d4ef4bce5161426ac77ec512a.png"}}]); \ No newline at end of file +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[6062],{5680:(e,t,r)=>{r.d(t,{xA:()=>u,yg:()=>p});var n=r(6540);function i(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function o(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?a(Object(r),!0).forEach((function(t){i(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):a(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function s(e,t){if(null==e)return{};var r,n,i=function(e,t){if(null==e)return{};var r,n,i={},a=Object.keys(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||(i[r]=e[r]);return i}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(i[r]=e[r])}return i}var c=n.createContext({}),l=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},u=function(e){var t=l(e.components);return n.createElement(c.Provider,{value:t},e.children)},d="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},h=n.forwardRef((function(e,t){var r=e.components,i=e.mdxType,a=e.originalType,c=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),d=l(r),h=i,p=d["".concat(c,".").concat(h)]||d[h]||m[h]||a;return r?n.createElement(p,o(o({ref:t},u),{},{components:r})):n.createElement(p,o({ref:t},u))}));function p(e,t){var r=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var a=r.length,o=new Array(a);o[0]=h;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[d]="string"==typeof e?e:i,o[1]=s;for(var l=2;l<a;l++)o[l]=r[l];return n.createElement.apply(null,o)}return n.createElement.apply(null,r)}h.displayName="MDXCreateElement"},1716:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>m,frontMatter:()=>a,metadata:()=>s,toc:()=>l});var n=r(8168),i=(r(6540),r(5680));const a={id:"overview",title:"Overview"},o=void 0,s={unversionedId:"external/architecture-and-design/overview",id:"external/architecture-and-design/overview",title:"Overview",description:"\x3c!--",source:"@site/docs/external/architecture-and-design/overview.md",sourceDirName:"external/architecture-and-design",slug:"/external/architecture-and-design/overview",permalink:"/weaver-dlt-interoperability/docs/external/architecture-and-design/overview",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/architecture-and-design/overview.md",tags:[],version:"current",frontMatter:{id:"overview",title:"Overview"},sidebar:"Documentation",previous:{title:"Legacy Integration",permalink:"/weaver-dlt-interoperability/docs/external/user-stories/legacy-integration"},next:{title:"Relay",permalink:"/weaver-dlt-interoperability/docs/external/architecture-and-design/relay"}},c={},l=[{value:"Network",id:"network",level:2},{value:"Relay",id:"relay",level:2},{value:"Synchronous vs Asynchronous message communication",id:"synchronous-vs-asynchronous-message-communication",level:2},{value:"Message vs connection oriented communication",id:"message-vs-connection-oriented-communication",level:2}],u={toc:l},d="wrapper";function m(e){let{components:t,...a}=e;return(0,i.yg)(d,(0,n.A)({},u,a,{components:t,mdxType:"MDXLayout"}),(0,i.yg)("p",null,"The below diagram shows a high level architecture diagram of the Weaver framework."),(0,i.yg)("p",null,(0,i.yg)("img",{src:r(9742).A,width:"1572",height:"941"})),(0,i.yg)("h2",{id:"network"},"Network"),(0,i.yg)("p",null,"The networks in the system can be made up of various heterogenious technologies, including Hyperledger Fabric and Corda. Each network in the system needs to contain an interoperability (IOP) module that enables them to communicate with the relays."),(0,i.yg)("h2",{id:"relay"},"Relay"),(0,i.yg)("p",null,"The relays act as a conduit to facilitate communication of protocols between networks (e.g. data transfer, asset exchange etc). The roles of the relays are described in more detail in ",(0,i.yg)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/external/architecture-and-design/relay"},"relay"),"."),(0,i.yg)("h1",{id:"design-decisions"},"Design Decisions"),(0,i.yg)("p",null,"The high level design decisions that were made for the system are outlined here."),(0,i.yg)("h2",{id:"synchronous-vs-asynchronous-message-communication"},"Synchronous vs Asynchronous message communication"),(0,i.yg)("p",null,"We decided to go with an asynchronous message architecture. The primary reason for this is because requests can take an arbitary amount of time to respond, it is not practical for a synchronous message to wait that long for a reply. For example, obtaining a 12 block confirmation on the Bitcoin network can take about 2 hours."),(0,i.yg)("h2",{id:"message-vs-connection-oriented-communication"},"Message vs connection oriented communication"),(0,i.yg)("p",null,"We decided to go with a message oriented architecture. The primary reason for this is because it makes the system more fault tolerant. With a message oriented architecture the requester and responder don't need to be alive at the same time. For example, if the requestor crashes while the responder is processing the request, the communication is not interrupted since the responder will just send a message when it has finished processing the request. The design choice also enables the systen to be made more fault tolerant in the future by implementing message queues between components in the system."))}m.isMDXComponent=!0},9742:(e,t,r)=>{r.d(t,{A:()=>n});const n=r.p+"assets/images/architecture_overview-7b33025d4ef4bce5161426ac77ec512a.png"}}]); \ No newline at end of file diff --git a/assets/js/b545330d.ea6ae7a5.js b/assets/js/b545330d.c1b451f5.js similarity index 91% rename from assets/js/b545330d.ea6ae7a5.js rename to assets/js/b545330d.c1b451f5.js index 4a2eb13f0..5704b066e 100644 --- a/assets/js/b545330d.ea6ae7a5.js +++ b/assets/js/b545330d.c1b451f5.js @@ -1 +1 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[6610],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>g});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function o(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?i(Object(r),!0).forEach((function(t){a(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):i(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function l(e,t){if(null==e)return{};var r,n,a=function(e,t){if(null==e)return{};var r,n,a={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var c=n.createContext({}),s=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},p=function(e){var t=s(e.components);return n.createElement(c.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},b=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,i=e.originalType,c=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),u=s(r),b=a,g=u["".concat(c,".").concat(b)]||u[b]||d[b]||i;return r?n.createElement(g,o(o({ref:t},p),{},{components:r})):n.createElement(g,o({ref:t},p))}));function g(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=r.length,o=new Array(i);o[0]=b;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l[u]="string"==typeof e?e:a,o[1]=l;for(var s=2;s<i;s++)o[s]=r[s];return n.createElement.apply(null,o)}return n.createElement.apply(null,r)}b.displayName="MDXCreateElement"},9270:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>d,frontMatter:()=>i,metadata:()=>l,toc:()=>s});var n=r(7462),a=(r(7294),r(3905));const i={id:"besu",title:"Hyperledger Besu"},o=void 0,l={unversionedId:"external/getting-started/enabling-weaver-network/besu",id:"external/getting-started/enabling-weaver-network/besu",title:"Hyperledger Besu",description:"\x3c!--",source:"@site/docs/external/getting-started/enabling-weaver-network/besu.md",sourceDirName:"external/getting-started/enabling-weaver-network",slug:"/external/getting-started/enabling-weaver-network/besu",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/besu",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/getting-started/enabling-weaver-network/besu.md",tags:[],version:"current",frontMatter:{id:"besu",title:"Hyperledger Besu"},sidebar:"Documentation",previous:{title:"Corda",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/corda"},next:{title:"Understanding Interoperability",permalink:"/weaver-dlt-interoperability/docs/external/what-is-interoperability/understanding-interoperability"}},c={},s=[],p={toc:s},u="wrapper";function d(e){let{components:t,...r}=e;return(0,a.kt)(u,(0,n.Z)({},p,r,{components:t,mdxType:"MDXLayout"}))}d.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[9727],{5680:(e,t,r)=>{r.d(t,{xA:()=>p,yg:()=>g});var n=r(6540);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function o(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?i(Object(r),!0).forEach((function(t){a(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):i(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function l(e,t){if(null==e)return{};var r,n,a=function(e,t){if(null==e)return{};var r,n,a={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var c=n.createContext({}),s=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},p=function(e){var t=s(e.components);return n.createElement(c.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},b=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,i=e.originalType,c=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),u=s(r),b=a,g=u["".concat(c,".").concat(b)]||u[b]||d[b]||i;return r?n.createElement(g,o(o({ref:t},p),{},{components:r})):n.createElement(g,o({ref:t},p))}));function g(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=r.length,o=new Array(i);o[0]=b;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l[u]="string"==typeof e?e:a,o[1]=l;for(var s=2;s<i;s++)o[s]=r[s];return n.createElement.apply(null,o)}return n.createElement.apply(null,r)}b.displayName="MDXCreateElement"},5263:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>d,frontMatter:()=>i,metadata:()=>l,toc:()=>s});var n=r(8168),a=(r(6540),r(5680));const i={id:"besu",title:"Hyperledger Besu"},o=void 0,l={unversionedId:"external/getting-started/enabling-weaver-network/besu",id:"external/getting-started/enabling-weaver-network/besu",title:"Hyperledger Besu",description:"\x3c!--",source:"@site/docs/external/getting-started/enabling-weaver-network/besu.md",sourceDirName:"external/getting-started/enabling-weaver-network",slug:"/external/getting-started/enabling-weaver-network/besu",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/besu",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/getting-started/enabling-weaver-network/besu.md",tags:[],version:"current",frontMatter:{id:"besu",title:"Hyperledger Besu"},sidebar:"Documentation",previous:{title:"Corda",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/corda"},next:{title:"Understanding Interoperability",permalink:"/weaver-dlt-interoperability/docs/external/what-is-interoperability/understanding-interoperability"}},c={},s=[],p={toc:s},u="wrapper";function d(e){let{components:t,...r}=e;return(0,a.yg)(u,(0,n.A)({},p,r,{components:t,mdxType:"MDXLayout"}))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/ba46e1b8.fcee89dd.js b/assets/js/ba46e1b8.161a0983.js similarity index 67% rename from assets/js/ba46e1b8.fcee89dd.js rename to assets/js/ba46e1b8.161a0983.js index f3f326c5f..9a24aa176 100644 --- a/assets/js/ba46e1b8.fcee89dd.js +++ b/assets/js/ba46e1b8.161a0983.js @@ -1 +1 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[8214],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>f});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function o(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?i(Object(r),!0).forEach((function(t){a(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):i(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function s(e,t){if(null==e)return{};var r,n,a=function(e,t){if(null==e)return{};var r,n,a={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var l=n.createContext({}),c=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},p=function(e){var t=c(e.components);return n.createElement(l.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,i=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=c(r),m=a,f=d["".concat(l,".").concat(m)]||d[m]||u[m]||i;return r?n.createElement(f,o(o({ref:t},p),{},{components:r})):n.createElement(f,o({ref:t},p))}));function f(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=r.length,o=new Array(i);o[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[d]="string"==typeof e?e:a,o[1]=s;for(var c=2;c<i;c++)o[c]=r[c];return n.createElement.apply(null,o)}return n.createElement.apply(null,r)}m.displayName="MDXCreateElement"},3527:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>o,default:()=>u,frontMatter:()=>i,metadata:()=>s,toc:()=>c});var n=r(7462),a=(r(7294),r(3905));const i={id:"introduction",title:"Weaver Framework"},o=void 0,s={unversionedId:"external/introduction",id:"external/introduction",title:"Weaver Framework",description:"\x3c!--",source:"@site/docs/external/introduction.md",sourceDirName:"external",slug:"/external/introduction",permalink:"/weaver-dlt-interoperability/docs/external/introduction",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/introduction.md",tags:[],version:"current",frontMatter:{id:"introduction",title:"Weaver Framework"},sidebar:"Documentation",next:{title:"Using Weaver",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/guide"}},l={},c=[],p={toc:c},d="wrapper";function u(e){let{components:t,...r}=e;return(0,a.kt)(d,(0,n.Z)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"Weaver is a framework that enables scalable interconnectivity between disparate distributed ledgers in a manner that preserves core tenets of decentralisation and security.\nThe framework, consisting of a family of protocols, is designed and built with the following key guiding principles, which are further discussed in ",(0,a.kt)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/external/design-principles"},"Design Principles"),":"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},"Inclusiveness"),": Avoid approaches that are specific to a particular DLT implementation and design."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},"Independence"),": Interoperable networks retain sovereignty on their own processes and access control rules."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},"Minimum Trust"),": Reduce trust to only what is essentials (i.e. identity providers in the network)."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},"Privacy by Design"),": Interaction between parties across networks should be kept private and confidential and revealed only to the interested parties."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},"No Intermediaries"),": No third-party intermediary should be relied upon for the purpose of cross-network data verification or settlement."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},"Minimal Shared Infrastructure"),": Rely on external infrastucture only for discovery, identification, and tracking/auditing, and not for cross-network transactions."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},"Leverage Consensus"),": Use the respective ledgers' native distributed consensus mechanisms as the trust basis for cross-network transactions."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},"Non-Intrusion"),": Require no changes to the DLT platforms and consensus mechanisms on which the networks are built, nor any dilution of the networks' security models."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},"Transparency"),": Facilitate tracking and auditing of cross-network transactions.")),(0,a.kt)("p",null,"The protocol is designed around the following key elements:"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("em",{parentName:"li"},"State Proofs"),": these allow a network to independently verify that any state it consumes from another network is valid according to the rules and policies of that network, or adheres to validity policies it imposes on state from that network."),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("em",{parentName:"li"},"Asset Locks and Claims"),": these allow a network to freeze an asset for a given time period on behalf of a user or allow a user to claim a frozen asset from its previous owner, either within a network or from a different network."),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("em",{parentName:"li"},"Relays"),": these are decentralised peer-to-peer services that enable communication of messages between networks.")),(0,a.kt)("p",null,"Weaver has a specification outlined through a set of ",(0,a.kt)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/external/specifications"},"RFCs")," and a reference implementation of that specification, which is discussed in this documentation."))}u.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[5674],{5680:(e,t,r)=>{r.d(t,{xA:()=>p,yg:()=>y});var n=r(6540);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function o(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?i(Object(r),!0).forEach((function(t){a(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):i(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function s(e,t){if(null==e)return{};var r,n,a=function(e,t){if(null==e)return{};var r,n,a={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var l=n.createContext({}),c=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},p=function(e){var t=c(e.components);return n.createElement(l.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,i=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=c(r),m=a,y=d["".concat(l,".").concat(m)]||d[m]||u[m]||i;return r?n.createElement(y,o(o({ref:t},p),{},{components:r})):n.createElement(y,o({ref:t},p))}));function y(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=r.length,o=new Array(i);o[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[d]="string"==typeof e?e:a,o[1]=s;for(var c=2;c<i;c++)o[c]=r[c];return n.createElement.apply(null,o)}return n.createElement.apply(null,r)}m.displayName="MDXCreateElement"},8602:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>o,default:()=>u,frontMatter:()=>i,metadata:()=>s,toc:()=>c});var n=r(8168),a=(r(6540),r(5680));const i={id:"introduction",title:"Weaver Framework"},o=void 0,s={unversionedId:"external/introduction",id:"external/introduction",title:"Weaver Framework",description:"\x3c!--",source:"@site/docs/external/introduction.md",sourceDirName:"external",slug:"/external/introduction",permalink:"/weaver-dlt-interoperability/docs/external/introduction",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/introduction.md",tags:[],version:"current",frontMatter:{id:"introduction",title:"Weaver Framework"},sidebar:"Documentation",next:{title:"Using Weaver",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/guide"}},l={},c=[],p={toc:c},d="wrapper";function u(e){let{components:t,...r}=e;return(0,a.yg)(d,(0,n.A)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,a.yg)("p",null,"Weaver is a framework that enables scalable interconnectivity between disparate distributed ledgers in a manner that preserves core tenets of decentralisation and security.\nThe framework, consisting of a family of protocols, is designed and built with the following key guiding principles, which are further discussed in ",(0,a.yg)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/external/design-principles"},"Design Principles"),":"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("strong",{parentName:"li"},"Inclusiveness"),": Avoid approaches that are specific to a particular DLT implementation and design."),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("strong",{parentName:"li"},"Independence"),": Interoperable networks retain sovereignty on their own processes and access control rules."),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("strong",{parentName:"li"},"Minimum Trust"),": Reduce trust to only what is essentials (i.e. identity providers in the network)."),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("strong",{parentName:"li"},"Privacy by Design"),": Interaction between parties across networks should be kept private and confidential and revealed only to the interested parties."),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("strong",{parentName:"li"},"No Intermediaries"),": No third-party intermediary should be relied upon for the purpose of cross-network data verification or settlement."),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("strong",{parentName:"li"},"Minimal Shared Infrastructure"),": Rely on external infrastucture only for discovery, identification, and tracking/auditing, and not for cross-network transactions."),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("strong",{parentName:"li"},"Leverage Consensus"),": Use the respective ledgers' native distributed consensus mechanisms as the trust basis for cross-network transactions."),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("strong",{parentName:"li"},"Non-Intrusion"),": Require no changes to the DLT platforms and consensus mechanisms on which the networks are built, nor any dilution of the networks' security models."),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("strong",{parentName:"li"},"Transparency"),": Facilitate tracking and auditing of cross-network transactions.")),(0,a.yg)("p",null,"The protocol is designed around the following key elements:"),(0,a.yg)("ol",null,(0,a.yg)("li",{parentName:"ol"},(0,a.yg)("em",{parentName:"li"},"State Proofs"),": these allow a network to independently verify that any state it consumes from another network is valid according to the rules and policies of that network, or adheres to validity policies it imposes on state from that network."),(0,a.yg)("li",{parentName:"ol"},(0,a.yg)("em",{parentName:"li"},"Asset Locks and Claims"),": these allow a network to freeze an asset for a given time period on behalf of a user or allow a user to claim a frozen asset from its previous owner, either within a network or from a different network."),(0,a.yg)("li",{parentName:"ol"},(0,a.yg)("em",{parentName:"li"},"Relays"),": these are decentralised peer-to-peer services that enable communication of messages between networks.")),(0,a.yg)("p",null,"Weaver has a specification outlined through a set of ",(0,a.yg)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/external/specifications"},"RFCs")," and a reference implementation of that specification, which is discussed in this documentation."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/bdfaba9c.b44eba83.js b/assets/js/bdfaba9c.b44eba83.js new file mode 100644 index 000000000..26252238c --- /dev/null +++ b/assets/js/bdfaba9c.b44eba83.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[1885],{5680:(e,t,i)=>{i.d(t,{xA:()=>h,yg:()=>g});var n=i(6540);function a(e,t,i){return t in e?Object.defineProperty(e,t,{value:i,enumerable:!0,configurable:!0,writable:!0}):e[t]=i,e}function o(e,t){var i=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),i.push.apply(i,n)}return i}function s(e){for(var t=1;t<arguments.length;t++){var i=null!=arguments[t]?arguments[t]:{};t%2?o(Object(i),!0).forEach((function(t){a(e,t,i[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(i)):o(Object(i)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(i,t))}))}return e}function r(e,t){if(null==e)return{};var i,n,a=function(e,t){if(null==e)return{};var i,n,a={},o=Object.keys(e);for(n=0;n<o.length;n++)i=o[n],t.indexOf(i)>=0||(a[i]=e[i]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n<o.length;n++)i=o[n],t.indexOf(i)>=0||Object.prototype.propertyIsEnumerable.call(e,i)&&(a[i]=e[i])}return a}var c=n.createContext({}),l=function(e){var t=n.useContext(c),i=t;return e&&(i="function"==typeof e?e(t):s(s({},t),e)),i},h=function(e){var t=l(e.components);return n.createElement(c.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},u=n.forwardRef((function(e,t){var i=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,h=r(e,["components","mdxType","originalType","parentName"]),p=l(i),u=a,g=p["".concat(c,".").concat(u)]||p[u]||d[u]||o;return i?n.createElement(g,s(s({ref:t},h),{},{components:i})):n.createElement(g,s({ref:t},h))}));function g(e,t){var i=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=i.length,s=new Array(o);s[0]=u;var r={};for(var c in t)hasOwnProperty.call(t,c)&&(r[c]=t[c]);r.originalType=e,r[p]="string"==typeof e?e:a,s[1]=r;for(var l=2;l<o;l++)s[l]=i[l];return n.createElement.apply(null,s)}return n.createElement.apply(null,i)}u.displayName="MDXCreateElement"},8634:(e,t,i)=>{i.r(t),i.d(t,{assets:()=>c,contentTitle:()=>s,default:()=>d,frontMatter:()=>o,metadata:()=>r,toc:()=>l});var n=i(8168),a=(i(6540),i(5680));const o={},s=void 0,r={permalink:"/weaver-dlt-interoperability/blog/2021/01/21/cross-chain-asset",source:"@site/blog/2021-01-21-cross-chain-asset.md",title:"cross-chain-asset",description:"\x3c!--",date:"2021-01-21T00:00:00.000Z",formattedDate:"January 21, 2021",tags:[],readingTime:10.435,hasTruncateMarker:!1,authors:[],frontMatter:{},nextItem:{title:"emergence-enterprise-interoperability",permalink:"/weaver-dlt-interoperability/blog/2021/01/21/emergence-enterprise-interoperability"}},c={authorsImageUrls:[]},l=[{value:"tags: enterprise, interoperability, asset-exchange",id:"tags-enterprise-interoperability-asset-exchange",level:2},{value:"Introduction",id:"introduction",level:2},{value:"Motivation and Use-case",id:"motivation-and-use-case",level:2},{value:"Cross-Chain Asset Exchange on Public Blockchains",id:"cross-chain-asset-exchange-on-public-blockchains",level:2},{value:"Extending Protocol Design To Permissioned Blockchains",id:"extending-protocol-design-to-permissioned-blockchains",level:2},{value:"Conclusion",id:"conclusion",level:2}],h={toc:l},p="wrapper";function d(e){let{components:t,...o}=e;return(0,a.yg)(p,(0,n.A)({},h,o,{components:t,mdxType:"MDXLayout"}),(0,a.yg)("hr",null),(0,a.yg)("p",null,"slug: cross-chain-asset\ntitle: Enabling Cross-Chain Asset Exchange On Permissioned Blockchains\nauthor: Yining Hu, Ermyas Abebe, Dileban Karunamoorthy, Venkatraman Ramakrishna\nauthor_title: Contributors\nauthor_url: ",(0,a.yg)("a",{parentName:"p",href:"https://hyperledger-labs.github.io/weaver-dlt-interoperability/"},"https://hyperledger-labs.github.io/weaver-dlt-interoperability/")),(0,a.yg)("h2",{id:"tags-enterprise-interoperability-asset-exchange"},"tags: ","[enterprise, interoperability, asset-exchange]"),(0,a.yg)("h2",{id:"introduction"},"Introduction"),(0,a.yg)("p",null,"Recent years have witnessed a growing demand for enabling interoperability across independent blockchains. Cross-chain asset exchange is a significant step towards blockchain interoperability. For public blockchains, the most popular application for asset exchange is cryptocurrency exchange. For permissioned blockchains, cross-chain asset exchange can be useful in ",(0,a.yg)("a",{parentName:"p",href:"https://www.mas.gov.sg/-/media/MAS/ProjectUbin/Project-Ubin-DvP-on-Distributed-Ledger-Technologies.pdf"},"Delivery Versus Payment (DvP)")," and ",(0,a.yg)("a",{parentName:"p",href:"https://www.mas.gov.sg/-/media/Jasper-Ubin-Design-Paper.pdf"},"cross-border payment")," scenarios. There exist various protocols designed for asset exchange on public blockchains. However, a widely adopted standard for designing such protocols for permissioned blockchains still does not exist. Moreover, most existing protocols are designed for public blockchains and their suitability to be applied to permissioned blockchains is unclear."),(0,a.yg)("p",null,"In this article, we aim to lay out a set of requirements for designing cross-chain asset exchange protocols between permissioned blockchains. First we present a canonical motivating use case and then list the various patterns that such cases will follow in real-life scenarios. We then present a short survey of existing cross-chain exchange protocols for public blockchains, following which we summarise the building blocks, core mechanisms and security properties commonly involved in the protocol designs. We then analyse the requirements imposed by permissioned blockchains in comparison to public blockchains, and discuss the additional properties with respect to these restrictions."),(0,a.yg)("h2",{id:"motivation-and-use-case"},"Motivation and Use-case"),(0,a.yg)("p",null,"In traditional financial markets parties trade assets such as securities and derivatives for cash or other assets. To reduce risk, various clearing and settlement processes and intermediaries are often involved. One form of settlement is a DvP where the transfer of securities is performed only in the event of a corresponding payment. This arrangement reduces principal risk by ensuring that both parties receive their end of the exchange. However, settlement in financial markets are slow and time consuming. It also involves counterparty risks and requires intermediaries."),(0,a.yg)("p",null,"Over the past few years, we have been seeing significant efforts in digitising and tokenising both currencies and securities on Distributed Ledger Technology (DLT) infrastructures. On the one hand we have seen concerted efforts around Central Bank Digital Currencies (CBDC) being added to the landscape of other blockchain based payment networks. On the other hand, we have also seen efforts such as that from the Australian Stock Exchange (ASX) to replace its current settlement system--Clearing House Electronic Subregister System (CHESS) with a DLT based platform by 2021."),(0,a.yg)("p",null,"Against this backdrop, a number of central banks have been exploring the potential of performing DvP settlement across a currency ledger and a securities ledger. In this article, we use this as a motivating use-case for our discussions. The scenario involves two decentralised ledgers, namely, a currency ledger and a securities ledger, based on different DLT protocols performing a coordinated transfer of assets in their respective ledgers. Figure 1 depicts this scenario in the context of two organisations--Bank A and Bank B--in which Bank B wants to purchase some securities owned by Bank A and both organisations have accounts on both ledgers. To effect this exchange the following two transactions will have to happen atomically across both networks: i) transfer of payment from Bank B's currency account to Bank A while at the same time ii) the entitlements of the designated securities is transferred from Bank A to Bank B. The scenario would need to guarantee that after the transaction execution, either both parties have their end of the exchange or neither does and that this exchange is performed in a timely manner. "),(0,a.yg)("p",null,(0,a.yg)("img",{alt:"alt text",src:i(2132).A,width:"904",height:"400"})),(0,a.yg)("p",null,"Figure 1. A typical DvP use-case."),(0,a.yg)("p",null,"Cross-chain transactions involving the movement of assets can generally take the form of either an asset exchange between parties or of value transfer from one network to another. The latter involves a scenario in which an asset in one network is locked or burned and a corresponding asset of similar value is issued in a corresponding network. This process generally involves validators or asset issuers in either or both ends of the network. While there are numerous use cases for this model in permissionless context, in this post we primarily focus on asset exchange scenarios, which are more broadly applicable in enterprise use-cases. Asset exchange scenarios generally involve two users swapping corresponding assets managed by the different networks, as in the example illustrated earlier. In asset exchange scenarios involving only two parties, both parties have accounts on both networks, although this might not be the case for exchanges involving more than two parties or networks."),(0,a.yg)("h2",{id:"cross-chain-asset-exchange-on-public-blockchains"},"Cross-Chain Asset Exchange on Public Blockchains"),(0,a.yg)("p",null,"Similar scenarios that involve a pair of transactions being coordinated across distinct blockchains have been studied for public blockchains. One main application area is to enable decentralised exchange across crypto-currency networks. To achieve this, a number of cross-chain asset exchange protocols have been proposed. The original atomic swap protocol was proposed by ",(0,a.yg)("a",{parentName:"p",href:"https://en.bitcoin.it/wiki/Atomic_swap"},"TierNolan")," in the Bitcoin Forum. The protocol leverages trusted escrow services on both blockchains and relies on the asset owners for execution. ",(0,a.yg)("a",{parentName:"p",href:"https://summa.one/"},"Prestwich")," later improved the protocol by removing the trusted escrow services and using a smart contract to automatically execute the swap. Both protocols, however, are asymmetric and hence enforce a particular sequence of events. More recently, a group of researchers developed ",(0,a.yg)("a",{parentName:"p",href:"https://arwen.io/whitepaper.pdf"},"Arwen"),", which guarantees the symmetricality of the protocol and further eases the asset owners' responsibilities in the protocol execution. "),(0,a.yg)("p",null,"We below first discuss the common patterns involved in the protocol design. More specifically, we present the main building blocks, core mechanisms, and security properties achieved by these protocols. "),(0,a.yg)("h1",{id:"building-blocks"},"Building blocks"),(0,a.yg)("p",null,"The design of a cross-chain asset exchange protocol in general contain the following building blocks: 1) the infrastructure for cross-chain state verification, and 2) the asset exchange protocol that specifies parties and sequences involved in the protocol execution. Cross-chain state verification can be performed by the exchanging parties themselves or by an external party."),(0,a.yg)("h1",{id:"core-mechanisms"},"Core Mechanisms"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("p",{parentName:"li"},"Fund locking: To initialise an asset exchange, it is common for one or both parties to first lock up funds with a fund-withholding party on his or her own blockchain. Temporary fund locking ensures the locked fund cannot be used for other purposes while the exchange is being executed. This scheme is often used with a specified timeout to provide flexibility for reclaiming locked funds if the exchange does not take place.")),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("p",{parentName:"li"},"Fund redeeming: In general, the execution requires a pair of transactions to occur on both blockchains, e.g., from User A to User B on Chain A and from User B to User A on Chain B. When certain conditions are met, the locked funds can be redeemed by, or paid to the respective users. The execution of the exchange can be carried out by users themselves, or through other trusted third parties. These trusted third parties can be stand-alone parties that are not otherwise involved in both blockchains, or part of either blockchain. ")),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("p",{parentName:"li"},"Refund: For protocols that are initialised with a temporary fund-locking, the locked funds can usually be reclaimed by the initial owner after a specified timeout. "))),(0,a.yg)("h1",{id:"security-properties"},"Security Properties"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("p",{parentName:"li"},"Atomicity: Atomicity is also sometimes referred to as safety. In general, atomicity implies indivisibility and irreducibility, namely, an atomic operation must be performed entirely or not performed at all. In the case of cross-chain asset exchange, when User A sends a payment to User B on Chain A, User B should also send corresponding delivery to User A on Chain B.")),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("p",{parentName:"li"},"Liveness: Specifies the design of an asset exchange protocol should ensure no party can be tricked into locking up funds forever or for a very long time."))),(0,a.yg)("h2",{id:"extending-protocol-design-to-permissioned-blockchains"},"Extending Protocol Design To Permissioned Blockchains"),(0,a.yg)("p",null,"Requirements of Permissioned Blockchains\nAs public blockchains offer decentralisation and transparency, existing cross-chain asset exchange protocols on public blockchains are often designed for users to voluntarily participant and execute. To ensure secure execution of these protocols, their designs usually incorporate economic incentives, together with on-chain punishment schemes. To ensure liveness, these protocols usually leverage group consensus and fault-tolerance."),(0,a.yg)("p",null,"Permissioned blockchains on the other hand require privacy. Additional economic incentives and punishments are often not required besides the existing business relationships and established legal jurisdictions. Therefore, compared to public blockchains, the design of cross-chain asset exchange protocols on permissioned blockchains allows a higher level of centralisation and requires auditability and individual or group accountability for off-chain dispute resolution rather than economic incentives and on-chain punishments. Moreover, as permissioned blockchains themselves offer a higher throughput and faster transaction processing than public blockchains, the asset exchange protocol ideally should not introduce significant processing overheads that limit the transaction processing capability."),(0,a.yg)("p",null,"Therefore, the challenges in designing cross-chain asset exchange protocols for permissioned networks can be summarised as follow:"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},"Permissioned networks are usually confidential by design, thus restricting access for its internal members and external clients. State verification is hard to achieve across distinct permissioned blockchains. Cross-chain asset exchange protocols must therefore incorporate additional mechanisms to overcome these challenges."),(0,a.yg)("li",{parentName:"ul"},"Unlike public blockchains, permissioned blockchains derive their security from and the ability to hold parties accountable for their actions. Any party acting maliciously should be identified and penalized during an off-chain dispute resolution process. Thus we can relax some of the constraints of the exchange protocol. For example, we can leverage trusted third-parties instead of having to financially incentivise regular users to participate in running the protocol.")),(0,a.yg)("h1",{id:"additional-properties"},"Additional Properties"),(0,a.yg)("p",null,"In addition to following the same set of building blocks, core mechanisms and security properties as public protocols, we also identify an additional set of desired properties for permissioned blockchains."),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("p",{parentName:"li"},"Scalability: Scalability is often restricted by two factors. Firstly, the transaction processing capability of the underlying infrastructures. When a protocol relies on public blockchains, the throughput is consequently limited by the transaction processing of the blockchains themselves. In contrast, some protocols are off-chain, which usually allow faster transaction processing. Secondly, for protocols that involve third parties for fund-locking, such as ",(0,a.yg)("a",{parentName:"p",href:"https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=8835387"},"Xclaim")," and ",(0,a.yg)("a",{parentName:"p",href:"https://arxiv.org/pdf/1908.03999.pdf"},"Dogethereum"),", the amount of money owned by these third parties limits the number of transaction requests they can process. As permissioned blockchains in general have a higher throughput compared to public blockchains, the protocol design should not trade off scalability.")),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("p",{parentName:"li"},"Auditability: Auditability for public blockchains specifies that any party with read right should be able to detect protocol failure. On permissioned blockchains, however, as parties have limited visibility over the ledger state, who can detect protocol failure will most-likely depend on the use-case. In addition, financial regulatory requirements such as AML and CTF might require cross-chain traceability and auditability of exchange transactions (i.e. it should be easy to trace why Alice just transferred Bob $1M on a CBDC network).")),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("p",{parentName:"li"},"Accountability: Accountability says faulty parties should be held accountable. This can refer to individual accountability or group accountability. As it is hard to enforce on-chain punishments on permissioned blockchains, the protocol design should at least allow adversaries to be held accountable.")),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("p",{parentName:"li"},"Compatibility: Compatibility specifies how easy it is to implement the protocol on other blockchain platforms. The protocol design should be generic and not to be limited to particular blockchain platforms.")),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("p",{parentName:"li"},"Extensibility: Extensibility specifies how easy it is to extend the protocol to other use cases, for instance, from two parties to multiple parties, or from one particular transaction pattern to other transaction patterns. ")),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("p",{parentName:"li"},"Privacy: Privacy is usually not automatically guaranteed by public blockchains. For sensitive use-cases, extra mechanisms such as a ",(0,a.yg)("a",{parentName:"p",href:"https://dl.acm.org/doi/pdf/10.1145/3319535.3363221?casa_token=_CXTS4E4hVsAAAAA:9YXRV8SUF7ljmdn2iovE1la3_j6Yn7O1oKqrdZZwxrO_u_Dg2sRqjYdVcTUCLFayNd-s8AWZfELaKA"},"trusted execution environment (TEE)")," can be used. Privacy is also of vital importance when it comes to permissioned blockchains. Most existing cross-chain protocols are designed for public blockchains. As the execution of these protocols may require asset owners or third-parties to access states on either blockchain ledger, executing a cross-chain asset exchange can put user privacy at risk.")),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("p",{parentName:"li"},"Low Cost: As many of the cross-chain exchange protocols involve sending on-chain transactions, the concern over number of transactions and transaction fees arises when the protocol design involves a public blockchain."))),(0,a.yg)("h2",{id:"conclusion"},"Conclusion"),(0,a.yg)("p",null,"To summarise, in this article we tackle the problem of enabling cross-chain asset exchange on permissioned blockchains and evaluate the different requirements imposed by public blockchains and permissioned blockchains. We also articulate a set of desired properties to guide the design of cross-chain asset exchange protocols."),(0,a.yg)("p",null,"For general-purpose interoperability of enterprise blockchains, we have developed the ",(0,a.yg)("a",{parentName:"p",href:"https://hyperledger-labs.github.io/weaver-dlt-interoperability/"},"Weaver")," tool that incorporates a cross-chain state verification engine to enable cross-chain state sharing and verification. Please check out our documentation for implementation details and example applications."))}d.isMDXComponent=!0},2132:(e,t,i)=>{i.d(t,{A:()=>n});const n=i.p+"assets/images/simple-dvp-13ac15534a3f185903ac1784bc5f1031.png"}}]); \ No newline at end of file diff --git a/assets/js/bf5dfefe.d4550e12.js b/assets/js/bf5dfefe.d4550e12.js new file mode 100644 index 000000000..23c68c92b --- /dev/null +++ b/assets/js/bf5dfefe.d4550e12.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[3836],{5680:(e,n,a)=>{a.d(n,{xA:()=>g,yg:()=>d});var t=a(6540);function r(e,n,a){return n in e?Object.defineProperty(e,n,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[n]=a,e}function i(e,n){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var t=Object.getOwnPropertySymbols(e);n&&(t=t.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),a.push.apply(a,t)}return a}function o(e){for(var n=1;n<arguments.length;n++){var a=null!=arguments[n]?arguments[n]:{};n%2?i(Object(a),!0).forEach((function(n){r(e,n,a[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(a)):i(Object(a)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(a,n))}))}return e}function l(e,n){if(null==e)return{};var a,t,r=function(e,n){if(null==e)return{};var a,t,r={},i=Object.keys(e);for(t=0;t<i.length;t++)a=i[t],n.indexOf(a)>=0||(r[a]=e[a]);return r}(e,n);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(t=0;t<i.length;t++)a=i[t],n.indexOf(a)>=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var c=t.createContext({}),s=function(e){var n=t.useContext(c),a=n;return e&&(a="function"==typeof e?e(n):o(o({},n),e)),a},g=function(e){var n=s(e.components);return t.createElement(c.Provider,{value:n},e.children)},p="mdxType",m={inlineCode:"code",wrapper:function(e){var n=e.children;return t.createElement(t.Fragment,{},n)}},b=t.forwardRef((function(e,n){var a=e.components,r=e.mdxType,i=e.originalType,c=e.parentName,g=l(e,["components","mdxType","originalType","parentName"]),p=s(a),b=r,d=p["".concat(c,".").concat(b)]||p[b]||m[b]||i;return a?t.createElement(d,o(o({ref:n},g),{},{components:a})):t.createElement(d,o({ref:n},g))}));function d(e,n){var a=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var i=a.length,o=new Array(i);o[0]=b;var l={};for(var c in n)hasOwnProperty.call(n,c)&&(l[c]=n[c]);l.originalType=e,l[p]="string"==typeof e?e:r,o[1]=l;for(var s=2;s<i;s++)o[s]=a[s];return t.createElement.apply(null,o)}return t.createElement.apply(null,a)}b.displayName="MDXCreateElement"},4733:(e,n,a)=>{a.r(n),a.d(n,{assets:()=>c,contentTitle:()=>o,default:()=>m,frontMatter:()=>i,metadata:()=>l,toc:()=>s});var t=a(8168),r=(a(6540),a(5680));const i={id:"fabric-fabric",title:"Asset Exchange: Fabric with Fabric",sidebar_label:"Fabric with Fabric",pagination_label:"Fabric with Fabric",pagination_prev:"external/getting-started/interop/asset-exchange/overview"},o=void 0,l={unversionedId:"external/getting-started/interop/asset-exchange/fabric-fabric",id:"external/getting-started/interop/asset-exchange/fabric-fabric",title:"Asset Exchange: Fabric with Fabric",description:"One Fabric network transfers a bond from Alice to Bob in exchange for a transfer of tokens from Bob to Alice in the other network",source:"@site/docs/external/getting-started/interop/asset-exchange/fabric-fabric.md",sourceDirName:"external/getting-started/interop/asset-exchange",slug:"/external/getting-started/interop/asset-exchange/fabric-fabric",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-fabric",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/getting-started/interop/asset-exchange/fabric-fabric.md",tags:[],version:"current",frontMatter:{id:"fabric-fabric",title:"Asset Exchange: Fabric with Fabric",sidebar_label:"Fabric with Fabric",pagination_label:"Fabric with Fabric",pagination_prev:"external/getting-started/interop/asset-exchange/overview"},sidebar:"Documentation",previous:{title:"Asset Exchange",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview"},next:{title:"Fabric with Corda",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-corda"}},c={},s=[],g={toc:s},p="wrapper";function m(e){let{components:n,...a}=e;return(0,r.yg)(p,(0,t.A)({},g,a,{components:n,mdxType:"MDXLayout"}),(0,r.yg)("p",null,"One Fabric network transfers a bond from Alice to Bob in exchange for a transfer of tokens from Bob to Alice in the other network\nEnsure that one of the following chaincodes have been deployed in both networks:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"simpleasset")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"simpleassetandinterop")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"simpleassettransfer"))),(0,r.yg)("p",null,"Run the following steps:"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:"left"},"The hash used in following steps can be replaced by any valid ",(0,r.yg)("inlineCode",{parentName:"td"},"SHA256")," hash.")))),(0,r.yg)("ol",null,(0,r.yg)("li",{parentName:"ol"},"Navigate to either the ",(0,r.yg)("inlineCode",{parentName:"li"},"samples/fabric/fabric-cli")," folder (for the Node.js version) or the ",(0,r.yg)("inlineCode",{parentName:"li"},"samples/fabric/go-cli")," folder (for the Golang version) in your clone of the Weaver repository."),(0,r.yg)("li",{parentName:"ol"},"Run the following to verify the status of the assets owned by ",(0,r.yg)("inlineCode",{parentName:"li"},"alice")," and ",(0,r.yg)("inlineCode",{parentName:"li"},"bob")," in the two networks:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"./scripts/getAssetStatus.sh 2\n"))),(0,r.yg)("li",{parentName:"ol"},"Complete the asset exchange in either of the two different ways:",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},"Using a single command:",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},"Run the following to trigger exchange of bond ",(0,r.yg)("inlineCode",{parentName:"li"},"bond01:a03")," owned by ",(0,r.yg)("inlineCode",{parentName:"li"},"alice")," in ",(0,r.yg)("inlineCode",{parentName:"li"},"network1")," with ",(0,r.yg)("inlineCode",{parentName:"li"},"100")," units of tokens ",(0,r.yg)("inlineCode",{parentName:"li"},"token1")," owned by ",(0,r.yg)("inlineCode",{parentName:"li"},"bob")," in ",(0,r.yg)("inlineCode",{parentName:"li"},"network2"),":",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset exchange-all --network1=network1 --network2=network2 --secret=secrettext --timeout-duration=100 alice:bond01:a03:bob:token1:100\n"))),(0,r.yg)("li",{parentName:"ul"},"To verify that ",(0,r.yg)("inlineCode",{parentName:"li"},"bob")," now owns a bond in exchange for ",(0,r.yg)("inlineCode",{parentName:"li"},"alice")," owning some tokens, run the following:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"./scripts/getAssetStatus.sh 2\n"))))),(0,r.yg)("li",{parentName:"ul"},"Using step-by-step commands:",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},"Generate Secret-Hash Pair using following command (prints hash in base64):",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre"},"./bin/fabric-cli hash --hash_fn=SHA256 secrettext\n"))),(0,r.yg)("li",{parentName:"ul"},"Run the following to trigger ",(0,r.yg)("inlineCode",{parentName:"li"},"alice")," locking ",(0,r.yg)("inlineCode",{parentName:"li"},"bond01:a03")," for ",(0,r.yg)("inlineCode",{parentName:"li"},"bob")," in ",(0,r.yg)("inlineCode",{parentName:"li"},"network1"),(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset exchange lock --timeout-duration=3600 --locker=alice --recipient=bob --hashBase64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs= --target-network=network1 --param=bond01:a03\n"))),(0,r.yg)("li",{parentName:"ul"},"Run the following to verify ",(0,r.yg)("inlineCode",{parentName:"li"},"alice"),"'s lock:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset exchange is-locked --locker=alice --recipient=bob --target-network=network1 --param=bond01:a03\n"))),(0,r.yg)("li",{parentName:"ul"},"Run the following to trigger ",(0,r.yg)("inlineCode",{parentName:"li"},"bob")," locking ",(0,r.yg)("inlineCode",{parentName:"li"},"100")," units of ",(0,r.yg)("inlineCode",{parentName:"li"},"token1")," for ",(0,r.yg)("inlineCode",{parentName:"li"},"alice")," in ",(0,r.yg)("inlineCode",{parentName:"li"},"network2"),":",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset exchange lock --fungible --timeout-duration=1800 --locker=bob --recipient=alice --hashBase64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs= --target-network=network2 --param=token1:100\n")),"Note the ",(0,r.yg)("inlineCode",{parentName:"li"},"contract-id")," printed as output in above command. The output line containing ",(0,r.yg)("inlineCode",{parentName:"li"},"contract-id")," (text in base64 after ",(0,r.yg)("inlineCode",{parentName:"li"},"Contract Id:"),") would like this:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"\u2139 Fungible Asset Locked with Contract Id: E0JZq8Z+eS//2Bt4WU0pU210MvNgDC2hdUT1RgszOq0=, preimage: null, hashvalue: ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs=\n"))),(0,r.yg)("li",{parentName:"ul"},"Run the following to verify ",(0,r.yg)("inlineCode",{parentName:"li"},"bob"),"'s lock:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset exchange is-locked --fungible --locker=bob --recipient=alice --target-network=network2 --contract-id=<contract-id>\n"))),(0,r.yg)("li",{parentName:"ul"},"Run the following to trigger ",(0,r.yg)("inlineCode",{parentName:"li"},"alice"),"'s claim for ",(0,r.yg)("inlineCode",{parentName:"li"},"100")," units of ",(0,r.yg)("inlineCode",{parentName:"li"},"token1")," locked by ",(0,r.yg)("inlineCode",{parentName:"li"},"bob")," in ",(0,r.yg)("inlineCode",{parentName:"li"},"network2"),":",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset exchange claim --fungible --recipient=alice --target-network=network2 --contract-id=<contract-id> --secret=<hash-pre-image>\n"))),(0,r.yg)("li",{parentName:"ul"},"Run the following to trigger ",(0,r.yg)("inlineCode",{parentName:"li"},"bob"),"'s claim for ",(0,r.yg)("inlineCode",{parentName:"li"},"bond01:a03")," locked by ",(0,r.yg)("inlineCode",{parentName:"li"},"alice")," in ",(0,r.yg)("inlineCode",{parentName:"li"},"network1"),":",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset exchange claim --recipient=bob --locker=alice --target-network=network1 --param=bond01:a03 --secret=<hash-pre-image>\n")))),"The above steps complete a successful asset exchange between two Fabric networks.\nIn addition to the above commands, following commands can be run if specified timeout has expired and the locked asset remains unclaimed.",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},"If ",(0,r.yg)("inlineCode",{parentName:"li"},"alice")," wants to unlock the bond asset, run the following to trigger ",(0,r.yg)("inlineCode",{parentName:"li"},"alice"),"'s re-claim for ",(0,r.yg)("inlineCode",{parentName:"li"},"bond01:a03")," locked in ",(0,r.yg)("inlineCode",{parentName:"li"},"network1"),":",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset exchange unlock --locker=alice --recipient=bob --target-network=network1 --param=bond01:a03\n"))),(0,r.yg)("li",{parentName:"ul"},"If ",(0,r.yg)("inlineCode",{parentName:"li"},"bob")," wants to unlock the token asset, run the following to trigger ",(0,r.yg)("inlineCode",{parentName:"li"},"bob"),"'s re-claim for ",(0,r.yg)("inlineCode",{parentName:"li"},"token1:100")," locked in ",(0,r.yg)("inlineCode",{parentName:"li"},"network2"),":",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset exchange unlock --fungible --locker=bob --target-network=network2 --contract-id=<contract-id>\n")))))))))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/bf5dfefe.e6b84837.js b/assets/js/bf5dfefe.e6b84837.js deleted file mode 100644 index ff4096dce..000000000 --- a/assets/js/bf5dfefe.e6b84837.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[8362],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>k});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,a,r=function(e,t){if(null==e)return{};var n,a,r={},i=Object.keys(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var c=a.createContext({}),s=function(e){var t=a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=s(e.components);return a.createElement(c.Provider,{value:t},e.children)},m="mdxType",b={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,c=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),m=s(n),d=r,k=m["".concat(c,".").concat(d)]||m[d]||b[d]||i;return n?a.createElement(k,o(o({ref:t},p),{},{components:n})):a.createElement(k,o({ref:t},p))}));function k(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,o=new Array(i);o[0]=d;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l[m]="string"==typeof e?e:r,o[1]=l;for(var s=2;s<i;s++)o[s]=n[s];return a.createElement.apply(null,o)}return a.createElement.apply(null,n)}d.displayName="MDXCreateElement"},7192:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>b,frontMatter:()=>i,metadata:()=>l,toc:()=>s});var a=n(7462),r=(n(7294),n(3905));const i={id:"fabric-fabric",title:"Asset Exchange: Fabric with Fabric",sidebar_label:"Fabric with Fabric",pagination_label:"Fabric with Fabric",pagination_prev:"external/getting-started/interop/asset-exchange/overview"},o=void 0,l={unversionedId:"external/getting-started/interop/asset-exchange/fabric-fabric",id:"external/getting-started/interop/asset-exchange/fabric-fabric",title:"Asset Exchange: Fabric with Fabric",description:"One Fabric network transfers a bond from Alice to Bob in exchange for a transfer of tokens from Bob to Alice in the other network",source:"@site/docs/external/getting-started/interop/asset-exchange/fabric-fabric.md",sourceDirName:"external/getting-started/interop/asset-exchange",slug:"/external/getting-started/interop/asset-exchange/fabric-fabric",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-fabric",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/getting-started/interop/asset-exchange/fabric-fabric.md",tags:[],version:"current",frontMatter:{id:"fabric-fabric",title:"Asset Exchange: Fabric with Fabric",sidebar_label:"Fabric with Fabric",pagination_label:"Fabric with Fabric",pagination_prev:"external/getting-started/interop/asset-exchange/overview"},sidebar:"Documentation",previous:{title:"Asset Exchange",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview"},next:{title:"Fabric with Corda",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-corda"}},c={},s=[],p={toc:s},m="wrapper";function b(e){let{components:t,...n}=e;return(0,r.kt)(m,(0,a.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"One Fabric network transfers a bond from Alice to Bob in exchange for a transfer of tokens from Bob to Alice in the other network\nEnsure that one of the following chaincodes have been deployed in both networks:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"simpleasset")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"simpleassetandinterop")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"simpleassettransfer"))),(0,r.kt)("p",null,"Run the following steps:"),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:"left"},"The hash used in following steps can be replaced by any valid ",(0,r.kt)("inlineCode",{parentName:"td"},"SHA256")," hash.")))),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},"Navigate to either the ",(0,r.kt)("inlineCode",{parentName:"li"},"samples/fabric/fabric-cli")," folder or the ",(0,r.kt)("inlineCode",{parentName:"li"},"samples/fabric/go-cli")," folder in your clone of the Weaver repository."),(0,r.kt)("li",{parentName:"ol"},"Run the following to verify the status of the assets owned by ",(0,r.kt)("inlineCode",{parentName:"li"},"alice")," and ",(0,r.kt)("inlineCode",{parentName:"li"},"bob")," in the two networks:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"./scripts/getAssetStatus.sh 2\n"))),(0,r.kt)("li",{parentName:"ol"},"Complete the asset exchange in either of the two different ways:",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"Using a single command:",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"Run the following to trigger exchange of bond ",(0,r.kt)("inlineCode",{parentName:"li"},"bond01:a03")," owned by ",(0,r.kt)("inlineCode",{parentName:"li"},"alice")," in ",(0,r.kt)("inlineCode",{parentName:"li"},"network1")," with ",(0,r.kt)("inlineCode",{parentName:"li"},"100")," units of tokens ",(0,r.kt)("inlineCode",{parentName:"li"},"token1")," owned by ",(0,r.kt)("inlineCode",{parentName:"li"},"bob")," in ",(0,r.kt)("inlineCode",{parentName:"li"},"network2"),":",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset exchange-all --network1=network1 --network2=network2 --secret=secrettext --timeout-duration=100 alice:bond01:a03:bob:token1:100\n"))),(0,r.kt)("li",{parentName:"ul"},"To verify that ",(0,r.kt)("inlineCode",{parentName:"li"},"bob")," now owns a bond in exchange for ",(0,r.kt)("inlineCode",{parentName:"li"},"alice")," owning some tokens, run the following:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"./scripts/getAssetStatus.sh 2\n"))))),(0,r.kt)("li",{parentName:"ul"},"Using step-by-step commands:",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"Generate Secret-Hash Pair using following command (prints hash in base64):",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},"./bin/fabric-cli hash --hash_fn=SHA256 secrettext\n"))),(0,r.kt)("li",{parentName:"ul"},"Run the following to trigger ",(0,r.kt)("inlineCode",{parentName:"li"},"alice")," locking ",(0,r.kt)("inlineCode",{parentName:"li"},"bond01:a03")," for ",(0,r.kt)("inlineCode",{parentName:"li"},"bob")," in ",(0,r.kt)("inlineCode",{parentName:"li"},"network1"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset exchange lock --timeout-duration=3600 --locker=alice --recipient=bob --hashBase64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs= --target-network=network1 --param=bond01:a03\n"))),(0,r.kt)("li",{parentName:"ul"},"Run the following to verify ",(0,r.kt)("inlineCode",{parentName:"li"},"alice"),"'s lock:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset exchange is-locked --locker=alice --recipient=bob --target-network=network1 --param=bond01:a03\n"))),(0,r.kt)("li",{parentName:"ul"},"Run the following to trigger ",(0,r.kt)("inlineCode",{parentName:"li"},"bob")," locking ",(0,r.kt)("inlineCode",{parentName:"li"},"100")," units of ",(0,r.kt)("inlineCode",{parentName:"li"},"token1")," for ",(0,r.kt)("inlineCode",{parentName:"li"},"alice")," in ",(0,r.kt)("inlineCode",{parentName:"li"},"network2"),":",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset exchange lock --fungible --timeout-duration=1800 --locker=bob --recipient=alice --hashBase64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs= --target-network=network2 --param=token1:100\n")),"Note the ",(0,r.kt)("inlineCode",{parentName:"li"},"contract-id")," printed as output in above command. The output line containing ",(0,r.kt)("inlineCode",{parentName:"li"},"contract-id")," (text in base64 after ",(0,r.kt)("inlineCode",{parentName:"li"},"Contract Id:"),") would like this:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"\u2139 Fungible Asset Locked with Contract Id: E0JZq8Z+eS//2Bt4WU0pU210MvNgDC2hdUT1RgszOq0=, preimage: null, hashvalue: ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs=\n"))),(0,r.kt)("li",{parentName:"ul"},"Run the following to verify ",(0,r.kt)("inlineCode",{parentName:"li"},"bob"),"'s lock:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset exchange is-locked --fungible --locker=bob --recipient=alice --target-network=network2 --contract-id=<contract-id>\n"))),(0,r.kt)("li",{parentName:"ul"},"Run the following to trigger ",(0,r.kt)("inlineCode",{parentName:"li"},"alice"),"'s claim for ",(0,r.kt)("inlineCode",{parentName:"li"},"100")," units of ",(0,r.kt)("inlineCode",{parentName:"li"},"token1")," locked by ",(0,r.kt)("inlineCode",{parentName:"li"},"bob")," in ",(0,r.kt)("inlineCode",{parentName:"li"},"network2"),":",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset exchange claim --fungible --recipient=alice --target-network=network2 --contract-id=<contract-id> --secret=<hash-pre-image>\n"))),(0,r.kt)("li",{parentName:"ul"},"Run the following to trigger ",(0,r.kt)("inlineCode",{parentName:"li"},"bob"),"'s claim for ",(0,r.kt)("inlineCode",{parentName:"li"},"bond01:a03")," locked by ",(0,r.kt)("inlineCode",{parentName:"li"},"alice")," in ",(0,r.kt)("inlineCode",{parentName:"li"},"network1"),":",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset exchange claim --recipient=bob --locker=alice --target-network=network1 --param=bond01:a03 --secret=<hash-pre-image>\n")))),"The above steps complete a successful asset exchange between two Fabric networks.\nIn addition to the above commands, following commands can be run if specified timeout has expired and the locked asset remains unclaimed.",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"If ",(0,r.kt)("inlineCode",{parentName:"li"},"alice")," wants to unlock the bond asset, run the following to trigger ",(0,r.kt)("inlineCode",{parentName:"li"},"alice"),"'s re-claim for ",(0,r.kt)("inlineCode",{parentName:"li"},"bond01:a03")," locked in ",(0,r.kt)("inlineCode",{parentName:"li"},"network1"),":",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset exchange unlock --locker=alice --recipient=bob --target-network=network1 --param=bond01:a03\n"))),(0,r.kt)("li",{parentName:"ul"},"If ",(0,r.kt)("inlineCode",{parentName:"li"},"bob")," wants to unlock the token asset, run the following to trigger ",(0,r.kt)("inlineCode",{parentName:"li"},"bob"),"'s re-claim for ",(0,r.kt)("inlineCode",{parentName:"li"},"token1:100")," locked in ",(0,r.kt)("inlineCode",{parentName:"li"},"network2"),":",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli asset exchange unlock --fungible --locker=bob --target-network=network2 --contract-id=<contract-id>\n")))))))))}b.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/c4f5d8e4.4bc13247.js b/assets/js/c4f5d8e4.4bc13247.js new file mode 100644 index 000000000..364f01800 --- /dev/null +++ b/assets/js/c4f5d8e4.4bc13247.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[2634],{2468:(e,t,a)=>{a.r(t),a.d(t,{default:()=>g});var r=a(8168),n=a(6540),l=a(53),i=a(5713),s=a(5489),c=a(4586),o=a(6025);const m={heroBanner:"heroBanner_UJJx",buttons:"buttons_pzbO",features:"features_keug",featureImage:"featureImage_yA8i",getStarted:"getStarted_Sjon",heading:"heading_AAq7"},u=[{title:"Network Neutral",imageUrl:"shared/undraw_docusaurus_mountain.svg",description:n.createElement(n.Fragment,null,"Weaver is designed to be agnostic to the underlying distributed ledger protocol and is based on a set of standard specifications.")},{title:"Secure",imageUrl:"shared/undraw_docusaurus_tree.svg",description:n.createElement(n.Fragment,null,"Verifiable state proofs and secure communication ensures integrity and confidentiality.")},{title:"Enterprise Grade",imageUrl:"shared/undraw_docusaurus_react.svg",description:n.createElement(n.Fragment,null,"A high availability architecture with flexible deployment models meets the needs of enterprises deploying Weaver.")}];function d(e){let{imageUrl:t,title:a,description:r}=e;const i=(0,o.A)(t);return n.createElement("div",{className:(0,l.A)("col col--4",m.feature)},i&&n.createElement("div",{className:"text--center"},n.createElement("img",{className:m.featureImage,src:i,alt:a})),n.createElement("h3",null,a),n.createElement("p",null,r))}const g=function(){const e=(0,c.A)(),{siteConfig:t={}}=e;return n.createElement(i.A,{title:`Hello from ${t.title}`,description:"Description will go into a meta tag in <head />"},n.createElement("header",{className:(0,l.A)("hero hero--primary",m.heroBanner)},n.createElement("div",{className:"container"},n.createElement("h1",{className:"hero__title"},t.title),n.createElement("p",{className:"hero__subtitle"},t.tagline),n.createElement("div",{className:m.buttons},n.createElement(s.A,{className:(0,l.A)("button button--outline button--secondary button--lg",m.getStarted),to:(0,o.A)("docs/external/introduction")},"Get Started")))),n.createElement("main",null,u&&u.length>0&&n.createElement("section",{className:m.features},n.createElement("div",{className:"container"},n.createElement("div",{className:"row"},u.map(((e,t)=>n.createElement(d,(0,r.A)({key:t},e)))))))))}}}]); \ No newline at end of file diff --git a/assets/js/c4f5d8e4.fba3a11a.js b/assets/js/c4f5d8e4.fba3a11a.js deleted file mode 100644 index 62551744e..000000000 --- a/assets/js/c4f5d8e4.fba3a11a.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[4195],{5239:(e,t,a)=>{a.r(t),a.d(t,{default:()=>g});var r=a(7462),n=a(7294),l=a(6010),i=a(3285),s=a(9960),c=a(2263),o=a(4996);const m={heroBanner:"heroBanner_UJJx",buttons:"buttons_pzbO",features:"features_keug",featureImage:"featureImage_yA8i",getStarted:"getStarted_Sjon",heading:"heading_AAq7"},u=[{title:"Network Neutral",imageUrl:"shared/undraw_docusaurus_mountain.svg",description:n.createElement(n.Fragment,null,"Weaver is designed to be agnostic to the underlying distributed ledger protocol and is based on a set of standard specifications.")},{title:"Secure",imageUrl:"shared/undraw_docusaurus_tree.svg",description:n.createElement(n.Fragment,null,"Verifiable state proofs and secure communication ensures integrity and confidentiality.")},{title:"Enterprise Grade",imageUrl:"shared/undraw_docusaurus_react.svg",description:n.createElement(n.Fragment,null,"A high availability architecture with flexible deployment models meets the needs of enterprises deploying Weaver.")}];function d(e){let{imageUrl:t,title:a,description:r}=e;const i=(0,o.Z)(t);return n.createElement("div",{className:(0,l.Z)("col col--4",m.feature)},i&&n.createElement("div",{className:"text--center"},n.createElement("img",{className:m.featureImage,src:i,alt:a})),n.createElement("h3",null,a),n.createElement("p",null,r))}const g=function(){const e=(0,c.Z)(),{siteConfig:t={}}=e;return n.createElement(i.Z,{title:`Hello from ${t.title}`,description:"Description will go into a meta tag in <head />"},n.createElement("header",{className:(0,l.Z)("hero hero--primary",m.heroBanner)},n.createElement("div",{className:"container"},n.createElement("h1",{className:"hero__title"},t.title),n.createElement("p",{className:"hero__subtitle"},t.tagline),n.createElement("div",{className:m.buttons},n.createElement(s.Z,{className:(0,l.Z)("button button--outline button--secondary button--lg",m.getStarted),to:(0,o.Z)("docs/external/introduction")},"Get Started")))),n.createElement("main",null,u&&u.length>0&&n.createElement("section",{className:m.features},n.createElement("div",{className:"container"},n.createElement("div",{className:"row"},u.map(((e,t)=>n.createElement(d,(0,r.Z)({key:t},e)))))))))}}}]); \ No newline at end of file diff --git a/assets/js/c9723ef0.f1ed0317.js b/assets/js/c9723ef0.f1ed0317.js new file mode 100644 index 000000000..7b1e86853 --- /dev/null +++ b/assets/js/c9723ef0.f1ed0317.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[7910],{5680:(e,t,n)=>{n.d(t,{xA:()=>d,yg:()=>m});var a=n(6540);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,a,r=function(e,t){if(null==e)return{};var n,a,r={},i=Object.keys(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=a.createContext({}),p=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},d=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},g="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},y=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),g=p(n),y=r,m=g["".concat(s,".").concat(y)]||g[y]||c[y]||i;return n?a.createElement(m,o(o({ref:t},d),{},{components:n})):a.createElement(m,o({ref:t},d))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,o=new Array(i);o[0]=y;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[g]="string"==typeof e?e:r,o[1]=l;for(var p=2;p<i;p++)o[p]=n[p];return a.createElement.apply(null,o)}return a.createElement.apply(null,n)}y.displayName="MDXCreateElement"},3939:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>c,frontMatter:()=>i,metadata:()=>l,toc:()=>p});var a=n(8168),r=(n(6540),n(5680));const i={id:"setup-packages-docker",title:"Setup with Imported Dockerized Weaver Components",pagination_prev:"external/getting-started/test-network/overview",pagination_next:"external/getting-started/test-network/ledger-initialization"},o=void 0,l={unversionedId:"external/getting-started/test-network/setup-packages-docker",id:"external/getting-started/test-network/setup-packages-docker",title:"Setup with Imported Dockerized Weaver Components",description:"\x3c!--",source:"@site/docs/external/getting-started/test-network/setup-packages-docker.md",sourceDirName:"external/getting-started/test-network",slug:"/external/getting-started/test-network/setup-packages-docker",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-packages-docker",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/getting-started/test-network/setup-packages-docker.md",tags:[],version:"current",frontMatter:{id:"setup-packages-docker",title:"Setup with Imported Dockerized Weaver Components",pagination_prev:"external/getting-started/test-network/overview",pagination_next:"external/getting-started/test-network/ledger-initialization"},sidebar:"Documentation",previous:{title:"Component Overview",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/overview"},next:{title:"Ledger Initialization",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/ledger-initialization"}},s={},p=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Software",id:"software",level:3},{value:"Credentials",id:"credentials",level:3},{value:"Package Access Token:",id:"package-access-token",level:4},{value:"Getting the Code and Documentation",id:"getting-the-code-and-documentation",level:2},{value:"Securing Components",id:"securing-components",level:2},{value:"Hyperledger Fabric Components",id:"hyperledger-fabric-components",level:2},{value:"Fabric Network",id:"fabric-network",level:3},{value:"Fabric Relay",id:"fabric-relay",level:3},{value:"Fabric Driver",id:"fabric-driver",level:3},{value:"Fabric IIN Agent",id:"fabric-iin-agent",level:3},{value:"Deployment",id:"deployment",level:4},{value:"Fabric Client (Application)",id:"fabric-client-application",level:3},{value:"Prerequisites",id:"prerequisites-1",level:4},{value:"Installation",id:"installation",level:4},{value:"Corda Components",id:"corda-components",level:2},{value:"Corda Network",id:"corda-network",level:3},{value:"Running with Interoperation CorDapp from GitHub Packages",id:"running-with-interoperation-cordapp-from-github-packages",level:4},{value:"Corda Relay",id:"corda-relay",level:3},{value:"Corda Driver",id:"corda-driver",level:3},{value:"Tear Down the Setup",id:"tear-down-the-setup",level:2},{value:"Relay",id:"relay",level:3},{value:"Fabric Driver",id:"fabric-driver-1",level:3},{value:"Corda Driver",id:"corda-driver-1",level:3},{value:"Corda Network",id:"corda-network-1",level:3},{value:"Fabric Network",id:"fabric-network-1",level:3}],d={toc:p},g="wrapper";function c(e){let{components:t,...n}=e;return(0,r.yg)(g,(0,a.A)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,r.yg)("p",null," In this document, we detail the steps using which you can bring up networks using the default configuration settings and by fetching pre-built Weaver interoperation modules, SDK libraries, and relay docker image, drivers docker images from GitHub Package repositories. To customize these settings (e.g., hostnames, ports), refer to the ",(0,r.yg)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/advanced-configuration"},"Advanced Configuration page"),"."),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:"left"},"All components are run within Docker containers, except client applications.")))),(0,r.yg)("p",null," Follow the instructions below to build and run components followed by interoperation flows. These instructions have been tested on Ubuntu Linux (bash shell) and Mac OS. In general, they should work on any system and shell as long as the various dependencies have been installed and configured."),(0,r.yg)("h2",{id:"prerequisites"},"Prerequisites"),(0,r.yg)("h3",{id:"software"},"Software"),(0,r.yg)("p",null,"Before starting, make sure you have the following software installed on your host machine:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Curl: ",(0,r.yg)("em",{parentName:"li"},"install using package manager, like ",(0,r.yg)("inlineCode",{parentName:"em"},"apt")," on Debian/Ubuntu Linux")),(0,r.yg)("li",{parentName:"ul"},"Git: ",(0,r.yg)("a",{parentName:"li",href:"https://git-scm.com/book/en/v2/Getting-Started-Installing-Git"},"sample instructions")),(0,r.yg)("li",{parentName:"ul"},"Docker: ",(0,r.yg)("a",{parentName:"li",href:"https://docs.docker.com/engine/install/"},"sample instructions")," (Latest version)"),(0,r.yg)("li",{parentName:"ul"},"Docker-Compose: ",(0,r.yg)("a",{parentName:"li",href:"https://docs.docker.com/compose/install/"},"sample instructions")," (Version 1.28.2 or higher, but lower than version V2)"),(0,r.yg)("li",{parentName:"ul"},"Golang: ",(0,r.yg)("a",{parentName:"li",href:"https://golang.org/dl/"},"sample instructions")," (Version 1.16 or higher)"),(0,r.yg)("li",{parentName:"ul"},"Java (JDK and JRE): ",(0,r.yg)("a",{parentName:"li",href:"https://openjdk.java.net/install/"},"sample instructions")," (Version 8)"),(0,r.yg)("li",{parentName:"ul"},"Node.js and NPM: ",(0,r.yg)("a",{parentName:"li",href:"https://nodejs.org/en/download/package-manager/"},"sample instructions")," (Version 11 to Version 16 Supported)"),(0,r.yg)("li",{parentName:"ul"},"Yarn: ",(0,r.yg)("a",{parentName:"li",href:"https://classic.yarnpkg.com/en/docs/install/"},"sample instructions"))),(0,r.yg)("h3",{id:"credentials"},"Credentials"),(0,r.yg)("p",null,"Make sure you have an SSH or GPG key registered in ",(0,r.yg)("a",{parentName:"p",href:"https://github.com"},"https://github.com")," to allow seamless cloning of repositories (at present, various setup scripts clone repositories using the ",(0,r.yg)("inlineCode",{parentName:"p"},"https://")," prefix but this may change to ",(0,r.yg)("inlineCode",{parentName:"p"},"git@")," in the future)."),(0,r.yg)("h4",{id:"package-access-token"},"Package Access Token:"),(0,r.yg)("p",null,"Create a personal access token with ",(0,r.yg)("inlineCode",{parentName:"p"},"read:packages")," access in GitHub in order to use modules published in GitHub packages. Refer ",(0,r.yg)("a",{parentName:"p",href:"https://docs.github.com/en/github/authenticating-to-github/keeping-your-account-and-data-secure/creating-a-personal-access-token"},"Creating a Personal Access Token")," for help."),(0,r.yg)("p",null,"Run ",(0,r.yg)("inlineCode",{parentName:"p"},"docker login ghcr.io"),", and provide GitHub email id as username and personal access token created above as password. This will allow the docker to fetch images of ",(0,r.yg)("inlineCode",{parentName:"p"},"relay"),", ",(0,r.yg)("inlineCode",{parentName:"p"},"fabric-driver")," and ",(0,r.yg)("inlineCode",{parentName:"p"},"corda-driver")," from ",(0,r.yg)("inlineCode",{parentName:"p"},"hyperledger-labs/weaver-dlt-interoperability"),"."),(0,r.yg)("h2",{id:"getting-the-code-and-documentation"},"Getting the Code and Documentation"),(0,r.yg)("p",null,"Clone the ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability"},"weaver-dlt-interoperability")," repository. The code to get a basic test network up and running and test data-sharing interoperation flows lies in the subfolder ",(0,r.yg)("inlineCode",{parentName:"p"},"tests/network-setups"),", which should be your starting point, though the setups will rely on other parts of the repository, as you will find out in the instructions given on this page."),(0,r.yg)("h2",{id:"securing-components"},"Securing Components"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:"left"},"The relays and drivers corresponding to the different test networks you will encounter below can be run with or without TLS enabled. But the default files used in the demonstrations assume that either all relays and drivers are TLS-enabled or none are. Therefore, you should determine at the outset whether or not you wish to run the entire set of components in TLS-enabled mode, and select appropriate commands in the provided instructions.")))),(0,r.yg)("h2",{id:"hyperledger-fabric-components"},"Hyperledger Fabric Components"),(0,r.yg)("p",null,"Using the sequence of instructions below, you can start two separate Fabric networks, each with a single channel and application contract (chaincode). You can also start an interoperation contract, a relay and a ",(0,r.yg)("em",{parentName:"p"},"driver")," acting on behalf of each network. You can build a Fabric CLI tool with which you can initialize both networks' ledgers with access control policies, foreign networks' security groups (i.e., membership providers' certificate chains), and some sample key-value pairs that can be shared during subsequent interoperation flows."),(0,r.yg)("h3",{id:"fabric-network"},"Fabric Network"),(0,r.yg)("p",null,"The code for this lies in the ",(0,r.yg)("inlineCode",{parentName:"p"},"tests/network-setups")," folder."),(0,r.yg)("p",null,"This folder contains code to create and launch networks ",(0,r.yg)("inlineCode",{parentName:"p"},"network1")," and ",(0,r.yg)("inlineCode",{parentName:"p"},"network2")," of identical specifications:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Network: 1 peer, 1 peer CA, 1 ordering service node, 1 ordering service CA"),(0,r.yg)("li",{parentName:"ul"},"Single channel named ",(0,r.yg)("inlineCode",{parentName:"li"},"mychannel")),(0,r.yg)("li",{parentName:"ul"},"One of the following contracts deployed on ",(0,r.yg)("inlineCode",{parentName:"li"},"mychannel"),", the choice depending on the ",(0,r.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/interoperability-modes"},"interoperability mode")," you wish to test:",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"simplestate")," (",(0,r.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/data-sharing"},"Data Sharing"),"): supports simple transactions (",(0,r.yg)("inlineCode",{parentName:"li"},"Create"),", ",(0,r.yg)("inlineCode",{parentName:"li"},"Read"),", ",(0,r.yg)("inlineCode",{parentName:"li"},"Update"),", ",(0,r.yg)("inlineCode",{parentName:"li"},"Delete"),") involving storage and lookup of <key, value> pairs."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"simplestatewithacl")," (",(0,r.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/data-sharing"},"Data Sharing"),"): identical to ",(0,r.yg)("inlineCode",{parentName:"li"},"simplestate")," but with extra security features to ensure that the Weaver infrastructure cannot be bypassed by a malicious client of the network."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"simpleasset")," (",(0,r.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview"},"Asset Exchange"),"): supports creation, modification, transfer, and deletion, as well as locking, unlocking, and claiming, of simple bonds and tokens (examples of non-fungible and fungible assets respectively)."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"simpleassetandinterop")," (",(0,r.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview"},"Asset Exchange"),"): identical to ",(0,r.yg)("inlineCode",{parentName:"li"},"simpleasset")," but where the locking, unlocking, and claiming logic is imported as a library in the chaincode rather than available in the common Fabric Interoperation Chaincode (a Weaver component)."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"simpleassettransfer")," (",(0,r.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview"},"Asset Exchange")," or ",(0,r.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-transfer"},"Asset Transfer"),"): augmentation of ",(0,r.yg)("inlineCode",{parentName:"li"},"simpleasset")," with asset pledging, claiming, and reclaiming features for cross-network transfers.")))),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:"left"},"For new users, we recommend testing the Data Sharing feature first with the ",(0,r.yg)("inlineCode",{parentName:"td"},"simplestate")," contract. To test the other modes, you can simply ",(0,r.yg)("a",{parentName:"td",href:"#tear-down-the-setup"},"tear down")," the Fabric networks and restart them with the appropriate chaincodes installed.")))),(0,r.yg)("p",null,"Follow the instructions below to build and launch the networks:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"tests/network-setups/fabric/dev")," folder."),(0,r.yg)("li",{parentName:"ul"},"To spin up both network1 and network2 with the interoperation chaincode and the default ",(0,r.yg)("inlineCode",{parentName:"li"},"simplestate")," chaincode installed, run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make start-interop\n"))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("em",{parentName:"li"},"To launch the networks with a different application chaincode from the above list, run"),":",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make start-interop CHAINCODE_NAME=<chaincode-name>\n"))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("em",{parentName:"li"},"To launch the networks with 2 organizations, each with a peer (this will enable more variation and experimentation, which you can attempt after testing interoperation protocols across basic network configurations), run"),":",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},'make start-interop-local PROFILE="2-nodes"\n')))),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:"left"},"If you do not wish to test Fabric-Fabric interoperation, you can choose to launch only one of the two networks along with its interoperation chaincode. For ",(0,r.yg)("inlineCode",{parentName:"td"},"network1"),", run ",(0,r.yg)("inlineCode",{parentName:"td"},"make start-interop-network1"),", and for ",(0,r.yg)("inlineCode",{parentName:"td"},"network2"),", run ",(0,r.yg)("inlineCode",{parentName:"td"},"make start-interop-network2"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:"left"},"If you wish to enable end-to-end confidentiality by default in the interoperation modules that are deployed during network launch, set the environment variable ",(0,r.yg)("inlineCode",{parentName:"td"},"E2E_CONFIDENTIALITY")," to ",(0,r.yg)("inlineCode",{parentName:"td"},"true")," in the command line as follows: ",(0,r.yg)("inlineCode",{parentName:"td"},"E2E_CONFIDENTIALITY=true make start-interop"))))),(0,r.yg)("p",null,"For more information, refer to the associated ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/tests/network-setups/fabric/dev"},"README"),"."),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},"Troubleshooting Tips"),":"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"If you see any errors during the launches, re-check the prerequisites (software installations and credentials). Ensure your network connection is working. As a safe bet, you can retry after cleanup: kill and remove all Docker containers and associated volumes.")),(0,r.yg)("h3",{id:"fabric-relay"},"Fabric Relay"),(0,r.yg)("p",null,"The relay is a module acting on behalf of a network, enabling interoperation flows with other networks by communicating with their relays.\nThe code for this lies in the ",(0,r.yg)("inlineCode",{parentName:"p"},"core/relay")," folder."),(0,r.yg)("p",null,"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"p"},"core/relay")," folder and run a relay as follows:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"The ",(0,r.yg)("inlineCode",{parentName:"li"},"docker-compose.yaml")," in this folder is minimally configured with default values. To modify it for use with the Fabric testnets, run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make convert-compose-method2\n"))),(0,r.yg)("li",{parentName:"ul"},"(The ",(0,r.yg)("inlineCode",{parentName:"li"},".env.n1")," and ",(0,r.yg)("inlineCode",{parentName:"li"},".env.n1.tls")," files in the ",(0,r.yg)("inlineCode",{parentName:"li"},"docker/testnet-envs")," directory contain environment variables used by the ",(0,r.yg)("inlineCode",{parentName:"li"},"network1")," relay at startup and runtime.)"),(0,r.yg)("li",{parentName:"ul"},"(The ",(0,r.yg)("inlineCode",{parentName:"li"},".env.n2")," and ",(0,r.yg)("inlineCode",{parentName:"li"},".env.n2.tls")," files in the ",(0,r.yg)("inlineCode",{parentName:"li"},"docker/testnet-envs")," directory contain environment variables used by the ",(0,r.yg)("inlineCode",{parentName:"li"},"network2")," relay at startup and runtime.)"),(0,r.yg)("li",{parentName:"ul"},"To deploy the relay server for ",(0,r.yg)("inlineCode",{parentName:"li"},"network1")," without TLS, run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.n1'\n")),"Instead, to deploy the relay server with TLS, run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.n1.tls'\n"))),(0,r.yg)("li",{parentName:"ul"},"To deploy the relay server for ",(0,r.yg)("inlineCode",{parentName:"li"},"network2")," without TLS, run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.n2'\n")),"Instead, to deploy the relay server with TLS, run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.n2.tls'\n"))),(0,r.yg)("li",{parentName:"ul"},"After launching the relay(s), you can revert the ",(0,r.yg)("inlineCode",{parentName:"li"},"docker-compose.yaml")," changes by running:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make convert-compose-method1\n")))),(0,r.yg)("p",null,"For more information, see the ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/core/relay/relay-docker.md"},"relay-docker README"),"."),(0,r.yg)("h3",{id:"fabric-driver"},"Fabric Driver"),(0,r.yg)("p",null,"A driver is a DLT-specific plugin invoked by the relay while channelling external data queries to the local peer network and collecting a response with proofs. The Fabric driver is built as a Fabric client application on the ",(0,r.yg)("inlineCode",{parentName:"p"},"fabric-network")," NPM package.\nThe code for this lies in the ",(0,r.yg)("inlineCode",{parentName:"p"},"core/drivers/fabric-driver")," folder."),(0,r.yg)("p",null,"Use the following steps to run Fabric drivers in Docker containers:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"core/drivers/fabric-driver")," folder.")),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"The ",(0,r.yg)("inlineCode",{parentName:"li"},".env.n1")," and ",(0,r.yg)("inlineCode",{parentName:"li"},".env.n1.tls")," files in the ",(0,r.yg)("inlineCode",{parentName:"li"},"docker-testnet-envs")," directory contain environment variables used by the ",(0,r.yg)("inlineCode",{parentName:"li"},"network1")," driver at startup and runtime. Edit either of these files (depending on whether you wish to start the relay with or without TLS) as follows:",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},"Replace ",(0,r.yg)("inlineCode",{parentName:"li"},"<PATH-TO-WEAVER>")," with the absolute path of the ",(0,r.yg)("inlineCode",{parentName:"li"},"weaver-dlt-interoperability")," clone folder."))),(0,r.yg)("li",{parentName:"ul"},"Repeat the above step for ",(0,r.yg)("inlineCode",{parentName:"li"},".env.n2")," or ",(0,r.yg)("inlineCode",{parentName:"li"},".env.n2.tls")," in ",(0,r.yg)("inlineCode",{parentName:"li"},"docker-testnet-envs")," directory, which contain environment variables for the ",(0,r.yg)("inlineCode",{parentName:"li"},"network2")," driver."),(0,r.yg)("li",{parentName:"ul"},"To deploy the Fabric driver for ",(0,r.yg)("inlineCode",{parentName:"li"},"network1")," without TLS, run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.n1' NETWORK_NAME=$(grep NETWORK_NAME docker-testnet-envs/.env.n1 | cut -d '=' -f 2)\n")),"Instead, to deploy the driver with TLS, run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.n1.tls' NETWORK_NAME=$(grep NETWORK_NAME docker-testnet-envs/.env.n1.tls | cut -d '=' -f 2)\n"))),(0,r.yg)("li",{parentName:"ul"},"To deploy the Fabric driver for ",(0,r.yg)("inlineCode",{parentName:"li"},"network2")," without TLS, run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.n2' NETWORK_NAME=$(grep NETWORK_NAME docker-testnet-envs/.env.n2 | cut -d '=' -f 2)\n")),"Instead, to deploy the driver with TLS, run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.n2.tls' NETWORK_NAME=$(grep NETWORK_NAME docker-testnet-envs/.env.n2.tls | cut -d '=' -f 2)\n")))),(0,r.yg)("h3",{id:"fabric-iin-agent"},"Fabric IIN Agent"),(0,r.yg)("p",null,"IIN Agent is a client of a member of a DLT network or security domain with special permissions to update security domain identities and configurations on the ledger via the network's interoperation module. The code for this lies in the ",(0,r.yg)("inlineCode",{parentName:"p"},"core/identity-management/iin-agent")," folder. Navigate to the ",(0,r.yg)("inlineCode",{parentName:"p"},"core/identity-management/iin-agent")," folder."),(0,r.yg)("h4",{id:"deployment"},"Deployment"),(0,r.yg)("p",null,"Use the following steps to run Fabric IIN Agents in Docker containers:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"The ",(0,r.yg)("inlineCode",{parentName:"li"},".env.n1.org1")," and ",(0,r.yg)("inlineCode",{parentName:"li"},".env.n1.org1.tls")," files in the ",(0,r.yg)("inlineCode",{parentName:"li"},"docker-testnet/envs")," directory contain environment variables used by the iin-agent of ",(0,r.yg)("inlineCode",{parentName:"li"},"org1")," of ",(0,r.yg)("inlineCode",{parentName:"li"},"network1")," at startup and runtime. Edit either of these files (depending on whether you wish to start the relay with or without TLS) as follows:",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},"Replace ",(0,r.yg)("inlineCode",{parentName:"li"},"<PATH-TO-WEAVER>")," with the absolute path of the ",(0,r.yg)("inlineCode",{parentName:"li"},"weaver-dlt-interoperability")," clone folder."),(0,r.yg)("li",{parentName:"ul"},"If Fabric network was started with 1 org, and IIN Agents are to be started with TLS enabled, update the ",(0,r.yg)("inlineCode",{parentName:"li"},"DNS_CONFIG_PATH")," variable as:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre"},"DNS_CONFIG_PATH=./docker-testnet/configs/dnsconfig-tls.json\n"))),(0,r.yg)("li",{parentName:"ul"},"If Fabric network was started with 2 orgs, and IIN Agents are to be started without TLS, update the ",(0,r.yg)("inlineCode",{parentName:"li"},"DNS_CONFIG_PATH")," variable as",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre"},"DNS_CONFIG_PATH=./docker-testnet/configs/dnsconfig-2-nodes.json\n"))),(0,r.yg)("li",{parentName:"ul"},"If Fabric network was started with 2 orgs and IIN Agents are to be started with TLS enabled, update the ",(0,r.yg)("inlineCode",{parentName:"li"},"DNS_CONFIG_PATH")," variable as:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre"},"DNS_CONFIG_PATH=./docker-testnet/configs/dnsconfig-tls-2-nodes.json\n"))))),(0,r.yg)("li",{parentName:"ul"},"Repeat the above steps for all other environment variable files (depending upon whether tls is enabled) in ",(0,r.yg)("inlineCode",{parentName:"li"},"docker-testnet/envs")," directory."),(0,r.yg)("li",{parentName:"ul"},"To deploy the Fabric IIN Agent for ",(0,r.yg)("inlineCode",{parentName:"li"},"org1")," of ",(0,r.yg)("inlineCode",{parentName:"li"},"network1")," without TLS, run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n1.org1' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n1.org1 | cut -d '=' -f 2)\n")),"Instead, to deploy the IIN Agent with TLS, run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n1.org1.tls' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n1.org1.tls | cut -d '=' -f 2)\n"))),(0,r.yg)("li",{parentName:"ul"},"To deploy the Fabric IIN Agent for ",(0,r.yg)("inlineCode",{parentName:"li"},"org2")," of ",(0,r.yg)("inlineCode",{parentName:"li"},"network1")," without TLS (",(0,r.yg)("em",{parentName:"li"},"only required if Fabric network was started with 2 orgs"),"), run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n1.org2' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n1.org2 | cut -d '=' -f 2)\n")),"Instead, to deploy the IIN Agent with TLS, run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n1.org2.tls' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n1.org2.tls | cut -d '=' -f 2)\n"))),(0,r.yg)("li",{parentName:"ul"},"To deploy the Fabric IIN Agent for ",(0,r.yg)("inlineCode",{parentName:"li"},"org1")," of ",(0,r.yg)("inlineCode",{parentName:"li"},"network2")," without TLS, run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n2.org1' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n2.org1 | cut -d '=' -f 2)\n")),"Instead, to deploy the IIN Agent with TLS, run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n2.org1.tls' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n2.org1.tls | cut -d '=' -f 2)\n"))),(0,r.yg)("li",{parentName:"ul"},"To deploy the Fabric IIN Agent for ",(0,r.yg)("inlineCode",{parentName:"li"},"org2")," of ",(0,r.yg)("inlineCode",{parentName:"li"},"network2")," without TLS (",(0,r.yg)("em",{parentName:"li"},"only required if Fabric network was started with 2 orgs"),"), run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n2.org2' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n2.org2 | cut -d '=' -f 2)\n")),"Instead, to deploy the IIN Agent with TLS, run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n2.org2.tls' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n2.org2.tls | cut -d '=' -f 2)\n")))),(0,r.yg)("h3",{id:"fabric-client-application"},"Fabric Client (Application)"),(0,r.yg)("p",null,"The CLI is used to interact with a Fabric network, configure it and run chaincode transactions to record data on the channel ledger or query data. It is also used to interact with remote networks through the relay in order to trigger an interoperation flow for data request and acceptance."),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"fabric-cli")," Node.js source code is located in the ",(0,r.yg)("inlineCode",{parentName:"p"},"samples/fabric/fabric-cli")," folder and the Golang source code in the ",(0,r.yg)("inlineCode",{parentName:"p"},"samples/fabric/go-cli")," folder."),(0,r.yg)("h4",{id:"prerequisites-1"},"Prerequisites"),(0,r.yg)("p",null,"If you are using a Linux system, make sure that lib64 is installed."),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:"left"},"For the Node.js version of the ",(0,r.yg)("inlineCode",{parentName:"td"},"fabric-cli"),", the setup and running instructions below were tested with all Node.js versions from v11.14.0 to v14.17.3.")))),(0,r.yg)("h4",{id:"installation"},"Installation"),(0,r.yg)("p",null,"You can install ",(0,r.yg)("inlineCode",{parentName:"p"},"fabric-cli")," as follows (for both the Node.js and Golang versions):"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"samples/fabric/fabric-cli")," folder (for the Node.js version) or the ",(0,r.yg)("inlineCode",{parentName:"li"},"samples/fabric/go-cli")," folder (for the Golang version)."),(0,r.yg)("li",{parentName:"ul"},"Create ",(0,r.yg)("inlineCode",{parentName:"li"},".npmrc")," from template ",(0,r.yg)("inlineCode",{parentName:"li"},".npmrc.template"),", by replacing ",(0,r.yg)("inlineCode",{parentName:"li"},"<personal-access-token>")," with yours created ",(0,r.yg)("a",{parentName:"li",href:"#package-access-token"},"above"),".."),(0,r.yg)("li",{parentName:"ul"},"Run the following to install dependencies (for the Node.js version) or the executable (for the Golang version):",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make build\n"))),(0,r.yg)("li",{parentName:"ul"},"Use the ",(0,r.yg)("inlineCode",{parentName:"li"},"fabric-cli")," executable in the ",(0,r.yg)("inlineCode",{parentName:"li"},"bin")," folder for ",(0,r.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/ledger-initialization"},"subsequent actions"),".")),(0,r.yg)("h2",{id:"corda-components"},"Corda Components"),(0,r.yg)("p",null,"Using the sequence of instructions below, you can start a Corda network and run an application CorDapp on it. You can also run an interoperation CorDapp, a relay and a ",(0,r.yg)("em",{parentName:"p"},"driver")," acting on behalf of the network. You can initialize the network's vault with access control policies, foreign networks' security groups (i.e., membership providers' certificate chains), and some sample state values that can be shared during subsequent interoperation flows."),(0,r.yg)("h3",{id:"corda-network"},"Corda Network"),(0,r.yg)("p",null,"The Corda networks' code lies in the ",(0,r.yg)("inlineCode",{parentName:"p"},"tests/network-setups/corda")," folder. You can launch two separate Corda networks, namely ",(0,r.yg)("inlineCode",{parentName:"p"},"Corda_Network")," and ",(0,r.yg)("inlineCode",{parentName:"p"},"Corda_Network2"),". Each network runs the ",(0,r.yg)("inlineCode",{parentName:"p"},"samples/corda/corda-simple-application")," CorDapp by default, which maintains a state named ",(0,r.yg)("inlineCode",{parentName:"p"},"SimpleState")," containing a set of key-value pairs (of strings)."),(0,r.yg)("p",null,"The following steps will, in addition to launching the network, build the CorDapp and a Corda client in ",(0,r.yg)("inlineCode",{parentName:"p"},"samples/corda/corda-simple-application/client"),"."),(0,r.yg)("h4",{id:"running-with-interoperation-cordapp-from-github-packages"},"Running with Interoperation CorDapp from GitHub Packages"),(0,r.yg)("p",null,"Follow the instructions below to build and launch the network:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"tests/network-setups/corda")," folder."),(0,r.yg)("li",{parentName:"ul"},"Create copy of ",(0,r.yg)("inlineCode",{parentName:"li"},"github.properties.template")," as ",(0,r.yg)("inlineCode",{parentName:"li"},"github.properties"),"."),(0,r.yg)("li",{parentName:"ul"},"Replace ",(0,r.yg)("inlineCode",{parentName:"li"},"<GITHUB email>")," with your GitHub email, and ",(0,r.yg)("inlineCode",{parentName:"li"},"<GITHUB Personal Access Token>")," with the access token created ",(0,r.yg)("a",{parentName:"li",href:"#package-access-token"},"above"),"."),(0,r.yg)("li",{parentName:"ul"},"To spin up the Corda networks with the Interoperation CorDapps:",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},"Each consisting of 1 node and a notary (for data-transfer), run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make start\n"))),(0,r.yg)("li",{parentName:"ul"},"Each consisting of 2 nodes and a notary (for asset-exchange/transfer), run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},'make start PROFILE="2-nodes"\n'))),(0,r.yg)("li",{parentName:"ul"},"Each consisting of 3 nodes and a notary (for asset-exchange/transfer), run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},'make start PROFILE="3-nodes"\n')))))),(0,r.yg)("p",null,"You should see the following message in the terminal:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre"},"Waiting for network node services to start\n")),(0,r.yg)("p",null,"The Corda nodes and notary may take a while (several minutes on memory-constrained systems) to start. If they start up successfully, you should something like the following for each network, though the number of node entries will depend on the profile you used to start the network with (replace ",(0,r.yg)("inlineCode",{parentName:"p"},"<network-name>")," with ",(0,r.yg)("inlineCode",{parentName:"p"},"Corda_Network")," or ",(0,r.yg)("inlineCode",{parentName:"p"},"Corda_Network2"),"):"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"PartyA node services started for network <network-name>\nPartyB node services started for network <network-name>\nPartyC node services started for network <network-name>\nNotary node services started for network <network-name>\n")),(0,r.yg)("h3",{id:"corda-relay"},"Corda Relay"),(0,r.yg)("p",null,"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"p"},"core/relay")," folder and run a relay for ",(0,r.yg)("inlineCode",{parentName:"p"},"Corda_Network")," and/or ",(0,r.yg)("inlineCode",{parentName:"p"},"Corda_Network2")," in Docker container as follows:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},"The ",(0,r.yg)("inlineCode",{parentName:"p"},"docker-compose.yaml")," in this folder is minimally configured with default values. To modify it for use with the Fabric testnets, run:"),(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make convert-compose-method2\n"))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},"(The ",(0,r.yg)("inlineCode",{parentName:"p"},".env.corda")," and ",(0,r.yg)("inlineCode",{parentName:"p"},".env.corda.tls")," files in the ",(0,r.yg)("inlineCode",{parentName:"p"},"docker/testnet-envs")," directory contain environment variables used by the ",(0,r.yg)("inlineCode",{parentName:"p"},"Corda_Network")," relay at startup and runtime.)")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},"(The ",(0,r.yg)("inlineCode",{parentName:"p"},".env.corda2")," and ",(0,r.yg)("inlineCode",{parentName:"p"},".env.corda2.tls")," files in the ",(0,r.yg)("inlineCode",{parentName:"p"},"docker/testnet-envs")," directory contain environment variables used by the ",(0,r.yg)("inlineCode",{parentName:"p"},"Corda_Network2")," relay at startup and runtime.)")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},"To deploy the relay server for ",(0,r.yg)("inlineCode",{parentName:"p"},"Corda_Network")," without TLS, run:"),(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.corda'\n")),(0,r.yg)("p",{parentName:"li"},"Instead, to deploy the relay server with TLS, run:"),(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.corda.tls'\n"))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},"To deploy the relay server for ",(0,r.yg)("inlineCode",{parentName:"p"},"Corda_Network2")," without TLS, run:"),(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.corda2'\n")),(0,r.yg)("p",{parentName:"li"},"Instead, to deploy the relay server with TLS, run:"),(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.corda2.tls'\n"))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},"After launching the relay(s), you can revert the ",(0,r.yg)("inlineCode",{parentName:"p"},"docker-compose.yaml")," changes by running:"),(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make convert-compose-method1\n")))),(0,r.yg)("h3",{id:"corda-driver"},"Corda Driver"),(0,r.yg)("p",null,"Use the following steps to run Corda drivers in Docker containers:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Navigate to the ",(0,r.yg)("inlineCode",{parentName:"li"},"core/drivers/corda-driver")," folder."),(0,r.yg)("li",{parentName:"ul"},"(The ",(0,r.yg)("inlineCode",{parentName:"li"},".env.corda")," and ",(0,r.yg)("inlineCode",{parentName:"li"},".env.corda.tls")," files in the ",(0,r.yg)("inlineCode",{parentName:"li"},"docker-testnet-envs")," contain environment variables used by the ",(0,r.yg)("inlineCode",{parentName:"li"},"Corda_Network")," driver at startup and runtime.)"),(0,r.yg)("li",{parentName:"ul"},"(The ",(0,r.yg)("inlineCode",{parentName:"li"},".env.corda2")," and ",(0,r.yg)("inlineCode",{parentName:"li"},".env.corda2.tls")," files in the ",(0,r.yg)("inlineCode",{parentName:"li"},"docker-testnet-envs")," contain environment variables used by the ",(0,r.yg)("inlineCode",{parentName:"li"},"Corda_Network2")," driver at startup and runtime.)"),(0,r.yg)("li",{parentName:"ul"},"To deploy the Corda driver for ",(0,r.yg)("inlineCode",{parentName:"li"},"Corda_Network")," without TLS, run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.corda'\n")),"Instead, to deploy the driver with TLS, run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.corda.tls'\n")),"If the driver starts successfully, it should log the following message when you run ",(0,r.yg)("inlineCode",{parentName:"li"},"docker logs corda-driver-Corda_Network"),":",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre"},"Corda driver gRPC server started. Listening on port 9099\n"))),(0,r.yg)("li",{parentName:"ul"},"To deploy the Corda driver for ",(0,r.yg)("inlineCode",{parentName:"li"},"Corda_Network2")," without TLS, run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.corda2'\n")),"Instead, to deploy the driver with TLS, run:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.corda2.tls'\n")),"If the driver starts successfully, it should log the following message when you run ",(0,r.yg)("inlineCode",{parentName:"li"},"docker logs corda-driver-Corda_Network2"),":",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre"},"Corda driver gRPC server started. Listening on port 9098\n")))),(0,r.yg)("h2",{id:"tear-down-the-setup"},"Tear Down the Setup"),(0,r.yg)("p",null,"Bring down the various components as follows (",(0,r.yg)("em",{parentName:"p"},"Navigate to the root folder of your clone of the Weaver repository"),"):"),(0,r.yg)("h3",{id:"relay"},"Relay"),(0,r.yg)("p",null,"To bring down the relays (for all 3 networks), run:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"cd core/relay\nmake convert-compose-method2\nmake stop COMPOSE_ARG='--env-file docker/testnet-envs/.env.n1'\nmake stop COMPOSE_ARG='--env-file docker/testnet-envs/.env.n2'\nmake stop COMPOSE_ARG='--env-file docker/testnet-envs/.env.corda'\nmake stop COMPOSE_ARG='--env-file docker/testnet-envs/.env.corda2'\nmake convert-compose-method1\ncd -\n")),(0,r.yg)("h3",{id:"fabric-driver-1"},"Fabric Driver"),(0,r.yg)("p",null,"To bring down the fabric drivers (for both networks), run:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"cd core/drivers/fabric-driver\nmake stop COMPOSE_ARG='--env-file docker-testnet-envs/.env.n1'\nmake stop COMPOSE_ARG='--env-file docker-testnet-envs/.env.n2'\ncd -\n")),(0,r.yg)("h3",{id:"corda-driver-1"},"Corda Driver"),(0,r.yg)("p",null,"To bring down the corda driver, run:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"cd core/drivers/corda-driver\nmake stop COMPOSE_ARG='--env-file docker-testnet-envs/.env.corda'\nmake stop COMPOSE_ARG='--env-file docker-testnet-envs/.env.corda2'\ncd -\n")),(0,r.yg)("h3",{id:"corda-network-1"},"Corda Network"),(0,r.yg)("p",null,"To bring down the Corda network:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"cd tests/network-setups/corda\nmake clean\ncd -\n")),(0,r.yg)("h3",{id:"fabric-network-1"},"Fabric Network"),(0,r.yg)("p",null,"To bring down both of the Fabric networks along with weaver components:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"cd tests/network-setups/fabric/dev\nmake clean\ncd -\n")))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/c9723ef0.f2cba00c.js b/assets/js/c9723ef0.f2cba00c.js deleted file mode 100644 index 90b3e98ea..000000000 --- a/assets/js/c9723ef0.f2cba00c.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[9167],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>u});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,a,r=function(e,t){if(null==e)return{};var n,a,r={},i=Object.keys(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=a.createContext({}),p=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},d=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},c="mdxType",k={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),c=p(n),m=r,u=c["".concat(s,".").concat(m)]||c[m]||k[m]||i;return n?a.createElement(u,o(o({ref:t},d),{},{components:n})):a.createElement(u,o({ref:t},d))}));function u(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,o=new Array(i);o[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:r,o[1]=l;for(var p=2;p<i;p++)o[p]=n[p];return a.createElement.apply(null,o)}return a.createElement.apply(null,n)}m.displayName="MDXCreateElement"},3190:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>k,frontMatter:()=>i,metadata:()=>l,toc:()=>p});var a=n(7462),r=(n(7294),n(3905));const i={id:"setup-packages-docker",title:"Setup with Imported Dockerized Weaver Components",pagination_prev:"external/getting-started/test-network/overview",pagination_next:"external/getting-started/test-network/ledger-initialization"},o=void 0,l={unversionedId:"external/getting-started/test-network/setup-packages-docker",id:"external/getting-started/test-network/setup-packages-docker",title:"Setup with Imported Dockerized Weaver Components",description:"\x3c!--",source:"@site/docs/external/getting-started/test-network/setup-packages-docker.md",sourceDirName:"external/getting-started/test-network",slug:"/external/getting-started/test-network/setup-packages-docker",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-packages-docker",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/getting-started/test-network/setup-packages-docker.md",tags:[],version:"current",frontMatter:{id:"setup-packages-docker",title:"Setup with Imported Dockerized Weaver Components",pagination_prev:"external/getting-started/test-network/overview",pagination_next:"external/getting-started/test-network/ledger-initialization"},sidebar:"Documentation",previous:{title:"Component Overview",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/overview"},next:{title:"Ledger Initialization",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/ledger-initialization"}},s={},p=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Software",id:"software",level:3},{value:"Credentials",id:"credentials",level:3},{value:"Package Access Token:",id:"package-access-token",level:4},{value:"Getting the Code and Documentation",id:"getting-the-code-and-documentation",level:2},{value:"Securing Components",id:"securing-components",level:2},{value:"Hyperledger Fabric Components",id:"hyperledger-fabric-components",level:2},{value:"Fabric Network",id:"fabric-network",level:3},{value:"Fabric Relay",id:"fabric-relay",level:3},{value:"Fabric Driver",id:"fabric-driver",level:3},{value:"Fabric IIN Agent",id:"fabric-iin-agent",level:3},{value:"Deployment",id:"deployment",level:4},{value:"Fabric Client (Application)",id:"fabric-client-application",level:3},{value:"Prerequisites",id:"prerequisites-1",level:4},{value:"Installation",id:"installation",level:4},{value:"Corda Components",id:"corda-components",level:2},{value:"Corda Network",id:"corda-network",level:3},{value:"Running with Interoperation CorDapp from Github Packages",id:"running-with-interoperation-cordapp-from-github-packages",level:4},{value:"Corda Relay",id:"corda-relay",level:3},{value:"Corda Driver",id:"corda-driver",level:3},{value:"Tear Down the Setup",id:"tear-down-the-setup",level:2},{value:"Relay",id:"relay",level:3},{value:"Fabric Driver",id:"fabric-driver-1",level:3},{value:"Corda Driver",id:"corda-driver-1",level:3},{value:"Corda Network",id:"corda-network-1",level:3},{value:"Fabric Network",id:"fabric-network-1",level:3}],d={toc:p},c="wrapper";function k(e){let{components:t,...n}=e;return(0,r.kt)(c,(0,a.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null," In this document, we detail the steps using which you can bring up networks using the default configuration settings and by fetching pre-built Weaver interoperation modules, SDK libraries, and relay docker image, drivers docker images from Github Package repositories. To customize these settings (e.g., hostnames, ports), refer to the ",(0,r.kt)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/advanced-configuration"},"Advanced Configuration page"),"."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:"left"},"All components are run within Docker containers, except client applications.")))),(0,r.kt)("p",null," Follow the instructions below to build and run components followed by interoperation flows. These instructions have been tested on Ubuntu Linux (bash shell) and Mac OS. In general, they should work on any system and shell as long as the various dependencies have been installed and configured."),(0,r.kt)("h2",{id:"prerequisites"},"Prerequisites"),(0,r.kt)("h3",{id:"software"},"Software"),(0,r.kt)("p",null,"Before starting, make sure you have the following software installed on your host machine:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Curl: ",(0,r.kt)("em",{parentName:"li"},"install using package manager, like ",(0,r.kt)("inlineCode",{parentName:"em"},"apt")," on Debian/Ubuntu Linux")),(0,r.kt)("li",{parentName:"ul"},"Git: ",(0,r.kt)("a",{parentName:"li",href:"https://git-scm.com/book/en/v2/Getting-Started-Installing-Git"},"sample instructions")),(0,r.kt)("li",{parentName:"ul"},"Docker: ",(0,r.kt)("a",{parentName:"li",href:"https://docs.docker.com/engine/install/"},"sample instructions")," (Latest version)"),(0,r.kt)("li",{parentName:"ul"},"Docker-Compose: ",(0,r.kt)("a",{parentName:"li",href:"https://docs.docker.com/compose/install/"},"sample instructions")," (Version 1.28.2 or higher, but lower than version V2)"),(0,r.kt)("li",{parentName:"ul"},"Golang: ",(0,r.kt)("a",{parentName:"li",href:"https://golang.org/dl/"},"sample instructions")," (Version 1.16 or higher)"),(0,r.kt)("li",{parentName:"ul"},"Java (JDK and JRE): ",(0,r.kt)("a",{parentName:"li",href:"https://openjdk.java.net/install/"},"sample instructions")," (Version 8)"),(0,r.kt)("li",{parentName:"ul"},"Node.js and NPM: ",(0,r.kt)("a",{parentName:"li",href:"https://nodejs.org/en/download/package-manager/"},"sample instructions")," (Version 11 to Version 16 Supported)"),(0,r.kt)("li",{parentName:"ul"},"Yarn: ",(0,r.kt)("a",{parentName:"li",href:"https://classic.yarnpkg.com/en/docs/install/"},"sample instructions"))),(0,r.kt)("h3",{id:"credentials"},"Credentials"),(0,r.kt)("p",null,"Make sure you have an SSH or GPG key registered in ",(0,r.kt)("a",{parentName:"p",href:"https://github.com"},"https://github.com")," to allow seamless cloning of repositories (at present, various setup scripts clone repositories using the ",(0,r.kt)("inlineCode",{parentName:"p"},"https://")," prefix but this may change to ",(0,r.kt)("inlineCode",{parentName:"p"},"git@")," in the future)."),(0,r.kt)("h4",{id:"package-access-token"},"Package Access Token:"),(0,r.kt)("p",null,"Create a personal access token with ",(0,r.kt)("inlineCode",{parentName:"p"},"read:packages")," access in github in order to use modules published in github packages. Refer ",(0,r.kt)("a",{parentName:"p",href:"https://docs.github.com/en/github/authenticating-to-github/keeping-your-account-and-data-secure/creating-a-personal-access-token"},"Creating a Personal Access Token")," for help."),(0,r.kt)("p",null,"Run ",(0,r.kt)("inlineCode",{parentName:"p"},"docker login ghcr.io"),", and provide github email id as username and personal access token created above as password. This will allow the docker to fetch images of ",(0,r.kt)("inlineCode",{parentName:"p"},"relay"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"fabric-driver")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"corda-driver")," from ",(0,r.kt)("inlineCode",{parentName:"p"},"hyperledger-labs/weaver-dlt-interoperability"),"."),(0,r.kt)("h2",{id:"getting-the-code-and-documentation"},"Getting the Code and Documentation"),(0,r.kt)("p",null,"Clone the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability"},"weaver-dlt-interoperability")," repository. The code to get a basic test network up and running and test data-sharing interoperation flows lies in the subfolder ",(0,r.kt)("inlineCode",{parentName:"p"},"tests/network-setups"),", which should be your starting point, though the setups will rely on other parts of the repository, as you will find out in the instructions given on this page."),(0,r.kt)("h2",{id:"securing-components"},"Securing Components"),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:"left"},"The relays and drivers corresponding to the different test networks you will encounter below can be run with or without TLS enabled. But the default files used in the demonstrations assume that either all relays and drivers are TLS-enabled or none are. Therefore, you should determine at the outset whether or not you wish to run the entire set of components in TLS-enabled mode, and select appropriate commands in the provided instructions.")))),(0,r.kt)("h2",{id:"hyperledger-fabric-components"},"Hyperledger Fabric Components"),(0,r.kt)("p",null,"Using the sequence of instructions below, you can start two separate Fabric networks, each with a single channel and application contract (chaincode). You can also start an interoperation contract, a relay and a ",(0,r.kt)("em",{parentName:"p"},"driver")," acting on behalf of each network. You can build a Fabric CLI tool with which you can initialize both networks' ledgers with access control policies, foreign networks' security groups (i.e., membership providers' certificate chains), and some sample key-value pairs that can be shared during subsequent interoperation flows."),(0,r.kt)("h3",{id:"fabric-network"},"Fabric Network"),(0,r.kt)("p",null,"The code for this lies in the ",(0,r.kt)("inlineCode",{parentName:"p"},"tests/network-setups")," folder."),(0,r.kt)("p",null,"This folder contains code to create and launch networks ",(0,r.kt)("inlineCode",{parentName:"p"},"network1")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"network2")," of identical specifications:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Network: 1 peer, 1 peer CA, 1 ordering service node, 1 ordering service CA"),(0,r.kt)("li",{parentName:"ul"},"Single channel named ",(0,r.kt)("inlineCode",{parentName:"li"},"mychannel")),(0,r.kt)("li",{parentName:"ul"},"One of the following contracts deployed on ",(0,r.kt)("inlineCode",{parentName:"li"},"mychannel"),", the choice depending on the ",(0,r.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/interoperability-modes"},"interoperability mode")," you wish to test:",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"simplestate")," (",(0,r.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/data-sharing"},"Data Sharing"),"): supports simple transactions (",(0,r.kt)("inlineCode",{parentName:"li"},"Create"),", ",(0,r.kt)("inlineCode",{parentName:"li"},"Read"),", ",(0,r.kt)("inlineCode",{parentName:"li"},"Update"),", ",(0,r.kt)("inlineCode",{parentName:"li"},"Delete"),") involving storage and lookup of <key, value> pairs."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"simplestatewithacl")," (",(0,r.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/data-sharing"},"Data Sharing"),"): identical to ",(0,r.kt)("inlineCode",{parentName:"li"},"simplestate")," but with extra security features to ensure that the Weaver infrastructure cannot be bypassed by a malicious client of the network."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"simpleasset")," (",(0,r.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview"},"Asset Exchange"),"): supports creation, modification, transfer, and deletion, as well as locking, unlocking, and claiming, of simple bonds and tokens (examples of non-fungible and fungible assets respectively)."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"simpleassetandinterop")," (",(0,r.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview"},"Asset Exchange"),"): identical to ",(0,r.kt)("inlineCode",{parentName:"li"},"simpleasset")," but where the locking, unlocking, and claiming logic is imported as a library in the chaincode rather than available in the common Fabric Interoperation Chaincode (a Weaver component)."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"simpleassettransfer")," (",(0,r.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview"},"Asset Exchange")," or ",(0,r.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-transfer"},"Asset Transfer"),"): augmentation of ",(0,r.kt)("inlineCode",{parentName:"li"},"simpleasset")," with asset pledging, claiming, and reclaiming features for cross-network transfers.")))),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:"left"},"For new users, we recommend testing the Data Sharing feature first with the ",(0,r.kt)("inlineCode",{parentName:"td"},"simplestate")," contract. To test the other modes, you can simply ",(0,r.kt)("a",{parentName:"td",href:"#tear-down-the-setup"},"tear down")," the Fabric networks and restart them with the appropriate chaincodes installed.")))),(0,r.kt)("p",null,"Follow the instructions below to build and launch the networks:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"tests/network-setups/fabric/dev")," folder."),(0,r.kt)("li",{parentName:"ul"},"To spin up both network1 and network2 with the interoperation chaincode and the default ",(0,r.kt)("inlineCode",{parentName:"li"},"simplestate")," chaincode installed, run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make start-interop\n"))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("em",{parentName:"li"},"To launch the networks with a different application chaincode from the above list, run"),":",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make start-interop CHAINCODE_NAME=<chaincode-name>\n"))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("em",{parentName:"li"},"To launch the networks with 2 organizations, each with a peer (this will enable more variation and experimentation, which you can attempt after testing interoperation protocols across basic network configurations), run"),":",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'make start-interop-local PROFILE="2-nodes"\n')))),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:"left"},"If you do not wish to test Fabric-Fabric interoperation, you can choose to launch only one of the two networks along with its interoperation chaincode. For ",(0,r.kt)("inlineCode",{parentName:"td"},"network1"),", run ",(0,r.kt)("inlineCode",{parentName:"td"},"make start-interop-network1"),", and for ",(0,r.kt)("inlineCode",{parentName:"td"},"network2"),", run ",(0,r.kt)("inlineCode",{parentName:"td"},"make start-interop-network2"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:"left"},"If you wish to enable end-to-end confidentiality by default in the interoperation modules that are deployed during network launch, set the environment variable ",(0,r.kt)("inlineCode",{parentName:"td"},"E2E_CONFIDENTIALITY")," to ",(0,r.kt)("inlineCode",{parentName:"td"},"true")," in the command line as follows: ",(0,r.kt)("inlineCode",{parentName:"td"},"E2E_CONFIDENTIALITY=true make start-interop"))))),(0,r.kt)("p",null,"For more information, refer to the associated ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/tests/network-setups/fabric/dev"},"README"),"."),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Troubleshooting Tips"),":"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"If you see any errors during the launches, re-check the prerequisites (software installations and credentials). Ensure your network connection is working. As a safe bet, you can retry after cleanup: kill and remove all Docker containers and associated volumes.")),(0,r.kt)("h3",{id:"fabric-relay"},"Fabric Relay"),(0,r.kt)("p",null,"The relay is a module acting on behalf of a network, enabling interoperation flows with other networks by communicating with their relays.\nThe code for this lies in the ",(0,r.kt)("inlineCode",{parentName:"p"},"core/relay")," folder."),(0,r.kt)("p",null,"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"p"},"core/relay")," folder and run a relay as follows:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"The ",(0,r.kt)("inlineCode",{parentName:"li"},"docker-compose.yaml")," in this folder is minimally configured with default values. To modify it for use with the Fabric testnets, run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make convert-compose-method2\n"))),(0,r.kt)("li",{parentName:"ul"},"(The ",(0,r.kt)("inlineCode",{parentName:"li"},".env.n1")," and ",(0,r.kt)("inlineCode",{parentName:"li"},".env.n1.tls")," files in the ",(0,r.kt)("inlineCode",{parentName:"li"},"docker/testnet-envs")," directory contain environment variables used by the ",(0,r.kt)("inlineCode",{parentName:"li"},"network1")," relay at startup and runtime.)"),(0,r.kt)("li",{parentName:"ul"},"(The ",(0,r.kt)("inlineCode",{parentName:"li"},".env.n2")," and ",(0,r.kt)("inlineCode",{parentName:"li"},".env.n2.tls")," files in the ",(0,r.kt)("inlineCode",{parentName:"li"},"docker/testnet-envs")," directory contain environment variables used by the ",(0,r.kt)("inlineCode",{parentName:"li"},"network2")," relay at startup and runtime.)"),(0,r.kt)("li",{parentName:"ul"},"To deploy the relay server for ",(0,r.kt)("inlineCode",{parentName:"li"},"network1")," without TLS, run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.n1'\n")),"Instead, to deploy the relay server with TLS, run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.n1.tls'\n"))),(0,r.kt)("li",{parentName:"ul"},"To deploy the relay server for ",(0,r.kt)("inlineCode",{parentName:"li"},"network2")," without TLS, run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.n2'\n")),"Instead, to deploy the relay server with TLS, run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.n2.tls'\n"))),(0,r.kt)("li",{parentName:"ul"},"After launching the relay(s), you can revert the ",(0,r.kt)("inlineCode",{parentName:"li"},"docker-compose.yaml")," changes by running:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make convert-compose-method1\n")))),(0,r.kt)("p",null,"For more information, see the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/core/relay/relay-docker.md"},"relay-docker README"),"."),(0,r.kt)("h3",{id:"fabric-driver"},"Fabric Driver"),(0,r.kt)("p",null,"A driver is a DLT-specific plugin invoked by the relay while channelling external data queries to the local peer network and collecting a response with proofs. The Fabric driver is built as a Fabric client application on the ",(0,r.kt)("inlineCode",{parentName:"p"},"fabric-network")," NPM package.\nThe code for this lies in the ",(0,r.kt)("inlineCode",{parentName:"p"},"core/drivers/fabric-driver")," folder."),(0,r.kt)("p",null,"Use the following steps to run Fabric drivers in Docker containers:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"core/drivers/fabric-driver")," folder.")),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"The ",(0,r.kt)("inlineCode",{parentName:"li"},".env.n1")," and ",(0,r.kt)("inlineCode",{parentName:"li"},".env.n1.tls")," files in the ",(0,r.kt)("inlineCode",{parentName:"li"},"docker-testnet-envs")," directory contain environment variables used by the ",(0,r.kt)("inlineCode",{parentName:"li"},"network1")," driver at startup and runtime. Edit either of these files (depending on whether you wish to start the relay with or without TLS) as follows:",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"Replace ",(0,r.kt)("inlineCode",{parentName:"li"},"<PATH-TO-WEAVER>")," with the absolute path of the ",(0,r.kt)("inlineCode",{parentName:"li"},"weaver-dlt-interoperability")," clone folder."))),(0,r.kt)("li",{parentName:"ul"},"Repeat the above step for ",(0,r.kt)("inlineCode",{parentName:"li"},".env.n2")," or ",(0,r.kt)("inlineCode",{parentName:"li"},".env.n2.tls")," in ",(0,r.kt)("inlineCode",{parentName:"li"},"docker-testnet-envs")," directory, which contain environment variables for the ",(0,r.kt)("inlineCode",{parentName:"li"},"network2")," driver."),(0,r.kt)("li",{parentName:"ul"},"To deploy the Fabric driver for ",(0,r.kt)("inlineCode",{parentName:"li"},"network1")," without TLS, run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.n1' NETWORK_NAME=$(grep NETWORK_NAME docker-testnet-envs/.env.n1 | cut -d '=' -f 2)\n")),"Instead, to deploy the driver with TLS, run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.n1.tls' NETWORK_NAME=$(grep NETWORK_NAME docker-testnet-envs/.env.n1.tls | cut -d '=' -f 2)\n"))),(0,r.kt)("li",{parentName:"ul"},"To deploy the Fabric driver for ",(0,r.kt)("inlineCode",{parentName:"li"},"network2")," without TLS, run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.n2' NETWORK_NAME=$(grep NETWORK_NAME docker-testnet-envs/.env.n2 | cut -d '=' -f 2)\n")),"Instead, to deploy the driver with TLS, run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.n2.tls' NETWORK_NAME=$(grep NETWORK_NAME docker-testnet-envs/.env.n2.tls | cut -d '=' -f 2)\n")))),(0,r.kt)("h3",{id:"fabric-iin-agent"},"Fabric IIN Agent"),(0,r.kt)("p",null,"IIN Agent is a client of a member of a DLT network or security domain with special permissions to update security domain identities and configurations on the ledger via the network's interoperation module. The code for this lies in the ",(0,r.kt)("inlineCode",{parentName:"p"},"core/identity-management/iin-agent")," folder. Navigate to the ",(0,r.kt)("inlineCode",{parentName:"p"},"core/identity-management/iin-agent")," folder."),(0,r.kt)("h4",{id:"deployment"},"Deployment"),(0,r.kt)("p",null,"Use the following steps to run Fabric IIN Agents in Docker containers:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"The ",(0,r.kt)("inlineCode",{parentName:"li"},".env.n1.org1")," and ",(0,r.kt)("inlineCode",{parentName:"li"},".env.n1.org1.tls")," files in the ",(0,r.kt)("inlineCode",{parentName:"li"},"docker-testnet/envs")," directory contain environment variables used by the iin-agent of ",(0,r.kt)("inlineCode",{parentName:"li"},"org1")," of ",(0,r.kt)("inlineCode",{parentName:"li"},"network1")," at startup and runtime. Edit either of these files (depending on whether you wish to start the relay with or without TLS) as follows:",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"Replace ",(0,r.kt)("inlineCode",{parentName:"li"},"<PATH-TO-WEAVER>")," with the absolute path of the ",(0,r.kt)("inlineCode",{parentName:"li"},"weaver-dlt-interoperability")," clone folder."),(0,r.kt)("li",{parentName:"ul"},"If Fabric network was started with 1 org, and IIN Agents are to be started with TLS enabled, update the ",(0,r.kt)("inlineCode",{parentName:"li"},"DNS_CONFIG_PATH")," variable as:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},"DNS_CONFIG_PATH=./docker-testnet/configs/dnsconfig-tls.json\n"))),(0,r.kt)("li",{parentName:"ul"},"If Fabric network was started with 2 orgs, and IIN Agents are to be started without TLS, update the ",(0,r.kt)("inlineCode",{parentName:"li"},"DNS_CONFIG_PATH")," variable as",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},"DNS_CONFIG_PATH=./docker-testnet/configs/dnsconfig-2-nodes.json\n"))),(0,r.kt)("li",{parentName:"ul"},"If Fabric network was started with 2 orgs and IIN Agents are to be started with TLS enabled, update the ",(0,r.kt)("inlineCode",{parentName:"li"},"DNS_CONFIG_PATH")," variable as:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},"DNS_CONFIG_PATH=./docker-testnet/configs/dnsconfig-tls-2-nodes.json\n"))))),(0,r.kt)("li",{parentName:"ul"},"Repeat the above steps for all other environment variable files (depending upon whether tls is enabled) in ",(0,r.kt)("inlineCode",{parentName:"li"},"docker-testnet/envs")," directory."),(0,r.kt)("li",{parentName:"ul"},"To deploy the Fabric IIN Agent for ",(0,r.kt)("inlineCode",{parentName:"li"},"org1")," of ",(0,r.kt)("inlineCode",{parentName:"li"},"network1")," without TLS, run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n1.org1' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n1.org1 | cut -d '=' -f 2)\n")),"Instead, to deploy the IIN Agent with TLS, run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n1.org1.tls' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n1.org1.tls | cut -d '=' -f 2)\n"))),(0,r.kt)("li",{parentName:"ul"},"To deploy the Fabric IIN Agent for ",(0,r.kt)("inlineCode",{parentName:"li"},"org2")," of ",(0,r.kt)("inlineCode",{parentName:"li"},"network1")," without TLS (",(0,r.kt)("em",{parentName:"li"},"only required if Fabric network was started with 2 orgs"),"), run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n1.org2' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n1.org2 | cut -d '=' -f 2)\n")),"Instead, to deploy the IIN Agent with TLS, run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n1.org2.tls' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n1.org2.tls | cut -d '=' -f 2)\n"))),(0,r.kt)("li",{parentName:"ul"},"To deploy the Fabric IIN Agent for ",(0,r.kt)("inlineCode",{parentName:"li"},"org1")," of ",(0,r.kt)("inlineCode",{parentName:"li"},"network2")," without TLS, run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n2.org1' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n2.org1 | cut -d '=' -f 2)\n")),"Instead, to deploy the IIN Agent with TLS, run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n2.org1.tls' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n2.org1.tls | cut -d '=' -f 2)\n"))),(0,r.kt)("li",{parentName:"ul"},"To deploy the Fabric IIN Agent for ",(0,r.kt)("inlineCode",{parentName:"li"},"org2")," of ",(0,r.kt)("inlineCode",{parentName:"li"},"network2")," without TLS (",(0,r.kt)("em",{parentName:"li"},"only required if Fabric network was started with 2 orgs"),"), run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n2.org2' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n2.org2 | cut -d '=' -f 2)\n")),"Instead, to deploy the IIN Agent with TLS, run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n2.org2.tls' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n2.org2.tls | cut -d '=' -f 2)\n")))),(0,r.kt)("h3",{id:"fabric-client-application"},"Fabric Client (Application)"),(0,r.kt)("p",null,"The CLI is used to interact with a Fabric network, configure it and run chaincode transactions to record data on the channel ledger or query data. It is also used to interact with remote networks through the relay in order to trigger an interoperation flow for data request and acceptance."),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"fabric-cli")," Node.js source code is located in the ",(0,r.kt)("inlineCode",{parentName:"p"},"samples/fabric/fabric-cli")," folder and the Golang source code in the ",(0,r.kt)("inlineCode",{parentName:"p"},"samples/fabric/go-cli")," folder."),(0,r.kt)("h4",{id:"prerequisites-1"},"Prerequisites"),(0,r.kt)("p",null,"If you are using a Linux system, make sure that lib64 is installed."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:"left"},"For the Node.js version of the ",(0,r.kt)("inlineCode",{parentName:"td"},"fabric-cli"),", the setup and running instructions below were tested with all Node.js versions from v11.14.0 to v14.17.3.")))),(0,r.kt)("h4",{id:"installation"},"Installation"),(0,r.kt)("p",null,"You can install ",(0,r.kt)("inlineCode",{parentName:"p"},"fabric-cli")," as follows (for both the Node.js and Golang versions):"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"samples/fabric/fabric-cli")," folder or the ",(0,r.kt)("inlineCode",{parentName:"li"},"samples/fabric/go-cli")," folder."),(0,r.kt)("li",{parentName:"ul"},"Create ",(0,r.kt)("inlineCode",{parentName:"li"},".npmrc")," from template ",(0,r.kt)("inlineCode",{parentName:"li"},".npmrc.template"),", by replacing ",(0,r.kt)("inlineCode",{parentName:"li"},"<personal-access-token>")," with yours created ",(0,r.kt)("a",{parentName:"li",href:"#package-access-token"},"above"),".."),(0,r.kt)("li",{parentName:"ul"},"Run the following to install dependencies (for the Node.js version) or the executable (for the Golang version):",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make build\n"))),(0,r.kt)("li",{parentName:"ul"},"Use the ",(0,r.kt)("inlineCode",{parentName:"li"},"fabric-cli")," executable in the ",(0,r.kt)("inlineCode",{parentName:"li"},"bin")," folder for ",(0,r.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/ledger-initialization"},"subsequent actions"),".")),(0,r.kt)("h2",{id:"corda-components"},"Corda Components"),(0,r.kt)("p",null,"Using the sequence of instructions below, you can start a Corda network and run an application CorDapp on it. You can also run an interoperation CorDapp, a relay and a ",(0,r.kt)("em",{parentName:"p"},"driver")," acting on behalf of the network. You can initialize the network's vault with access control policies, foreign networks' security groups (i.e., membership providers' certificate chains), and some sample state values that can be shared during subsequent interoperation flows."),(0,r.kt)("h3",{id:"corda-network"},"Corda Network"),(0,r.kt)("p",null,"The Corda networks' code lies in the ",(0,r.kt)("inlineCode",{parentName:"p"},"tests/network-setups/corda")," folder. You can launch two separate Corda networks, namely ",(0,r.kt)("inlineCode",{parentName:"p"},"Corda_Network")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"Corda_Network2"),". Each network runs the ",(0,r.kt)("inlineCode",{parentName:"p"},"samples/corda/corda-simple-application")," CorDapp by default, which maintains a state named ",(0,r.kt)("inlineCode",{parentName:"p"},"SimpleState")," containing a set of key-value pairs (of strings)."),(0,r.kt)("p",null,"The following steps will, in addition to launching the network, build the CorDapp and a Corda client in ",(0,r.kt)("inlineCode",{parentName:"p"},"samples/corda/corda-simple-application/client"),"."),(0,r.kt)("h4",{id:"running-with-interoperation-cordapp-from-github-packages"},"Running with Interoperation CorDapp from Github Packages"),(0,r.kt)("p",null,"Follow the instructions below to build and launch the network:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"tests/network-setups/corda")," folder."),(0,r.kt)("li",{parentName:"ul"},"Create copy of ",(0,r.kt)("inlineCode",{parentName:"li"},"github.properties.template")," as ",(0,r.kt)("inlineCode",{parentName:"li"},"github.properties"),"."),(0,r.kt)("li",{parentName:"ul"},"Replace ",(0,r.kt)("inlineCode",{parentName:"li"},"<GITHUB email>")," with your github email, and ",(0,r.kt)("inlineCode",{parentName:"li"},"<GITHUB Personal Access Token>")," with the access token created ",(0,r.kt)("a",{parentName:"li",href:"#package-access-token"},"above"),"."),(0,r.kt)("li",{parentName:"ul"},"To spin up the Corda networks with the Interoperation CorDapps:",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"Each consisting of 1 node and a notary (for data-transfer), run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make start\n"))),(0,r.kt)("li",{parentName:"ul"},"Each consisting of 2 nodes and a notary (for asset-exchange/transfer), run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'make start PROFILE="2-nodes"\n'))),(0,r.kt)("li",{parentName:"ul"},"Each consisting of 3 nodes and a notary (for asset-exchange/transfer), run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'make start PROFILE="3-nodes"\n')))))),(0,r.kt)("p",null,"You should see the following message in the terminal:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"Waiting for network node services to start\n")),(0,r.kt)("p",null,"The Corda nodes and notary may take a while (several minutes on memory-constrained systems) to start. If they start up successfully, you should something like the following for each network, though the number of node entries will depend on the profile you used to start the network with (replace ",(0,r.kt)("inlineCode",{parentName:"p"},"<network-name>")," with ",(0,r.kt)("inlineCode",{parentName:"p"},"Corda_Network")," or ",(0,r.kt)("inlineCode",{parentName:"p"},"Corda_Network2"),"):"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"PartyA node services started for network <network-name>\nPartyB node services started for network <network-name>\nPartyC node services started for network <network-name>\nNotary node services started for network <network-name>\n")),(0,r.kt)("h3",{id:"corda-relay"},"Corda Relay"),(0,r.kt)("p",null,"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"p"},"core/relay")," folder and run a relay for ",(0,r.kt)("inlineCode",{parentName:"p"},"Corda_Network")," and/or ",(0,r.kt)("inlineCode",{parentName:"p"},"Corda_Network2")," in Docker container as follows:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"The ",(0,r.kt)("inlineCode",{parentName:"p"},"docker-compose.yaml")," in this folder is minimally configured with default values. To modify it for use with the Fabric testnets, run:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make convert-compose-method2\n"))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"(The ",(0,r.kt)("inlineCode",{parentName:"p"},".env.corda")," and ",(0,r.kt)("inlineCode",{parentName:"p"},".env.corda.tls")," files in the ",(0,r.kt)("inlineCode",{parentName:"p"},"docker/testnet-envs")," directory contain environment variables used by the ",(0,r.kt)("inlineCode",{parentName:"p"},"Corda_Network")," relay at startup and runtime.)")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"(The ",(0,r.kt)("inlineCode",{parentName:"p"},".env.corda2")," and ",(0,r.kt)("inlineCode",{parentName:"p"},".env.corda2.tls")," files in the ",(0,r.kt)("inlineCode",{parentName:"p"},"docker/testnet-envs")," directory contain environment variables used by the ",(0,r.kt)("inlineCode",{parentName:"p"},"Corda_Network2")," relay at startup and runtime.)")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"To deploy the relay server for ",(0,r.kt)("inlineCode",{parentName:"p"},"Corda_Network")," without TLS, run:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.corda'\n")),(0,r.kt)("p",{parentName:"li"},"Instead, to deploy the relay server with TLS, run:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.corda.tls'\n"))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"To deploy the relay server for ",(0,r.kt)("inlineCode",{parentName:"p"},"Corda_Network2")," without TLS, run:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.corda2'\n")),(0,r.kt)("p",{parentName:"li"},"Instead, to deploy the relay server with TLS, run:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.corda2.tls'\n"))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"After launching the relay(s), you can revert the ",(0,r.kt)("inlineCode",{parentName:"p"},"docker-compose.yaml")," changes by running:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make convert-compose-method1\n")))),(0,r.kt)("h3",{id:"corda-driver"},"Corda Driver"),(0,r.kt)("p",null,"Use the following steps to run Corda drivers in Docker containers:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the ",(0,r.kt)("inlineCode",{parentName:"li"},"core/drivers/corda-driver")," folder."),(0,r.kt)("li",{parentName:"ul"},"(The ",(0,r.kt)("inlineCode",{parentName:"li"},".env.corda")," and ",(0,r.kt)("inlineCode",{parentName:"li"},".env.corda.tls")," files in the ",(0,r.kt)("inlineCode",{parentName:"li"},"docker-testnet-envs")," contain environment variables used by the ",(0,r.kt)("inlineCode",{parentName:"li"},"Corda_Network")," driver at startup and runtime.)"),(0,r.kt)("li",{parentName:"ul"},"(The ",(0,r.kt)("inlineCode",{parentName:"li"},".env.corda2")," and ",(0,r.kt)("inlineCode",{parentName:"li"},".env.corda2.tls")," files in the ",(0,r.kt)("inlineCode",{parentName:"li"},"docker-testnet-envs")," contain environment variables used by the ",(0,r.kt)("inlineCode",{parentName:"li"},"Corda_Network2")," driver at startup and runtime.)"),(0,r.kt)("li",{parentName:"ul"},"To deploy the Corda driver for ",(0,r.kt)("inlineCode",{parentName:"li"},"Corda_Network")," without TLS, run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.corda'\n")),"Instead, to deploy the driver with TLS, run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.corda.tls'\n")),"If the driver starts successfully, it should log the following message when you run ",(0,r.kt)("inlineCode",{parentName:"li"},"docker logs corda-driver-Corda_Network"),":",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},"Corda driver gRPC server started. Listening on port 9099\n"))),(0,r.kt)("li",{parentName:"ul"},"To deploy the Corda driver for ",(0,r.kt)("inlineCode",{parentName:"li"},"Corda_Network2")," without TLS, run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.corda2'\n")),"Instead, to deploy the driver with TLS, run:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.corda2.tls'\n")),"If the driver starts successfully, it should log the following message when you run ",(0,r.kt)("inlineCode",{parentName:"li"},"docker logs corda-driver-Corda_Network2"),":",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},"Corda driver gRPC server started. Listening on port 9098\n")))),(0,r.kt)("h2",{id:"tear-down-the-setup"},"Tear Down the Setup"),(0,r.kt)("p",null,"Bring down the various components as follows (",(0,r.kt)("em",{parentName:"p"},"Navigate to the root folder of your clone of the Weaver repository"),"):"),(0,r.kt)("h3",{id:"relay"},"Relay"),(0,r.kt)("p",null,"To bring down the relays (for all 3 networks), run:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"cd core/relay\nmake convert-compose-method2\nmake stop COMPOSE_ARG='--env-file docker/testnet-envs/.env.n1'\nmake stop COMPOSE_ARG='--env-file docker/testnet-envs/.env.n2'\nmake stop COMPOSE_ARG='--env-file docker/testnet-envs/.env.corda'\nmake stop COMPOSE_ARG='--env-file docker/testnet-envs/.env.corda2'\nmake convert-compose-method1\ncd -\n")),(0,r.kt)("h3",{id:"fabric-driver-1"},"Fabric Driver"),(0,r.kt)("p",null,"To bring down the fabric drivers (for both networks), run:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"cd core/drivers/fabric-driver\nmake stop COMPOSE_ARG='--env-file docker-testnet-envs/.env.n1'\nmake stop COMPOSE_ARG='--env-file docker-testnet-envs/.env.n2'\ncd -\n")),(0,r.kt)("h3",{id:"corda-driver-1"},"Corda Driver"),(0,r.kt)("p",null,"To bring down the corda driver, run:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"cd core/drivers/corda-driver\nmake stop COMPOSE_ARG='--env-file docker-testnet-envs/.env.corda'\nmake stop COMPOSE_ARG='--env-file docker-testnet-envs/.env.corda2'\ncd -\n")),(0,r.kt)("h3",{id:"corda-network-1"},"Corda Network"),(0,r.kt)("p",null,"To bring down the Corda network:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"cd tests/network-setups/corda\nmake clean\ncd -\n")),(0,r.kt)("h3",{id:"fabric-network-1"},"Fabric Network"),(0,r.kt)("p",null,"To bring down both of the Fabric networks along with weaver components:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"cd tests/network-setups/fabric/dev\nmake clean\ncd -\n")))}k.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/c9886a33.715d8bed.js b/assets/js/c9886a33.715d8bed.js deleted file mode 100644 index a966e92b4..000000000 --- a/assets/js/c9886a33.715d8bed.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[5671],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>f});var r=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function a(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){i(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,r,i=function(e,t){if(null==e)return{};var n,r,i={},o=Object.keys(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var c=r.createContext({}),u=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},p=function(e){var t=u(e.components);return r.createElement(c.Provider,{value:t},e.children)},d="mdxType",s={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,c=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),d=u(n),m=i,f=d["".concat(c,".").concat(m)]||d[m]||s[m]||o;return n?r.createElement(f,a(a({ref:t},p),{},{components:n})):r.createElement(f,a({ref:t},p))}));function f(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,a=new Array(o);a[0]=m;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l[d]="string"==typeof e?e:i,a[1]=l;for(var u=2;u<o;u++)a[u]=n[u];return r.createElement.apply(null,a)}return r.createElement.apply(null,n)}m.displayName="MDXCreateElement"},2238:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>s,frontMatter:()=>o,metadata:()=>l,toc:()=>u});var r=n(7462),i=(n(7294),n(3905));const o={},a=void 0,l={unversionedId:"internal/documentation-guidelines",id:"internal/documentation-guidelines",title:"documentation-guidelines",description:"\x3c!--",source:"@site/docs/internal/documentation-guidelines.md",sourceDirName:"internal",slug:"/internal/documentation-guidelines",permalink:"/weaver-dlt-interoperability/docs/internal/documentation-guidelines",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/internal/documentation-guidelines.md",tags:[],version:"current",frontMatter:{}},c={},u=[],p={toc:u},d="wrapper";function s(e){let{components:t,...n}=e;return(0,i.kt)(d,(0,r.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("hr",null),(0,i.kt)("p",null,"id: documentation-guidelines\ntitle: Documentation Guidelines"),(0,i.kt)("hr",null),(0,i.kt)("h1",{id:"documentation-guidelines"},"Documentation Guidelines"))}s.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/ccc49370.753c1031.js b/assets/js/ccc49370.753c1031.js deleted file mode 100644 index 541d0f1b3..000000000 --- a/assets/js/ccc49370.753c1031.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[6103],{5203:(e,t,n)=>{n.r(t),n.d(t,{default:()=>h});var a=n(7294),l=n(6010),r=n(1944),o=n(5281),i=n(9460),c=n(9058),s=n(756),m=n(7462),d=n(5999),u=n(2244);function g(e){const{nextItem:t,prevItem:n}=e;return a.createElement("nav",{className:"pagination-nav docusaurus-mt-lg","aria-label":(0,d.I)({id:"theme.blog.post.paginator.navAriaLabel",message:"Blog post page navigation",description:"The ARIA label for the blog posts pagination"})},n&&a.createElement(u.Z,(0,m.Z)({},n,{subLabel:a.createElement(d.Z,{id:"theme.blog.post.paginator.newerPost",description:"The blog post button label to navigate to the newer/previous post"},"Newer Post")})),t&&a.createElement(u.Z,(0,m.Z)({},t,{subLabel:a.createElement(d.Z,{id:"theme.blog.post.paginator.olderPost",description:"The blog post button label to navigate to the older/next post"},"Older Post"),isNext:!0})))}function f(){const{assets:e,metadata:t}=(0,i.C)(),{title:n,description:l,date:o,tags:c,authors:s,frontMatter:m}=t,{keywords:d}=m,u=e.image??m.image;return a.createElement(r.d,{title:n,description:l,keywords:d,image:u},a.createElement("meta",{property:"og:type",content:"article"}),a.createElement("meta",{property:"article:published_time",content:o}),s.some((e=>e.url))&&a.createElement("meta",{property:"article:author",content:s.map((e=>e.url)).filter(Boolean).join(",")}),c.length>0&&a.createElement("meta",{property:"article:tag",content:c.map((e=>e.label)).join(",")}))}var v=n(9407);function p(e){let{sidebar:t,children:n}=e;const{metadata:l,toc:r}=(0,i.C)(),{nextItem:o,prevItem:m,frontMatter:d}=l,{hide_table_of_contents:u,toc_min_heading_level:f,toc_max_heading_level:p}=d;return a.createElement(c.Z,{sidebar:t,toc:!u&&r.length>0?a.createElement(v.Z,{toc:r,minHeadingLevel:f,maxHeadingLevel:p}):void 0},a.createElement(s.Z,null,n),(o||m)&&a.createElement(g,{nextItem:o,prevItem:m}))}function h(e){const t=e.content;return a.createElement(i.n,{content:e.content,isBlogPostPage:!0},a.createElement(r.FG,{className:(0,l.Z)(o.k.wrapper.blogPages,o.k.page.blogPostPage)},a.createElement(f,null),a.createElement(p,{sidebar:e.sidebar},a.createElement(t,null))))}},9407:(e,t,n)=>{n.d(t,{Z:()=>m});var a=n(7462),l=n(7294),r=n(6010),o=n(3743);const i={tableOfContents:"tableOfContents_bqdL",docItemContainer:"docItemContainer_F8PC"},c="table-of-contents__link toc-highlight",s="table-of-contents__link--active";function m(e){let{className:t,...n}=e;return l.createElement("div",{className:(0,r.Z)(i.tableOfContents,"thin-scrollbar",t)},l.createElement(o.Z,(0,a.Z)({},n,{linkClassName:c,linkActiveClassName:s})))}},3743:(e,t,n)=>{n.d(t,{Z:()=>f});var a=n(7462),l=n(7294),r=n(6668);function o(e){const t=e.map((e=>({...e,parentIndex:-1,children:[]}))),n=Array(7).fill(-1);t.forEach(((e,t)=>{const a=n.slice(2,e.level);e.parentIndex=Math.max(...a),n[e.level]=t}));const a=[];return t.forEach((e=>{const{parentIndex:n,...l}=e;n>=0?t[n].children.push(l):a.push(l)})),a}function i(e){let{toc:t,minHeadingLevel:n,maxHeadingLevel:a}=e;return t.flatMap((e=>{const t=i({toc:e.children,minHeadingLevel:n,maxHeadingLevel:a});return function(e){return e.level>=n&&e.level<=a}(e)?[{...e,children:t}]:t}))}function c(e){const t=e.getBoundingClientRect();return t.top===t.bottom?c(e.parentNode):t}function s(e,t){let{anchorTopOffset:n}=t;const a=e.find((e=>c(e).top>=n));if(a){return function(e){return e.top>0&&e.bottom<window.innerHeight/2}(c(a))?a:e[e.indexOf(a)-1]??null}return e[e.length-1]??null}function m(){const e=(0,l.useRef)(0),{navbar:{hideOnScroll:t}}=(0,r.L)();return(0,l.useEffect)((()=>{e.current=t?0:document.querySelector(".navbar").clientHeight}),[t]),e}function d(e){const t=(0,l.useRef)(void 0),n=m();(0,l.useEffect)((()=>{if(!e)return()=>{};const{linkClassName:a,linkActiveClassName:l,minHeadingLevel:r,maxHeadingLevel:o}=e;function i(){const e=function(e){return Array.from(document.getElementsByClassName(e))}(a),i=function(e){let{minHeadingLevel:t,maxHeadingLevel:n}=e;const a=[];for(let l=t;l<=n;l+=1)a.push(`h${l}.anchor`);return Array.from(document.querySelectorAll(a.join()))}({minHeadingLevel:r,maxHeadingLevel:o}),c=s(i,{anchorTopOffset:n.current}),m=e.find((e=>c&&c.id===function(e){return decodeURIComponent(e.href.substring(e.href.indexOf("#")+1))}(e)));e.forEach((e=>{!function(e,n){n?(t.current&&t.current!==e&&t.current.classList.remove(l),e.classList.add(l),t.current=e):e.classList.remove(l)}(e,e===m)}))}return document.addEventListener("scroll",i),document.addEventListener("resize",i),i(),()=>{document.removeEventListener("scroll",i),document.removeEventListener("resize",i)}}),[e,n])}function u(e){let{toc:t,className:n,linkClassName:a,isChild:r}=e;return t.length?l.createElement("ul",{className:r?void 0:n},t.map((e=>l.createElement("li",{key:e.id},l.createElement("a",{href:`#${e.id}`,className:a??void 0,dangerouslySetInnerHTML:{__html:e.value}}),l.createElement(u,{isChild:!0,toc:e.children,className:n,linkClassName:a}))))):null}const g=l.memo(u);function f(e){let{toc:t,className:n="table-of-contents table-of-contents__left-border",linkClassName:c="table-of-contents__link",linkActiveClassName:s,minHeadingLevel:m,maxHeadingLevel:u,...f}=e;const v=(0,r.L)(),p=m??v.tableOfContents.minHeadingLevel,h=u??v.tableOfContents.maxHeadingLevel,b=function(e){let{toc:t,minHeadingLevel:n,maxHeadingLevel:a}=e;return(0,l.useMemo)((()=>i({toc:o(t),minHeadingLevel:n,maxHeadingLevel:a})),[t,n,a])}({toc:t,minHeadingLevel:p,maxHeadingLevel:h});return d((0,l.useMemo)((()=>{if(c&&s)return{linkClassName:c,linkActiveClassName:s,minHeadingLevel:p,maxHeadingLevel:h}}),[c,s,p,h])),l.createElement(g,(0,a.Z)({toc:b,className:n,linkClassName:c},f))}}}]); \ No newline at end of file diff --git a/assets/js/ccc49370.b810f065.js b/assets/js/ccc49370.b810f065.js new file mode 100644 index 000000000..d280a89dd --- /dev/null +++ b/assets/js/ccc49370.b810f065.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[3249],{4029:(e,t,n)=>{n.r(t),n.d(t,{default:()=>h});var a=n(6540),l=n(53),r=n(1003),o=n(7559),i=n(7131),c=n(6669),s=n(5623),m=n(8168),d=n(1312),u=n(9022);function g(e){const{nextItem:t,prevItem:n}=e;return a.createElement("nav",{className:"pagination-nav docusaurus-mt-lg","aria-label":(0,d.T)({id:"theme.blog.post.paginator.navAriaLabel",message:"Blog post page navigation",description:"The ARIA label for the blog posts pagination"})},n&&a.createElement(u.A,(0,m.A)({},n,{subLabel:a.createElement(d.A,{id:"theme.blog.post.paginator.newerPost",description:"The blog post button label to navigate to the newer/previous post"},"Newer Post")})),t&&a.createElement(u.A,(0,m.A)({},t,{subLabel:a.createElement(d.A,{id:"theme.blog.post.paginator.olderPost",description:"The blog post button label to navigate to the older/next post"},"Older Post"),isNext:!0})))}function f(){const{assets:e,metadata:t}=(0,i.e)(),{title:n,description:l,date:o,tags:c,authors:s,frontMatter:m}=t,{keywords:d}=m,u=e.image??m.image;return a.createElement(r.be,{title:n,description:l,keywords:d,image:u},a.createElement("meta",{property:"og:type",content:"article"}),a.createElement("meta",{property:"article:published_time",content:o}),s.some((e=>e.url))&&a.createElement("meta",{property:"article:author",content:s.map((e=>e.url)).filter(Boolean).join(",")}),c.length>0&&a.createElement("meta",{property:"article:tag",content:c.map((e=>e.label)).join(",")}))}var v=n(7763);function p(e){let{sidebar:t,children:n}=e;const{metadata:l,toc:r}=(0,i.e)(),{nextItem:o,prevItem:m,frontMatter:d}=l,{hide_table_of_contents:u,toc_min_heading_level:f,toc_max_heading_level:p}=d;return a.createElement(c.A,{sidebar:t,toc:!u&&r.length>0?a.createElement(v.A,{toc:r,minHeadingLevel:f,maxHeadingLevel:p}):void 0},a.createElement(s.A,null,n),(o||m)&&a.createElement(g,{nextItem:o,prevItem:m}))}function h(e){const t=e.content;return a.createElement(i.i,{content:e.content,isBlogPostPage:!0},a.createElement(r.e3,{className:(0,l.A)(o.G.wrapper.blogPages,o.G.page.blogPostPage)},a.createElement(f,null),a.createElement(p,{sidebar:e.sidebar},a.createElement(t,null))))}},7763:(e,t,n)=>{n.d(t,{A:()=>m});var a=n(8168),l=n(6540),r=n(53),o=n(5195);const i={tableOfContents:"tableOfContents_bqdL",docItemContainer:"docItemContainer_F8PC"},c="table-of-contents__link toc-highlight",s="table-of-contents__link--active";function m(e){let{className:t,...n}=e;return l.createElement("div",{className:(0,r.A)(i.tableOfContents,"thin-scrollbar",t)},l.createElement(o.A,(0,a.A)({},n,{linkClassName:c,linkActiveClassName:s})))}},5195:(e,t,n)=>{n.d(t,{A:()=>f});var a=n(8168),l=n(6540),r=n(6342);function o(e){const t=e.map((e=>({...e,parentIndex:-1,children:[]}))),n=Array(7).fill(-1);t.forEach(((e,t)=>{const a=n.slice(2,e.level);e.parentIndex=Math.max(...a),n[e.level]=t}));const a=[];return t.forEach((e=>{const{parentIndex:n,...l}=e;n>=0?t[n].children.push(l):a.push(l)})),a}function i(e){let{toc:t,minHeadingLevel:n,maxHeadingLevel:a}=e;return t.flatMap((e=>{const t=i({toc:e.children,minHeadingLevel:n,maxHeadingLevel:a});return function(e){return e.level>=n&&e.level<=a}(e)?[{...e,children:t}]:t}))}function c(e){const t=e.getBoundingClientRect();return t.top===t.bottom?c(e.parentNode):t}function s(e,t){let{anchorTopOffset:n}=t;const a=e.find((e=>c(e).top>=n));if(a){return function(e){return e.top>0&&e.bottom<window.innerHeight/2}(c(a))?a:e[e.indexOf(a)-1]??null}return e[e.length-1]??null}function m(){const e=(0,l.useRef)(0),{navbar:{hideOnScroll:t}}=(0,r.p)();return(0,l.useEffect)((()=>{e.current=t?0:document.querySelector(".navbar").clientHeight}),[t]),e}function d(e){const t=(0,l.useRef)(void 0),n=m();(0,l.useEffect)((()=>{if(!e)return()=>{};const{linkClassName:a,linkActiveClassName:l,minHeadingLevel:r,maxHeadingLevel:o}=e;function i(){const e=function(e){return Array.from(document.getElementsByClassName(e))}(a),i=function(e){let{minHeadingLevel:t,maxHeadingLevel:n}=e;const a=[];for(let l=t;l<=n;l+=1)a.push(`h${l}.anchor`);return Array.from(document.querySelectorAll(a.join()))}({minHeadingLevel:r,maxHeadingLevel:o}),c=s(i,{anchorTopOffset:n.current}),m=e.find((e=>c&&c.id===function(e){return decodeURIComponent(e.href.substring(e.href.indexOf("#")+1))}(e)));e.forEach((e=>{!function(e,n){n?(t.current&&t.current!==e&&t.current.classList.remove(l),e.classList.add(l),t.current=e):e.classList.remove(l)}(e,e===m)}))}return document.addEventListener("scroll",i),document.addEventListener("resize",i),i(),()=>{document.removeEventListener("scroll",i),document.removeEventListener("resize",i)}}),[e,n])}function u(e){let{toc:t,className:n,linkClassName:a,isChild:r}=e;return t.length?l.createElement("ul",{className:r?void 0:n},t.map((e=>l.createElement("li",{key:e.id},l.createElement("a",{href:`#${e.id}`,className:a??void 0,dangerouslySetInnerHTML:{__html:e.value}}),l.createElement(u,{isChild:!0,toc:e.children,className:n,linkClassName:a}))))):null}const g=l.memo(u);function f(e){let{toc:t,className:n="table-of-contents table-of-contents__left-border",linkClassName:c="table-of-contents__link",linkActiveClassName:s,minHeadingLevel:m,maxHeadingLevel:u,...f}=e;const v=(0,r.p)(),p=m??v.tableOfContents.minHeadingLevel,h=u??v.tableOfContents.maxHeadingLevel,b=function(e){let{toc:t,minHeadingLevel:n,maxHeadingLevel:a}=e;return(0,l.useMemo)((()=>i({toc:o(t),minHeadingLevel:n,maxHeadingLevel:a})),[t,n,a])}({toc:t,minHeadingLevel:p,maxHeadingLevel:h});return d((0,l.useMemo)((()=>{if(c&&s)return{linkClassName:c,linkActiveClassName:s,minHeadingLevel:p,maxHeadingLevel:h}}),[c,s,p,h])),l.createElement(g,(0,a.A)({toc:b,className:n,linkClassName:c},f))}}}]); \ No newline at end of file diff --git a/assets/js/cd2e0b0a.cfaa347a.js b/assets/js/cd2e0b0a.cfaa347a.js deleted file mode 100644 index 40ce11fbb..000000000 --- a/assets/js/cd2e0b0a.cfaa347a.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[5261],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>f});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,a,r=function(e,t){if(null==e)return{};var n,a,r={},o=Object.keys(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=a.createContext({}),d=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=d(e.components);return a.createElement(l.Provider,{value:t},e.children)},c="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},u=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),c=d(n),u=r,f=c["".concat(l,".").concat(u)]||c[u]||h[u]||o;return n?a.createElement(f,i(i({ref:t},p),{},{components:n})):a.createElement(f,i({ref:t},p))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=u;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[c]="string"==typeof e?e:r,i[1]=s;for(var d=2;d<o;d++)i[d]=n[d];return a.createElement.apply(null,i)}return a.createElement.apply(null,n)}u.displayName="MDXCreateElement"},9805:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>h,frontMatter:()=>o,metadata:()=>s,toc:()=>d});var a=n(7462),r=(n(7294),n(3905));const o={},i=void 0,s={unversionedId:"internal/development/cordapp-interop/cordapp-interop",id:"internal/development/cordapp-interop/cordapp-interop",title:"cordapp-interop",description:"\x3c!--",source:"@site/docs/internal/development/cordapp-interop/cordapp-interop.md",sourceDirName:"internal/development/cordapp-interop",slug:"/internal/development/cordapp-interop/",permalink:"/weaver-dlt-interoperability/docs/internal/development/cordapp-interop/",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/internal/development/cordapp-interop/cordapp-interop.md",tags:[],version:"current",frontMatter:{}},l={},d=[{value:"General Corda notes",id:"general-corda-notes",level:2},{value:"1. Authentication of external networks",id:"1-authentication-of-external-networks",level:2},{value:"Foreign Network Information Management",id:"foreign-network-information-management",level:3},{value:"FNIM CorDapp Assets",id:"fnim-cordapp-assets",level:4},{value:"FNIM API Assets",id:"fnim-api-assets",level:4},{value:"FNIM Flows",id:"fnim-flows",level:4},{value:"FNIM Query Flows",id:"fnim-query-flows",level:4},{value:"FNIM application REST API and Corda flow connections",id:"fnim-application-rest-api-and-corda-flow-connections",level:4},{value:"Access Control",id:"access-control",level:3},{value:"Access Control CorDapp Assets",id:"access-control-cordapp-assets",level:4},{value:"Access Control API Assets",id:"access-control-api-assets",level:4},{value:"Access Control Flows",id:"access-control-flows",level:4},{value:"Access Control Query Flows",id:"access-control-query-flows",level:4},{value:"Access Control Application REST API and Corda Flow Connections",id:"access-control-application-rest-api-and-corda-flow-connections",level:4},{value:"2. Handle external networks querying a Corda application for state",id:"2-handle-external-networks-querying-a-corda-application-for-state",level:2},{value:"Handle Requests From Foreign Network - CorDapp Assets",id:"handle-requests-from-foreign-network---cordapp-assets",level:4},{value:"Handle Requests From Foreign Network - API Assets",id:"handle-requests-from-foreign-network---api-assets",level:4},{value:"Handle Requests From Foreign Network - Flows",id:"handle-requests-from-foreign-network---flows",level:4},{value:"Handle Requests From Foreign Network - Application REST API and Corda Flow Connections",id:"handle-requests-from-foreign-network---application-rest-api-and-corda-flow-connections",level:4},{value:"3. Requests to get state from external networks",id:"3-requests-to-get-state-from-external-networks",level:2},{value:"Request State from External Network - CorDapp Assets",id:"request-state-from-external-network---cordapp-assets",level:4},{value:"WriteStateFromExternalNetworkFlows",id:"writestatefromexternalnetworkflows",level:4},{value:"Application REST API and Corda flow connections",id:"application-rest-api-and-corda-flow-connections",level:4}],p={toc:d},c="wrapper";function h(e){let{components:t,...n}=e;return(0,r.kt)(c,(0,a.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("hr",null),(0,r.kt)("p",null,"id: cordapp-interop\ntitle: Interoperation CorDapp"),(0,r.kt)("hr",null),(0,r.kt)("h1",{id:"interoperation-cordapp"},"Interoperation CorDapp"),(0,r.kt)("hr",null),(0,r.kt)("p",null," Contributors: Chander Govindarajan, Allison Irvin, Isabell Kiral"),(0,r.kt)("hr",null),(0,r.kt)("p",null,"This document contains the specification for the interoperation application including the system, the CorDapp flow design and the application server details.\nThis CorDapp serves as the bridge between an established CorDapp and the relay.\nThere are three main functions of the Interoperation CorDapp:"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},"It defines states, contracts and flows for authenticating participants of an external network and providing access control to Corda application states. "),(0,r.kt)("li",{parentName:"ol"},"It defines flows for enabling an external network to query a Corda application."),(0,r.kt)("li",{parentName:"ol"},"It defines flows for enabling a Corda application to query an external network.")),(0,r.kt)("p",null,"The Corda interoperability application consists of the CorDapp itself, containing flows, contracts and state definitions, as well as a webserver with a REST API that connects to the Corda nodes via RPC to trigger flows.\nThere is no user interface for the interoperability functionality.\nThe REST API is designed to be consumed by a Corda application that wishes to incorporate state synchronisation with an external network. "),(0,r.kt)("p",null,"To view the assets, flows and API specification in full without any of the descriptions see these pages:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/internal/development/cordapp-interop/cordapp-interop-assets"},"CorDapp Assets"))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/internal/development/cordapp-interop/cordapp-interop-api-assets"},"API Assets"))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/internal/development/cordapp-interop/cordapp-interop-flows"},"Flows"))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/internal/development/cordapp-interop/cordapp-interop-rest-api"},"REST API")),(0,r.kt)("hr",{parentName:"li"}))),(0,r.kt)("h2",{id:"general-corda-notes"},"General Corda notes"),(0,r.kt)("p",null,"Corda provides many state interfaces to aid in standardisation across CorDapps.\nStates must extend the ",(0,r.kt)("inlineCode",{parentName:"p"},"ContractState")," interface, which contains a list of ",(0,r.kt)("inlineCode",{parentName:"p"},"AbstractParty"),", called ",(0,r.kt)("inlineCode",{parentName:"p"},"participants"),".\nThis defines which Corda identities must sign off on transactions that consume state of that type.\nFor states where instances evolve by superseding itself, Corda provides the ",(0,r.kt)("inlineCode",{parentName:"p"},"LinearState")," interface.\nThis includes a property ",(0,r.kt)("inlineCode",{parentName:"p"},"linearId"),", which is a unique identifier that all versions of the state will preserve throughout the lifecycle of the state. "),(0,r.kt)("h2",{id:"1-authentication-of-external-networks"},"1. Authentication of external networks"),(0,r.kt)("h3",{id:"foreign-network-information-management"},"Foreign Network Information Management"),(0,r.kt)("p",null,"In order to control access to state in a Corda application or to verify state coming from an external network, the Corda network needs to have some way of authenticating parties in the external network.\nThe Foreign Network Information Management (FNIM) state contains a network map of the foreign network, including an identifier associated with the foreign network as well as a description of each of the foreign network nodes (",(0,r.kt)("inlineCode",{parentName:"p"},"FNNode"),"s).\nThis FNIM state is used to verify the identity of external network parties interacting with the Corda network.\nEvery interaction requires a signature of the external network party.\nThe signature is verified against the provided certificate and the authenticity of the certificate is verified against the FNIM state.\nIn our current design, the definition of these ",(0,r.kt)("inlineCode",{parentName:"p"},"FNNode"),"s is very Fabric-centric, as the Fabric-Fabric interoperability design used the network map the way it was stored on the Ordering Service channel.\nIn order to not have to make significant changes to the way the Fabric network published its network map, this format was used to consume the FNIM in the Interoperation CorDapp, complete with fields such as ",(0,r.kt)("inlineCode",{parentName:"p"},"crypto_config")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"fabric_node_ous"),".\nThe Fabric nodes' info was also stored as a key-value with the key being the name of the Fabric organisation (e.g. ",(0,r.kt)("inlineCode",{parentName:"p"},"SellerMSP"),").\nIn a more generalised interoperation protocol, we should think about common features that all DLT networks are required to provide in order for external networks to be able to properly identify and authenticate participants. "),(0,r.kt)("p",null,"An FNIM state is created for an external network on the level of a group of Corda participants.\nThe Corda participants that are listed in the FNIM state are responsible for creating the FNIM state and ensuring it is kept up to date with the external network configuration.\nIn the current model, this is done manually, with the endpoint to fetch the network map from the external network through the relay hardcoded into the interoperation REST API endpoint.\nThis endpoint is also used to update the FNIM state when the foreign network topology changes.\nThe application middleware checks if there is an FNIM state for that networkId already, and if so, deletes it before creating a new state with the updated details.\nIn our demo, the participants of the FNIM state are also hardcoded.\nThe flow that creates an FNIM state does not require any manual sign-off by counterparties.\nThe flow triggers a subflow in all participant nodes listed in the state, that checks the transaction against the contract and signs the transaction if the verification passes. "),(0,r.kt)("p",null,"In a more generalised protocol, it would be preferable to have a standardised format for the publication of network maps.\nFor example, having a decentralised identity platform for the storage of DLT network that were discoverable by other networks would be ideal.\nOtherwise, having all networks provide their network map through a consistent API, would also be helpful."),(0,r.kt)("p",null,"The Corda parties that control the creation and management of FNIM states in the Corda network also needs to be revisited.\nFor example, ensuring currency of an FNIM state for a particular external network could be up to a group of participants that share some state together that they wish to have synchronised with the external network.\nAlternatively, a dedicated group of Corda parties could be responsible for maintaining currency of the configurations of all the external networks that any group of participants may wish to interoperate with in a Corda network.\nThe mechanism for updating FNIM state when external network configuration changes should also be revisited, rather than deleting the existing state and creating a new one. "),(0,r.kt)("p",null,"Similarly to the requirement for a Corda network to have access to the network map of an external network, the external network must also have a snapshot of the Corda network they wish to interoperate with in order to validate requests and responses.\nThe exposure of the network map is currently done through the individual Corda applications as the information that each network wishes to share externally will vary on a case-by-case basis.\nThis model can be revised if needed for the next iteration of the protocol."),(0,r.kt)("h4",{id:"fnim-cordapp-assets"},"FNIM CorDapp Assets"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"class ForeignNetworkInformationManagementState(\n linearId: UniqueIdentifier = UniqueIdentifier(),\n participants: List<Party>,\n networkId: String,\n topology: List<FNNode>\n) : LinearState\n\nclass FNNode(\n admins: List<String>,\n crypto_config: CryptoConfig,\n fabric_node_ous: String?,\n intermediate_certs: List<String>,\n name: String,\n organizational_unit_identifiers: List<String>,\n revocation_list: List<String>,\n root_certs: List<String>,\n signing_identity: String?,\n tls_intermediate_certs: List<String>,\n tls_root_certs: List<String>\n)\n\nclass CryptoConfig(\n identity_identifier_hash_function: String,\n signature_hash_family: String\n)\n")),(0,r.kt)("h4",{id:"fnim-api-assets"},"FNIM API Assets"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"class FNIMStateRequest(\n networkId: String,\n topology: List<FNNode>,\n participants: List<String>\n)\n\nclass FNIMStateResponse(\n linearId: UniqueIdentifier,\n networkId: String,\n topology: List<FNNode>,\n participants: List<String>\n)\n\nclass ForeignNetworkMapInformationIntermediateResponse(\n CarrierMSP: FNNode,\n SellerMSP: FNNode\n)\n")),(0,r.kt)("h4",{id:"fnim-flows"},"FNIM Flows"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"class FNIMInitiator(\n networkId: String,\n topology: List<FNNode>,\n participants: List<Party>) {\n // creates FNIM record for an external network\n}\n\nclass FNIMExitInitiator(\n id: String ) {\n // marks FNIM state as consumed\n}\n")),(0,r.kt)("h4",{id:"fnim-query-flows"},"FNIM Query Flows"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"class QueryForeignNetworkInformationManagementStates : List<ForeignNetworkInformationManagementState> {\n // returns list of FNIM states\n}\n\nclass QueryForeignNetworkInformationManagementStatesById(\n linearId: UniqueIdentifier) ForeignNetworkInformationManagementState {\n // returns FNIM state\n}\n\nclass QueryForeignNetworkInformationManagementStateByNetworkId(\n networkId: String) ForeignNetworkInformationManagementState {\n // returns FNIM state for specified network\n}\n")),(0,r.kt)("h4",{id:"fnim-application-rest-api-and-corda-flow-connections"},"FNIM application REST API and Corda flow connections"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"GET storeFNIM\nreq: {}\nres: ForeignNetworkMapInformationIntermediateResponse, or failure\ncalls: \n 1. <foreign-network-id-and-certs-configuration-url> to get ForeignNetworkMapInformationIntermediateResponse\n 2. QueryForeignNetworkInformationManagementStateByNetworkId to check if FNIM exists for this network already\n 3. FNIMExitInitiator (if FNIM exists already)\n 4. FNIMInitiator\n\nPOST foreignNetworkInfos\nreq: FNIMStateRequest\nres: FNIMStateResponse, or failure\ncalls: FNIMInitiator\n\nDELETE foreignNetworkInfos/{id}\nreq: {}\nres: id, or failure\ncalls: FNIMExitInitiator\n\nGET foreignNetworkInfos\nreq: {}\nres: List<ForeignNetworkInformationManagementState>, or failure\ncalls: QueryForeignNetworkInformationManagementStates\n\nGET foreignNetworkInfos/{id}\nreq: {}\nres: ForeignNetworkInformationManagementState, or failure\ncalls: QueryForeignNetworkInformationManagementStatesById\n")),(0,r.kt)("h3",{id:"access-control"},"Access Control"),(0,r.kt)("p",null,"The Interoperation CorDapp allows groups of Corda parties to grant access to their application states through ",(0,r.kt)("inlineCode",{parentName:"p"},"AccessControlStates"),".\nThese Access Control states are issued on a per-application state and per-external network basis (for example, for a particular letter of credit and for a particular external network).\nThe application state for which the Access Control state pertains is denoted by the ",(0,r.kt)("inlineCode",{parentName:"p"},"stateLinearId")," and the external network is specified by the ",(0,r.kt)("inlineCode",{parentName:"p"},"externalNetworkId")," that should match the ",(0,r.kt)("inlineCode",{parentName:"p"},"externalNetworkId")," for the FNIM state.\nThe Access Control state also lists the certificates of the parties of the external network who are allowed to make requests for state.\nThese are included in the ",(0,r.kt)("inlineCode",{parentName:"p"},"externalNetworkCertificates")," field. "),(0,r.kt)("p",null,"This is just one approach that could be used to grant access to foreign network participants.\nIt may be desirable to be able to set access control rules on a Corda application level (e.g. allow one Access Control state to govern access to ",(0,r.kt)("em",{parentName:"p"},"all")," Corda states for a given application).\nTherefore, this may need to be revisited for the next version of the interoperation protocol."),(0,r.kt)("p",null,"As the Access Control state defines whether an external party can access state from the Corda ledger, explicit approval needs to be given by each participant of the Corda state.\nThese approvals are captured in an Access Control Request State.\nOnce all participants have manually approved the request through initiating the ",(0,r.kt)("inlineCode",{parentName:"p"},"AccessControlIssueRequestApprover"),", an Access Control state will be created. "),(0,r.kt)("p",null,"The workflow to grant access to application states needs to be built into the application for a particular CorDapp.\nFor example, as a part of a trade logistics application, one part of the user interface could include allowing particular external network participants to request a current view of a letter of credit state.\nAll participants of that letter of credit would have to approve the access control request before it becomes active.\nThis workflow was not built into the Corda-Fabric interoperability demo, with the creation and approval of an Access Control request being triggered through the interoperation middleware when an external network request for Corda state is received."),(0,r.kt)("h4",{id:"access-control-cordapp-assets"},"Access Control CorDapp Assets"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"class AccessControlIssueRequestState(\n linearId: UniqueIdentifier = UniqueIdentifier(),\n externalNetworkId: String,\n externalNetworkCertificates: List<String>,\n requestApprovals: List<DigitalSignature.WithKey>,\n stateLinearId: UniqueIdentifier,\n participants: List<Party>\n) : LinearState\n\nclass AccessControlState(\n linearId: UniqueIdentifier = UniqueIdentifier(),\n externalNetworkId: String,\n externalNetworkCertificates: List<String>,\n stateLinearId: UniqueIdentifier,\n participants: List<Party>\n) : LinearState\n")),(0,r.kt)("h4",{id:"access-control-api-assets"},"Access Control API Assets"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"class AccessControlIssueRequestStateRequest(\n externalNetworkId: String,\n externalNetworkCertificates: List<String>,\n stateLinearId: String,\n participants: List<String>\n)\n\nclass AccessControlIssueRequestStateResponse(\n linearId: UniqueIdentifier,\n externalNetworkId: String,\n externalNetworkCertificates: List<String>,\n requestApprovals: List<String>,\n stateLinearId: String,\n participants: List<String>\n)\n\nclass AccessControlStateResponse(\n linearId: UniqueIdentifier,\n externalNetworkId: String,\n externalNetworkCertificates: List<String>,\n stateLinearId: String,\n participants: List<String>\n)\n")),(0,r.kt)("h4",{id:"access-control-flows"},"Access Control Flows"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"class AccessControlIssueRequestInitiator(\n externalNetworkCertificates: List<String>,\n externalNetworkId: String,\n stateLinearId: UniqueIdentifier,\n participants: List<Party> {\n // Creates an access control request on the ledger for a particular document\n}\n\nclass AccessControlIssueRequestApprover(\n id: UniqueIdentifier){\n // Allows for a party to approve an access control issuance request\n // Once all parties listed as a participant of the state the access control request pertains to\n // have approved the request, an AccessControlState is created\n}\n")),(0,r.kt)("h4",{id:"access-control-query-flows"},"Access Control Query Flows"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"class QueryAccessControlIssueRequestStates() List<AccessControlIssueRequestState> {\n // returns access control requests\n}\n\nclass QueryAccessControlIssueRequestStateByLinearId(linearId: UniqueIdentifier) AccessControlIssueRequestState {\n // returns access control request by Id\n}\n\nclass QueryAccessControlStates() List<AccessControlState> {\n // returns list of access control states\n}\n\nclass QueryAccessControlStateByLinearId(linearId: UniqueIdentifier) AccessControlState {\n // returns access control state by Id\n}\n\nclass QueryAccessControlStatesByStateIdAndNetworkId(\n stateLinearId: UniqueIdentifier,\n externalNetworkId: String\n ) AccessControlState {\n // returns access control state by the linearId of the application state and the external network Id\n}\n")),(0,r.kt)("h4",{id:"access-control-application-rest-api-and-corda-flow-connections"},"Access Control Application REST API and Corda Flow Connections"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"POST accessControlRequests/new\nreq: AccessControlIssueRequestStateRequest\nres: AccessControlIssueRequestStateResponse, or failure\ncalls: AccessControlIssueRequestInitiator\n\nPOST /accessControlRequests/approve/{id}\nreq: id\nres: AccessControlIssueRequestStateResponse, or failure\ncalls: AccessControlIssueRequestApprover\n\nGET accessControlRequests\nreq: {}\nres: AccessControlIssueRequestStateResponse, or failure\ncalls: QueryAccessControlIssueRequestStateByLinearId\n\nGET accessControlStates\nreq: {}\nres: List<AccessControlState>, or failure\ncalls: QueryAccessControlStates\n\nGET accessControlStates/{id}\nreq: {}\nres: AccessControlStateResponse, or failure\ncalls: QueryAccessControlIssueRequestStateByLinearId\n")),(0,r.kt)("h2",{id:"2-handle-external-networks-querying-a-corda-application-for-state"},"2. Handle external networks querying a Corda application for state"),(0,r.kt)("p",null,"An external network can make a request for Corda state by reaching the interoperability CorDapp through the relay. "),(0,r.kt)("p",null,"For an external network request to be successful it must fulfill the following:"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},"The identity of the requester needs to be authenticated through a signature on the request and a provided certificate. The signature is either made on the ",(0,r.kt)("inlineCode",{parentName:"li"},"linearId")," or the ",(0,r.kt)("inlineCode",{parentName:"li"},"txId")," that is provided in the request."),(0,r.kt)("li",{parentName:"ol"},"The certificate needs to be validated against the FNIM stored for the external network (i.e. the certificate needs to be issued by an issuing CA listed in the FNIM and the hierarchy of certificates in the FNIM needs to be validated up to the rootCA)."),(0,r.kt)("li",{parentName:"ol"},"The desired state needs to be located in the vault of the Corda node processing the request."),(0,r.kt)("li",{parentName:"ol"},"A corresponding Access Control state needs to be found for the desired state and the certificate of the requester needs to be listed in the Access Control state.")),(0,r.kt)("p",null,"The Corda node processing the request then needs to assemble a response object that includes the desired state and a signature on the state that provides evidence that this was the current view of the state according to that node.\nThe Corda node then needs to forward the request on to all participants of the state, who run through the same process for validation of the request and assembly of the response object.\nThe responses from each of the Corda nodes are collected by the initial Corda node and returned to the relay who pass the response back to the requesting network.\nCollectively, the responses from all Corda nodes (provided they shared the same view of the state) should be enough to convince the requester of the current state in the Corda ledger.\nThis assumes that the requesting network trusts that the Corda network participants are not colluding to misrepresent the state.\nWhether we want to provide stronger assurances of the currency and finality of state by requiring the Notary also sign off on the state can be assessed in the next iteration."),(0,r.kt)("p",null,"There must be some way of identifying the desired Corda state without necessitating that the interoperation Cordapp be aware of the data classes of the Corda application.\nIn Fabric, this was done by the requesting network passing the chaincode query function name and the query in the request.\nIn Corda, this approach needs to be revisited because there is no concept of a chaincode query function.\nThe initial approach taken in the demo was to identify the Corda state by linearId as this guarantees that the state can be uniquely identified in the vault.\nHowever, there is no guarantee that states will have a unique identifier as not all application states will extend the ",(0,r.kt)("inlineCode",{parentName:"p"},"LinearState")," interface.\nAs well, the ",(0,r.kt)("inlineCode",{parentName:"p"},"linearId")," is a property generated in Corda on creation of the state and may be meaningless in the business process.\nTherefore, it cannot be assumed that an external network will have visibility of the ",(0,r.kt)("inlineCode",{parentName:"p"},"linearId"),".\nOur workaround for the demo was to create a custom endpoint ",(0,r.kt)("inlineCode",{parentName:"p"},"externalNetworkRequestByTxId")," where the desired state was identified by a property unique to a letter of credit - the ",(0,r.kt)("inlineCode",{parentName:"p"},"txId"),".\nA set of linearIds that corresponded to that txId were then found using a custom flow called ",(0,r.kt)("inlineCode",{parentName:"p"},"GetLinearIdsFromTxId"),".\nThe request was then validated according to the criteria above (valid signature, valid certificate according to FNIM, valid Access Control state) and a response object generated for each state located by linearId.\nOther approaches that could be more appropriate for Corda may include creating query flows in the CorDapp application that work in a similar way to chaincode query functions.\nThis would involve investigating if cross-CorDapp triggering of flows is possible, and if so, how they can be executed.\nAnother approach could be requiring a ",(0,r.kt)("inlineCode",{parentName:"p"},"CustomQueryCriteria")," in the request that comes from the external network.\nAgain, we would have to investigate if ",(0,r.kt)("inlineCode",{parentName:"p"},"CustomQueryCriteria")," can be used in a CorDapp that has no knowledge of the application states for which that query pertains.\nRegardless of the approach to address state within Corda, for the next iteration of the protocol we need to think about how to generalise this across enterprise DLTs. "),(0,r.kt)("p",null,"Another workaround for the demo also of note here is the automatic generation of an Access Control state for the states specified in the request.\nAs we had not implemented any workflow or user interface in the Corda application for granting access to external network participants, creation of an Access Control state was triggered when the interoperation CorDapp received a request from an external network.\nNote that the functionality for a Corda application to incorporate the creation of Access Control states into their workflows is present in the interoperation APIs.\nThis workaround was put in place purely because the demo did not include a demonstration of this workflow.\nSome further thought will need to be put into the workflow in the application CorDapp, especially with how external network parties are represented (for example, will the application CorDapp require access to the participant certificates listed in the FNIM?)."),(0,r.kt)("p",null,"Things to think about in the next iteration of the protocol:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Trust model of the relay - does the request need to be encrypted?"),(0,r.kt)("li",{parentName:"ul"},"How do we address the Corda nodes in the request so the relay can know which node to forward the request on to"),(0,r.kt)("li",{parentName:"ul"},"Do we need to include guidelines about the encryption and signature schemes that can be used? Will accepted encryption and signature schemes vary on a network-by-network basis? If so, do we need some way of publishing what encryption and signature schemes a network accepts?"),(0,r.kt)("li",{parentName:"ul"},"How to generalise the addressing of state? In Corda this could be a ",(0,r.kt)("inlineCode",{parentName:"li"},"CustomQueryCriteria"),", in Fabric this is currently done through chaincode function and query"),(0,r.kt)("li",{parentName:"ul"},"How to handle multiple states being found"),(0,r.kt)("li",{parentName:"ul"},"Next iteration needs to handle replay attacks - provide a nonce in the request"),(0,r.kt)("li",{parentName:"ul"},"Currently the ",(0,r.kt)("inlineCode",{parentName:"li"},"organizationName")," of the requester is required in the request. We need a more general way of linking the requester identity with the issuing CA in the FNIM. ")),(0,r.kt)("h4",{id:"handle-requests-from-foreign-network---cordapp-assets"},"Handle Requests From Foreign Network - CorDapp Assets"),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"StateQueryResponse")," is the object assembled by each Corda node for each requested state.\nThe ",(0,r.kt)("inlineCode",{parentName:"p"},"requestedState")," field is a JSON string of the ",(0,r.kt)("inlineCode",{parentName:"p"},"QueryResponse")," that is encoded in Base64 as a bytearray.\nThe ",(0,r.kt)("inlineCode",{parentName:"p"},"certificate")," is the certificate of the Corda node providing the state and is used by the requesting network to validate the signature and the identity of the Corda node against their locally stored copy of the Corda network FNIM.\nThe ",(0,r.kt)("inlineCode",{parentName:"p"},"signature")," is the signature of the Corda node signed on the ",(0,r.kt)("inlineCode",{parentName:"p"},"requestedState")," bytearray. "),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"state")," field in ",(0,r.kt)("inlineCode",{parentName:"p"},"QueryResponse")," is a JSON string of the Corda application state.\nFor the demo, some of the JSON attributes were manipulated by converting to lowercase from camelcase, and renaming some fields.\nThis was done as the Fabric application was expecting the letter of credit state to be returned in a particular form.\nIdeally, the Interoperation CorDapp would not manipulate the state in any way before it is returned.\nIt also cannot be expected that the Corda application needs to modify its data structures in any way to conform with an external network's data structure.\nIt should be up to the consuming network to parse the state it receives into a meaningful format for its own application. "),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"class StateQueryResponse(\n requestedState: ByteArray, \n certificate: ByteArray,\n signature: ByteArray \n)\n\nclass QueryResponse(\n state: String,\n linearId: String\n)\n")),(0,r.kt)("h4",{id:"handle-requests-from-foreign-network---api-assets"},"Handle Requests From Foreign Network - API Assets"),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"ExternalNetworkRequest")," or ",(0,r.kt)("inlineCode",{parentName:"p"},"ExternalNetworkRequestWithTxId")," are the two request bodies that the external network can provide.\nThese are based on whether the external network is identifying the Corda application state by ",(0,r.kt)("inlineCode",{parentName:"p"},"linearId")," or ",(0,r.kt)("inlineCode",{parentName:"p"},"txId"),".\nAs mentioned previously, for the demo the latter request type was used as we assumed that the external network would not have any visibility of the ",(0,r.kt)("inlineCode",{parentName:"p"},"linearId")," property of a Corda state.\nThe ",(0,r.kt)("inlineCode",{parentName:"p"},"externalNetworkId")," needs to match with the ",(0,r.kt)("inlineCode",{parentName:"p"},"externalNetworkId")," used to store the FNIM for the requesting network.\nThe ",(0,r.kt)("inlineCode",{parentName:"p"},"organizationName")," is a Fabric-specific artifact that stems from the way identities are grouped under organizations.\nThis field is needed in order to validate the identity of the requester in the FNIM by finding the correct issuing CA of the credentials.\nThis will need to be revised in the next iteration of the protocol as the FNIM will need to be generalised to be applicable to all enterprise DLTs. "),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"class ExternalNetworkRequest(\n externalNetworkId: String,\n organizationName: String,\n requesterCertificate: String,\n requesterSignature: String,\n stateLinearId: String\n)\n\nclass ExternalNetworkRequestWithTxId(\n externalNetworkId: String,\n organizationName: String,\n requesterCertificate: String,\n requesterSignature: String,\n txId: String\n)\n")),(0,r.kt)("h4",{id:"handle-requests-from-foreign-network---flows"},"Handle Requests From Foreign Network - Flows"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"class StateQueryInitiator(\n externalNetworkId: String,\n organizationName: String,\n stateLinearId: UniqueIdentifier,\n requesterCertString: String,\n requesterSignature: String,\n txId: String?\n) List<StateQueryResponse> {\n // returns requested state and associated proof\n}\n\nclass GetLinearIdsFromTxId(\n txId: String\n) List<UniqueIdentifier> {\n // returns list ids for states that match the query criterion\n}\n")),(0,r.kt)("h4",{id:"handle-requests-from-foreign-network---application-rest-api-and-corda-flow-connections"},"Handle Requests From Foreign Network - Application REST API and Corda Flow Connections"),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"externalNetworkRequest POST")," endpoint is used to find the Corda application state based on ",(0,r.kt)("inlineCode",{parentName:"p"},"linearId"),".\nIt will return a ",(0,r.kt)("inlineCode",{parentName:"p"},"StateQueryResponse")," for each Corda node listed as a participant in the state, or in the case that a state is not found or access is denied for the requester, will fail.\nThe ",(0,r.kt)("inlineCode",{parentName:"p"},"externalNetworkRequestByTxId POST")," endpoint finds Corda application state based on ",(0,r.kt)("inlineCode",{parentName:"p"},"txId")," and could potentially match with multiple states.\nTherefore, for each accessible state found, each Corda node listed as a participant in the state will provide a ",(0,r.kt)("inlineCode",{parentName:"p"},"StateQueryResponse"),".\nIf no states are found or the requester does not have permission to access the state, an empty list will be returned.\nNote that the access control calls that are made are purely a workaround from the fact that the setup of state access control was not built into the demo."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"POST externalNetworkRequest\nreq: ExternalNetworkRequest\nres: List<StateQueryResponse>, or failure\ncalls: \n 1. <interoperation-webserver1-url>/accessControlRequests/new\n 2. <interoperation-webserver2-url>/accessControlRequests/approve\n 3. StateQueryInitiator\n\nPOST externalNetworkRequestByTxId\nreq: ExternalNetworkRequestWithTxId\nres: List<List<StateQueryResponse>?>\ncalls: \n 1. <interoperation-webserver1-url>/accessControlRequests/new\n 2. <interoperation-webserver2-url>/accessControlRequests/approve\n 3. GetLinearIdsFromTxId\n 4. StateQueryInitiator (for each linearId)\n")),(0,r.kt)("h2",{id:"3-requests-to-get-state-from-external-networks"},"3. Requests to get state from external networks"),(0,r.kt)("p",null,"In the opposite case from the previous section, the Interoperation CorDapp also allows a Corda application to request a state from an external network.\nThis consists of the following steps:"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},"A Corda application uses the Interoperation CorDapp API to trigger the request to the external network (takes a ",(0,r.kt)("inlineCode",{parentName:"li"},"ExternalStateRequest"),")"),(0,r.kt)("li",{parentName:"ol"},"The Interoperation CorDapp creates a request object to send to the foreign network's relay (",(0,r.kt)("inlineCode",{parentName:"li"},"RelayRequestObject"),")"),(0,r.kt)("li",{parentName:"ol"},"The returned state and proofs are validated"),(0,r.kt)("li",{parentName:"ol"},"The external network's state is stored in the vault along with the associated proofs"),(0,r.kt)("li",{parentName:"ol"},"The ",(0,r.kt)("inlineCode",{parentName:"li"},"linearId")," of the state is returned to the Corda application"),(0,r.kt)("li",{parentName:"ol"},"The Corda application retrieves the state from the vault")),(0,r.kt)("h4",{id:"request-state-from-external-network---cordapp-assets"},"Request State from External Network - CorDapp Assets"),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"ExternalStateRequest")," is the request object the webserver receives as part of the ",(0,r.kt)("inlineCode",{parentName:"p"},"POST requestExternalState")," endpoint.\nIt is used by the webserver to know how to address the relay and it is also passed on to the ",(0,r.kt)("inlineCode",{parentName:"p"},"CreateExternalRequestStateObject")," flow to construct the request object that will be forwarded to the relay.\nThe ",(0,r.kt)("inlineCode",{parentName:"p"},"url")," and the ",(0,r.kt)("inlineCode",{parentName:"p"},"path")," are required to the webserver knows how to address the relay to forward the request on to.\nThe ",(0,r.kt)("inlineCode",{parentName:"p"},"externalNetworkId")," identifies the external network the relay needs to forward the request to and needs to match the id used in the FNIM.\nThe ",(0,r.kt)("inlineCode",{parentName:"p"},"arguments")," contains the arguments that will be passed to the specified chaincode function, ",(0,r.kt)("inlineCode",{parentName:"p"},"function"),".\nThese parameters, ",(0,r.kt)("inlineCode",{parentName:"p"},"arguments")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"function")," are very Fabric-centric and we should generalise the method of addressing state across DLTs for future iterations of the interoperation protocol.\nThe ",(0,r.kt)("inlineCode",{parentName:"p"},"participants")," is the list of Corda participants that will need own the Fabric state when it is stored in Corda.\nTo make this code a little cleaner, we should probably have the request object received by the webserver defined in the API assets, which should include ",(0,r.kt)("inlineCode",{parentName:"p"},"url"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"path"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"participants")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"requestParameters"),".\nThe ",(0,r.kt)("inlineCode",{parentName:"p"},"requestParameters")," would be forwarded on to the ",(0,r.kt)("inlineCode",{parentName:"p"},"CreateExternalRequestStateObject")," flow, and would only include those fields relevant to the flow (",(0,r.kt)("inlineCode",{parentName:"p"},"externalNetworkId"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"function")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"arguments"),").\nHowever, seeing as the way we address state in a more general protocol is going to change, we probably don't need to worry about cleaning this up in the demo code. "),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"class ExternalStateRequest(\n url: String,\n path: String,\n externalNetworkId: String,\n arguments: String,\n function: String,\n participants: List<String>\n)\n")),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"RelayRequestObject")," is what the interoperation CorDapp sends to the relay to forward on to the Fabric network.\n",(0,r.kt)("inlineCode",{parentName:"p"},"operationType")," defines the type of operation the Corda network wants to perform on the chaincode - either ",(0,r.kt)("inlineCode",{parentName:"p"},"INVOKE")," or ",(0,r.kt)("inlineCode",{parentName:"p"},"QUERY"),".\nFor now, the ",(0,r.kt)("inlineCode",{parentName:"p"},"QUERY")," operation is the only one that is supported on the Fabric end and is hardcoded in the ",(0,r.kt)("inlineCode",{parentName:"p"},"CreateExternalRequestStateObject")," flow where an instance of ",(0,r.kt)("inlineCode",{parentName:"p"},"RelayRequestObject")," is created.\nTo be consistent, ",(0,r.kt)("inlineCode",{parentName:"p"},"operationType")," should probably have been included in the ",(0,r.kt)("inlineCode",{parentName:"p"},"ExternalStateRequest")," that was passed into the flow.\nAgain, seeing as the way we address state is going to change, we won't worry about changing the demo code.\nThe ",(0,r.kt)("inlineCode",{parentName:"p"},"policy")," refers to the endorsement policy of the Fabric channel for the particular state that the Corda application is requesting.\nA more detailed discussion of how the ",(0,r.kt)("inlineCode",{parentName:"p"},"policy")," is defined and how it ",(0,r.kt)("em",{parentName:"p"},"should")," be defined is in the ",(0,r.kt)("a",{parentName:"p",href:"#writestatefromexternalnetworkflows"},"flows section"),".\nThe fields ",(0,r.kt)("inlineCode",{parentName:"p"},"function")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"arguments")," are copied across from what is provided in the ",(0,r.kt)("inlineCode",{parentName:"p"},"ExternalStateRequest")," that comes from the client application.\nOn the Fabric end, the Fabric nodes will want to authenticate the Corda node making the request - enabled through ",(0,r.kt)("inlineCode",{parentName:"p"},"clientOrganizationId"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"clientCertificate")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"clientSignature"),". "),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"class RelayRequestObject(\n operationType: String,\n policy: String,\n function: String,\n arguments: List<String>,\n clientOrganizationId: String,\n clientCertificate: String,\n clientSignature: String\n)\n")),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"ExternalStateObjectState")," is the way the state and proof that is returned from the external network is saved as a state in the Corda vault."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"class ExternalStateObjectState(\n linearId: UniqueIdentifier = UniqueIdentifier(),\n participants: List<Party>,\n externalState: String,\n externalNetworkId: String,\n responseObject: List<FormattedResponse>\n) : LinearState\n\nclass FormattedResponse(\n organizationName: String,\n decryptedPayload: String,\n certString: String,\n signatureBytes: ByteArray,\n message: ByteArray,\n publicKey: PublicKey\n)\n\nclass RelayResponseObject(\n requestId: String,\n status: String,\n response: List<NodeResponse>?\n)\n\nclass NodeResponse(\n proposal: String,\n proposalResponse: String\n)\n\nclass RelayRequestId(\n requestId: String\n)\n\nclass ParsedQueryObject(\n linearId: UniqueIdentifier,\n txId: String?\n)\n\nclass NetworkMapObject(\n networkId: String,\n nodes: List<Node>\n)\n\nclass Node(\n name: String,\n address: String,\n hierarchicalCerts: List<ByteArray>,\n hierarchicalCANames: List<String>\n)\n")),(0,r.kt)("h4",{id:"writestatefromexternalnetworkflows"},"WriteStateFromExternalNetworkFlows"),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"CreateExternalRequestStateObject")," flow takes the request from the Corda application (through the webserver) and creates the request object that the relay needs to pass on to the external network.\nIt first looks up the FNIM for the external network based off the provided external netowrk id.\nThe ",(0,r.kt)("inlineCode",{parentName:"p"},"policy")," for the ",(0,r.kt)("inlineCode",{parentName:"p"},"RelayRequestObject")," is created by concatenating the name of each of the ",(0,r.kt)("inlineCode",{parentName:"p"},"FNNode"),"s that are present in the ",(0,r.kt)("inlineCode",{parentName:"p"},"ForeignNetworkInformationManagementState")," for that network, separated by the ",(0,r.kt)("inlineCode",{parentName:"p"},"&")," symbol (e.g. for the demo ",(0,r.kt)("inlineCode",{parentName:"p"},"SellerMSP & CarrierMSP"),").\nThis approach is not ideal as it is very Fabric-centric and is currently hardcoded to be all of the nodes listed in the FNIM for the network, which may or may not be the correct endorsement policy needed for the state.\nHow endorsement policy should be represented in the interoperation CorDapp has been raised as an ",(0,r.kt)("a",{parentName:"p",href:"https://github.ibm.com/dlt-interoperability/cordapp-interop/issues/35"},"issue in the ",(0,r.kt)("inlineCode",{parentName:"a"},"cordapp-interop")," repo"),'.\nThe endorsement policy is a concept that is present in all permissioned DLTs (although not always called "endorsement policy").\nIt refers to the set of parties who have ownership of a state, or who control the update of a state.\nWe should generalise this concept in the next iteration of the protocol and store the endorsement policies for an external network as states that can be looked up by the interop CorDapp.\nThe ',(0,r.kt)("inlineCode",{parentName:"p"},"clientCertificate")," is a string of the Corda node X.509 certificate in PEM format.\nThe signature is a Base 64 string, signed on a concatenation of the ",(0,r.kt)("inlineCode",{parentName:"p"},"function"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"arguments")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"clientOrganizationId")," represented as Base 64 byte arrays."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"class CreateExternalRequestStateObject(\n request: ExternalStateRequest\n) RelayRequestObject {\n // returns request object to query relay about a foreign network state\n}\n")),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"WriteExternalStateInitiator")," flow is used to verify the state proof that is returned from the external network and commit the state to the vault. "),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"class WriteExternalStateInitiator(\n nodeResponses: List<NodeResponse>,\n externalNetworkId: String,\n participants: List<Party>\n) UniqueIdentifier {\n // writes external state to ledger and returns unique identifier to be used to query from MarcoPolo\n}\n")),(0,r.kt)("h4",{id:"application-rest-api-and-corda-flow-connections"},"Application REST API and Corda flow connections"),(0,r.kt)("hr",null),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"POST requestExternalState\nreq: ExternalStateRequest\nres: UniqueIdentifier, or failure\ncalls: \n 1. CreateExternalRequestStateObject\n 2. HTTP POST request to relay with the provided url and path\n 3. HTTP GET request to relay to get the response from the external network\n 4. WriteExternalStateInitiator\n")))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/ce7e6f90.8f1959db.js b/assets/js/ce7e6f90.248e2db7.js similarity index 91% rename from assets/js/ce7e6f90.8f1959db.js rename to assets/js/ce7e6f90.248e2db7.js index 5e2dbfab8..3e20c948f 100644 --- a/assets/js/ce7e6f90.8f1959db.js +++ b/assets/js/ce7e6f90.248e2db7.js @@ -1 +1 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[9962],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>f});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},o=Object.keys(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var c=r.createContext({}),p=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},d=function(e){var t=p(e.components);return r.createElement(c.Provider,{value:t},e.children)},s="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},y=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),s=p(n),y=a,f=s["".concat(c,".").concat(y)]||s[y]||u[y]||o;return n?r.createElement(f,i(i({ref:t},d),{},{components:n})):r.createElement(f,i({ref:t},d))}));function f(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=y;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l[s]="string"==typeof e?e:a,i[1]=l;for(var p=2;p<o;p++)i[p]=n[p];return r.createElement.apply(null,i)}return r.createElement.apply(null,n)}y.displayName="MDXCreateElement"},5636:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>u,frontMatter:()=>o,metadata:()=>l,toc:()=>p});var r=n(7462),a=(n(7294),n(3905));const o={id:"legal-and-regulation",title:"Legal and Regulation"},i=void 0,l={unversionedId:"external/deployment-considerations/legal-and-regulation",id:"external/deployment-considerations/legal-and-regulation",title:"Legal and Regulation",description:"\x3c!--",source:"@site/docs/external/deployment-considerations/legal-and-regulation.md",sourceDirName:"external/deployment-considerations",slug:"/external/deployment-considerations/legal-and-regulation",permalink:"/weaver-dlt-interoperability/docs/external/deployment-considerations/legal-and-regulation",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/deployment-considerations/legal-and-regulation.md",tags:[],version:"current",frontMatter:{id:"legal-and-regulation",title:"Legal and Regulation"},sidebar:"Documentation",previous:{title:"Governance and Policies",permalink:"/weaver-dlt-interoperability/docs/external/deployment-considerations/governance-and-policies"},next:{title:"Specifications",permalink:"/weaver-dlt-interoperability/docs/external/specifications"}},c={},p=[],d={toc:p},s="wrapper";function u(e){let{components:t,...n}=e;return(0,a.kt)(s,(0,r.Z)({},d,n,{components:t,mdxType:"MDXLayout"}))}u.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[3304],{5680:(e,t,n)=>{n.d(t,{xA:()=>d,yg:()=>f});var r=n(6540);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},o=Object.keys(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var c=r.createContext({}),p=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},d=function(e){var t=p(e.components);return r.createElement(c.Provider,{value:t},e.children)},s="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},y=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),s=p(n),y=a,f=s["".concat(c,".").concat(y)]||s[y]||u[y]||o;return n?r.createElement(f,i(i({ref:t},d),{},{components:n})):r.createElement(f,i({ref:t},d))}));function f(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=y;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l[s]="string"==typeof e?e:a,i[1]=l;for(var p=2;p<o;p++)i[p]=n[p];return r.createElement.apply(null,i)}return r.createElement.apply(null,n)}y.displayName="MDXCreateElement"},7738:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>u,frontMatter:()=>o,metadata:()=>l,toc:()=>p});var r=n(8168),a=(n(6540),n(5680));const o={id:"legal-and-regulation",title:"Legal and Regulation"},i=void 0,l={unversionedId:"external/deployment-considerations/legal-and-regulation",id:"external/deployment-considerations/legal-and-regulation",title:"Legal and Regulation",description:"\x3c!--",source:"@site/docs/external/deployment-considerations/legal-and-regulation.md",sourceDirName:"external/deployment-considerations",slug:"/external/deployment-considerations/legal-and-regulation",permalink:"/weaver-dlt-interoperability/docs/external/deployment-considerations/legal-and-regulation",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/deployment-considerations/legal-and-regulation.md",tags:[],version:"current",frontMatter:{id:"legal-and-regulation",title:"Legal and Regulation"},sidebar:"Documentation",previous:{title:"Governance and Policies",permalink:"/weaver-dlt-interoperability/docs/external/deployment-considerations/governance-and-policies"},next:{title:"Specifications",permalink:"/weaver-dlt-interoperability/docs/external/specifications"}},c={},p=[],d={toc:p},s="wrapper";function u(e){let{components:t,...n}=e;return(0,a.yg)(s,(0,r.A)({},d,n,{components:t,mdxType:"MDXLayout"}))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/d85aeaf8.86ca9d44.js b/assets/js/d85aeaf8.86ca9d44.js deleted file mode 100644 index dc93921d5..000000000 --- a/assets/js/d85aeaf8.86ca9d44.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[5651],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>m});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function s(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?a(Object(r),!0).forEach((function(t){o(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):a(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function i(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},a=Object.keys(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=n.createContext({}),c=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},p=function(e){var t=c(e.components);return n.createElement(l.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},f=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),u=c(r),f=o,m=u["".concat(l,".").concat(f)]||u[f]||d[f]||a;return r?n.createElement(m,s(s({ref:t},p),{},{components:r})):n.createElement(m,s({ref:t},p))}));function m(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,s=new Array(a);s[0]=f;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i[u]="string"==typeof e?e:o,s[1]=i;for(var c=2;c<a;c++)s[c]=r[c];return n.createElement.apply(null,s)}return n.createElement.apply(null,r)}f.displayName="MDXCreateElement"},9402:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>s,default:()=>d,frontMatter:()=>a,metadata:()=>i,toc:()=>c});var n=r(7462),o=(r(7294),r(3905));const a={},s=void 0,i={unversionedId:"internal/development/cordapp-interop/cordapp-interop-flows",id:"internal/development/cordapp-interop/cordapp-interop-flows",title:"cordapp-interop-flows",description:"\x3c!--",source:"@site/docs/internal/development/cordapp-interop/cordapp-interop-flows.md",sourceDirName:"internal/development/cordapp-interop",slug:"/internal/development/cordapp-interop/cordapp-interop-flows",permalink:"/weaver-dlt-interoperability/docs/internal/development/cordapp-interop/cordapp-interop-flows",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/internal/development/cordapp-interop/cordapp-interop-flows.md",tags:[],version:"current",frontMatter:{}},l={},c=[{value:"AccessControlFlows",id:"accesscontrolflows",level:3},{value:"AccessControlQueryFlows",id:"accesscontrolqueryflows",level:3},{value:"FNIMFlows",id:"fnimflows",level:3},{value:"FNIMQueryFlows",id:"fnimqueryflows",level:3},{value:"HandleRequestsFromForeignNetworkFlows",id:"handlerequestsfromforeignnetworkflows",level:3},{value:"WriteStateFromExternalNetworkFlows",id:"writestatefromexternalnetworkflows",level:3}],p={toc:c},u="wrapper";function d(e){let{components:t,...r}=e;return(0,o.kt)(u,(0,n.Z)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("hr",null),(0,o.kt)("p",null,"id: cordapp-interop-flows\ntitle: Flows"),(0,o.kt)("hr",null),(0,o.kt)("h3",{id:"accesscontrolflows"},"AccessControlFlows"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"class AccessControlIssueRequestInitiator(\n externalNetworkCertificates: List<String>,\n externalNetworkId: String,\n stateLinearId: UniqueIdentifier,\n participants: List<Party> {\n // creates an access control state on the ledger for a particular document\n}\n\nclass AccessControlIssueRequestApprover(\n id: UniqueIdentifier){\n // allows for a party to approve an access control issuance request\n}\n")),(0,o.kt)("h3",{id:"accesscontrolqueryflows"},"AccessControlQueryFlows"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"class QueryAccessControlIssueRequestStates() List<AccessControlIssueRequestState> {\n // returns access control requests\n}\n\nclass QueryAccessControlIssueRequestStateByLinearId(linearId: UniqueIdentifier) AccessControlIssueRequestState {\n // returns access control request by Id\n}\n\nclass QueryAccessControlStates() List<AccessControlState> {\n // returns list of access control states\n}\n\nclass QueryAccessControlStateByLinearId(linearId: UniqueIdentifier) AccessControlState {\n // returns access control state by Id\n}\n")),(0,o.kt)("h3",{id:"fnimflows"},"FNIMFlows"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"class FNIMInitiator(\n networkId: String,\n topology: List<FNNode>,\n participants: List<Party>) {\n // creates FNIM record for an external network\n}\n\nclass FNIMExitInitiator(\n id: String ) {\n // marks FNIM state as consumed\n}\n")),(0,o.kt)("h3",{id:"fnimqueryflows"},"FNIMQueryFlows"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"class QueryForeignNetworkInformationManagementStates : List<ForeignNetworkInformationManagementState> {\n // returns list of FNIM states\n}\n\nclass QueryForeignNetworkInformationManagementStatesById(\n linearId: UniqueIdentifier) ForeignNetworkInformationManagementState {\n // returns FNIM state\n}\n\nclass QueryForeignNetworkInformationManagementStateByNetworkId(\n networkId: String) ForeignNetworkInformationManagementState {\n // returns FNIM state for specified network\n}\n")),(0,o.kt)("h3",{id:"handlerequestsfromforeignnetworkflows"},"HandleRequestsFromForeignNetworkFlows"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"class StateQueryInitiator(\n externalNetworkId: String,\n organizationName: String,\n stateLinearId: UniqueIdentifier,\n requesterCertString: String,\n requesterSignature: String,\n txId: String?\n) List<StateQueryResponse> {\n // returns requested state\n}\n\nclass GetLinearIdsFromTxId(\n txId: String\n) List<UniqueIdentifier> {\n // returns list ids for states that match the query criterion\n}\n")),(0,o.kt)("h3",{id:"writestatefromexternalnetworkflows"},"WriteStateFromExternalNetworkFlows"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"class CreateExternalRequestStateObject(\n request: ExternalStateRequest\n) RelayRequestObject {\n // returns request object to query relay about a foreign network state\n}\n\nclass WriteExternalStateInitiator(\n nodeResponses: List<NodeResponse>,\n externalNetworkId: String,\n participants: List<Party>\n) UniqueIdentifier {\n // writes external state to ledger and returns unique identifier to be used to query from MarcoPolo\n}\n")))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/da157423.5f099098.js b/assets/js/da157423.5f099098.js deleted file mode 100644 index 7f1635421..000000000 --- a/assets/js/da157423.5f099098.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[3395],{3905:(e,t,a)=>{a.d(t,{Zo:()=>c,kt:()=>u});var r=a(7294);function n(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function l(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,r)}return a}function i(e){for(var t=1;t<arguments.length;t++){var a=null!=arguments[t]?arguments[t]:{};t%2?l(Object(a),!0).forEach((function(t){n(e,t,a[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(a)):l(Object(a)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(a,t))}))}return e}function o(e,t){if(null==e)return{};var a,r,n=function(e,t){if(null==e)return{};var a,r,n={},l=Object.keys(e);for(r=0;r<l.length;r++)a=l[r],t.indexOf(a)>=0||(n[a]=e[a]);return n}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(r=0;r<l.length;r++)a=l[r],t.indexOf(a)>=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(n[a]=e[a])}return n}var s=r.createContext({}),p=function(e){var t=r.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},c=function(e){var t=p(e.components);return r.createElement(s.Provider,{value:t},e.children)},d="mdxType",k={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var a=e.components,n=e.mdxType,l=e.originalType,s=e.parentName,c=o(e,["components","mdxType","originalType","parentName"]),d=p(a),m=n,u=d["".concat(s,".").concat(m)]||d[m]||k[m]||l;return a?r.createElement(u,i(i({ref:t},c),{},{components:a})):r.createElement(u,i({ref:t},c))}));function u(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var l=a.length,i=new Array(l);i[0]=m;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[d]="string"==typeof e?e:n,i[1]=o;for(var p=2;p<l;p++)i[p]=a[p];return r.createElement.apply(null,i)}return r.createElement.apply(null,a)}m.displayName="MDXCreateElement"},1253:(e,t,a)=>{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>k,frontMatter:()=>l,metadata:()=>o,toc:()=>p});var r=a(7462),n=(a(7294),a(3905));const l={id:"data-sharing",title:"Data Sharing",pagination_prev:"external/getting-started/interop/overview",pagination_next:"external/getting-started/enabling-weaver-network/overview"},i=void 0,o={unversionedId:"external/getting-started/interop/data-sharing",id:"external/getting-started/interop/data-sharing",title:"Data Sharing",description:"\x3c!--",source:"@site/docs/external/getting-started/interop/data-sharing.md",sourceDirName:"external/getting-started/interop",slug:"/external/getting-started/interop/data-sharing",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/data-sharing",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/getting-started/interop/data-sharing.md",tags:[],version:"current",frontMatter:{id:"data-sharing",title:"Data Sharing",pagination_prev:"external/getting-started/interop/overview",pagination_next:"external/getting-started/enabling-weaver-network/overview"},sidebar:"Documentation",previous:{title:"Testing Interoperation Modes",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/overview"},next:{title:"Enabling Weaver in Existing DLT Applications",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/overview"}},s={},p=[{value:"Corda to Corda",id:"corda-to-corda",level:2},{value:"Corda to Fabric",id:"corda-to-fabric",level:2},{value:"Fabric to Corda",id:"fabric-to-corda",level:2},{value:"Fabric to Fabric",id:"fabric-to-fabric",level:2}],c={toc:p},d="wrapper";function k(e){let{components:t,...a}=e;return(0,n.kt)(d,(0,r.Z)({},c,a,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("p",null,"This document lists sample ways in which you can exercise the data-sharing interoperation protocol on the test network ",(0,n.kt)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/overview"},"launched earlier"),"."),(0,n.kt)("p",null,"Once the networks, relays, and drivers have been launched, and the ledgers bootstrapped, you can trigger four different interoperation flows corresponding to distinct data-sharing combinations as follows:"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},(0,n.kt)("strong",{parentName:"li"},"Corda to Corda"),": Either Corda network requests state and proof from another Corda network"),(0,n.kt)("li",{parentName:"ol"},(0,n.kt)("strong",{parentName:"li"},"Corda to Fabric"),": The Corda network requests state and proof from either Fabric network"),(0,n.kt)("li",{parentName:"ol"},(0,n.kt)("strong",{parentName:"li"},"Fabric to Corda"),": Either Fabric network requests state and proof from the Corda network"),(0,n.kt)("li",{parentName:"ol"},(0,n.kt)("strong",{parentName:"li"},"Fabric to Fabric"),": One Fabric network requests state and proof from another Fabric network")),(0,n.kt)("p",null,"We assume that one of the following chaincodes have been deployed in either Fabric network you are testing with:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"simplestate")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"simplestatewithacl"))),(0,n.kt)("h2",{id:"corda-to-corda"},"Corda to Corda"),(0,n.kt)("p",null,"To test the scenario where ",(0,n.kt)("inlineCode",{parentName:"p"},"Corda_Network")," requests the value of the state (key) ",(0,n.kt)("inlineCode",{parentName:"p"},"H")," from ",(0,n.kt)("inlineCode",{parentName:"p"},"Corda_Network2"),", do the following:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"(",(0,n.kt)("em",{parentName:"li"},"Make sure the following are running"),": ",(0,n.kt)("inlineCode",{parentName:"li"},"Corda_Network"),", relay, and driver; ",(0,n.kt)("inlineCode",{parentName:"li"},"Corda_Network2"),", relay, and driver)"),(0,n.kt)("li",{parentName:"ul"},"Navigate to the ",(0,n.kt)("inlineCode",{parentName:"li"},"samples/corda/corda-simple-application")," folder."),(0,n.kt)("li",{parentName:"ul"},"Run the following:",(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},"If Relays and Drivers are deployed in the host machine:",(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},"Without TLS:",(0,n.kt)("pre",{parentName:"li"},(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients request-state localhost:9081 localhost:9082/Corda_Network2/localhost:30006#com.cordaSimpleApplication.flow.GetStateByKey:H\n"))),(0,n.kt)("li",{parentName:"ul"},"With TLS:",(0,n.kt)("pre",{parentName:"li"},(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"RELAY_TLS=true RELAY_TLSCA_CERT_PATHS=../../../core/relay/credentials/fabric_ca_cert.pem NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients request-state localhost:9081 localhost:9082/Corda_Network2/localhost:30006#com.cordaSimpleApplication.flow.GetStateByKey:H\n"))))),(0,n.kt)("li",{parentName:"ul"},"If Relays and Drivers are deployed in Docker containers:",(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},"Without TLS:",(0,n.kt)("pre",{parentName:"li"},(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients request-state localhost:9081 relay-corda2:9082/Corda_Network2/corda_network2_partya_1:10003#com.cordaSimpleApplication.flow.GetStateByKey:H\n"))),(0,n.kt)("li",{parentName:"ul"},"With TLS:",(0,n.kt)("pre",{parentName:"li"},(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"RELAY_TLS=true RELAY_TLSCA_CERT_PATHS=../../../core/relay/credentials/docker/ca-cert.pem NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients request-state localhost:9081 relay-corda2:9082/Corda_Network2/corda_network2_partya_1:10003#com.cordaSimpleApplication.flow.GetStateByKey:H\n"))))))),(0,n.kt)("li",{parentName:"ul"},"Query the value of the requested state using key ",(0,n.kt)("inlineCode",{parentName:"li"},"H")," in ",(0,n.kt)("inlineCode",{parentName:"li"},"Corda_Network")," by running the following command:",(0,n.kt)("pre",{parentName:"li"},(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients get-state H\n")))),(0,n.kt)("p",null,"To test the scenario where ",(0,n.kt)("inlineCode",{parentName:"p"},"Corda_Network2")," requests the value of the state (key) ",(0,n.kt)("inlineCode",{parentName:"p"},"C")," from ",(0,n.kt)("inlineCode",{parentName:"p"},"Corda_Network"),", do the following:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"(",(0,n.kt)("em",{parentName:"li"},"Make sure the following are running"),": ",(0,n.kt)("inlineCode",{parentName:"li"},"Corda_Network"),", relay, and driver; ",(0,n.kt)("inlineCode",{parentName:"li"},"Corda_Network2"),", relay, and driver)"),(0,n.kt)("li",{parentName:"ul"},"Navigate to the ",(0,n.kt)("inlineCode",{parentName:"li"},"samples/corda/corda-simple-application")," folder."),(0,n.kt)("li",{parentName:"ul"},"Run the following:",(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},"If Relays and Drivers are deployed in the host machine:",(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},"Without TLS:",(0,n.kt)("pre",{parentName:"li"},(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"NETWORK_NAME=Corda_Network2 CORDA_PORT=30006 ./clients/build/install/clients/bin/clients request-state localhost:9082 localhost:9081/Corda_Network/localhost:10006#com.cordaSimpleApplication.flow.GetStateByKey:C\n"))),(0,n.kt)("li",{parentName:"ul"},"With TLS:",(0,n.kt)("pre",{parentName:"li"},(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"RELAY_TLS=true RELAY_TLSCA_CERT_PATHS=../../../core/relay/credentials/fabric_ca_cert.pem NETWORK_NAME=Corda_Network2 CORDA_PORT=30006 ./clients/build/install/clients/bin/clients request-state localhost:9082 localhost:9081/Corda_Network/localhost:10006#com.cordaSimpleApplication.flow.GetStateByKey:C\n"))))),(0,n.kt)("li",{parentName:"ul"},"If Relays and Drivers are deployed in Docker containers:",(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},"Without TLS:",(0,n.kt)("pre",{parentName:"li"},(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"NETWORK_NAME=Corda_Network2 CORDA_PORT=30006 ./clients/build/install/clients/bin/clients request-state localhost:9082 relay-corda:9081/Corda_Network/corda_partya_1:10003#com.cordaSimpleApplication.flow.GetStateByKey:C\n"))),(0,n.kt)("li",{parentName:"ul"},"With TLS:",(0,n.kt)("pre",{parentName:"li"},(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"RELAY_TLS=true RELAY_TLSCA_CERT_PATHS=../../../core/relay/credentials/docker/ca-cert.pem NETWORK_NAME=Corda_Network2 CORDA_PORT=30006 ./clients/build/install/clients/bin/clients request-state localhost:9082 relay-corda:9081/Corda_Network/corda_partya_1:10003#com.cordaSimpleApplication.flow.GetStateByKey:C\n"))))))),(0,n.kt)("li",{parentName:"ul"},"Query the value of the requested state, using the key ",(0,n.kt)("inlineCode",{parentName:"li"},"C")," in ",(0,n.kt)("inlineCode",{parentName:"li"},"Corda_Network")," by running the following command:",(0,n.kt)("pre",{parentName:"li"},(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"NETWORK_NAME=Corda_Network2 CORDA_PORT=30006 ./clients/build/install/clients/bin/clients get-state C\n")))),(0,n.kt)("h2",{id:"corda-to-fabric"},"Corda to Fabric"),(0,n.kt)("p",null,"To test the scenario where ",(0,n.kt)("inlineCode",{parentName:"p"},"Corda_Network")," requests the value of the state (key) ",(0,n.kt)("inlineCode",{parentName:"p"},"a")," from ",(0,n.kt)("inlineCode",{parentName:"p"},"network1"),", do the following:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"(",(0,n.kt)("em",{parentName:"li"},"Make sure the following are running"),": Corda network, relay, and driver; Fabric ",(0,n.kt)("inlineCode",{parentName:"li"},"network1"),", relay, and driver)"),(0,n.kt)("li",{parentName:"ul"},"Navigate to the ",(0,n.kt)("inlineCode",{parentName:"li"},"samples/corda/corda-simple-application")," folder."),(0,n.kt)("li",{parentName:"ul"},"Run the following:",(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},"If Relays and Drivers are deployed in the host machine:",(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},"Without TLS:",(0,n.kt)("pre",{parentName:"li"},(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients request-state localhost:9081 localhost:9080/network1/mychannel:simplestate:Read:a\n"))),(0,n.kt)("li",{parentName:"ul"},"With TLS:",(0,n.kt)("pre",{parentName:"li"},(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"RELAY_TLS=true RELAY_TLSCA_CERT_PATHS=../../../core/relay/credentials/fabric_ca_cert.pem NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients request-state localhost:9081 localhost:9080/network1/mychannel:simplestate:Read:a\n"))))),(0,n.kt)("li",{parentName:"ul"},"If Relays and Drivers are deployed in Docker containers:",(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},"Without TLS:",(0,n.kt)("pre",{parentName:"li"},(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients request-state localhost:9081 relay-network1:9080/network1/mychannel:simplestate:Read:a\n"))),(0,n.kt)("li",{parentName:"ul"},"With TLS:",(0,n.kt)("pre",{parentName:"li"},(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"RELAY_TLS=true RELAY_TLSCA_CERT_PATHS=../../../core/relay/credentials/docker/ca-cert.pem NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients request-state localhost:9081 relay-network1:9080/network1/mychannel:simplestate:Read:a\n"))))))),(0,n.kt)("li",{parentName:"ul"},"Query the value of the requested state (key) ",(0,n.kt)("inlineCode",{parentName:"li"},"a")," in ",(0,n.kt)("inlineCode",{parentName:"li"},"Corda_Network")," using the following:",(0,n.kt)("pre",{parentName:"li"},(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients get-state a\n")))),(0,n.kt)("p",null,"To test the scenario where ",(0,n.kt)("inlineCode",{parentName:"p"},"Corda_Network")," requests the value of the state (key) ",(0,n.kt)("inlineCode",{parentName:"p"},"Arcturus")," from ",(0,n.kt)("inlineCode",{parentName:"p"},"network2"),", do the following:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"(",(0,n.kt)("em",{parentName:"li"},"Make sure the following are running"),": Corda network, relay, and driver; Fabric ",(0,n.kt)("inlineCode",{parentName:"li"},"network2"),", relay, and driver)"),(0,n.kt)("li",{parentName:"ul"},"Navigate to the ",(0,n.kt)("inlineCode",{parentName:"li"},"samples/corda/corda-simple-application")," folder."),(0,n.kt)("li",{parentName:"ul"},"Run the following:",(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},"If Relays and Drivers are deployed in the host machine:",(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},"Without TLS:",(0,n.kt)("pre",{parentName:"li"},(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients request-state localhost:9081 localhost:9083/network2/mychannel:simplestate:Read:Arcturus\n"))),(0,n.kt)("li",{parentName:"ul"},"With TLS:",(0,n.kt)("pre",{parentName:"li"},(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"RELAY_TLS=true RELAY_TLSCA_CERT_PATHS=../../../core/relay/credentials/fabric_ca_cert.pem NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients request-state localhost:9081 localhost:9083/network2/mychannel:simplestate:Read:Arcturus\n"))))),(0,n.kt)("li",{parentName:"ul"},"If Relays and Drivers are deployed in Docker containers:",(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},"Without TLS:",(0,n.kt)("pre",{parentName:"li"},(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients request-state localhost:9081 relay-network2:9083/network2/mychannel:simplestate:Read:Arcturus\n"))),(0,n.kt)("li",{parentName:"ul"},"With TLS:",(0,n.kt)("pre",{parentName:"li"},(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"RELAY_TLS=true RELAY_TLSCA_CERT_PATHS=../../../core/relay/credentials/docker/ca-cert.pem NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients request-state localhost:9081 relay-network2:9083/network2/mychannel:simplestate:Read:Arcturus\n"))))))),(0,n.kt)("li",{parentName:"ul"},"Query the value of the requested state (key) ",(0,n.kt)("inlineCode",{parentName:"li"},"Arcturus")," in ",(0,n.kt)("inlineCode",{parentName:"li"},"Corda_Network")," using the following:",(0,n.kt)("pre",{parentName:"li"},(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients get-state Arcturus\n")))),(0,n.kt)("table",null,(0,n.kt)("thead",{parentName:"table"},(0,n.kt)("tr",{parentName:"thead"},(0,n.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,n.kt)("tbody",{parentName:"table"},(0,n.kt)("tr",{parentName:"tbody"},(0,n.kt)("td",{parentName:"tr",align:"left"},"You can test the above data transfer scenario with ",(0,n.kt)("inlineCode",{parentName:"td"},"Corda_Network2")," instead of ",(0,n.kt)("inlineCode",{parentName:"td"},"Corda_Network")," by changing the following in the ",(0,n.kt)("inlineCode",{parentName:"td"},"request-state")," or ",(0,n.kt)("inlineCode",{parentName:"td"},"get-state")," command:",(0,n.kt)("ul",null,(0,n.kt)("li",null,"Network name environment variable:",(0,n.kt)("ul",null,(0,n.kt)("li",null,(0,n.kt)("inlineCode",{parentName:"td"},"NETWORK_NAME=Corda_Network")," to ",(0,n.kt)("inlineCode",{parentName:"td"},"NETWORK_NAME=Corda_Network2")))),(0,n.kt)("li",null,"Corda node's RPC endpoint port environment variable:",(0,n.kt)("ul",null,(0,n.kt)("li",null,(0,n.kt)("inlineCode",{parentName:"td"},"CORDA_PORT=10006")," to ",(0,n.kt)("inlineCode",{parentName:"td"},"CORDA_PORT=30006")))),(0,n.kt)("li",null,"Local relay address",(0,n.kt)("ul",null,(0,n.kt)("li",null,(0,n.kt)("inlineCode",{parentName:"td"},"localhost:9081")," to ",(0,n.kt)("inlineCode",{parentName:"td"},"localhost:9082")," (host deployment of relays and drivers)"),(0,n.kt)("li",null,(0,n.kt)("inlineCode",{parentName:"td"},"relay-corda2:9081")," to ",(0,n.kt)("inlineCode",{parentName:"td"},"relay-corda2:9082")," (Docker container deployment of relays and drivers)")))))))),(0,n.kt)("h2",{id:"fabric-to-corda"},"Fabric to Corda"),(0,n.kt)("p",null,"To test the scenario where ",(0,n.kt)("inlineCode",{parentName:"p"},"network1")," requests the value of the state (key) ",(0,n.kt)("inlineCode",{parentName:"p"},"H")," from ",(0,n.kt)("inlineCode",{parentName:"p"},"Corda_Network"),", do the following:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"(",(0,n.kt)("em",{parentName:"li"},"Make sure the following are running"),": Corda network, relay, and driver; Fabric ",(0,n.kt)("inlineCode",{parentName:"li"},"network1"),", relay, and driver)"),(0,n.kt)("li",{parentName:"ul"},"Navigate to the ",(0,n.kt)("inlineCode",{parentName:"li"},"samples/fabric/fabric-cli")," (for the Node.js version) or the ",(0,n.kt)("inlineCode",{parentName:"li"},"samples/fabric/go-cli")," (for the Golang version) folder."),(0,n.kt)("li",{parentName:"ul"},"(Make sure you have configured ",(0,n.kt)("inlineCode",{parentName:"li"},"fabric-cli")," as per earlier instructions)"),(0,n.kt)("li",{parentName:"ul"},"Edit ",(0,n.kt)("inlineCode",{parentName:"li"},"chaincode.json"),": in the ",(0,n.kt)("inlineCode",{parentName:"li"},"simplestate:Create:args")," attribute, replace the argument ",(0,n.kt)("inlineCode",{parentName:"li"},'"a"')," with ",(0,n.kt)("inlineCode",{parentName:"li"},'"H"')," (this specifies the key to which the data from the remote view is to be written into); i.e.,:",(0,n.kt)("pre",{parentName:"li"},(0,n.kt)("code",{parentName:"pre",className:"language-json"},'"args": ["a", ""]\n')),"with",(0,n.kt)("pre",{parentName:"li"},(0,n.kt)("code",{parentName:"pre",className:"language-json"},'"args": ["H", ""]\n'))),(0,n.kt)("li",{parentName:"ul"},"Run the following:",(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},"If Relays and Drivers are deployed in the host machine:",(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},"Without TLS:",(0,n.kt)("pre",{parentName:"li"},(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli interop --local-network=network1 --sign=true --requesting-org=Org1MSP localhost:9081/Corda_Network/localhost:10006#com.cordaSimpleApplication.flow.GetStateByKey:H --debug=true\n"))),(0,n.kt)("li",{parentName:"ul"},"With TLS:",(0,n.kt)("pre",{parentName:"li"},(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli interop --local-network=network1 --sign=true --requesting-org=Org1MSP --relay-tls=true --relay-tls-ca-files=../../../core/relay/credentials/fabric_ca_cert.pem localhost:9081/Corda_Network/localhost:10006#com.cordaSimpleApplication.flow.GetStateByKey:H --debug=true\n"))))),(0,n.kt)("li",{parentName:"ul"},"If Relays and Drivers are deployed in Docker containers:",(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},"Without TLS:",(0,n.kt)("pre",{parentName:"li"},(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli interop --local-network=network1 --sign=true --requesting-org=Org1MSP relay-corda:9081/Corda_Network/corda_partya_1:10003#com.cordaSimpleApplication.flow.GetStateByKey:H --debug=true\n"))),(0,n.kt)("li",{parentName:"ul"},"With TLS:",(0,n.kt)("pre",{parentName:"li"},(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli interop --local-network=network1 --sign=true --requesting-org=Org1MSP --relay-tls=true --relay-tls-ca-files=../../../core/relay/credentials/docker/ca-cert.pem relay-corda:9081/Corda_Network/corda_partya_1:10003#com.cordaSimpleApplication.flow.GetStateByKey:H --debug=true\n"))))))),(0,n.kt)("li",{parentName:"ul"},"Query the value of the requested state (key) ",(0,n.kt)("inlineCode",{parentName:"li"},"H")," in ",(0,n.kt)("inlineCode",{parentName:"li"},"network1")," using the following:",(0,n.kt)("pre",{parentName:"li"},(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli chaincode query mychannel simplestate read '[\"H\"]' --local-network=network1\n")))),(0,n.kt)("p",null,"To test the scenario where ",(0,n.kt)("inlineCode",{parentName:"p"},"network2")," requests the value of the state (key) ",(0,n.kt)("inlineCode",{parentName:"p"},"H")," from ",(0,n.kt)("inlineCode",{parentName:"p"},"Corda_Network"),", do the following:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"(",(0,n.kt)("em",{parentName:"li"},"Make sure the following are running"),": Corda network, relay, and driver; Fabric ",(0,n.kt)("inlineCode",{parentName:"li"},"network2"),", relay, and driver)"),(0,n.kt)("li",{parentName:"ul"},"Navigate to the ",(0,n.kt)("inlineCode",{parentName:"li"},"samples/fabric/fabric-cli")," (for the Node.js version) or the ",(0,n.kt)("inlineCode",{parentName:"li"},"samples/fabric/go-cli")," (for the Golang version) folder."),(0,n.kt)("li",{parentName:"ul"},"(Make sure you have configured ",(0,n.kt)("inlineCode",{parentName:"li"},"fabric-cli")," as per earlier instructions)"),(0,n.kt)("li",{parentName:"ul"},"Edit ",(0,n.kt)("inlineCode",{parentName:"li"},"chaincode.json"),": in the ",(0,n.kt)("inlineCode",{parentName:"li"},"simplestate:Create:args")," attribute, replace the argument ",(0,n.kt)("inlineCode",{parentName:"li"},'"a"')," with ",(0,n.kt)("inlineCode",{parentName:"li"},'"H"')," (this specifies the key to which the data from the remote view is to be written into); i.e.,:",(0,n.kt)("pre",{parentName:"li"},(0,n.kt)("code",{parentName:"pre",className:"language-json"},'"args": ["a", ""]\n')),"with",(0,n.kt)("pre",{parentName:"li"},(0,n.kt)("code",{parentName:"pre",className:"language-json"},'"args": ["H", ""]\n'))),(0,n.kt)("li",{parentName:"ul"},"Run the following:",(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},"If Relays and Drivers are deployed in the host machine:",(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},"Without TLS:",(0,n.kt)("pre",{parentName:"li"},(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli interop --local-network=network2 --sign=true --requesting-org=Org1MSP localhost:9081/Corda_Network/localhost:10006#com.cordaSimpleApplication.flow.GetStateByKey:H --debug=true\n"))),(0,n.kt)("li",{parentName:"ul"},"With TLS:",(0,n.kt)("pre",{parentName:"li"},(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli interop --local-network=network2 --sign=true --requesting-org=Org1MSP --relay-tls=true --relay-tls-ca-files=../../../core/relay/credentials/fabric_ca_cert.pem localhost:9081/Corda_Network/localhost:10006#com.cordaSimpleApplication.flow.GetStateByKey:H --debug=true\n"))))),(0,n.kt)("li",{parentName:"ul"},"If Relays and Drivers are deployed in Docker containers:",(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},"Without TLS:",(0,n.kt)("pre",{parentName:"li"},(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli interop --local-network=network2 --sign=true --requesting-org=Org1MSP relay-corda:9081/Corda_Network/corda_partya_1:10003#com.cordaSimpleApplication.flow.GetStateByKey:H --debug=true\n"))),(0,n.kt)("li",{parentName:"ul"},"With TLS:",(0,n.kt)("pre",{parentName:"li"},(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli interop --local-network=network2 --sign=true --requesting-org=Org1MSP --relay-tls=true --relay-tls-ca-files=../../../core/relay/credentials/docker/ca-cert.pem relay-corda:9081/Corda_Network/corda_partya_1:10003#com.cordaSimpleApplication.flow.GetStateByKey:H --debug=true\n"))))))),(0,n.kt)("li",{parentName:"ul"},"Query the value of the requested state (key) ",(0,n.kt)("inlineCode",{parentName:"li"},"H")," in ",(0,n.kt)("inlineCode",{parentName:"li"},"network2")," using the following:",(0,n.kt)("pre",{parentName:"li"},(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli chaincode query mychannel simplestate read '[\"H\"]' --local-network=network2\n")))),(0,n.kt)("table",null,(0,n.kt)("thead",{parentName:"table"},(0,n.kt)("tr",{parentName:"thead"},(0,n.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,n.kt)("tbody",{parentName:"table"},(0,n.kt)("tr",{parentName:"tbody"},(0,n.kt)("td",{parentName:"tr",align:"left"},"You can test the above data transfer scenario with ",(0,n.kt)("inlineCode",{parentName:"td"},"Corda_Network2")," instead of ",(0,n.kt)("inlineCode",{parentName:"td"},"Corda_Network")," by changing the following in the view address (last parameter in the ",(0,n.kt)("inlineCode",{parentName:"td"},"interop")," command):",(0,n.kt)("ul",null,(0,n.kt)("li",null,"Local relay address (prefix):",(0,n.kt)("ul",null,(0,n.kt)("li",null,(0,n.kt)("inlineCode",{parentName:"td"},"localhost:9081")," to ",(0,n.kt)("inlineCode",{parentName:"td"},"localhost:9082")," (host deployment of relays and drivers)"),(0,n.kt)("li",null,(0,n.kt)("inlineCode",{parentName:"td"},"relay-corda2:9081")," to ",(0,n.kt)("inlineCode",{parentName:"td"},"relay-corda2:9082")," (Docker container deployment of relays and drivers)"))),(0,n.kt)("li",null,"Network name:",(0,n.kt)("ul",null,(0,n.kt)("li",null,(0,n.kt)("inlineCode",{parentName:"td"},"Corda_Network")," to ",(0,n.kt)("inlineCode",{parentName:"td"},"Corda_Network2")))),(0,n.kt)("li",null,"Corda node's RPC endpoint:",(0,n.kt)("ul",null,(0,n.kt)("li",null,(0,n.kt)("inlineCode",{parentName:"td"},"localhost:10006")," to ",(0,n.kt)("inlineCode",{parentName:"td"},"localhost:30006")," (host deployment of relays and drivers)"),(0,n.kt)("li",null,(0,n.kt)("inlineCode",{parentName:"td"},"corda_partya_1:10003")," to ",(0,n.kt)("inlineCode",{parentName:"td"},"corda_network2_partya_1:10003")," (Docker container deployment of relays and drivers)")))))))),(0,n.kt)("h2",{id:"fabric-to-fabric"},"Fabric to Fabric"),(0,n.kt)("p",null,"To test the scenario where ",(0,n.kt)("inlineCode",{parentName:"p"},"network1")," requests the value of the state (key) ",(0,n.kt)("inlineCode",{parentName:"p"},"Arcturus")," from ",(0,n.kt)("inlineCode",{parentName:"p"},"network2"),", do the following:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"(",(0,n.kt)("em",{parentName:"li"},"Make sure the following are running"),": Fabric ",(0,n.kt)("inlineCode",{parentName:"li"},"network1"),", relay, and driver; Fabric ",(0,n.kt)("inlineCode",{parentName:"li"},"network2"),", relay, and driver)"),(0,n.kt)("li",{parentName:"ul"},"Navigate to the ",(0,n.kt)("inlineCode",{parentName:"li"},"samples/fabric/fabric-cli")," (for the Node.js version) or the ",(0,n.kt)("inlineCode",{parentName:"li"},"samples/fabric/go-cli")," (for the Golang version) folder."),(0,n.kt)("li",{parentName:"ul"},"(Make sure you have configured ",(0,n.kt)("inlineCode",{parentName:"li"},"fabric-cli")," as per earlier instructions)"),(0,n.kt)("li",{parentName:"ul"},"Edit ",(0,n.kt)("inlineCode",{parentName:"li"},"chaincode.json"),": in the ",(0,n.kt)("inlineCode",{parentName:"li"},"simplestate:Create:args")," attribute, replace the argument ",(0,n.kt)("inlineCode",{parentName:"li"},'"a"')," with ",(0,n.kt)("inlineCode",{parentName:"li"},'"Arcturus"')," (this specifies the key to which the data from the remote view is to be written into); i.e.,:",(0,n.kt)("pre",{parentName:"li"},(0,n.kt)("code",{parentName:"pre",className:"language-json"},'"args": ["a", ""]\n')),"with",(0,n.kt)("pre",{parentName:"li"},(0,n.kt)("code",{parentName:"pre",className:"language-json"},'"args": ["Arcturus", ""]\n'))),(0,n.kt)("li",{parentName:"ul"},"Run the following:",(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},"If Relays and Drivers are deployed in the host machine:",(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},"Without TLS:",(0,n.kt)("pre",{parentName:"li"},(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli interop --local-network=network1 --requesting-org=Org1MSP localhost:9083/network2/mychannel:simplestate:Read:Arcturus\n"))),(0,n.kt)("li",{parentName:"ul"},"With TLS:",(0,n.kt)("pre",{parentName:"li"},(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli interop --local-network=network1 --requesting-org=Org1MSP --relay-tls=true --relay-tls-ca-files=../../../core/relay/credentials/fabric_ca_cert.pem localhost:9083/network2/mychannel:simplestate:Read:Arcturus\n"))))),(0,n.kt)("li",{parentName:"ul"},"If Relays and Drivers are deployed in Docker containers:",(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},"Without TLS:",(0,n.kt)("pre",{parentName:"li"},(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli interop --local-network=network1 --requesting-org=Org1MSP relay-network2:9083/network2/mychannel:simplestate:Read:Arcturus\n"))),(0,n.kt)("li",{parentName:"ul"},"With TLS:",(0,n.kt)("pre",{parentName:"li"},(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli interop --local-network=network1 --requesting-org=Org1MSP --relay-tls=true --relay-tls-ca-files=../../../core/relay/credentials/docker/ca-cert.pem relay-network2:9083/network2/mychannel:simplestate:Read:Arcturus\n")))))))),(0,n.kt)("table",null,(0,n.kt)("thead",{parentName:"table"},(0,n.kt)("tr",{parentName:"thead"},(0,n.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,n.kt)("tbody",{parentName:"table"},(0,n.kt)("tr",{parentName:"tbody"},(0,n.kt)("td",{parentName:"tr",align:"left"},"If you wish to enable end-to-end confidentiality for this data sharing session, add the ",(0,n.kt)("inlineCode",{parentName:"td"},"--e2e-confidentiality=true")," switch to any of the above commands. For example: ",(0,n.kt)("inlineCode",{parentName:"td"},"./bin/fabric-cli interop --local-network=network1 --requesting-org=Org1MSP --e2e-confidentiality=true localhost:9083/network2/mychannel:simplestate:Read:Arcturus"))))),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"Query the value of the requested state (key) ",(0,n.kt)("inlineCode",{parentName:"li"},"Arcturus")," in ",(0,n.kt)("inlineCode",{parentName:"li"},"network1")," using the following:",(0,n.kt)("pre",{parentName:"li"},(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli chaincode query mychannel simplestate read '[\"Arcturus\"]' --local-network=network1\n")))),(0,n.kt)("p",null,"To test the scenario where ",(0,n.kt)("inlineCode",{parentName:"p"},"network2")," requests the value of the state (key) ",(0,n.kt)("inlineCode",{parentName:"p"},"a")," from ",(0,n.kt)("inlineCode",{parentName:"p"},"network1"),", do the following:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"(",(0,n.kt)("em",{parentName:"li"},"Make sure the following are running"),": Fabric ",(0,n.kt)("inlineCode",{parentName:"li"},"network1"),", relay, and driver; Fabric ",(0,n.kt)("inlineCode",{parentName:"li"},"network2"),", relay, and driver)"),(0,n.kt)("li",{parentName:"ul"},"Navigate to the ",(0,n.kt)("inlineCode",{parentName:"li"},"samples/fabric/fabric-cli")," (for the Node.js version) or the ",(0,n.kt)("inlineCode",{parentName:"li"},"samples/fabric/go-cli")," (for the Golang version) folder."),(0,n.kt)("li",{parentName:"ul"},"(Make sure you have configured ",(0,n.kt)("inlineCode",{parentName:"li"},"fabric-cli")," as per earlier instructions)"),(0,n.kt)("li",{parentName:"ul"},"(There is no need to edit ",(0,n.kt)("inlineCode",{parentName:"li"},"chaincode.json")," to change the key as the default argument ",(0,n.kt)("inlineCode",{parentName:"li"},'"a"')," is what we intend to use in this data sharing use scenario.)"),(0,n.kt)("li",{parentName:"ul"},"Run the following:",(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},"If Relays and Drivers are deployed in the host machine:",(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},"Without TLS:",(0,n.kt)("pre",{parentName:"li"},(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli interop --local-network=network2 --requesting-org=Org1MSP localhost:9080/network1/mychannel:simplestate:Read:a\n"))),(0,n.kt)("li",{parentName:"ul"},"With TLS:",(0,n.kt)("pre",{parentName:"li"},(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli interop --local-network=network2 --requesting-org=Org1MSP --relay-tls=true --relay-tls-ca-files=../../../core/relay/credentials/fabric_ca_cert.pem localhost:9080/network1/mychannel:simplestate:Read:a\n"))))),(0,n.kt)("li",{parentName:"ul"},"If Relays and Drivers are deployed in Docker containers:",(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},"Without TLS:",(0,n.kt)("pre",{parentName:"li"},(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli interop --local-network=network2 --requesting-org=Org1MSP relay-network1:9080/network1/mychannel:simplestate:Read:a\n"))),(0,n.kt)("li",{parentName:"ul"},"With TLS:",(0,n.kt)("pre",{parentName:"li"},(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli interop --local-network=network2 --requesting-org=Org1MSP --relay-tls=true --relay-tls-ca-files=../../../core/relay/credentials/docker/ca-cert.pem relay-network1:9080/network1/mychannel:simplestate:Read:a:173\n")))))))),(0,n.kt)("table",null,(0,n.kt)("thead",{parentName:"table"},(0,n.kt)("tr",{parentName:"thead"},(0,n.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,n.kt)("tbody",{parentName:"table"},(0,n.kt)("tr",{parentName:"tbody"},(0,n.kt)("td",{parentName:"tr",align:"left"},"If you wish to enable end-to-end confidentiality for this data sharing session, add the ",(0,n.kt)("inlineCode",{parentName:"td"},"--e2e-confidentiality=true")," switch to any of the above commands. For example: ",(0,n.kt)("inlineCode",{parentName:"td"},"./bin/fabric-cli interop --local-network=network2 --requesting-org=Org1MSP --e2e-confidentiality=true localhost:9080/network1/mychannel:simplestate:Read:a"))))),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"Query the value of the requested state (key) ",(0,n.kt)("inlineCode",{parentName:"li"},"a")," in ",(0,n.kt)("inlineCode",{parentName:"li"},"network2")," using the following:",(0,n.kt)("pre",{parentName:"li"},(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli chaincode query mychannel simplestate read '[\"a\"]' --local-network=network2\n")))))}k.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/da157423.6e722b62.js b/assets/js/da157423.6e722b62.js new file mode 100644 index 000000000..855439d6f --- /dev/null +++ b/assets/js/da157423.6e722b62.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[320],{5680:(e,a,t)=>{t.d(a,{xA:()=>g,yg:()=>m});var r=t(6540);function n(e,a,t){return a in e?Object.defineProperty(e,a,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[a]=t,e}function l(e,a){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);a&&(r=r.filter((function(a){return Object.getOwnPropertyDescriptor(e,a).enumerable}))),t.push.apply(t,r)}return t}function i(e){for(var a=1;a<arguments.length;a++){var t=null!=arguments[a]?arguments[a]:{};a%2?l(Object(t),!0).forEach((function(a){n(e,a,t[a])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):l(Object(t)).forEach((function(a){Object.defineProperty(e,a,Object.getOwnPropertyDescriptor(t,a))}))}return e}function o(e,a){if(null==e)return{};var t,r,n=function(e,a){if(null==e)return{};var t,r,n={},l=Object.keys(e);for(r=0;r<l.length;r++)t=l[r],a.indexOf(t)>=0||(n[t]=e[t]);return n}(e,a);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(r=0;r<l.length;r++)t=l[r],a.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(n[t]=e[t])}return n}var s=r.createContext({}),p=function(e){var a=r.useContext(s),t=a;return e&&(t="function"==typeof e?e(a):i(i({},a),e)),t},g=function(e){var a=p(e.components);return r.createElement(s.Provider,{value:a},e.children)},c="mdxType",y={inlineCode:"code",wrapper:function(e){var a=e.children;return r.createElement(r.Fragment,{},a)}},d=r.forwardRef((function(e,a){var t=e.components,n=e.mdxType,l=e.originalType,s=e.parentName,g=o(e,["components","mdxType","originalType","parentName"]),c=p(t),d=n,m=c["".concat(s,".").concat(d)]||c[d]||y[d]||l;return t?r.createElement(m,i(i({ref:a},g),{},{components:t})):r.createElement(m,i({ref:a},g))}));function m(e,a){var t=arguments,n=a&&a.mdxType;if("string"==typeof e||n){var l=t.length,i=new Array(l);i[0]=d;var o={};for(var s in a)hasOwnProperty.call(a,s)&&(o[s]=a[s]);o.originalType=e,o[c]="string"==typeof e?e:n,i[1]=o;for(var p=2;p<l;p++)i[p]=t[p];return r.createElement.apply(null,i)}return r.createElement.apply(null,t)}d.displayName="MDXCreateElement"},3948:(e,a,t)=>{t.r(a),t.d(a,{assets:()=>s,contentTitle:()=>i,default:()=>y,frontMatter:()=>l,metadata:()=>o,toc:()=>p});var r=t(8168),n=(t(6540),t(5680));const l={id:"data-sharing",title:"Data Sharing",pagination_prev:"external/getting-started/interop/overview",pagination_next:"external/getting-started/enabling-weaver-network/overview"},i=void 0,o={unversionedId:"external/getting-started/interop/data-sharing",id:"external/getting-started/interop/data-sharing",title:"Data Sharing",description:"\x3c!--",source:"@site/docs/external/getting-started/interop/data-sharing.md",sourceDirName:"external/getting-started/interop",slug:"/external/getting-started/interop/data-sharing",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/data-sharing",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/getting-started/interop/data-sharing.md",tags:[],version:"current",frontMatter:{id:"data-sharing",title:"Data Sharing",pagination_prev:"external/getting-started/interop/overview",pagination_next:"external/getting-started/enabling-weaver-network/overview"},sidebar:"Documentation",previous:{title:"Testing Interoperation Modes",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/overview"},next:{title:"Enabling Weaver in Existing DLT Applications",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/overview"}},s={},p=[{value:"Corda to Corda",id:"corda-to-corda",level:2},{value:"Corda to Fabric",id:"corda-to-fabric",level:2},{value:"Fabric to Corda",id:"fabric-to-corda",level:2},{value:"Fabric to Fabric",id:"fabric-to-fabric",level:2}],g={toc:p},c="wrapper";function y(e){let{components:a,...t}=e;return(0,n.yg)(c,(0,r.A)({},g,t,{components:a,mdxType:"MDXLayout"}),(0,n.yg)("p",null,"This document lists sample ways in which you can exercise the data-sharing interoperation protocol on the test network ",(0,n.yg)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/overview"},"launched earlier"),"."),(0,n.yg)("p",null,"Once the networks, relays, and drivers have been launched, and the ledgers bootstrapped, you can trigger four different interoperation flows corresponding to distinct data-sharing combinations as follows:"),(0,n.yg)("ol",null,(0,n.yg)("li",{parentName:"ol"},(0,n.yg)("strong",{parentName:"li"},"Corda to Corda"),": Either Corda network requests state and proof from another Corda network"),(0,n.yg)("li",{parentName:"ol"},(0,n.yg)("strong",{parentName:"li"},"Corda to Fabric"),": The Corda network requests state and proof from either Fabric network"),(0,n.yg)("li",{parentName:"ol"},(0,n.yg)("strong",{parentName:"li"},"Fabric to Corda"),": Either Fabric network requests state and proof from the Corda network"),(0,n.yg)("li",{parentName:"ol"},(0,n.yg)("strong",{parentName:"li"},"Fabric to Fabric"),": One Fabric network requests state and proof from another Fabric network")),(0,n.yg)("p",null,"We assume that one of the following chaincodes have been deployed in either Fabric network you are testing with:"),(0,n.yg)("ul",null,(0,n.yg)("li",{parentName:"ul"},(0,n.yg)("inlineCode",{parentName:"li"},"simplestate")),(0,n.yg)("li",{parentName:"ul"},(0,n.yg)("inlineCode",{parentName:"li"},"simplestatewithacl"))),(0,n.yg)("h2",{id:"corda-to-corda"},"Corda to Corda"),(0,n.yg)("p",null,"To test the scenario where ",(0,n.yg)("inlineCode",{parentName:"p"},"Corda_Network")," requests the value of the state (key) ",(0,n.yg)("inlineCode",{parentName:"p"},"H")," from ",(0,n.yg)("inlineCode",{parentName:"p"},"Corda_Network2")," and writes the value to a key ",(0,n.yg)("inlineCode",{parentName:"p"},"H")," in its local state, do the following:"),(0,n.yg)("ul",null,(0,n.yg)("li",{parentName:"ul"},"(",(0,n.yg)("em",{parentName:"li"},"Make sure the following are running"),": ",(0,n.yg)("inlineCode",{parentName:"li"},"Corda_Network"),", relay, and driver; ",(0,n.yg)("inlineCode",{parentName:"li"},"Corda_Network2"),", relay, and driver)"),(0,n.yg)("li",{parentName:"ul"},"Navigate to the ",(0,n.yg)("inlineCode",{parentName:"li"},"samples/corda/corda-simple-application")," folder in your clone of the Weaver repository."),(0,n.yg)("li",{parentName:"ul"},"Run the following:",(0,n.yg)("ul",{parentName:"li"},(0,n.yg)("li",{parentName:"ul"},"If Relays and Drivers are deployed in the host machine:",(0,n.yg)("ul",{parentName:"li"},(0,n.yg)("li",{parentName:"ul"},"Without TLS:",(0,n.yg)("pre",{parentName:"li"},(0,n.yg)("code",{parentName:"pre",className:"language-bash"},"NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients request-state localhost:9081 localhost:9082/Corda_Network2/localhost:30006#com.cordaSimpleApplication.flow.GetStateByKey:H\n"))),(0,n.yg)("li",{parentName:"ul"},"With TLS:",(0,n.yg)("pre",{parentName:"li"},(0,n.yg)("code",{parentName:"pre",className:"language-bash"},"RELAY_TLS=true RELAY_TLSCA_CERT_PATHS=../../../core/relay/credentials/fabric_ca_cert.pem NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients request-state localhost:9081 localhost:9082/Corda_Network2/localhost:30006#com.cordaSimpleApplication.flow.GetStateByKey:H\n"))))),(0,n.yg)("li",{parentName:"ul"},"If Relays and Drivers are deployed in Docker containers:",(0,n.yg)("ul",{parentName:"li"},(0,n.yg)("li",{parentName:"ul"},"Without TLS:",(0,n.yg)("pre",{parentName:"li"},(0,n.yg)("code",{parentName:"pre",className:"language-bash"},"NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients request-state localhost:9081 relay-corda2:9082/Corda_Network2/corda_network2_partya_1:10003#com.cordaSimpleApplication.flow.GetStateByKey:H\n"))),(0,n.yg)("li",{parentName:"ul"},"With TLS:",(0,n.yg)("pre",{parentName:"li"},(0,n.yg)("code",{parentName:"pre",className:"language-bash"},"RELAY_TLS=true RELAY_TLSCA_CERT_PATHS=../../../core/relay/credentials/docker/ca-cert.pem NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients request-state localhost:9081 relay-corda2:9082/Corda_Network2/corda_network2_partya_1:10003#com.cordaSimpleApplication.flow.GetStateByKey:H\n"))))))),(0,n.yg)("li",{parentName:"ul"},"Query the value of the requested state using key ",(0,n.yg)("inlineCode",{parentName:"li"},"H")," in ",(0,n.yg)("inlineCode",{parentName:"li"},"Corda_Network")," by running the following command:",(0,n.yg)("pre",{parentName:"li"},(0,n.yg)("code",{parentName:"pre",className:"language-bash"},"NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients get-state H\n")))),(0,n.yg)("p",null,"To test the scenario where ",(0,n.yg)("inlineCode",{parentName:"p"},"Corda_Network2")," requests the value of the state (key) ",(0,n.yg)("inlineCode",{parentName:"p"},"C")," from ",(0,n.yg)("inlineCode",{parentName:"p"},"Corda_Network")," and writes the value to a key ",(0,n.yg)("inlineCode",{parentName:"p"},"C")," in its local state, do the following:"),(0,n.yg)("ul",null,(0,n.yg)("li",{parentName:"ul"},"(",(0,n.yg)("em",{parentName:"li"},"Make sure the following are running"),": ",(0,n.yg)("inlineCode",{parentName:"li"},"Corda_Network"),", relay, and driver; ",(0,n.yg)("inlineCode",{parentName:"li"},"Corda_Network2"),", relay, and driver)"),(0,n.yg)("li",{parentName:"ul"},"Navigate to the ",(0,n.yg)("inlineCode",{parentName:"li"},"samples/corda/corda-simple-application")," folder in your clone of the Weaver repository."),(0,n.yg)("li",{parentName:"ul"},"Run the following:",(0,n.yg)("ul",{parentName:"li"},(0,n.yg)("li",{parentName:"ul"},"If Relays and Drivers are deployed in the host machine:",(0,n.yg)("ul",{parentName:"li"},(0,n.yg)("li",{parentName:"ul"},"Without TLS:",(0,n.yg)("pre",{parentName:"li"},(0,n.yg)("code",{parentName:"pre",className:"language-bash"},"NETWORK_NAME=Corda_Network2 CORDA_PORT=30006 ./clients/build/install/clients/bin/clients request-state localhost:9082 localhost:9081/Corda_Network/localhost:10006#com.cordaSimpleApplication.flow.GetStateByKey:C\n"))),(0,n.yg)("li",{parentName:"ul"},"With TLS:",(0,n.yg)("pre",{parentName:"li"},(0,n.yg)("code",{parentName:"pre",className:"language-bash"},"RELAY_TLS=true RELAY_TLSCA_CERT_PATHS=../../../core/relay/credentials/fabric_ca_cert.pem NETWORK_NAME=Corda_Network2 CORDA_PORT=30006 ./clients/build/install/clients/bin/clients request-state localhost:9082 localhost:9081/Corda_Network/localhost:10006#com.cordaSimpleApplication.flow.GetStateByKey:C\n"))))),(0,n.yg)("li",{parentName:"ul"},"If Relays and Drivers are deployed in Docker containers:",(0,n.yg)("ul",{parentName:"li"},(0,n.yg)("li",{parentName:"ul"},"Without TLS:",(0,n.yg)("pre",{parentName:"li"},(0,n.yg)("code",{parentName:"pre",className:"language-bash"},"NETWORK_NAME=Corda_Network2 CORDA_PORT=30006 ./clients/build/install/clients/bin/clients request-state localhost:9082 relay-corda:9081/Corda_Network/corda_partya_1:10003#com.cordaSimpleApplication.flow.GetStateByKey:C\n"))),(0,n.yg)("li",{parentName:"ul"},"With TLS:",(0,n.yg)("pre",{parentName:"li"},(0,n.yg)("code",{parentName:"pre",className:"language-bash"},"RELAY_TLS=true RELAY_TLSCA_CERT_PATHS=../../../core/relay/credentials/docker/ca-cert.pem NETWORK_NAME=Corda_Network2 CORDA_PORT=30006 ./clients/build/install/clients/bin/clients request-state localhost:9082 relay-corda:9081/Corda_Network/corda_partya_1:10003#com.cordaSimpleApplication.flow.GetStateByKey:C\n"))))))),(0,n.yg)("li",{parentName:"ul"},"Query the value of the requested state, using the key ",(0,n.yg)("inlineCode",{parentName:"li"},"C")," in ",(0,n.yg)("inlineCode",{parentName:"li"},"Corda_Network")," by running the following command:",(0,n.yg)("pre",{parentName:"li"},(0,n.yg)("code",{parentName:"pre",className:"language-bash"},"NETWORK_NAME=Corda_Network2 CORDA_PORT=30006 ./clients/build/install/clients/bin/clients get-state C\n")))),(0,n.yg)("h2",{id:"corda-to-fabric"},"Corda to Fabric"),(0,n.yg)("p",null,"To test the scenario where ",(0,n.yg)("inlineCode",{parentName:"p"},"Corda_Network")," requests the value of the state (key) ",(0,n.yg)("inlineCode",{parentName:"p"},"a")," from ",(0,n.yg)("inlineCode",{parentName:"p"},"network1")," and writes the value to a key ",(0,n.yg)("inlineCode",{parentName:"p"},"a")," in its local state, do the following:"),(0,n.yg)("ul",null,(0,n.yg)("li",{parentName:"ul"},"(",(0,n.yg)("em",{parentName:"li"},"Make sure the following are running"),": Corda network, relay, and driver; Fabric ",(0,n.yg)("inlineCode",{parentName:"li"},"network1"),", relay, and driver)"),(0,n.yg)("li",{parentName:"ul"},"Navigate to the ",(0,n.yg)("inlineCode",{parentName:"li"},"samples/corda/corda-simple-application")," folder in your clone of the Weaver repository."),(0,n.yg)("li",{parentName:"ul"},"Run the following:",(0,n.yg)("ul",{parentName:"li"},(0,n.yg)("li",{parentName:"ul"},"If Relays and Drivers are deployed in the host machine:",(0,n.yg)("ul",{parentName:"li"},(0,n.yg)("li",{parentName:"ul"},"Without TLS:",(0,n.yg)("pre",{parentName:"li"},(0,n.yg)("code",{parentName:"pre",className:"language-bash"},"NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients request-state localhost:9081 localhost:9080/network1/mychannel:simplestate:Read:a\n"))),(0,n.yg)("li",{parentName:"ul"},"With TLS:",(0,n.yg)("pre",{parentName:"li"},(0,n.yg)("code",{parentName:"pre",className:"language-bash"},"RELAY_TLS=true RELAY_TLSCA_CERT_PATHS=../../../core/relay/credentials/fabric_ca_cert.pem NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients request-state localhost:9081 localhost:9080/network1/mychannel:simplestate:Read:a\n"))))),(0,n.yg)("li",{parentName:"ul"},"If Relays and Drivers are deployed in Docker containers:",(0,n.yg)("ul",{parentName:"li"},(0,n.yg)("li",{parentName:"ul"},"Without TLS:",(0,n.yg)("pre",{parentName:"li"},(0,n.yg)("code",{parentName:"pre",className:"language-bash"},"NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients request-state localhost:9081 relay-network1:9080/network1/mychannel:simplestate:Read:a\n"))),(0,n.yg)("li",{parentName:"ul"},"With TLS:",(0,n.yg)("pre",{parentName:"li"},(0,n.yg)("code",{parentName:"pre",className:"language-bash"},"RELAY_TLS=true RELAY_TLSCA_CERT_PATHS=../../../core/relay/credentials/docker/ca-cert.pem NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients request-state localhost:9081 relay-network1:9080/network1/mychannel:simplestate:Read:a\n"))))))),(0,n.yg)("li",{parentName:"ul"},"Query the value of the requested state (key) ",(0,n.yg)("inlineCode",{parentName:"li"},"a")," in ",(0,n.yg)("inlineCode",{parentName:"li"},"Corda_Network")," using the following:",(0,n.yg)("pre",{parentName:"li"},(0,n.yg)("code",{parentName:"pre",className:"language-bash"},"NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients get-state a\n")))),(0,n.yg)("p",null,"To test the scenario where ",(0,n.yg)("inlineCode",{parentName:"p"},"Corda_Network")," requests the value of the state (key) ",(0,n.yg)("inlineCode",{parentName:"p"},"Arcturus")," from ",(0,n.yg)("inlineCode",{parentName:"p"},"network2")," and writes the value to a key ",(0,n.yg)("inlineCode",{parentName:"p"},"Arcturus")," in its local state, do the following:"),(0,n.yg)("ul",null,(0,n.yg)("li",{parentName:"ul"},"(",(0,n.yg)("em",{parentName:"li"},"Make sure the following are running"),": Corda network, relay, and driver; Fabric ",(0,n.yg)("inlineCode",{parentName:"li"},"network2"),", relay, and driver)"),(0,n.yg)("li",{parentName:"ul"},"Navigate to the ",(0,n.yg)("inlineCode",{parentName:"li"},"samples/corda/corda-simple-application")," folder in your clone of the Weaver repository."),(0,n.yg)("li",{parentName:"ul"},"Run the following:",(0,n.yg)("ul",{parentName:"li"},(0,n.yg)("li",{parentName:"ul"},"If Relays and Drivers are deployed in the host machine:",(0,n.yg)("ul",{parentName:"li"},(0,n.yg)("li",{parentName:"ul"},"Without TLS:",(0,n.yg)("pre",{parentName:"li"},(0,n.yg)("code",{parentName:"pre",className:"language-bash"},"NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients request-state localhost:9081 localhost:9083/network2/mychannel:simplestate:Read:Arcturus\n"))),(0,n.yg)("li",{parentName:"ul"},"With TLS:",(0,n.yg)("pre",{parentName:"li"},(0,n.yg)("code",{parentName:"pre",className:"language-bash"},"RELAY_TLS=true RELAY_TLSCA_CERT_PATHS=../../../core/relay/credentials/fabric_ca_cert.pem NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients request-state localhost:9081 localhost:9083/network2/mychannel:simplestate:Read:Arcturus\n"))))),(0,n.yg)("li",{parentName:"ul"},"If Relays and Drivers are deployed in Docker containers:",(0,n.yg)("ul",{parentName:"li"},(0,n.yg)("li",{parentName:"ul"},"Without TLS:",(0,n.yg)("pre",{parentName:"li"},(0,n.yg)("code",{parentName:"pre",className:"language-bash"},"NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients request-state localhost:9081 relay-network2:9083/network2/mychannel:simplestate:Read:Arcturus\n"))),(0,n.yg)("li",{parentName:"ul"},"With TLS:",(0,n.yg)("pre",{parentName:"li"},(0,n.yg)("code",{parentName:"pre",className:"language-bash"},"RELAY_TLS=true RELAY_TLSCA_CERT_PATHS=../../../core/relay/credentials/docker/ca-cert.pem NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients request-state localhost:9081 relay-network2:9083/network2/mychannel:simplestate:Read:Arcturus\n"))))))),(0,n.yg)("li",{parentName:"ul"},"Query the value of the requested state (key) ",(0,n.yg)("inlineCode",{parentName:"li"},"Arcturus")," in ",(0,n.yg)("inlineCode",{parentName:"li"},"Corda_Network")," using the following:",(0,n.yg)("pre",{parentName:"li"},(0,n.yg)("code",{parentName:"pre",className:"language-bash"},"NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients get-state Arcturus\n")))),(0,n.yg)("table",null,(0,n.yg)("thead",{parentName:"table"},(0,n.yg)("tr",{parentName:"thead"},(0,n.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,n.yg)("tbody",{parentName:"table"},(0,n.yg)("tr",{parentName:"tbody"},(0,n.yg)("td",{parentName:"tr",align:"left"},"You can test the above data transfer scenario with ",(0,n.yg)("inlineCode",{parentName:"td"},"Corda_Network2")," instead of ",(0,n.yg)("inlineCode",{parentName:"td"},"Corda_Network")," by changing the following in the ",(0,n.yg)("inlineCode",{parentName:"td"},"request-state")," or ",(0,n.yg)("inlineCode",{parentName:"td"},"get-state")," command:",(0,n.yg)("ul",null,(0,n.yg)("li",null,"Network name environment variable:",(0,n.yg)("ul",null,(0,n.yg)("li",null,(0,n.yg)("inlineCode",{parentName:"td"},"NETWORK_NAME=Corda_Network")," to ",(0,n.yg)("inlineCode",{parentName:"td"},"NETWORK_NAME=Corda_Network2")))),(0,n.yg)("li",null,"Corda node's RPC endpoint port environment variable:",(0,n.yg)("ul",null,(0,n.yg)("li",null,(0,n.yg)("inlineCode",{parentName:"td"},"CORDA_PORT=10006")," to ",(0,n.yg)("inlineCode",{parentName:"td"},"CORDA_PORT=30006")))),(0,n.yg)("li",null,"Local relay address",(0,n.yg)("ul",null,(0,n.yg)("li",null,(0,n.yg)("inlineCode",{parentName:"td"},"localhost:9081")," to ",(0,n.yg)("inlineCode",{parentName:"td"},"localhost:9082")," (host deployment of relays and drivers)"),(0,n.yg)("li",null,(0,n.yg)("inlineCode",{parentName:"td"},"relay-corda2:9081")," to ",(0,n.yg)("inlineCode",{parentName:"td"},"relay-corda2:9082")," (Docker container deployment of relays and drivers)")))))))),(0,n.yg)("h2",{id:"fabric-to-corda"},"Fabric to Corda"),(0,n.yg)("p",null,"To test the scenario where ",(0,n.yg)("inlineCode",{parentName:"p"},"network1")," requests the value of the state (key) ",(0,n.yg)("inlineCode",{parentName:"p"},"H")," from ",(0,n.yg)("inlineCode",{parentName:"p"},"Corda_Network")," and writes the value to a key ",(0,n.yg)("inlineCode",{parentName:"p"},"H")," in its local state, do the following:"),(0,n.yg)("ul",null,(0,n.yg)("li",{parentName:"ul"},"(",(0,n.yg)("em",{parentName:"li"},"Make sure the following are running"),": Corda network, relay, and driver; Fabric ",(0,n.yg)("inlineCode",{parentName:"li"},"network1"),", relay, and driver)"),(0,n.yg)("li",{parentName:"ul"},"Navigate to the ",(0,n.yg)("inlineCode",{parentName:"li"},"samples/fabric/fabric-cli")," (for the Node.js version) or the ",(0,n.yg)("inlineCode",{parentName:"li"},"samples/fabric/go-cli")," (for the Golang version) folder in your clone of the Weaver repository."),(0,n.yg)("li",{parentName:"ul"},"(Make sure you have configured ",(0,n.yg)("inlineCode",{parentName:"li"},"fabric-cli")," as per earlier instructions)"),(0,n.yg)("li",{parentName:"ul"},"Edit ",(0,n.yg)("inlineCode",{parentName:"li"},"chaincode.json"),": in the ",(0,n.yg)("inlineCode",{parentName:"li"},"simplestate:Create:args")," attribute, replace the argument ",(0,n.yg)("inlineCode",{parentName:"li"},'"a"')," with ",(0,n.yg)("inlineCode",{parentName:"li"},'"H"')," (this specifies the key to which the data from the remote view is to be written into); i.e.,:",(0,n.yg)("pre",{parentName:"li"},(0,n.yg)("code",{parentName:"pre",className:"language-json"},'"args": ["a", ""]\n')),"with",(0,n.yg)("pre",{parentName:"li"},(0,n.yg)("code",{parentName:"pre",className:"language-json"},'"args": ["H", ""]\n'))),(0,n.yg)("li",{parentName:"ul"},"Run the following:",(0,n.yg)("ul",{parentName:"li"},(0,n.yg)("li",{parentName:"ul"},"If Relays and Drivers are deployed in the host machine:",(0,n.yg)("ul",{parentName:"li"},(0,n.yg)("li",{parentName:"ul"},"Without TLS:",(0,n.yg)("pre",{parentName:"li"},(0,n.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli interop --local-network=network1 --sign=true --requesting-org=Org1MSP localhost:9081/Corda_Network/localhost:10006#com.cordaSimpleApplication.flow.GetStateByKey:H --debug=true\n"))),(0,n.yg)("li",{parentName:"ul"},"With TLS:",(0,n.yg)("pre",{parentName:"li"},(0,n.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli interop --local-network=network1 --sign=true --requesting-org=Org1MSP --relay-tls=true --relay-tls-ca-files=../../../core/relay/credentials/fabric_ca_cert.pem localhost:9081/Corda_Network/localhost:10006#com.cordaSimpleApplication.flow.GetStateByKey:H --debug=true\n"))))),(0,n.yg)("li",{parentName:"ul"},"If Relays and Drivers are deployed in Docker containers:",(0,n.yg)("ul",{parentName:"li"},(0,n.yg)("li",{parentName:"ul"},"Without TLS:",(0,n.yg)("pre",{parentName:"li"},(0,n.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli interop --local-network=network1 --sign=true --requesting-org=Org1MSP relay-corda:9081/Corda_Network/corda_partya_1:10003#com.cordaSimpleApplication.flow.GetStateByKey:H --debug=true\n"))),(0,n.yg)("li",{parentName:"ul"},"With TLS:",(0,n.yg)("pre",{parentName:"li"},(0,n.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli interop --local-network=network1 --sign=true --requesting-org=Org1MSP --relay-tls=true --relay-tls-ca-files=../../../core/relay/credentials/docker/ca-cert.pem relay-corda:9081/Corda_Network/corda_partya_1:10003#com.cordaSimpleApplication.flow.GetStateByKey:H --debug=true\n"))))))),(0,n.yg)("li",{parentName:"ul"},"Query the value of the requested state (key) ",(0,n.yg)("inlineCode",{parentName:"li"},"H")," in ",(0,n.yg)("inlineCode",{parentName:"li"},"network1")," using the following:",(0,n.yg)("pre",{parentName:"li"},(0,n.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli chaincode query mychannel simplestate read '[\"H\"]' --local-network=network1\n")))),(0,n.yg)("p",null,"To test the scenario where ",(0,n.yg)("inlineCode",{parentName:"p"},"network2")," requests the value of the state (key) ",(0,n.yg)("inlineCode",{parentName:"p"},"H")," from ",(0,n.yg)("inlineCode",{parentName:"p"},"Corda_Network")," and writes the value to a key ",(0,n.yg)("inlineCode",{parentName:"p"},"H")," in its local state, do the following:"),(0,n.yg)("ul",null,(0,n.yg)("li",{parentName:"ul"},"(",(0,n.yg)("em",{parentName:"li"},"Make sure the following are running"),": Corda network, relay, and driver; Fabric ",(0,n.yg)("inlineCode",{parentName:"li"},"network2"),", relay, and driver)"),(0,n.yg)("li",{parentName:"ul"},"Navigate to the ",(0,n.yg)("inlineCode",{parentName:"li"},"samples/fabric/fabric-cli")," (for the Node.js version) or the ",(0,n.yg)("inlineCode",{parentName:"li"},"samples/fabric/go-cli")," (for the Golang version) folder in your clone of the Weaver repository."),(0,n.yg)("li",{parentName:"ul"},"(Make sure you have configured ",(0,n.yg)("inlineCode",{parentName:"li"},"fabric-cli")," as per earlier instructions)"),(0,n.yg)("li",{parentName:"ul"},"Edit ",(0,n.yg)("inlineCode",{parentName:"li"},"chaincode.json"),": in the ",(0,n.yg)("inlineCode",{parentName:"li"},"simplestate:Create:args")," attribute, replace the argument ",(0,n.yg)("inlineCode",{parentName:"li"},'"a"')," with ",(0,n.yg)("inlineCode",{parentName:"li"},'"H"')," (this specifies the key to which the data from the remote view is to be written into); i.e.,:",(0,n.yg)("pre",{parentName:"li"},(0,n.yg)("code",{parentName:"pre",className:"language-json"},'"args": ["a", ""]\n')),"with",(0,n.yg)("pre",{parentName:"li"},(0,n.yg)("code",{parentName:"pre",className:"language-json"},'"args": ["H", ""]\n'))),(0,n.yg)("li",{parentName:"ul"},"Run the following:",(0,n.yg)("ul",{parentName:"li"},(0,n.yg)("li",{parentName:"ul"},"If Relays and Drivers are deployed in the host machine:",(0,n.yg)("ul",{parentName:"li"},(0,n.yg)("li",{parentName:"ul"},"Without TLS:",(0,n.yg)("pre",{parentName:"li"},(0,n.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli interop --local-network=network2 --sign=true --requesting-org=Org1MSP localhost:9081/Corda_Network/localhost:10006#com.cordaSimpleApplication.flow.GetStateByKey:H --debug=true\n"))),(0,n.yg)("li",{parentName:"ul"},"With TLS:",(0,n.yg)("pre",{parentName:"li"},(0,n.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli interop --local-network=network2 --sign=true --requesting-org=Org1MSP --relay-tls=true --relay-tls-ca-files=../../../core/relay/credentials/fabric_ca_cert.pem localhost:9081/Corda_Network/localhost:10006#com.cordaSimpleApplication.flow.GetStateByKey:H --debug=true\n"))))),(0,n.yg)("li",{parentName:"ul"},"If Relays and Drivers are deployed in Docker containers:",(0,n.yg)("ul",{parentName:"li"},(0,n.yg)("li",{parentName:"ul"},"Without TLS:",(0,n.yg)("pre",{parentName:"li"},(0,n.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli interop --local-network=network2 --sign=true --requesting-org=Org1MSP relay-corda:9081/Corda_Network/corda_partya_1:10003#com.cordaSimpleApplication.flow.GetStateByKey:H --debug=true\n"))),(0,n.yg)("li",{parentName:"ul"},"With TLS:",(0,n.yg)("pre",{parentName:"li"},(0,n.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli interop --local-network=network2 --sign=true --requesting-org=Org1MSP --relay-tls=true --relay-tls-ca-files=../../../core/relay/credentials/docker/ca-cert.pem relay-corda:9081/Corda_Network/corda_partya_1:10003#com.cordaSimpleApplication.flow.GetStateByKey:H --debug=true\n"))))))),(0,n.yg)("li",{parentName:"ul"},"Query the value of the requested state (key) ",(0,n.yg)("inlineCode",{parentName:"li"},"H")," in ",(0,n.yg)("inlineCode",{parentName:"li"},"network2")," using the following:",(0,n.yg)("pre",{parentName:"li"},(0,n.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli chaincode query mychannel simplestate read '[\"H\"]' --local-network=network2\n")))),(0,n.yg)("table",null,(0,n.yg)("thead",{parentName:"table"},(0,n.yg)("tr",{parentName:"thead"},(0,n.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,n.yg)("tbody",{parentName:"table"},(0,n.yg)("tr",{parentName:"tbody"},(0,n.yg)("td",{parentName:"tr",align:"left"},"You can test the above data transfer scenario with ",(0,n.yg)("inlineCode",{parentName:"td"},"Corda_Network2")," instead of ",(0,n.yg)("inlineCode",{parentName:"td"},"Corda_Network")," by changing the following in the view address (last parameter in the ",(0,n.yg)("inlineCode",{parentName:"td"},"interop")," command):",(0,n.yg)("ul",null,(0,n.yg)("li",null,"Local relay address (prefix):",(0,n.yg)("ul",null,(0,n.yg)("li",null,(0,n.yg)("inlineCode",{parentName:"td"},"localhost:9081")," to ",(0,n.yg)("inlineCode",{parentName:"td"},"localhost:9082")," (host deployment of relays and drivers)"),(0,n.yg)("li",null,(0,n.yg)("inlineCode",{parentName:"td"},"relay-corda2:9081")," to ",(0,n.yg)("inlineCode",{parentName:"td"},"relay-corda2:9082")," (Docker container deployment of relays and drivers)"))),(0,n.yg)("li",null,"Network name:",(0,n.yg)("ul",null,(0,n.yg)("li",null,(0,n.yg)("inlineCode",{parentName:"td"},"Corda_Network")," to ",(0,n.yg)("inlineCode",{parentName:"td"},"Corda_Network2")))),(0,n.yg)("li",null,"Corda node's RPC endpoint:",(0,n.yg)("ul",null,(0,n.yg)("li",null,(0,n.yg)("inlineCode",{parentName:"td"},"localhost:10006")," to ",(0,n.yg)("inlineCode",{parentName:"td"},"localhost:30006")," (host deployment of relays and drivers)"),(0,n.yg)("li",null,(0,n.yg)("inlineCode",{parentName:"td"},"corda_partya_1:10003")," to ",(0,n.yg)("inlineCode",{parentName:"td"},"corda_network2_partya_1:10003")," (Docker container deployment of relays and drivers)")))))))),(0,n.yg)("h2",{id:"fabric-to-fabric"},"Fabric to Fabric"),(0,n.yg)("p",null,"To test the scenario where ",(0,n.yg)("inlineCode",{parentName:"p"},"network1")," requests the value of the state (key) ",(0,n.yg)("inlineCode",{parentName:"p"},"Arcturus")," from ",(0,n.yg)("inlineCode",{parentName:"p"},"network2")," and writes the value to a key ",(0,n.yg)("inlineCode",{parentName:"p"},"Arcturus")," in its local state, do the following:"),(0,n.yg)("ul",null,(0,n.yg)("li",{parentName:"ul"},"(",(0,n.yg)("em",{parentName:"li"},"Make sure the following are running"),": Fabric ",(0,n.yg)("inlineCode",{parentName:"li"},"network1"),", relay, and driver; Fabric ",(0,n.yg)("inlineCode",{parentName:"li"},"network2"),", relay, and driver)"),(0,n.yg)("li",{parentName:"ul"},"Navigate to the ",(0,n.yg)("inlineCode",{parentName:"li"},"samples/fabric/fabric-cli")," (for the Node.js version) or the ",(0,n.yg)("inlineCode",{parentName:"li"},"samples/fabric/go-cli")," (for the Golang version) folder in your clone of the Weaver repository."),(0,n.yg)("li",{parentName:"ul"},"(Make sure you have configured ",(0,n.yg)("inlineCode",{parentName:"li"},"fabric-cli")," as per earlier instructions)"),(0,n.yg)("li",{parentName:"ul"},"Edit ",(0,n.yg)("inlineCode",{parentName:"li"},"chaincode.json"),": in the ",(0,n.yg)("inlineCode",{parentName:"li"},"simplestate:Create:args")," attribute, replace the argument ",(0,n.yg)("inlineCode",{parentName:"li"},'"a"')," with ",(0,n.yg)("inlineCode",{parentName:"li"},'"Arcturus"')," (this specifies the key to which the data from the remote view is to be written into); i.e.,:",(0,n.yg)("pre",{parentName:"li"},(0,n.yg)("code",{parentName:"pre",className:"language-json"},'"args": ["a", ""]\n')),"with",(0,n.yg)("pre",{parentName:"li"},(0,n.yg)("code",{parentName:"pre",className:"language-json"},'"args": ["Arcturus", ""]\n'))),(0,n.yg)("li",{parentName:"ul"},"Run the following:",(0,n.yg)("ul",{parentName:"li"},(0,n.yg)("li",{parentName:"ul"},"If Relays and Drivers are deployed in the host machine:",(0,n.yg)("ul",{parentName:"li"},(0,n.yg)("li",{parentName:"ul"},"Without TLS:",(0,n.yg)("pre",{parentName:"li"},(0,n.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli interop --local-network=network1 --requesting-org=Org1MSP localhost:9083/network2/mychannel:simplestate:Read:Arcturus\n"))),(0,n.yg)("li",{parentName:"ul"},"With TLS:",(0,n.yg)("pre",{parentName:"li"},(0,n.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli interop --local-network=network1 --requesting-org=Org1MSP --relay-tls=true --relay-tls-ca-files=../../../core/relay/credentials/fabric_ca_cert.pem localhost:9083/network2/mychannel:simplestate:Read:Arcturus\n"))))),(0,n.yg)("li",{parentName:"ul"},"If Relays and Drivers are deployed in Docker containers:",(0,n.yg)("ul",{parentName:"li"},(0,n.yg)("li",{parentName:"ul"},"Without TLS:",(0,n.yg)("pre",{parentName:"li"},(0,n.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli interop --local-network=network1 --requesting-org=Org1MSP relay-network2:9083/network2/mychannel:simplestate:Read:Arcturus\n"))),(0,n.yg)("li",{parentName:"ul"},"With TLS:",(0,n.yg)("pre",{parentName:"li"},(0,n.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli interop --local-network=network1 --requesting-org=Org1MSP --relay-tls=true --relay-tls-ca-files=../../../core/relay/credentials/docker/ca-cert.pem relay-network2:9083/network2/mychannel:simplestate:Read:Arcturus\n")))))))),(0,n.yg)("table",null,(0,n.yg)("thead",{parentName:"table"},(0,n.yg)("tr",{parentName:"thead"},(0,n.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,n.yg)("tbody",{parentName:"table"},(0,n.yg)("tr",{parentName:"tbody"},(0,n.yg)("td",{parentName:"tr",align:"left"},"If you wish to enable end-to-end confidentiality for this data sharing session, add the ",(0,n.yg)("inlineCode",{parentName:"td"},"--e2e-confidentiality=true")," switch to any of the above commands. For example: ",(0,n.yg)("inlineCode",{parentName:"td"},"./bin/fabric-cli interop --local-network=network1 --requesting-org=Org1MSP --e2e-confidentiality=true localhost:9083/network2/mychannel:simplestate:Read:Arcturus"))))),(0,n.yg)("ul",null,(0,n.yg)("li",{parentName:"ul"},"Query the value of the requested state (key) ",(0,n.yg)("inlineCode",{parentName:"li"},"Arcturus")," in ",(0,n.yg)("inlineCode",{parentName:"li"},"network1")," using the following:",(0,n.yg)("pre",{parentName:"li"},(0,n.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli chaincode query mychannel simplestate read '[\"Arcturus\"]' --local-network=network1\n")))),(0,n.yg)("p",null,"To test the scenario where ",(0,n.yg)("inlineCode",{parentName:"p"},"network2")," requests the value of the state (key) ",(0,n.yg)("inlineCode",{parentName:"p"},"a")," from ",(0,n.yg)("inlineCode",{parentName:"p"},"network1")," and writes the value to a key ",(0,n.yg)("inlineCode",{parentName:"p"},"a")," in its local state, do the following:"),(0,n.yg)("ul",null,(0,n.yg)("li",{parentName:"ul"},"(",(0,n.yg)("em",{parentName:"li"},"Make sure the following are running"),": Fabric ",(0,n.yg)("inlineCode",{parentName:"li"},"network1"),", relay, and driver; Fabric ",(0,n.yg)("inlineCode",{parentName:"li"},"network2"),", relay, and driver)"),(0,n.yg)("li",{parentName:"ul"},"Navigate to the ",(0,n.yg)("inlineCode",{parentName:"li"},"samples/fabric/fabric-cli")," (for the Node.js version) or the ",(0,n.yg)("inlineCode",{parentName:"li"},"samples/fabric/go-cli")," (for the Golang version) folder in your clone of the Weaver repository."),(0,n.yg)("li",{parentName:"ul"},"(Make sure you have configured ",(0,n.yg)("inlineCode",{parentName:"li"},"fabric-cli")," as per earlier instructions)"),(0,n.yg)("li",{parentName:"ul"},"(There is no need to edit ",(0,n.yg)("inlineCode",{parentName:"li"},"chaincode.json")," to change the key as the default argument ",(0,n.yg)("inlineCode",{parentName:"li"},'"a"')," is what we intend to use in this data sharing use scenario.)"),(0,n.yg)("li",{parentName:"ul"},"Run the following:",(0,n.yg)("ul",{parentName:"li"},(0,n.yg)("li",{parentName:"ul"},"If Relays and Drivers are deployed in the host machine:",(0,n.yg)("ul",{parentName:"li"},(0,n.yg)("li",{parentName:"ul"},"Without TLS:",(0,n.yg)("pre",{parentName:"li"},(0,n.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli interop --local-network=network2 --requesting-org=Org1MSP localhost:9080/network1/mychannel:simplestate:Read:a\n"))),(0,n.yg)("li",{parentName:"ul"},"With TLS:",(0,n.yg)("pre",{parentName:"li"},(0,n.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli interop --local-network=network2 --requesting-org=Org1MSP --relay-tls=true --relay-tls-ca-files=../../../core/relay/credentials/fabric_ca_cert.pem localhost:9080/network1/mychannel:simplestate:Read:a\n"))))),(0,n.yg)("li",{parentName:"ul"},"If Relays and Drivers are deployed in Docker containers:",(0,n.yg)("ul",{parentName:"li"},(0,n.yg)("li",{parentName:"ul"},"Without TLS:",(0,n.yg)("pre",{parentName:"li"},(0,n.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli interop --local-network=network2 --requesting-org=Org1MSP relay-network1:9080/network1/mychannel:simplestate:Read:a\n"))),(0,n.yg)("li",{parentName:"ul"},"With TLS:",(0,n.yg)("pre",{parentName:"li"},(0,n.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli interop --local-network=network2 --requesting-org=Org1MSP --relay-tls=true --relay-tls-ca-files=../../../core/relay/credentials/docker/ca-cert.pem relay-network1:9080/network1/mychannel:simplestate:Read:a:173\n")))))))),(0,n.yg)("table",null,(0,n.yg)("thead",{parentName:"table"},(0,n.yg)("tr",{parentName:"thead"},(0,n.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,n.yg)("tbody",{parentName:"table"},(0,n.yg)("tr",{parentName:"tbody"},(0,n.yg)("td",{parentName:"tr",align:"left"},"If you wish to enable end-to-end confidentiality for this data sharing session, add the ",(0,n.yg)("inlineCode",{parentName:"td"},"--e2e-confidentiality=true")," switch to any of the above commands. For example: ",(0,n.yg)("inlineCode",{parentName:"td"},"./bin/fabric-cli interop --local-network=network2 --requesting-org=Org1MSP --e2e-confidentiality=true localhost:9080/network1/mychannel:simplestate:Read:a"))))),(0,n.yg)("ul",null,(0,n.yg)("li",{parentName:"ul"},"Query the value of the requested state (key) ",(0,n.yg)("inlineCode",{parentName:"li"},"a")," in ",(0,n.yg)("inlineCode",{parentName:"li"},"network2")," using the following:",(0,n.yg)("pre",{parentName:"li"},(0,n.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/fabric-cli chaincode query mychannel simplestate read '[\"a\"]' --local-network=network2\n")))))}y.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/e0bf5ccd.6a6cefd8.js b/assets/js/e0bf5ccd.6a6cefd8.js new file mode 100644 index 000000000..dd28ee941 --- /dev/null +++ b/assets/js/e0bf5ccd.6a6cefd8.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[2729],{5680:(e,n,t)=>{t.d(n,{xA:()=>p,yg:()=>y});var i=t(6540);function a(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function r(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);n&&(i=i.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,i)}return t}function o(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?r(Object(t),!0).forEach((function(n){a(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):r(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function l(e,n){if(null==e)return{};var t,i,a=function(e,n){if(null==e)return{};var t,i,a={},r=Object.keys(e);for(i=0;i<r.length;i++)t=r[i],n.indexOf(t)>=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(i=0;i<r.length;i++)t=r[i],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var s=i.createContext({}),c=function(e){var n=i.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):o(o({},n),e)),t},p=function(e){var n=c(e.components);return i.createElement(s.Provider,{value:n},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var n=e.children;return i.createElement(i.Fragment,{},n)}},m=i.forwardRef((function(e,n){var t=e.components,a=e.mdxType,r=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),d=c(t),m=a,y=d["".concat(s,".").concat(m)]||d[m]||u[m]||r;return t?i.createElement(y,o(o({ref:n},p),{},{components:t})):i.createElement(y,o({ref:n},p))}));function y(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var r=t.length,o=new Array(r);o[0]=m;var l={};for(var s in n)hasOwnProperty.call(n,s)&&(l[s]=n[s]);l.originalType=e,l[d]="string"==typeof e?e:a,o[1]=l;for(var c=2;c<r;c++)o[c]=t[c];return i.createElement.apply(null,o)}return i.createElement.apply(null,t)}m.displayName="MDXCreateElement"},2024:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>s,contentTitle:()=>o,default:()=>u,frontMatter:()=>r,metadata:()=>l,toc:()=>c});var i=t(8168),a=(t(6540),t(5680));const r={id:"design-principles",title:"Design Principles"},o=void 0,l={unversionedId:"external/design-principles",id:"external/design-principles",title:"Design Principles",description:"\x3c!--",source:"@site/docs/external/design-principles.md",sourceDirName:"external",slug:"/external/design-principles",permalink:"/weaver-dlt-interoperability/docs/external/design-principles",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/design-principles.md",tags:[],version:"current",frontMatter:{id:"design-principles",title:"Design Principles"},sidebar:"Documentation",previous:{title:"Interoperability Modes",permalink:"/weaver-dlt-interoperability/docs/external/interoperability-modes"},next:{title:"Overview",permalink:"/weaver-dlt-interoperability/docs/external/user-stories/overview"}},s={},c=[{value:"How to determine need for interoperation, and its mode and mechanics?",id:"how-to-determine-need-for-interoperation-and-its-mode-and-mechanics",level:3},{value:"Principles and Ideals for Interoperability Solution Design",id:"principles-and-ideals-for-interoperability-solution-design",level:3},{value:"Favor Technical Assurances over Social Assurances",id:"favor-technical-assurances-over-social-assurances",level:4},{value:"Be Inclusive and Accommodate Heterogeneity",id:"be-inclusive-and-accommodate-heterogeneity",level:4},{value:"Allow Networks to Retain Independence and Collective Sovereignty",id:"allow-networks-to-retain-independence-and-collective-sovereignty",level:4},{value:"Minimize Network Coupling",id:"minimize-network-coupling",level:4},{value:"Do not Compromise on Privacy and Confidentiality",id:"do-not-compromise-on-privacy-and-confidentiality",level:4},{value:"Minimize Trust Footprint and Avoid Centralization",id:"minimize-trust-footprint-and-avoid-centralization",level:4},{value:"Favor dependence on proofs over trust",id:"favor-dependence-on-proofs-over-trust",level:4},{value:"Minimize Impact and Adaptation",id:"minimize-impact-and-adaptation",level:4},{value:"Maximize Operational Efficiency",id:"maximize-operational-efficiency",level:4},{value:"Design Guidelines for Network Architects and Developers",id:"design-guidelines-for-network-architects-and-developers",level:3}],p={toc:c},d="wrapper";function u(e){let{components:n,...t}=e;return(0,a.yg)(d,(0,i.A)({},p,t,{components:n,mdxType:"MDXLayout"}),(0,a.yg)("p",null,"We list principles and considerations that guide the design of a framework for interoperability between decentralized networks, along with associated reasoning. Our present solution, though a work-in-progress, attempts to adhere to these principles."),(0,a.yg)("h3",{id:"how-to-determine-need-for-interoperation-and-its-mode-and-mechanics"},"How to determine need for interoperation, and its mode and mechanics?"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},"Assess dependence decision (i,e., between networks) to determine goals and required assurances:",(0,a.yg)("ul",{parentName:"li"},(0,a.yg)("li",{parentName:"ul"},"The decision to depend on a network is a complex one, as a network is itself an affiliation of independent parties."),(0,a.yg)("li",{parentName:"ul"},"There are different approaches with varying levels of complexity and assurance."),(0,a.yg)("li",{parentName:"ul"},"Examine structural assurances provided by networks and their participants, and do a cost-benefit analysis to determine a suitable approach."))),(0,a.yg)("li",{parentName:"ul"},"The mechanics of interoperation can be derived from assumptions made in the above assessment."),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("strong",{parentName:"li"},"Our assumptions and aproach"),":",(0,a.yg)("ul",{parentName:"li"},(0,a.yg)("li",{parentName:"ul"},"Individual network participants are untrustworthy."),(0,a.yg)("li",{parentName:"ul"},"The network is trustworthy in the collective."),(0,a.yg)("li",{parentName:"ul"},"The internal consensus mechanism of a network protects it from Byzantine failures."),(0,a.yg)("li",{parentName:"ul"},"Interoperability needs will not force structural changes or forks in a network nor constrain that network's internal evolution.")))),(0,a.yg)("h3",{id:"principles-and-ideals-for-interoperability-solution-design"},"Principles and Ideals for Interoperability Solution Design"),(0,a.yg)("p",null,"Here are our guiding principles that accord with our assumptions and approach, in no particular order."),(0,a.yg)("h4",{id:"favor-technical-assurances-over-social-assurances"},"Favor Technical Assurances over Social Assurances"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},"Technical assurances are provided by protocols and security mechanisms, including distributed consensus."),(0,a.yg)("li",{parentName:"ul"},"Social assurances include governance (collectively, through a consortium, or via a hierarchy), legal rules and regulations, reputations and history of past behavior."),(0,a.yg)("li",{parentName:"ul"},"The reason to favor the former is that it can provide provable guarantees that are independent of the trustworthiness of individual participants, whereas the latter can be brittle and rely on participants' compliance.")),(0,a.yg)("h4",{id:"be-inclusive-and-accommodate-heterogeneity"},"Be Inclusive and Accommodate Heterogeneity"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},"Avoid approaches for protocol design that are specific to a particular DLT implementation or network structure."),(0,a.yg)("li",{parentName:"ul"},"Specify the communication protocol in a network-neutral language."),(0,a.yg)("li",{parentName:"ul"},"Design protocol units that can abstract out common features for information and assurances from diverse DLTs.")),(0,a.yg)("h4",{id:"allow-networks-to-retain-independence-and-collective-sovereignty"},"Allow Networks to Retain Independence and Collective Sovereignty"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},"A network is treated as an independent self-governing system with the freedom of choice to interoperate with another on a need basis."),(0,a.yg)("li",{parentName:"ul"},"Network members retain collective sovereignty over their internal processes as well as access control rules governing remote interoperation."),(0,a.yg)("li",{parentName:"ul"},"Networks have full and collective control, via their native consensus and smart contract mechanisms, over exposure of data, assets, and transactions to other networks.",(0,a.yg)("ul",{parentName:"li"},(0,a.yg)("li",{parentName:"ul"},"A network acts as a unit for framing and enforcing rules controlling access to information held on its ledger(s) by a remote network."))),(0,a.yg)("li",{parentName:"ul"},"Similarly, networks have full and collective control, via their native consensus and smart contract mechanisms, over acceptance of data or assets and verifications of transactions occurring in, other networks.")),(0,a.yg)("h4",{id:"minimize-network-coupling"},"Minimize Network Coupling"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},"Networks/consortia must retain independence for governance and configuration",(0,a.yg)("ul",{parentName:"li"},(0,a.yg)("li",{parentName:"ul"},"Therefore, interoperation must require loose coupling rather than a merging or overlapping of two networks"))),(0,a.yg)("li",{parentName:"ul"},"Loose coupling between dependent networks allows changes to counterparty networks' implementations with minimal or no impact to cross-network dependencies."),(0,a.yg)("li",{parentName:"ul"},"Domain decoupling:",(0,a.yg)("ul",{parentName:"li"},(0,a.yg)("li",{parentName:"ul"},"Define standards for contract interfaces"),(0,a.yg)("li",{parentName:"ul"},"Define standards for representing data types and assets types (e.g. ",(0,a.yg)("a",{parentName:"li",href:"https://www.gs1.org/traceability"},"https://www.gs1.org/traceability"),")"),(0,a.yg)("li",{parentName:"ul"},"Define standards for identity portability"))),(0,a.yg)("li",{parentName:"ul"},"Communication decoupling:",(0,a.yg)("ul",{parentName:"li"},(0,a.yg)("li",{parentName:"ul"},"Define standards for network interface/API"),(0,a.yg)("li",{parentName:"ul"},"Define standards for protocol behavior"),(0,a.yg)("li",{parentName:"ul"},"Define standards for messaging formats")))),(0,a.yg)("h4",{id:"do-not-compromise-on-privacy-and-confidentiality"},"Do not Compromise on Privacy and Confidentiality"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},"By design, a permissioned network should retain its privacy, and interoperation mechanisms should not leak information outside the bounds of what access control rules allow."),(0,a.yg)("li",{parentName:"ul"},"Cross-network communications should be kept private and confidential and revealed only to interested parties, applying the principle of least privilege.")),(0,a.yg)("h4",{id:"minimize-trust-footprint-and-avoid-centralization"},"Minimize Trust Footprint and Avoid Centralization"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},"Design for decentralization across networks as within networks:",(0,a.yg)("ul",{parentName:"li"},(0,a.yg)("li",{parentName:"ul"},"Avoid introducing centralized services that are easy to compromise"),(0,a.yg)("li",{parentName:"ul"},"Assume that failure scenarios that apply to networks also hold for any service coordinating interoperability."))),(0,a.yg)("li",{parentName:"ul"},"Reduce trust to only what is essential (i.e. identity providers in the network)."),(0,a.yg)("li",{parentName:"ul"},"No trusted third-party intermediary or infrastructure (e.g., Polka Dot, Cosmos) should be relied upon for the purpose of cross network data verification or settlement."),(0,a.yg)("li",{parentName:"ul"},"Reduce trust and centralization to only essential functions that cannot be completely decentralized:",(0,a.yg)("ul",{parentName:"li"},(0,a.yg)("li",{parentName:"ul"},"Communicate messages across networks using some networking infrastructure:",(0,a.yg)("ul",{parentName:"li"},(0,a.yg)("li",{parentName:"ul"},"This communication infrastructure is not trusted to maintain confidentiality or integrity of messages, and it may mount denial of service attacks."))),(0,a.yg)("li",{parentName:"ul"},"Identity provision and verification:",(0,a.yg)("ul",{parentName:"li"},(0,a.yg)("li",{parentName:"ul"},"This is necessary for permissioned networks that have private memberships governed by a ",(0,a.yg)("em",{parentName:"li"},"committee")," that may be centralized or distributed.")))))),(0,a.yg)("h4",{id:"favor-dependence-on-proofs-over-trust"},"Favor dependence on proofs over trust"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("em",{parentName:"li"},'This is also implied by the "No Trusted Intermediaries" principle'),"."),(0,a.yg)("li",{parentName:"ul"},"Information transferred across networks must carry verifiable proofs."),(0,a.yg)("li",{parentName:"ul"},"The receiving network must be able to specify a ",(0,a.yg)("em",{parentName:"li"},"verification policy")," for proofs that it can independently and collectively (i.e., through consensus) verify.")),(0,a.yg)("h4",{id:"minimize-impact-and-adaptation"},"Minimize Impact and Adaptation"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},"Enabling interoperation must not require changes to existing network protocols."),(0,a.yg)("li",{parentName:"ul"},"Enabling interoperation must not impact existing network operation in any way nor require any blockchain forks."),(0,a.yg)("li",{parentName:"ul"},"Adaptation in existing smart contracts and applications must be avoided unless absolutely necessary, and follow modular principles.")),(0,a.yg)("h4",{id:"maximize-operational-efficiency"},"Maximize Operational Efficiency"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},"Minimize payloads in cross-network protocol units."),(0,a.yg)("li",{parentName:"ul"},"Strive for event-driven asynchronous messaging architectures (",(0,a.yg)("em",{parentName:"li"},'this is also implied by the "Minimal Coupling" principle'),").")),(0,a.yg)("h3",{id:"design-guidelines-for-network-architects-and-developers"},"Design Guidelines for Network Architects and Developers"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},"Architects and application developers (both in the smart contract and services layers) must design with interoperability in mind:",(0,a.yg)("ul",{parentName:"li"},(0,a.yg)("li",{parentName:"ul"},"This has the advantage of minimizing or eliminating any code adaptations required for interoperability during a network's life cycle."))),(0,a.yg)("li",{parentName:"ul"},"Apply standards when defining assets, data and logic within network apps to maximize external consumption:",(0,a.yg)("ul",{parentName:"li"},(0,a.yg)("li",{parentName:"ul"},"Networks with well-defined standards-based interfaces simplifies interoperability:",(0,a.yg)("ul",{parentName:"li"},(0,a.yg)("li",{parentName:"ul"},"Interfaces include: contracts, data/assets, identity, APIs, protocol, messaging."))))),(0,a.yg)("li",{parentName:"ul"},"Enables network implementation to evolve while eliminating or minimising external impact:",(0,a.yg)("ul",{parentName:"li"},(0,a.yg)("li",{parentName:"ul"},"Implement in a modular way: many patterns and principles exist in the field of web services."),(0,a.yg)("li",{parentName:"ul"},"Decouple interoperability-related application modules as much as possible (",(0,a.yg)("em",{parentName:"li"},"this guideline applies to blockchain-related modules within enterprise apps too"),").",(0,a.yg)("ul",{parentName:"li"},(0,a.yg)("li",{parentName:"ul"},"This will make maintenance easier and also allow administrators to minimize the amount of code that needs to be deployed in higher-security enterprise zones.")))))))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/e0bf5ccd.8049887a.js b/assets/js/e0bf5ccd.8049887a.js deleted file mode 100644 index d1cf245d7..000000000 --- a/assets/js/e0bf5ccd.8049887a.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[881],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>k});var i=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,i)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?r(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):r(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,i,a=function(e,t){if(null==e)return{};var n,i,a={},r=Object.keys(e);for(i=0;i<r.length;i++)n=r[i],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(i=0;i<r.length;i++)n=r[i],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=i.createContext({}),c=function(e){var t=i.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=c(e.components);return i.createElement(s.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},m=i.forwardRef((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),d=c(n),m=a,k=d["".concat(s,".").concat(m)]||d[m]||u[m]||r;return n?i.createElement(k,o(o({ref:t},p),{},{components:n})):i.createElement(k,o({ref:t},p))}));function k(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,o=new Array(r);o[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[d]="string"==typeof e?e:a,o[1]=l;for(var c=2;c<r;c++)o[c]=n[c];return i.createElement.apply(null,o)}return i.createElement.apply(null,n)}m.displayName="MDXCreateElement"},7820:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>u,frontMatter:()=>r,metadata:()=>l,toc:()=>c});var i=n(7462),a=(n(7294),n(3905));const r={id:"design-principles",title:"Design Principles"},o=void 0,l={unversionedId:"external/design-principles",id:"external/design-principles",title:"Design Principles",description:"\x3c!--",source:"@site/docs/external/design-principles.md",sourceDirName:"external",slug:"/external/design-principles",permalink:"/weaver-dlt-interoperability/docs/external/design-principles",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/design-principles.md",tags:[],version:"current",frontMatter:{id:"design-principles",title:"Design Principles"},sidebar:"Documentation",previous:{title:"Interoperability Modes",permalink:"/weaver-dlt-interoperability/docs/external/interoperability-modes"},next:{title:"Overview",permalink:"/weaver-dlt-interoperability/docs/external/user-stories/overview"}},s={},c=[{value:"How to determine need for interoperation, and its mode and mechanics?",id:"how-to-determine-need-for-interoperation-and-its-mode-and-mechanics",level:3},{value:"Principles and Ideals for Interoperability Solution Design",id:"principles-and-ideals-for-interoperability-solution-design",level:3},{value:"Favor Technical Assurances over Social Assurances",id:"favor-technical-assurances-over-social-assurances",level:4},{value:"Be Inclusive and Accommodate Heterogeneity",id:"be-inclusive-and-accommodate-heterogeneity",level:4},{value:"Allow Networks to Retain Independence and Collective Sovereignty",id:"allow-networks-to-retain-independence-and-collective-sovereignty",level:4},{value:"Minimize Network Coupling",id:"minimize-network-coupling",level:4},{value:"Do not Compromise on Privacy and Confidentiality",id:"do-not-compromise-on-privacy-and-confidentiality",level:4},{value:"Minimize Trust Footprint and Avoid Centralization",id:"minimize-trust-footprint-and-avoid-centralization",level:4},{value:"Favor dependence on proofs over trust",id:"favor-dependence-on-proofs-over-trust",level:4},{value:"Minimize Impact and Adaptation",id:"minimize-impact-and-adaptation",level:4},{value:"Maximize Operational Efficiency",id:"maximize-operational-efficiency",level:4},{value:"Design Guidelines for Network Architects and Developers",id:"design-guidelines-for-network-architects-and-developers",level:3}],p={toc:c},d="wrapper";function u(e){let{components:t,...n}=e;return(0,a.kt)(d,(0,i.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"We list principles and considerations that guide the design of a framework for interoperability between decentralized networks, along with associated reasoning. Our present solution, though a work-in-progress, attempts to adhere to these principles."),(0,a.kt)("h3",{id:"how-to-determine-need-for-interoperation-and-its-mode-and-mechanics"},"How to determine need for interoperation, and its mode and mechanics?"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Assess dependence decision (i,e., between networks) to determine goals and required assurances:",(0,a.kt)("ul",{parentName:"li"},(0,a.kt)("li",{parentName:"ul"},"The decision to depend on a network is a complex one, as a network is itself an affiliation of independent parties."),(0,a.kt)("li",{parentName:"ul"},"There are different approaches with varying levels of complexity and assurance."),(0,a.kt)("li",{parentName:"ul"},"Examine structural assurances provided by networks and their participants, and do a cost-benefit analysis to determine a suitable approach."))),(0,a.kt)("li",{parentName:"ul"},"The mechanics of interoperation can be derived from assumptions made in the above assessment."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},"Our assumptions and aproach"),":",(0,a.kt)("ul",{parentName:"li"},(0,a.kt)("li",{parentName:"ul"},"Individual network participants are untrustworthy."),(0,a.kt)("li",{parentName:"ul"},"The network is trustworthy in the collective."),(0,a.kt)("li",{parentName:"ul"},"The internal consensus mechanism of a network protects it from Byzantine failures."),(0,a.kt)("li",{parentName:"ul"},"Interoperability needs will not force structural changes or forks in a network nor constrain that network's internal evolution.")))),(0,a.kt)("h3",{id:"principles-and-ideals-for-interoperability-solution-design"},"Principles and Ideals for Interoperability Solution Design"),(0,a.kt)("p",null,"Here are our guiding principles that accord with our assumptions and approach, in no particular order."),(0,a.kt)("h4",{id:"favor-technical-assurances-over-social-assurances"},"Favor Technical Assurances over Social Assurances"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Technical assurances are provided by protocols and security mechanisms, including distributed consensus."),(0,a.kt)("li",{parentName:"ul"},"Social assurances include governance (collectively, through a consortium, or via a hierarchy), legal rules and regulations, reputations and history of past behavior."),(0,a.kt)("li",{parentName:"ul"},"The reason to favor the former is that it can provide provable guarantees that are independent of the trustworthiness of individual participants, whereas the latter can be brittle and rely on participants' compliance.")),(0,a.kt)("h4",{id:"be-inclusive-and-accommodate-heterogeneity"},"Be Inclusive and Accommodate Heterogeneity"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Avoid approaches for protocol design that are specific to a particular DLT implementation or network structure."),(0,a.kt)("li",{parentName:"ul"},"Specify the communication protocol in a network-neutral language."),(0,a.kt)("li",{parentName:"ul"},"Design protocol units that can abstract out common features for information and assurances from diverse DLTs.")),(0,a.kt)("h4",{id:"allow-networks-to-retain-independence-and-collective-sovereignty"},"Allow Networks to Retain Independence and Collective Sovereignty"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"A network is treated as an independent self-governing system with the freedom of choice to interoperate with another on a need basis."),(0,a.kt)("li",{parentName:"ul"},"Network members retain collective sovereignty over their internal processes as well as access control rules governing remote interoperation."),(0,a.kt)("li",{parentName:"ul"},"Networks have full and collective control, via their native consensus and smart contract mechanisms, over exposure of data, assets, and transactions to other networks.",(0,a.kt)("ul",{parentName:"li"},(0,a.kt)("li",{parentName:"ul"},"A network acts as a unit for framing and enforcing rules controlling access to information held on its ledger(s) by a remote network."))),(0,a.kt)("li",{parentName:"ul"},"Similarly, networks have full and collective control, via their native consensus and smart contract mechanisms, over acceptance of data or assets and verifications of transactions occurring in, other networks.")),(0,a.kt)("h4",{id:"minimize-network-coupling"},"Minimize Network Coupling"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Networks/consortia must retain independence for governance and configuration",(0,a.kt)("ul",{parentName:"li"},(0,a.kt)("li",{parentName:"ul"},"Therefore, interoperation must require loose coupling rather than a merging or overlapping of two networks"))),(0,a.kt)("li",{parentName:"ul"},"Loose coupling between dependent networks allows changes to counterparty networks' implementations with minimal or no impact to cross-network dependencies."),(0,a.kt)("li",{parentName:"ul"},"Domain decoupling:",(0,a.kt)("ul",{parentName:"li"},(0,a.kt)("li",{parentName:"ul"},"Define standards for contract interfaces"),(0,a.kt)("li",{parentName:"ul"},"Define standards for representing data types and assets types (e.g. ",(0,a.kt)("a",{parentName:"li",href:"https://www.gs1.org/traceability"},"https://www.gs1.org/traceability"),")"),(0,a.kt)("li",{parentName:"ul"},"Define standards for identity portability"))),(0,a.kt)("li",{parentName:"ul"},"Communication decoupling:",(0,a.kt)("ul",{parentName:"li"},(0,a.kt)("li",{parentName:"ul"},"Define standards for network interface/API"),(0,a.kt)("li",{parentName:"ul"},"Define standards for protocol behavior"),(0,a.kt)("li",{parentName:"ul"},"Define standards for messaging formats")))),(0,a.kt)("h4",{id:"do-not-compromise-on-privacy-and-confidentiality"},"Do not Compromise on Privacy and Confidentiality"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"By design, a permissioned network should retain its privacy, and interoperation mechanisms should not leak information outside the bounds of what access control rules allow."),(0,a.kt)("li",{parentName:"ul"},"Cross-network communications should be kept private and confidential and revealed only to interested parties, applying the principle of least privilege.")),(0,a.kt)("h4",{id:"minimize-trust-footprint-and-avoid-centralization"},"Minimize Trust Footprint and Avoid Centralization"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Design for decentralization across networks as within networks:",(0,a.kt)("ul",{parentName:"li"},(0,a.kt)("li",{parentName:"ul"},"Avoid introducing centralized services that are easy to compromise"),(0,a.kt)("li",{parentName:"ul"},"Assume that failure scenarios that apply to networks also hold for any service coordinating interoperability."))),(0,a.kt)("li",{parentName:"ul"},"Reduce trust to only what is essential (i.e. identity providers in the network)."),(0,a.kt)("li",{parentName:"ul"},"No trusted third-party intermediary or infrastructure (e.g., Polka Dot, Cosmos) should be relied upon for the purpose of cross network data verification or settlement."),(0,a.kt)("li",{parentName:"ul"},"Reduce trust and centralization to only essential functions that cannot be completely decentralized:",(0,a.kt)("ul",{parentName:"li"},(0,a.kt)("li",{parentName:"ul"},"Communicate messages across networks using some networking infrastructure:",(0,a.kt)("ul",{parentName:"li"},(0,a.kt)("li",{parentName:"ul"},"This communication infrastructure is not trusted to maintain confidentiality or integrity of messages, and it may mount denial of service attacks."))),(0,a.kt)("li",{parentName:"ul"},"Identity provision and verification:",(0,a.kt)("ul",{parentName:"li"},(0,a.kt)("li",{parentName:"ul"},"This is necessary for permissioned networks that have private memberships governed by a ",(0,a.kt)("em",{parentName:"li"},"committee")," that may be centralized or distributed.")))))),(0,a.kt)("h4",{id:"favor-dependence-on-proofs-over-trust"},"Favor dependence on proofs over trust"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("em",{parentName:"li"},'This is also implied by the "No Trusted Intermediaries" principle'),"."),(0,a.kt)("li",{parentName:"ul"},"Information transferred across networks must carry verifiable proofs."),(0,a.kt)("li",{parentName:"ul"},"The receiving network must be able to specify a ",(0,a.kt)("em",{parentName:"li"},"verification policy")," for proofs that it can independently and collectively (i.e., through consensus) verify.")),(0,a.kt)("h4",{id:"minimize-impact-and-adaptation"},"Minimize Impact and Adaptation"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Enabling interoperation must not require changes to existing network protocols."),(0,a.kt)("li",{parentName:"ul"},"Enabling interoperation must not impact existing network operation in any way nor require any blockchain forks."),(0,a.kt)("li",{parentName:"ul"},"Adaptation in existing smart contracts and applications must be avoided unless absolutely necessary, and follow modular principles.")),(0,a.kt)("h4",{id:"maximize-operational-efficiency"},"Maximize Operational Efficiency"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Minimize payloads in cross-network protocol units."),(0,a.kt)("li",{parentName:"ul"},"Strive for event-driven asynchronous messaging architectures (",(0,a.kt)("em",{parentName:"li"},'this is also implied by the "Minimal Coupling" principle'),").")),(0,a.kt)("h3",{id:"design-guidelines-for-network-architects-and-developers"},"Design Guidelines for Network Architects and Developers"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Architects and application developers (both in the smart contract and services layers) must design with interoperability in mind:",(0,a.kt)("ul",{parentName:"li"},(0,a.kt)("li",{parentName:"ul"},"This has the advantage of minimizing or eliminating any code adaptations required for interoperability during a network's life cycle."))),(0,a.kt)("li",{parentName:"ul"},"Apply standards when defining assets, data and logic within network apps to maximize external consumption:",(0,a.kt)("ul",{parentName:"li"},(0,a.kt)("li",{parentName:"ul"},"Networks with well-defined standards-based interfaces simplifies interoperability:",(0,a.kt)("ul",{parentName:"li"},(0,a.kt)("li",{parentName:"ul"},"Interfaces include: contracts, data/assets, identity, APIs, protocol, messaging."))))),(0,a.kt)("li",{parentName:"ul"},"Enables network implementation to evolve while eliminating or minimising external impact:",(0,a.kt)("ul",{parentName:"li"},(0,a.kt)("li",{parentName:"ul"},"Implement in a modular way: many patterns and principles exist in the field of web services."),(0,a.kt)("li",{parentName:"ul"},"Decouple interoperability-related application modules as much as possible (",(0,a.kt)("em",{parentName:"li"},"this guideline applies to blockchain-related modules within enterprise apps too"),").",(0,a.kt)("ul",{parentName:"li"},(0,a.kt)("li",{parentName:"ul"},"This will make maintenance easier and also allow administrators to minimize the amount of code that needs to be deployed in higher-security enterprise zones.")))))))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/e67be6b3.d1eae093.js b/assets/js/e67be6b3.d1eae093.js new file mode 100644 index 000000000..d79f665a9 --- /dev/null +++ b/assets/js/e67be6b3.d1eae093.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[5117],{5680:(e,r,t)=>{t.d(r,{xA:()=>p,yg:()=>m});var n=t(6540);function a(e,r,t){return r in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function i(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);r&&(n=n.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),t.push.apply(t,n)}return t}function o(e){for(var r=1;r<arguments.length;r++){var t=null!=arguments[r]?arguments[r]:{};r%2?i(Object(t),!0).forEach((function(r){a(e,r,t[r])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):i(Object(t)).forEach((function(r){Object.defineProperty(e,r,Object.getOwnPropertyDescriptor(t,r))}))}return e}function l(e,r){if(null==e)return{};var t,n,a=function(e,r){if(null==e)return{};var t,n,a={},i=Object.keys(e);for(n=0;n<i.length;n++)t=i[n],r.indexOf(t)>=0||(a[t]=e[t]);return a}(e,r);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)t=i[n],r.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var s=n.createContext({}),c=function(e){var r=n.useContext(s),t=r;return e&&(t="function"==typeof e?e(r):o(o({},r),e)),t},p=function(e){var r=c(e.components);return n.createElement(s.Provider,{value:r},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var r=e.children;return n.createElement(n.Fragment,{},r)}},y=n.forwardRef((function(e,r){var t=e.components,a=e.mdxType,i=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),d=c(t),y=a,m=d["".concat(s,".").concat(y)]||d[y]||u[y]||i;return t?n.createElement(m,o(o({ref:r},p),{},{components:t})):n.createElement(m,o({ref:r},p))}));function m(e,r){var t=arguments,a=r&&r.mdxType;if("string"==typeof e||a){var i=t.length,o=new Array(i);o[0]=y;var l={};for(var s in r)hasOwnProperty.call(r,s)&&(l[s]=r[s]);l.originalType=e,l[d]="string"==typeof e?e:a,o[1]=l;for(var c=2;c<i;c++)o[c]=t[c];return n.createElement.apply(null,o)}return n.createElement.apply(null,t)}y.displayName="MDXCreateElement"},810:(e,r,t)=>{t.r(r),t.d(r,{assets:()=>s,contentTitle:()=>o,default:()=>u,frontMatter:()=>i,metadata:()=>l,toc:()=>c});var n=t(8168),a=(t(6540),t(5680));const i={id:"relay",title:"Relay"},o=void 0,l={unversionedId:"external/architecture-and-design/relay",id:"external/architecture-and-design/relay",title:"Relay",description:"\x3c!--",source:"@site/docs/external/architecture-and-design/relay.md",sourceDirName:"external/architecture-and-design",slug:"/external/architecture-and-design/relay",permalink:"/weaver-dlt-interoperability/docs/external/architecture-and-design/relay",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/architecture-and-design/relay.md",tags:[],version:"current",frontMatter:{id:"relay",title:"Relay"},sidebar:"Documentation",previous:{title:"Overview",permalink:"/weaver-dlt-interoperability/docs/external/architecture-and-design/overview"},next:{title:"Drivers",permalink:"/weaver-dlt-interoperability/docs/external/architecture-and-design/drivers"}},s={},c=[],p={toc:c},d="wrapper";function u(e){let{components:r,...i}=e;return(0,a.yg)(d,(0,n.A)({},p,i,{components:r,mdxType:"MDXLayout"}),(0,a.yg)("p",null,(0,a.yg)("img",{src:t(3228).A,width:"1418",height:"510"})),(0,a.yg)("p",null,"As mentioned in the overview, relays facilitate communication of protocols between networks. To do this, they are composed of three main pieces:"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"Relay service")," - A gRPC server that listens for and handles incoming requests from other relays. For example, a remote network requesting state."),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"App service")," - A gRPC server that listens for and handles requests from applications that are requesting an asset from a remote network."),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"Driver")," - The driver is responsible for all communication between the relay and its network. The driver is described in more detail in ",(0,a.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/architecture-and-design/drivers"},"drivers"),".")),(0,a.yg)("p",null,"The diagram below shows an example communication between two networks, A and B, where network A is requesting state from network B."),(0,a.yg)("p",null,(0,a.yg)("img",{src:t(7073).A,width:"1643",height:"487"})),(0,a.yg)("ol",null,(0,a.yg)("li",{parentName:"ol"},"An application sends a request to their networks relay over gRPC"),(0,a.yg)("li",{parentName:"ol"},"The local relay inspects the query within the request and uses the relevant information to forward the request to the correct remote relay"),(0,a.yg)("li",{parentName:"ol"},"The remote relay's driver interprets the query and invokes the smart contract for the query"),(0,a.yg)("li",{parentName:"ol"},"Once network B has returned a response to its relay, the relay forwards the response back to relay A"),(0,a.yg)("li",{parentName:"ol"},"The application gets the response from the relay, this can either be via a push or pull mechanism"),(0,a.yg)("li",{parentName:"ol"},"The application invokes a domain specific smart contract to process the response from network B")))}u.isMDXComponent=!0},3228:(e,r,t)=>{t.d(r,{A:()=>n});const n=t.p+"assets/images/relay_architecture-26238a46409ead54fb26da49e2df22c7.png"},7073:(e,r,t)=>{t.d(r,{A:()=>n});const n=t.p+"assets/images/relay_flow-a6320d0cf553ee5b95a94cab63f44883.png"}}]); \ No newline at end of file diff --git a/assets/js/e67be6b3.dd0dd4dd.js b/assets/js/e67be6b3.dd0dd4dd.js deleted file mode 100644 index 359eb7c2d..000000000 --- a/assets/js/e67be6b3.dd0dd4dd.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[54],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>h});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function o(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?i(Object(r),!0).forEach((function(t){a(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):i(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function l(e,t){if(null==e)return{};var r,n,a=function(e,t){if(null==e)return{};var r,n,a={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var s=n.createContext({}),c=function(e){var t=n.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},p=function(e){var t=c(e.components);return n.createElement(s.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,i=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),d=c(r),m=a,h=d["".concat(s,".").concat(m)]||d[m]||u[m]||i;return r?n.createElement(h,o(o({ref:t},p),{},{components:r})):n.createElement(h,o({ref:t},p))}));function h(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=r.length,o=new Array(i);o[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[d]="string"==typeof e?e:a,o[1]=l;for(var c=2;c<i;c++)o[c]=r[c];return n.createElement.apply(null,o)}return n.createElement.apply(null,r)}m.displayName="MDXCreateElement"},8552:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>u,frontMatter:()=>i,metadata:()=>l,toc:()=>c});var n=r(7462),a=(r(7294),r(3905));const i={id:"relay",title:"Relay"},o=void 0,l={unversionedId:"external/architecture-and-design/relay",id:"external/architecture-and-design/relay",title:"Relay",description:"\x3c!--",source:"@site/docs/external/architecture-and-design/relay.md",sourceDirName:"external/architecture-and-design",slug:"/external/architecture-and-design/relay",permalink:"/weaver-dlt-interoperability/docs/external/architecture-and-design/relay",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/architecture-and-design/relay.md",tags:[],version:"current",frontMatter:{id:"relay",title:"Relay"},sidebar:"Documentation",previous:{title:"Overview",permalink:"/weaver-dlt-interoperability/docs/external/architecture-and-design/overview"},next:{title:"Drivers",permalink:"/weaver-dlt-interoperability/docs/external/architecture-and-design/drivers"}},s={},c=[],p={toc:c},d="wrapper";function u(e){let{components:t,...i}=e;return(0,a.kt)(d,(0,n.Z)({},p,i,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,(0,a.kt)("img",{src:r(125).Z,width:"1418",height:"510"})),(0,a.kt)("p",null,"As mentioned in the overview, relays facilitate communication of protocols between networks. To do this, they are composed of three main pieces:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"Relay service")," - A gRPC server that listens for and handles incoming requests from other relays. For example, a remote network requesting state."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"App service")," - A gRPC server that listens for and handles requests from applications that are requesting an asset from a remote network."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"Driver")," - The driver is responsible for all communication between the relay and its network. The driver is described in more detail in ",(0,a.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/architecture-and-design/drivers"},"drivers"),".")),(0,a.kt)("p",null,"The diagram below shows an example communication between two networks, A and B, where network A is requesting state from network B."),(0,a.kt)("p",null,(0,a.kt)("img",{src:r(161).Z,width:"1643",height:"487"})),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"An application sends a request to their networks relay over gRPC"),(0,a.kt)("li",{parentName:"ol"},"The local relay inspects the query within the request and uses the relevant information to forward the request to the correct remote relay"),(0,a.kt)("li",{parentName:"ol"},"The remote relay's driver interprets the query and invokes the smart contract for the query"),(0,a.kt)("li",{parentName:"ol"},"Once network B has returned a response to its relay, the relay forwards the response back to relay A"),(0,a.kt)("li",{parentName:"ol"},"The application gets the response from the relay, this can either be via a push or pull mechanism"),(0,a.kt)("li",{parentName:"ol"},"The application invokes a domain specific smart contract to process the response from network B")))}u.isMDXComponent=!0},125:(e,t,r)=>{r.d(t,{Z:()=>n});const n=r.p+"assets/images/relay_architecture-26238a46409ead54fb26da49e2df22c7.png"},161:(e,t,r)=>{r.d(t,{Z:()=>n});const n=r.p+"assets/images/relay_flow-a6320d0cf553ee5b95a94cab63f44883.png"}}]); \ No newline at end of file diff --git a/assets/js/ec2d6a08.3be2a974.js b/assets/js/ec2d6a08.a3f9a2ee.js similarity index 63% rename from assets/js/ec2d6a08.3be2a974.js rename to assets/js/ec2d6a08.a3f9a2ee.js index bdda2b8f0..dfa6accf2 100644 --- a/assets/js/ec2d6a08.3be2a974.js +++ b/assets/js/ec2d6a08.a3f9a2ee.js @@ -1 +1 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[6896],{3905:(e,t,r)=>{r.d(t,{Zo:()=>c,kt:()=>h});var a=r(7294);function n(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,a)}return r}function o(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?i(Object(r),!0).forEach((function(t){n(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):i(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function l(e,t){if(null==e)return{};var r,a,n=function(e,t){if(null==e)return{};var r,a,n={},i=Object.keys(e);for(a=0;a<i.length;a++)r=i[a],t.indexOf(r)>=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a<i.length;a++)r=i[a],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var s=a.createContext({}),p=function(e){var t=a.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},c=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var r=e.components,n=e.mdxType,i=e.originalType,s=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),d=p(r),m=n,h=d["".concat(s,".").concat(m)]||d[m]||u[m]||i;return r?a.createElement(h,o(o({ref:t},c),{},{components:r})):a.createElement(h,o({ref:t},c))}));function h(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var i=r.length,o=new Array(i);o[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[d]="string"==typeof e?e:n,o[1]=l;for(var p=2;p<i;p++)o[p]=r[p];return a.createElement.apply(null,o)}return a.createElement.apply(null,r)}m.displayName="MDXCreateElement"},5592:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>u,frontMatter:()=>i,metadata:()=>l,toc:()=>p});var a=r(7462),n=(r(7294),r(3905));const i={id:"overview",title:"Component Overview"},o=void 0,l={unversionedId:"external/getting-started/test-network/overview",id:"external/getting-started/test-network/overview",title:"Component Overview",description:"\x3c!--",source:"@site/docs/external/getting-started/test-network/overview.md",sourceDirName:"external/getting-started/test-network",slug:"/external/getting-started/test-network/overview",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/overview",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/getting-started/test-network/overview.md",tags:[],version:"current",frontMatter:{id:"overview",title:"Component Overview"},sidebar:"Documentation",previous:{title:"Using Weaver",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/guide"},next:{title:"Setup with Locally Built Weaver Components",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-local"}},s={},p=[],c={toc:p},d="wrapper";function u(e){let{components:t,...r}=e;return(0,n.kt)(d,(0,a.Z)({},c,r,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("p",null,"Weaver offers a basic test network launching capability, both to demonstrate interoperation modes and to serve as a testbed for development and prototyping. Different modes (or scenarios) require different sets of components, but collectively you will need to run the following:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/tests/network-setups/fabric/dev"},"Fabric testnet")," - A pair of basic Fabric networks for testing interop flows"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/tests/network-setups/corda"},"Corda testnet")," - A pair of basic Corda networks for testing interop flows"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/tests/network-setups/besu"},"Besu testnet")," - A pair of basic Besu networks for testing interop flows"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/core/relay"},"Relay")," - The server module and protocol for cross-DLT interoperability. An instance of this is needed for every Fabric and Corda network"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/core/drivers/fabric-driver"},"Fabric driver")," - Driver used by the Fabric networks relay to communicate with the Fabric testnet"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/core/drivers/corda-driver"},"Corda driver")," - Driver used by the Corda networks relay to communicate with the Corda testnet"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/core/network/fabric-interop-cc"},"Fabric Interop chaincode")," - The Fabric interoperability contracts handle the dual process of servicing requests for views from external networks, and verifying requested views for integrity"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/core/network/corda-interop-app"},"Corda interop app")," CorDapp used to handle interop duties between the relay and the application"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/core/network/besu/contracts/interop"},"Besu interop contract")," Solidity smart contract(s) used to handle interop duties for a Besu network"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/samples/fabric/fabric-cli"},"Fabric client")," - Fabric client used to trigger interop flows initiated from the Fabric side and to manage Fabric state"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/samples/corda/corda-simple-application"},"Corda client app")," - CorDapp and client used to trigger interop flows initiated from the Corda side and to manage Corda state"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/samples/besu/simpleasset"},"Besu sample application")," - A sample application for asset exchange across two besu networks using HTLC"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/samples/besu/besu-cli"},"Besu client app")," - Besu client used to interact with the contracts deployed on the Besu testnet")),(0,n.kt)("p",null,"You can launch these components in one of several different ways:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("strong",{parentName:"li"},"Setup with Locally Built Weaver Components"),":",(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-local"},"Deployed on Host Machine"),": Build the above components purely from your local clone of the Weaver code repository. If you wish to experiment with source code modifications, this is the right option to choose."),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-local-docker"},"Deployed in Docker containers"),": This is similar to the above option, except with relays and drivers launched in Docker containers rather than in the host."))),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("strong",{parentName:"li"},"Setup with Imported Weaver Components"),":",(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-packages"},"Deployed on Host Machine"),": Import pre-built Weaver components from Github Packages instead of building them locally. If you wish to see how Weaver works using pre-tested components and without, choose this option."),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-packages-docker"},"Deployed in Docker containers"),": This is similar to the above option, except with relays and drivers launched in Docker containers rather than in the host.")))),(0,n.kt)("p",null,"After setting up and launching the components, you must initialize the network by following steps in ",(0,n.kt)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/ledger-initialization"},"Ledger Initialization"),".\nThen you can test the following interoperation modes:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/data-sharing"},"Data Sharing")," among Fabric and Corda networks"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview"},"Asset Exchange")," between Fabric networks")))}u.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[5826],{5680:(e,t,r)=>{r.d(t,{xA:()=>c,yg:()=>y});var a=r(6540);function n(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,a)}return r}function o(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?i(Object(r),!0).forEach((function(t){n(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):i(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function l(e,t){if(null==e)return{};var r,a,n=function(e,t){if(null==e)return{};var r,a,n={},i=Object.keys(e);for(a=0;a<i.length;a++)r=i[a],t.indexOf(r)>=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a<i.length;a++)r=i[a],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var s=a.createContext({}),p=function(e){var t=a.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},c=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},d="mdxType",g={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},u=a.forwardRef((function(e,t){var r=e.components,n=e.mdxType,i=e.originalType,s=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),d=p(r),u=n,y=d["".concat(s,".").concat(u)]||d[u]||g[u]||i;return r?a.createElement(y,o(o({ref:t},c),{},{components:r})):a.createElement(y,o({ref:t},c))}));function y(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var i=r.length,o=new Array(i);o[0]=u;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[d]="string"==typeof e?e:n,o[1]=l;for(var p=2;p<i;p++)o[p]=r[p];return a.createElement.apply(null,o)}return a.createElement.apply(null,r)}u.displayName="MDXCreateElement"},1240:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>g,frontMatter:()=>i,metadata:()=>l,toc:()=>p});var a=r(8168),n=(r(6540),r(5680));const i={id:"overview",title:"Component Overview"},o=void 0,l={unversionedId:"external/getting-started/test-network/overview",id:"external/getting-started/test-network/overview",title:"Component Overview",description:"\x3c!--",source:"@site/docs/external/getting-started/test-network/overview.md",sourceDirName:"external/getting-started/test-network",slug:"/external/getting-started/test-network/overview",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/overview",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/getting-started/test-network/overview.md",tags:[],version:"current",frontMatter:{id:"overview",title:"Component Overview"},sidebar:"Documentation",previous:{title:"Using Weaver",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/guide"},next:{title:"Setup with Locally Built Weaver Components",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-local"}},s={},p=[],c={toc:p},d="wrapper";function g(e){let{components:t,...r}=e;return(0,n.yg)(d,(0,a.A)({},c,r,{components:t,mdxType:"MDXLayout"}),(0,n.yg)("p",null,"Weaver offers a basic test network launching capability, both to demonstrate interoperation modes and to serve as a testbed for development and prototyping. Different modes (or scenarios) require different sets of components, but collectively you will need to run the following:"),(0,n.yg)("ul",null,(0,n.yg)("li",{parentName:"ul"},(0,n.yg)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/tests/network-setups/fabric/dev"},"Fabric testnet")," - A pair of basic Fabric networks for testing interop flows"),(0,n.yg)("li",{parentName:"ul"},(0,n.yg)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/tests/network-setups/corda"},"Corda testnet")," - A pair of basic Corda networks for testing interop flows"),(0,n.yg)("li",{parentName:"ul"},(0,n.yg)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/tests/network-setups/besu"},"Besu testnet")," - A pair of basic Besu networks for testing interop flows"),(0,n.yg)("li",{parentName:"ul"},(0,n.yg)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/core/relay"},"Relay")," - The server module and protocol for cross-DLT interoperability. An instance of this is needed for every Fabric and Corda network"),(0,n.yg)("li",{parentName:"ul"},(0,n.yg)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/core/drivers/fabric-driver"},"Fabric driver")," - Driver used by the Fabric networks relay to communicate with the Fabric testnet"),(0,n.yg)("li",{parentName:"ul"},(0,n.yg)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/core/drivers/corda-driver"},"Corda driver")," - Driver used by the Corda networks relay to communicate with the Corda testnet"),(0,n.yg)("li",{parentName:"ul"},(0,n.yg)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/core/network/fabric-interop-cc"},"Fabric Interop chaincode")," - The Fabric interoperability contracts handle the dual process of servicing requests for views from external networks, and verifying requested views for integrity"),(0,n.yg)("li",{parentName:"ul"},(0,n.yg)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/core/network/corda-interop-app"},"Corda interop app")," CorDapp used to handle interop duties between the relay and the application"),(0,n.yg)("li",{parentName:"ul"},(0,n.yg)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/core/network/besu/contracts/interop"},"Besu interop contract")," Solidity smart contract(s) used to handle interop duties for a Besu network"),(0,n.yg)("li",{parentName:"ul"},(0,n.yg)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/samples/fabric/fabric-cli"},"Fabric client")," - Fabric client used to trigger interop flows initiated from the Fabric side and to manage Fabric state"),(0,n.yg)("li",{parentName:"ul"},(0,n.yg)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/samples/corda/corda-simple-application"},"Corda client app")," - CorDapp and client used to trigger interop flows initiated from the Corda side and to manage Corda state"),(0,n.yg)("li",{parentName:"ul"},(0,n.yg)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/samples/besu/simpleasset"},"Besu sample application")," - A sample application for asset exchange across two besu networks using HTLC"),(0,n.yg)("li",{parentName:"ul"},(0,n.yg)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/tree/main/samples/besu/besu-cli"},"Besu client app")," - Besu client used to interact with the contracts deployed on the Besu testnet")),(0,n.yg)("p",null,"You can launch these components in one of several different ways:"),(0,n.yg)("ul",null,(0,n.yg)("li",{parentName:"ul"},(0,n.yg)("strong",{parentName:"li"},"Setup with Locally Built Weaver Components"),":",(0,n.yg)("ul",{parentName:"li"},(0,n.yg)("li",{parentName:"ul"},(0,n.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-local"},"Deployed on Host Machine"),": Build the above components purely from your local clone of the Weaver code repository. If you wish to experiment with source code modifications, this is the right option to choose."),(0,n.yg)("li",{parentName:"ul"},(0,n.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-local-docker"},"Deployed in Docker containers"),": This is similar to the above option, except with relays and drivers launched in Docker containers rather than in the host."))),(0,n.yg)("li",{parentName:"ul"},(0,n.yg)("strong",{parentName:"li"},"Setup with Imported Weaver Components"),":",(0,n.yg)("ul",{parentName:"li"},(0,n.yg)("li",{parentName:"ul"},(0,n.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-packages"},"Deployed on Host Machine"),": Import pre-built Weaver components from GitHub Packages instead of building them locally. If you wish to see how Weaver works using pre-tested components and without, choose this option."),(0,n.yg)("li",{parentName:"ul"},(0,n.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-packages-docker"},"Deployed in Docker containers"),": This is similar to the above option, except with relays and drivers launched in Docker containers rather than in the host.")))),(0,n.yg)("p",null,"After setting up and launching the components, you must initialize the network by following steps in ",(0,n.yg)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/ledger-initialization"},"Ledger Initialization"),".\nThen you can test the following interoperation modes:"),(0,n.yg)("ul",null,(0,n.yg)("li",{parentName:"ul"},(0,n.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/data-sharing"},"Data Sharing")," among Fabric and Corda networks"),(0,n.yg)("li",{parentName:"ul"},(0,n.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview"},"Asset Exchange")," among Fabric, Corda, and Besu networks"),(0,n.yg)("li",{parentName:"ul"},(0,n.yg)("a",{parentName:"li",href:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-transfer"},"Asset Transfer")," between Fabric networks")))}g.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/ec8cb05d.8a20dddb.js b/assets/js/ec8cb05d.c43d8a02.js similarity index 69% rename from assets/js/ec8cb05d.8a20dddb.js rename to assets/js/ec8cb05d.c43d8a02.js index dcd47dfba..76923e672 100644 --- a/assets/js/ec8cb05d.8a20dddb.js +++ b/assets/js/ec8cb05d.c43d8a02.js @@ -1 +1 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[9856],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>h});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function o(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?i(Object(r),!0).forEach((function(t){a(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):i(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function c(e,t){if(null==e)return{};var r,n,a=function(e,t){if(null==e)return{};var r,n,a={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var s=n.createContext({}),l=function(e){var t=n.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},p=function(e){var t=l(e.components);return n.createElement(s.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},f=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,i=e.originalType,s=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),d=l(r),f=a,h=d["".concat(s,".").concat(f)]||d[f]||u[f]||i;return r?n.createElement(h,o(o({ref:t},p),{},{components:r})):n.createElement(h,o({ref:t},p))}));function h(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=r.length,o=new Array(i);o[0]=f;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c[d]="string"==typeof e?e:a,o[1]=c;for(var l=2;l<i;l++)o[l]=r[l];return n.createElement.apply(null,o)}return n.createElement.apply(null,r)}f.displayName="MDXCreateElement"},9561:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>u,frontMatter:()=>i,metadata:()=>c,toc:()=>l});var n=r(7462),a=(r(7294),r(3905));const i={id:"weaver-dapps",title:"Weaver Dapps"},o=void 0,c={unversionedId:"external/architecture-and-design/weaver-dapps",id:"external/architecture-and-design/weaver-dapps",title:"Weaver Dapps",description:"\x3c!--",source:"@site/docs/external/architecture-and-design/weaver-dapps.md",sourceDirName:"external/architecture-and-design",slug:"/external/architecture-and-design/weaver-dapps",permalink:"/weaver-dlt-interoperability/docs/external/architecture-and-design/weaver-dapps",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/architecture-and-design/weaver-dapps.md",tags:[],version:"current",frontMatter:{id:"weaver-dapps",title:"Weaver Dapps"},sidebar:"Documentation",previous:{title:"Drivers",permalink:"/weaver-dlt-interoperability/docs/external/architecture-and-design/drivers"},next:{title:"Decentralized Identity",permalink:"/weaver-dlt-interoperability/docs/external/architecture-and-design/decentralized-identity"}},s={},l=[{value:"Fabric",id:"fabric",level:2},{value:"Corda",id:"corda",level:2}],p={toc:l},d="wrapper";function u(e){let{components:t,...i}=e;return(0,a.kt)(d,(0,n.Z)({},p,i,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"As mentioned in the ",(0,a.kt)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/external/architecture-and-design/overview"},"overview"),", DLTs that integrate with Weaver must contain an interop (IOP) module to facilitate interoperation between ledgers. The interop module contains all the logic responsible for membership, verification policies and access control policies (refer to the RFCs for more information on these). Below shows the architecture of how these interop modules work with the two currently supported DLTs, Fabric and Corda."),(0,a.kt)("h2",{id:"fabric"},"Fabric"),(0,a.kt)("p",null,"When Fabric is the requesting network, the IOP module is used to verify the proof and then forward the state onto the application chaincode."),(0,a.kt)("p",null,(0,a.kt)("img",{src:r(4243).Z,width:"1562",height:"395"})),(0,a.kt)("p",null,"When Fabric is the responding network, the IOP module is in charge of verifying the identity of the requester, making sure the requester has access to the state they are requesting, and then finally retrieving the state from the application chaincode to send back to the requesting network."),(0,a.kt)("p",null,(0,a.kt)("img",{src:r(793).Z,width:"1462",height:"439"})),(0,a.kt)("p",null,"Verification Policy, Access Control and Membership are modular components within the interop chaincode for seperation of concerns of the code."),(0,a.kt)("h2",{id:"corda"},"Corda"),(0,a.kt)("p",null,"As can be seen from the diagrams below, the architecture for Corda is very similar to that of Fabric. The main difference is that the interop module and the application specific flows are in seperate CorDapps, instead of seperate chaincodes like in Fabric."),(0,a.kt)("p",null,(0,a.kt)("img",{src:r(8594).Z,width:"1562",height:"395"})),(0,a.kt)("p",null,(0,a.kt)("img",{src:r(9283).Z,width:"1462",height:"439"})))}u.isMDXComponent=!0},8594:(e,t,r)=>{r.d(t,{Z:()=>n});const n=r.p+"assets/images/corda_dapp_flow1-ff627af484504ac801bbb175b2940f72.png"},9283:(e,t,r)=>{r.d(t,{Z:()=>n});const n=r.p+"assets/images/corda_dapp_flow2-aef05d1649f2cdc62ff7f7dac5d9d746.png"},4243:(e,t,r)=>{r.d(t,{Z:()=>n});const n=r.p+"assets/images/fabric_dapp_flow1-2035e1e29e1d75e37636daf7863f4e83.png"},793:(e,t,r)=>{r.d(t,{Z:()=>n});const n=r.p+"assets/images/fabric_dapp_flow2-cb868570a5685af68eb3df1b91c14721.png"}}]); \ No newline at end of file +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[3129],{5680:(e,t,r)=>{r.d(t,{xA:()=>p,yg:()=>h});var n=r(6540);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function o(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?i(Object(r),!0).forEach((function(t){a(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):i(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function c(e,t){if(null==e)return{};var r,n,a=function(e,t){if(null==e)return{};var r,n,a={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var s=n.createContext({}),l=function(e){var t=n.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},p=function(e){var t=l(e.components);return n.createElement(s.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},f=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,i=e.originalType,s=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),d=l(r),f=a,h=d["".concat(s,".").concat(f)]||d[f]||u[f]||i;return r?n.createElement(h,o(o({ref:t},p),{},{components:r})):n.createElement(h,o({ref:t},p))}));function h(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=r.length,o=new Array(i);o[0]=f;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c[d]="string"==typeof e?e:a,o[1]=c;for(var l=2;l<i;l++)o[l]=r[l];return n.createElement.apply(null,o)}return n.createElement.apply(null,r)}f.displayName="MDXCreateElement"},5534:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>u,frontMatter:()=>i,metadata:()=>c,toc:()=>l});var n=r(8168),a=(r(6540),r(5680));const i={id:"weaver-dapps",title:"Weaver Dapps"},o=void 0,c={unversionedId:"external/architecture-and-design/weaver-dapps",id:"external/architecture-and-design/weaver-dapps",title:"Weaver Dapps",description:"\x3c!--",source:"@site/docs/external/architecture-and-design/weaver-dapps.md",sourceDirName:"external/architecture-and-design",slug:"/external/architecture-and-design/weaver-dapps",permalink:"/weaver-dlt-interoperability/docs/external/architecture-and-design/weaver-dapps",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/architecture-and-design/weaver-dapps.md",tags:[],version:"current",frontMatter:{id:"weaver-dapps",title:"Weaver Dapps"},sidebar:"Documentation",previous:{title:"Drivers",permalink:"/weaver-dlt-interoperability/docs/external/architecture-and-design/drivers"},next:{title:"Decentralized Identity",permalink:"/weaver-dlt-interoperability/docs/external/architecture-and-design/decentralized-identity"}},s={},l=[{value:"Fabric",id:"fabric",level:2},{value:"Corda",id:"corda",level:2}],p={toc:l},d="wrapper";function u(e){let{components:t,...i}=e;return(0,a.yg)(d,(0,n.A)({},p,i,{components:t,mdxType:"MDXLayout"}),(0,a.yg)("p",null,"As mentioned in the ",(0,a.yg)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/external/architecture-and-design/overview"},"overview"),", DLTs that integrate with Weaver must contain an interop (IOP) module to facilitate interoperation between ledgers. The interop module contains all the logic responsible for membership, verification policies and access control policies (refer to the RFCs for more information on these). Below shows the architecture of how these interop modules work with the two currently supported DLTs, Fabric and Corda."),(0,a.yg)("h2",{id:"fabric"},"Fabric"),(0,a.yg)("p",null,"When Fabric is the requesting network, the IOP module is used to verify the proof and then forward the state onto the application chaincode."),(0,a.yg)("p",null,(0,a.yg)("img",{src:r(4844).A,width:"1562",height:"395"})),(0,a.yg)("p",null,"When Fabric is the responding network, the IOP module is in charge of verifying the identity of the requester, making sure the requester has access to the state they are requesting, and then finally retrieving the state from the application chaincode to send back to the requesting network."),(0,a.yg)("p",null,(0,a.yg)("img",{src:r(4903).A,width:"1462",height:"439"})),(0,a.yg)("p",null,"Verification Policy, Access Control and Membership are modular components within the interop chaincode for separation of concerns of the code."),(0,a.yg)("h2",{id:"corda"},"Corda"),(0,a.yg)("p",null,"As can be seen from the diagrams below, the architecture for Corda is very similar to that of Fabric. The main difference is that the interop module and the application specific flows are in separate CorDapps, instead of separate chaincodes like in Fabric."),(0,a.yg)("p",null,(0,a.yg)("img",{src:r(3682).A,width:"1562",height:"395"})),(0,a.yg)("p",null,(0,a.yg)("img",{src:r(4649).A,width:"1462",height:"439"})))}u.isMDXComponent=!0},3682:(e,t,r)=>{r.d(t,{A:()=>n});const n=r.p+"assets/images/corda_dapp_flow1-ff627af484504ac801bbb175b2940f72.png"},4649:(e,t,r)=>{r.d(t,{A:()=>n});const n=r.p+"assets/images/corda_dapp_flow2-aef05d1649f2cdc62ff7f7dac5d9d746.png"},4844:(e,t,r)=>{r.d(t,{A:()=>n});const n=r.p+"assets/images/fabric_dapp_flow1-2035e1e29e1d75e37636daf7863f4e83.png"},4903:(e,t,r)=>{r.d(t,{A:()=>n});const n=r.p+"assets/images/fabric_dapp_flow2-cb868570a5685af68eb3df1b91c14721.png"}}]); \ No newline at end of file diff --git a/assets/js/ee4141e0.dc6336f7.js b/assets/js/ee4141e0.06a2c3bd.js similarity index 70% rename from assets/js/ee4141e0.dc6336f7.js rename to assets/js/ee4141e0.06a2c3bd.js index 8b8e84729..cb3f40d1e 100644 --- a/assets/js/ee4141e0.dc6336f7.js +++ b/assets/js/ee4141e0.06a2c3bd.js @@ -1 +1 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[2752],{4469:e=>{e.exports=JSON.parse('{"name":"docusaurus-plugin-content-blog","id":"default"}')}}]); \ No newline at end of file +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[3062],{2945:e=>{e.exports=JSON.parse('{"name":"docusaurus-plugin-content-blog","id":"default"}')}}]); \ No newline at end of file diff --git a/assets/js/ee88fe61.2770da30.js b/assets/js/ee88fe61.bee863c7.js similarity index 90% rename from assets/js/ee88fe61.2770da30.js rename to assets/js/ee88fe61.bee863c7.js index ddc146cd8..91cf43f61 100644 --- a/assets/js/ee88fe61.2770da30.js +++ b/assets/js/ee88fe61.bee863c7.js @@ -1 +1 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[1749],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>f});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function c(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function a(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?c(Object(r),!0).forEach((function(t){o(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):c(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function i(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},c=Object.keys(e);for(n=0;n<c.length;n++)r=c[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var c=Object.getOwnPropertySymbols(e);for(n=0;n<c.length;n++)r=c[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=n.createContext({}),s=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},p=function(e){var t=s(e.components);return n.createElement(l.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},y=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,c=e.originalType,l=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),u=s(r),y=o,f=u["".concat(l,".").concat(y)]||u[y]||d[y]||c;return r?n.createElement(f,a(a({ref:t},p),{},{components:r})):n.createElement(f,a({ref:t},p))}));function f(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var c=r.length,a=new Array(c);a[0]=y;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i[u]="string"==typeof e?e:o,a[1]=i;for(var s=2;s<c;s++)a[s]=r[s];return n.createElement.apply(null,a)}return n.createElement.apply(null,r)}y.displayName="MDXCreateElement"},8866:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>a,default:()=>d,frontMatter:()=>c,metadata:()=>i,toc:()=>s});var n=r(7462),o=(r(7294),r(3905));const c={id:"access-control",title:"Access Control"},a=void 0,i={unversionedId:"external/security-model/access-control",id:"external/security-model/access-control",title:"Access Control",description:"\x3c!--",source:"@site/docs/external/security-model/access-control.md",sourceDirName:"external/security-model",slug:"/external/security-model/access-control",permalink:"/weaver-dlt-interoperability/docs/external/security-model/access-control",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/security-model/access-control.md",tags:[],version:"current",frontMatter:{id:"access-control",title:"Access Control"},sidebar:"Documentation",previous:{title:"Authentication",permalink:"/weaver-dlt-interoperability/docs/external/security-model/authentication"},next:{title:"Proofs and Verification",permalink:"/weaver-dlt-interoperability/docs/external/security-model/proofs-and-verification"}},l={},s=[],p={toc:s},u="wrapper";function d(e){let{components:t,...r}=e;return(0,o.kt)(u,(0,n.Z)({},p,r,{components:t,mdxType:"MDXLayout"}))}d.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[7477],{5680:(e,t,r)=>{r.d(t,{xA:()=>p,yg:()=>f});var n=r(6540);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function c(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function a(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?c(Object(r),!0).forEach((function(t){o(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):c(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function i(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},c=Object.keys(e);for(n=0;n<c.length;n++)r=c[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var c=Object.getOwnPropertySymbols(e);for(n=0;n<c.length;n++)r=c[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=n.createContext({}),s=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},p=function(e){var t=s(e.components);return n.createElement(l.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},y=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,c=e.originalType,l=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),u=s(r),y=o,f=u["".concat(l,".").concat(y)]||u[y]||d[y]||c;return r?n.createElement(f,a(a({ref:t},p),{},{components:r})):n.createElement(f,a({ref:t},p))}));function f(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var c=r.length,a=new Array(c);a[0]=y;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i[u]="string"==typeof e?e:o,a[1]=i;for(var s=2;s<c;s++)a[s]=r[s];return n.createElement.apply(null,a)}return n.createElement.apply(null,r)}y.displayName="MDXCreateElement"},1173:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>a,default:()=>d,frontMatter:()=>c,metadata:()=>i,toc:()=>s});var n=r(8168),o=(r(6540),r(5680));const c={id:"access-control",title:"Access Control"},a=void 0,i={unversionedId:"external/security-model/access-control",id:"external/security-model/access-control",title:"Access Control",description:"\x3c!--",source:"@site/docs/external/security-model/access-control.md",sourceDirName:"external/security-model",slug:"/external/security-model/access-control",permalink:"/weaver-dlt-interoperability/docs/external/security-model/access-control",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/security-model/access-control.md",tags:[],version:"current",frontMatter:{id:"access-control",title:"Access Control"},sidebar:"Documentation",previous:{title:"Authentication",permalink:"/weaver-dlt-interoperability/docs/external/security-model/authentication"},next:{title:"Proofs and Verification",permalink:"/weaver-dlt-interoperability/docs/external/security-model/proofs-and-verification"}},l={},s=[],p={toc:s},u="wrapper";function d(e){let{components:t,...r}=e;return(0,o.yg)(u,(0,n.A)({},p,r,{components:t,mdxType:"MDXLayout"}))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/eeaeeec1.1c1133a0.js b/assets/js/eeaeeec1.1c1133a0.js deleted file mode 100644 index 756f3c822..000000000 --- a/assets/js/eeaeeec1.1c1133a0.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[2649],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>y});var i=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,i)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?a(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):a(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,i,r=function(e,t){if(null==e)return{};var n,i,r={},a=Object.keys(e);for(i=0;i<a.length;i++)n=a[i],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(i=0;i<a.length;i++)n=a[i],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=i.createContext({}),d=function(e){var t=i.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},c=function(e){var t=d(e.components);return i.createElement(l.Provider,{value:t},e.children)},p="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},h=i.forwardRef((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,l=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),p=d(n),h=r,y=p["".concat(l,".").concat(h)]||p[h]||u[h]||a;return n?i.createElement(y,o(o({ref:t},c),{},{components:n})):i.createElement(y,o({ref:t},c))}));function y(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,o=new Array(a);o[0]=h;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[p]="string"==typeof e?e:r,o[1]=s;for(var d=2;d<a;d++)o[d]=n[d];return i.createElement.apply(null,o)}return i.createElement.apply(null,n)}h.displayName="MDXCreateElement"},898:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>o,default:()=>u,frontMatter:()=>a,metadata:()=>s,toc:()=>d});var i=n(7462),r=(n(7294),n(3905));const a={id:"understanding-interoperability",title:"Understanding Interoperability"},o=void 0,s={unversionedId:"external/what-is-interoperability/understanding-interoperability",id:"external/what-is-interoperability/understanding-interoperability",title:"Understanding Interoperability",description:"\x3c!--",source:"@site/docs/external/what-is-interoperability/understanding-interoperability.md",sourceDirName:"external/what-is-interoperability",slug:"/external/what-is-interoperability/understanding-interoperability",permalink:"/weaver-dlt-interoperability/docs/external/what-is-interoperability/understanding-interoperability",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/what-is-interoperability/understanding-interoperability.md",tags:[],version:"current",frontMatter:{id:"understanding-interoperability",title:"Understanding Interoperability"},sidebar:"Documentation",previous:{title:"Hyperledger Besu",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/besu"},next:{title:"Levels of Interoperability",permalink:"/weaver-dlt-interoperability/docs/external/what-is-interoperability/levels-of-interoperability"}},l={},d=[{value:"Unique Technical Challenges",id:"unique-technical-challenges",level:2},{value:"Single-party vs Multi-party Trust\xa0",id:"single-party-vs-multi-party-trust",level:3},{value:"Data vs Asset",id:"data-vs-asset",level:3},{value:"The Role of Standards",id:"the-role-of-standards",level:2}],c={toc:d},p="wrapper";function u(e){let{components:t,...a}=e;return(0,r.kt)(p,(0,i.Z)({},c,a,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"Permissioned DLTs have been gaining significant traction in industry since their inception. They have enabled enterprises to harness the innovation of public blockchains, while adhering to the privacy, confidentiality and regulatory constraints that businesses operate under. Permissioned DLTs offer enterprises an infrastructure for managing inter-firm asset, data and business workflow, without the need for a central intermediary that introduces additional sources of risk. Businesses are able to transact directly while reducing counter-party risk and mitigating the need for costly and time-consuming dispute resolution processes, often involving legal and judicial systems. Thus far, the application of this technology has enabled digitisation and disintermediation of many entrenched industry processes, resulting in significant improvements in efficiency, transparency, risk and fraud."),(0,r.kt)("p",null,"For practical reasons, the adoption of permissioned blockchains has thus far been driven through use-cases. Enterprises have been coalescing into consortia to create specialised networks that address narrowly-scoped use-cases in isolation.\nThis use-case driven approach to blockchain adoption is creating a proliferation of niche and isolated networks that are quickly becoming data and value silos.\nIn addition, these use-cases often represent a slice of a complex end-to-end business process. To deliver real value, permissioned networks need to seamlessly integrate with each other and with existing systems in order to holistically transform industries. This requirement for interoperation is coming to the fore as networks transition to production and scale towards broader adoption."),(0,r.kt)("p",null,"Interoperability in the context of Distributed Ledger Technologies involves enabling the seamless flow of data and value across disparate networks in a manner that preserves their trust and security tenets. This capability can offer a number of benefits such as:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Removing data and value silos"),(0,r.kt)("li",{parentName:"ul"},"Increasing market sizes, liquidity and overall efficiency"),(0,r.kt)("li",{parentName:"ul"},"Improving network effects"),(0,r.kt)("li",{parentName:"ul"},"Enabling orchestration of complex business functionality across networks"),(0,r.kt)("li",{parentName:"ul"},"Enabling scale and groawth of networks"),(0,r.kt)("li",{parentName:"ul"},"Encouraging further adoption of the technology")),(0,r.kt)("h2",{id:"unique-technical-challenges"},"Unique Technical Challenges"),(0,r.kt)("p",null,"Enabling interoperation between distributed ledgers presents numerous technical challenges compared to traditional systems integration approaches. This primarily stems from the need to preserve the benefits of decentralised trust beyond the boundaries of a single network. Hence, a naive approach to interoperability based on traditional point-to-point API integration is insufficient for preserving the underlying trust decentralised networks provide. There are two unique challenges present in DLT interoperation:"),(0,r.kt)("h3",{id:"single-party-vs-multi-party-trust"},"Single-party vs Multi-party Trust\xa0"),(0,r.kt)("p",null,"In distributed ledger architectures, the authority over state lies in a collective and the protocol they employ to ensure its integrity. When one network or an entity consumes state from another, it would need to establish the veracity of the state according to the shared consensus view of parties in the network. This requirement is different than traditional integration with centralised systems wherein the trust for the validity of data is placed on the single party providing the data. Establishing the veracity of state in a decentralized network is not trivial. In most cases, a consumer of state might not be able to observe the full ledger of the network itself.\xa0Hence, a consumer needs to obtain an independently verifiable cryptographic proof on the validity of state according to the consensus rules and policies of the source network."),(0,r.kt)("p",null,(0,r.kt)("img",{alt:"single-party vs multi-party trust model",src:n(2044).Z,width:"688",height:"333"})),(0,r.kt)("h3",{id:"data-vs-asset"},"Data vs Asset"),(0,r.kt)("p",null,"Interoperation should not compromise the invariants enforced by individual networks such as protections against double spends on assets."),(0,r.kt)("h2",{id:"the-role-of-standards"},"The Role of Standards"),(0,r.kt)("p",null,"The term \u2018interoperability\u2019 is used rather loosely in many contexts and oftentimes without the same implication. What some call \u2018interoperability\u2019, others refer to as \u2018integration\u2019, \u2018interconnectivity\u2019 or \u2018compatibility\u2019."),(0,r.kt)("p",null,"The primary goal of interoperability is freedom of choice. Interoperability enables users to choose implementations of systems they find suitable for a given problem without constraints on the system\u2019s ability to communicate with other implementations. "),(0,r.kt)("p",null,"Implicit in the term interoperability is open standards, which distinguishes it from any form of bespoke integration. Open standards can either be de jure standards ratified by a formal standards organization such as ANSI, IETF, or ISO, or de facto standards proposed and adopted by communities, industries and the market. Open standards enable and encourage implementors to build systems that can work together."))}u.isMDXComponent=!0},2044:(e,t,n)=>{n.d(t,{Z:()=>i});const i=n.p+"assets/images/multi-party-trust-model-3b5ef5b0911c9d1b5578012100073f5b.png"}}]); \ No newline at end of file diff --git a/assets/js/eeaeeec1.396e8a1a.js b/assets/js/eeaeeec1.396e8a1a.js new file mode 100644 index 000000000..e6476be28 --- /dev/null +++ b/assets/js/eeaeeec1.396e8a1a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[7957],{5680:(e,t,n)=>{n.d(t,{xA:()=>c,yg:()=>y});var i=n(6540);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,i)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?a(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):a(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,i,r=function(e,t){if(null==e)return{};var n,i,r={},a=Object.keys(e);for(i=0;i<a.length;i++)n=a[i],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(i=0;i<a.length;i++)n=a[i],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=i.createContext({}),d=function(e){var t=i.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},c=function(e){var t=d(e.components);return i.createElement(l.Provider,{value:t},e.children)},p="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},h=i.forwardRef((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,l=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),p=d(n),h=r,y=p["".concat(l,".").concat(h)]||p[h]||u[h]||a;return n?i.createElement(y,o(o({ref:t},c),{},{components:n})):i.createElement(y,o({ref:t},c))}));function y(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,o=new Array(a);o[0]=h;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[p]="string"==typeof e?e:r,o[1]=s;for(var d=2;d<a;d++)o[d]=n[d];return i.createElement.apply(null,o)}return i.createElement.apply(null,n)}h.displayName="MDXCreateElement"},6576:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>o,default:()=>u,frontMatter:()=>a,metadata:()=>s,toc:()=>d});var i=n(8168),r=(n(6540),n(5680));const a={id:"understanding-interoperability",title:"Understanding Interoperability"},o=void 0,s={unversionedId:"external/what-is-interoperability/understanding-interoperability",id:"external/what-is-interoperability/understanding-interoperability",title:"Understanding Interoperability",description:"\x3c!--",source:"@site/docs/external/what-is-interoperability/understanding-interoperability.md",sourceDirName:"external/what-is-interoperability",slug:"/external/what-is-interoperability/understanding-interoperability",permalink:"/weaver-dlt-interoperability/docs/external/what-is-interoperability/understanding-interoperability",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/what-is-interoperability/understanding-interoperability.md",tags:[],version:"current",frontMatter:{id:"understanding-interoperability",title:"Understanding Interoperability"},sidebar:"Documentation",previous:{title:"Hyperledger Besu",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/besu"},next:{title:"Levels of Interoperability",permalink:"/weaver-dlt-interoperability/docs/external/what-is-interoperability/levels-of-interoperability"}},l={},d=[{value:"Unique Technical Challenges",id:"unique-technical-challenges",level:2},{value:"Single-party vs Multi-party Trust\xa0",id:"single-party-vs-multi-party-trust",level:3},{value:"Data vs Asset",id:"data-vs-asset",level:3},{value:"The Role of Standards",id:"the-role-of-standards",level:2}],c={toc:d},p="wrapper";function u(e){let{components:t,...a}=e;return(0,r.yg)(p,(0,i.A)({},c,a,{components:t,mdxType:"MDXLayout"}),(0,r.yg)("p",null,"Permissioned DLTs have been gaining significant traction in industry since their inception. They have enabled enterprises to harness the innovation of public blockchains, while adhering to the privacy, confidentiality and regulatory constraints that businesses operate under. Permissioned DLTs offer enterprises an infrastructure for managing inter-firm asset, data and business workflow, without the need for a central intermediary that introduces additional sources of risk. Businesses are able to transact directly while reducing counter-party risk and mitigating the need for costly and time-consuming dispute resolution processes, often involving legal and judicial systems. Thus far, the application of this technology has enabled digitisation and disintermediation of many entrenched industry processes, resulting in significant improvements in efficiency, transparency, risk and fraud."),(0,r.yg)("p",null,"For practical reasons, the adoption of permissioned blockchains has thus far been driven through use-cases. Enterprises have been coalescing into consortia to create specialised networks that address narrowly-scoped use-cases in isolation.\nThis use-case driven approach to blockchain adoption is creating a proliferation of niche and isolated networks that are quickly becoming data and value silos.\nIn addition, these use-cases often represent a slice of a complex end-to-end business process. To deliver real value, permissioned networks need to seamlessly integrate with each other and with existing systems in order to holistically transform industries. This requirement for interoperation is coming to the fore as networks transition to production and scale towards broader adoption."),(0,r.yg)("p",null,"Interoperability in the context of Distributed Ledger Technologies involves enabling the seamless flow of data and value across disparate networks in a manner that preserves their trust and security tenets. This capability can offer a number of benefits such as:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Removing data and value silos"),(0,r.yg)("li",{parentName:"ul"},"Increasing market sizes, liquidity and overall efficiency"),(0,r.yg)("li",{parentName:"ul"},"Improving network effects"),(0,r.yg)("li",{parentName:"ul"},"Enabling orchestration of complex business functionality across networks"),(0,r.yg)("li",{parentName:"ul"},"Enabling scale and groawth of networks"),(0,r.yg)("li",{parentName:"ul"},"Encouraging further adoption of the technology")),(0,r.yg)("h2",{id:"unique-technical-challenges"},"Unique Technical Challenges"),(0,r.yg)("p",null,"Enabling interoperation between distributed ledgers presents numerous technical challenges compared to traditional systems integration approaches. This primarily stems from the need to preserve the benefits of decentralised trust beyond the boundaries of a single network. Hence, a naive approach to interoperability based on traditional point-to-point API integration is insufficient for preserving the underlying trust decentralised networks provide. There are two unique challenges present in DLT interoperation:"),(0,r.yg)("h3",{id:"single-party-vs-multi-party-trust"},"Single-party vs Multi-party Trust\xa0"),(0,r.yg)("p",null,"In distributed ledger architectures, the authority over state lies in a collective and the protocol they employ to ensure its integrity. When one network or an entity consumes state from another, it would need to establish the veracity of the state according to the shared consensus view of parties in the network. This requirement is different than traditional integration with centralised systems wherein the trust for the validity of data is placed on the single party providing the data. Establishing the veracity of state in a decentralized network is not trivial. In most cases, a consumer of state might not be able to observe the full ledger of the network itself.\xa0Hence, a consumer needs to obtain an independently verifiable cryptographic proof on the validity of state according to the consensus rules and policies of the source network."),(0,r.yg)("p",null,(0,r.yg)("img",{alt:"single-party vs multi-party trust model",src:n(5586).A,width:"688",height:"333"})),(0,r.yg)("h3",{id:"data-vs-asset"},"Data vs Asset"),(0,r.yg)("p",null,"Interoperation should not compromise the invariants enforced by individual networks such as protections against double spends on assets."),(0,r.yg)("h2",{id:"the-role-of-standards"},"The Role of Standards"),(0,r.yg)("p",null,"The term \u2018interoperability\u2019 is used rather loosely in many contexts and oftentimes without the same implication. What some call \u2018interoperability\u2019, others refer to as \u2018integration\u2019, \u2018interconnectivity\u2019 or \u2018compatibility\u2019."),(0,r.yg)("p",null,"The primary goal of interoperability is freedom of choice. Interoperability enables users to choose implementations of systems they find suitable for a given problem without constraints on the system\u2019s ability to communicate with other implementations. "),(0,r.yg)("p",null,"Implicit in the term interoperability is open standards, which distinguishes it from any form of bespoke integration. Open standards can either be de jure standards ratified by a formal standards organization such as ANSI, IETF, or ISO, or de facto standards proposed and adopted by communities, industries and the market. Open standards enable and encourage implementors to build systems that can work together."))}u.isMDXComponent=!0},5586:(e,t,n)=>{n.d(t,{A:()=>i});const i=n.p+"assets/images/multi-party-trust-model-3b5ef5b0911c9d1b5578012100073f5b.png"}}]); \ No newline at end of file diff --git a/assets/js/eed74c9c.4f784c5c.js b/assets/js/eed74c9c.4f784c5c.js deleted file mode 100644 index 19f3e33fc..000000000 --- a/assets/js/eed74c9c.4f784c5c.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[2238],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>d});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?o(Object(r),!0).forEach((function(t){a(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):o(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function l(e,t){if(null==e)return{};var r,n,a=function(e,t){if(null==e)return{};var r,n,a={},o=Object.keys(e);for(n=0;n<o.length;n++)r=o[n],t.indexOf(r)>=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n<o.length;n++)r=o[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var c=n.createContext({}),p=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},u=function(e){var t=p(e.components);return n.createElement(c.Provider,{value:t},e.children)},m="mdxType",s={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},f=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),m=p(r),f=a,d=m["".concat(c,".").concat(f)]||m[f]||s[f]||o;return r?n.createElement(d,i(i({ref:t},u),{},{components:r})):n.createElement(d,i({ref:t},u))}));function d(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,i=new Array(o);i[0]=f;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l[m]="string"==typeof e?e:a,i[1]=l;for(var p=2;p<o;p++)i[p]=r[p];return n.createElement.apply(null,i)}return n.createElement.apply(null,r)}f.displayName="MDXCreateElement"},4563:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>s,frontMatter:()=>o,metadata:()=>l,toc:()=>p});var n=r(7462),a=(r(7294),r(3905));const o={},i=void 0,l={unversionedId:"internal/team",id:"internal/team",title:"team",description:"\x3c!--",source:"@site/docs/internal/team.md",sourceDirName:"internal",slug:"/internal/team",permalink:"/weaver-dlt-interoperability/docs/internal/team",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/internal/team.md",tags:[],version:"current",frontMatter:{}},c={},p=[{value:"title: Team",id:"title-team",level:2}],u={toc:p},m="wrapper";function s(e){let{components:t,...r}=e;return(0,a.kt)(m,(0,n.Z)({},u,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("hr",null),(0,a.kt)("p",null,"id: team"),(0,a.kt)("h2",{id:"title-team"},"title: Team"))}s.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/f0c74005.1e80f4a8.js b/assets/js/f0c74005.1e80f4a8.js deleted file mode 100644 index fd426292a..000000000 --- a/assets/js/f0c74005.1e80f4a8.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[457],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>u});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,a,r=function(e,t){if(null==e)return{};var n,a,r={},i=Object.keys(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=a.createContext({}),p=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},d=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},c="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),c=p(n),h=r,u=c["".concat(s,".").concat(h)]||c[h]||m[h]||i;return n?a.createElement(u,o(o({ref:t},d),{},{components:n})):a.createElement(u,o({ref:t},d))}));function u(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,o=new Array(i);o[0]=h;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:r,o[1]=l;for(var p=2;p<i;p++)o[p]=n[p];return a.createElement.apply(null,o)}return a.createElement.apply(null,n)}h.displayName="MDXCreateElement"},4682:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>m,frontMatter:()=>i,metadata:()=>l,toc:()=>p});var a=n(7462),r=(n(7294),n(3905));const i={id:"corda",title:"Corda"},o=void 0,l={unversionedId:"external/getting-started/enabling-weaver-network/corda",id:"external/getting-started/enabling-weaver-network/corda",title:"Corda",description:"\x3c!--",source:"@site/docs/external/getting-started/enabling-weaver-network/corda.md",sourceDirName:"external/getting-started/enabling-weaver-network",slug:"/external/getting-started/enabling-weaver-network/corda",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/corda",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/getting-started/enabling-weaver-network/corda.md",tags:[],version:"current",frontMatter:{id:"corda",title:"Corda"},sidebar:"Documentation",previous:{title:"Hyperledger Fabric",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/fabric"},next:{title:"Hyperledger Besu",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/besu"}},s={},p=[{value:"Model",id:"model",level:2},{value:"Procedural Overview",id:"procedural-overview",level:2},{value:"Development Phase",id:"development-phase",level:2},{value:"CorDapp",id:"cordapp",level:3},{value:"For Data Sharing",id:"for-data-sharing",level:4},{value:"For Asset Exchange",id:"for-asset-exchange",level:4},{value:"For Asset Transfer",id:"for-asset-transfer",level:4},{value:"Contracts CorDapp",id:"contracts-cordapp",level:3},{value:"Client Layer applications",id:"client-layer-applications",level:2},{value:"For Identity Administration",id:"for-identity-administration",level:4},{value:"For Data Sharing",id:"for-data-sharing-1",level:4},{value:"For Asset exchange",id:"for-asset-exchange-1",level:4},{value:"For Asset Transfer",id:"for-asset-transfer-1",level:4},{value:"Pre-Configuration Phase",id:"pre-configuration-phase",level:2},{value:"Startup and Bootstrap Phase",id:"startup-and-bootstrap-phase",level:2},{value:"For Asset Exchange",id:"for-asset-exchange-2",level:3},{value:"Install Interoperation CorDapp on Nodes",id:"install-interoperation-cordapp-on-nodes",level:3},{value:"For Data Sharing or Asset Transfer",id:"for-data-sharing-or-asset-transfer",level:3},{value:"Install Interoperation CorDapp on Nodes",id:"install-interoperation-cordapp-on-nodes-1",level:4},{value:"Launch Relay",id:"launch-relay",level:4},{value:"Launch Driver",id:"launch-driver",level:4},{value:"Vault Initialization",id:"vault-initialization",level:4}],d={toc:p},c="wrapper";function m(e){let{components:t,...i}=e;return(0,r.kt)(c,(0,a.Z)({},d,i,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"After testing the Weaver interoperation mechanisms on ",(0,r.kt)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/overview"},"basic sample networks"),", you may be interested in finding out how you can equip an existing real network, whether in development or in production, to exercise these mechanisms. In this document, we will demonstrate how to equip a Corda network and application with Weaver components and capabilities."),(0,r.kt)("h2",{id:"model"},"Model"),(0,r.kt)("p",null,"The figure below illustrates a typical Corda network. The infrastructure consists of a set of nodes (each maintaining its share of the global state in a local vault), notaries, and CAs. On the nodes are installed one or more CorDapps, representing shared business logic across subsets of those nodes. The core of a CorDapp consists of a collection of workflows (or flows) and contracts acting on states; we layer the flows above the contracts in thebelow image just to illustrate that flows represent transaction (state update) triggers, and contract validations occur during the executions of flows. Further up in the stack lie client applications associated with CorDapps that can are used to trigger flows (and by implication, contracts)."),(0,r.kt)("p",null,(0,r.kt)("img",{alt:"alt text",src:n(4610).Z,width:"1255",height:"681"})),(0,r.kt)("p",null,"Such a network equipped with Weaver components and capabilities will look like the figure below. Legacy components are marked in grey and Weaver and bridging components in green."),(0,r.kt)("p",null,(0,r.kt)("img",{alt:"alt text",src:n(318).Z,width:"1791",height:"682"})),(0,r.kt)("p",null,"The relay and driver are the only additional infrastructure that need to be installed. One or more relays can be installed, as can one or more drivers. The drivers are illustrated in the client layer rather than in the bottom layer because, though they are coupled with relays, they trigger flows just like any client application does."),(0,r.kt)("p",null,"Existing CorDapp flows and contracts deployed on the network's nodes remain undisturbed. All that is required is the deployment of an Interoperation CorDapp (flows and contracts) on every node that needs to offer or consume state from foreign networks."),(0,r.kt)("p",null,"Client applications will need some additional code and configuration because the decisions to exercise interoperation mechanisms (relay queries for data sharing or atomic asset exchanges) are strictly part of business logic. But Weaver's Corda Interoperation Node SDK offers various helper functions to ease this process and keep the adaptation to a minimum, as we wil see later in this document. Finally, an ",(0,r.kt)("em",{parentName:"p"},"identity service")," must be offered by the network to expose its CAs' certificate chains to foreign networks, thereby laying the basis for interoperation. This service simply needs to offer a REST endpoint, and can be implemented as a standalone application or (more conveniently) as an augmentation of one or more of the existing client layer applications."),(0,r.kt)("h2",{id:"procedural-overview"},"Procedural Overview"),(0,r.kt)("p",null,"A Corda network is typically created in phases, in the following sequence:"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("strong",{parentName:"li"},"Development"),": This involves writing CorDapp which consists of contracts and workflows, and client layer applications. The cordapp's deployment name/ID and its transaction API must be designed first, but subsequent development of the two layers of applications can then proceed parallelly."),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("strong",{parentName:"li"},"Pre-Configuration"),": This involves creating a desired specification (as a set of configuration diles) of the network topology and the ledgers it maintains."),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("strong",{parentName:"li"},"Startup and Bootstrap"),": This is the launch phase, in which the network components and applications are started and bootstrapped (i.e., configured with initial state and operating rules).")),(0,r.kt)("p",null,"Assuming that the reader is familiar with this procedure, we will walk through the changes required in each phase to make your network ready for interoperation using Weaver components and code templates. This will involve code addition and adaptation, deployment of additional modules, additional configuration, and creation of additional ledger state records. The requirements and effort will vary with the mode of interoperation you wish to support in your Fabric network."),(0,r.kt)("h2",{id:"development-phase"},"Development Phase"),(0,r.kt)("p",null,"A Corda distributed application's business logic code spans three layers as illustrated in the network model:"),(0,r.kt)("h3",{id:"cordapp"},"CorDapp"),(0,r.kt)("p",null,"CorDapps (Corda Distributed Applications) are distributed applications that run on the Corda platform. The goal of a CorDapp is to allow nodes to reach agreement on updates to the ledger. They achieve this goal by defining flows that Corda node owners can invoke over RPC."),(0,r.kt)("h4",{id:"for-data-sharing"},"For Data Sharing"),(0,r.kt)("p",null,"No code changes are required for Weaver enablement, because data sharing involves:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"View packaging (and optionally, encryption) logic and access control logic in a source network, and"),(0,r.kt)("li",{parentName:"ul"},"View validation logic in a destination network")),(0,r.kt)("p",null,"This logic is standard and independent of contract, workflow, and state, particulars. It is already implemented in the Interoperation CorDapp offered by Weaver. Hence you just need to deploy that CorDapp to exercise data sharing from, or to, your application CorDapp. Your application CorDapp can be oblivious of the Interoperation CorDapp's workings and of the view request-response protocol."),(0,r.kt)("h4",{id:"for-asset-exchange"},"For Asset Exchange"),(0,r.kt)("p",null,"To exchange an asset using Weaver, the asset's state on the ledger must be controlled in the following ways:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Locked in favor of a party"),(0,r.kt)("li",{parentName:"ul"},"Claimed by the party to whom the asset is pledged"),(0,r.kt)("li",{parentName:"ul"},"Returned to the original owner if it is not claimed within a given timeframe")),(0,r.kt)("p",null,"In addition, the state of the asset (i.e., whether it is locked), and its current and targeted owners, must be determinable by looking at the ledger records."),(0,r.kt)("p",null,"The bookkeeping logic required to maintain records of locks can be abstracted away from the particulars of a digital asset and its workflow. But as such assets and their properties (including ownership) can be, and are, encoded in an arbitrary number of ways, we cannot provide a one-size-fits all set of functions (like in the data sharing protocol) to exchange any kind of asset. Instead, we must rely on the application CorDapp managing an asset, as it knows precisely what the asset's properties are and how they can be updated and queried on the ledger."),(0,r.kt)("p",null,"What Weaver offers, therefore, is the following:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Lock management logic implemented in the Interoperation CorDapp that treats each asset as an abstract object (an instance of generic corda's ",(0,r.kt)("inlineCode",{parentName:"li"},"ContractState"),") and is agnostic of the assets' internals. It consumes (burns) the asset state and creates a new ",(0,r.kt)("inlineCode",{parentName:"li"},"HTLC")," state that indicates that the asset is locked, while in claim and unlock new asset state is created (minted) with appropriate owner while consuming ",(0,r.kt)("inlineCode",{parentName:"li"},"HTLC")," state. This logic can be exercised in by installing Interoperation CorDapp on the nodes."),(0,r.kt)("li",{parentName:"ul"},"A set of template functions with sample (and extensible) code that must be added to the application CorDapp to augment the above lock management functions.")),(0,r.kt)("p",null,"Below, we list the template functions with sample code that you, as a developer, must use and adapt within your CorDapp."),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"Flow to get Asset State"),": For non-fungible assets, create a flow like:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-kotlin"},"class RetrieveStateAndRef(\n val type: String, \n val id: String\n): FlowLogic<StateAndRef<AssetState>>\n")),"And for fungible assets, create a flow like:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-kotlin"},"class RetrieveStateAndRef(\n val type: String, \n val quantity: Long\n): FlowLogic<StateAndRef<AssetState>>\n")),"The name of these flows can be anything, but the parameters should be same, and return type should ",(0,r.kt)("inlineCode",{parentName:"li"},"StateAndRef"),". These flows are supposed to get the ",(0,r.kt)("inlineCode",{parentName:"li"},"StateAndRef")," object to the asset state that has to be locked, which can be identified by ",(0,r.kt)("inlineCode",{parentName:"li"},"type")," and ",(0,r.kt)("inlineCode",{parentName:"li"},"id")," for non-fungible assets, and ",(0,r.kt)("inlineCode",{parentName:"li"},"type")," and ",(0,r.kt)("inlineCode",{parentName:"li"},"quantity")," for fungible assets."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"Flow to update owner in asset state"),": Create a flow like:",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-kotlin"},"class UpdateOwnerFromPointer(\n val statePointer: StaticPointer<AssetState>\n) : FlowLogic<AssetState>()\n")),"Again the name can be anything but the function parameter should be same, i.e. take a ",(0,r.kt)("inlineCode",{parentName:"li"},"StaticPointer")," and return the ",(0,r.kt)("inlineCode",{parentName:"li"},"ContractState")," of the asset involved in asset exchange. This flow is supposed to resolve the ",(0,r.kt)("inlineCode",{parentName:"li"},"StaticPointer")," to actual asset, and update the owner of this asset to the caller of this flow.")),(0,r.kt)("h4",{id:"for-asset-transfer"},"For Asset Transfer"),(0,r.kt)("p",null,(0,r.kt)("em",{parentName:"p"},"TBD")),(0,r.kt)("h3",{id:"contracts-cordapp"},"Contracts CorDapp"),(0,r.kt)("p",null,"No code changes are required for Weaver enablement. For asset exchange, Weaver assumes that application CorDapp that manages assets must already have a asset creation (mint) contract command and asset deletion (burn) contract command, which can be invoked when ",(0,r.kt)("inlineCode",{parentName:"p"},"Issuer")," party is involved in the transaction."),(0,r.kt)("h2",{id:"client-layer-applications"},"Client Layer applications"),(0,r.kt)("p",null,"Weaver provides an SDK to help you adapt your applications to exercise the various interoperability modes. These are called out as ",(0,r.kt)("strong",{parentName:"p"},"SDK Helpers")," in the network model illustrated earlier. Your Corda network's Client layer applications have business logic embedded in them that, broadly speaking, accept data from users and other external agents and invoke workflows from CorDapp over RPC. When you use Weaver for network interoperability, other options can be added, namely requesting and accepting data from foreign networks, and triggering locks and claims for atomic exchanges spanning two networks. Weaver's Corda Interoperation SDK offers a library to exercise these options. But this will involve modification to the application's business logic.\nTo use Weaver's Corda SDK, you need to create a ",(0,r.kt)("a",{parentName:"p",href:"https://docs.github.com/en/github/authenticating-to-github/keeping-your-account-and-data-secure/creating-a-personal-access-token"},"personal access token")," with ",(0,r.kt)("inlineCode",{parentName:"p"},"read:packages")," access in Github, to access weaver packages.\nYou also need to add the following to your application's ",(0,r.kt)("inlineCode",{parentName:"p"},"build.gradle")," file:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-groovy"},"repositories {\n maven {\n url https://maven.pkg.github.com/hyperledger-labs/weaver-dlt-interoperability\n credentials {\n username <github-email>\n password <github-personal-access-token>\n }\n }\n}\ndependencies {\n implementation(group: 'com.weaver.corda.sdk', name: 'weaver-corda-sdk', version: \"1.2.13\")\n implementation(group: 'com.weaver.corda.app.interop', name: 'interop-contracts', version: \"1.2.13\")\n implementation(group: 'com.weaver.corda.app.interop', name: 'interop-workflows', version: \"1.2.13\")\n implementation(group: 'com.weaver', name: 'protos-java-kt', version: \"1.5.7\")\n}\n")),(0,r.kt)("p",null,"(Or check out the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/packages/952245"},"package website")," and select a different version.)"),(0,r.kt)("h4",{id:"for-identity-administration"},"For Identity Administration"),(0,r.kt)("p",null,"A Corda network needs to share its security domain (or membership) configuration, i.e., its nodes' CA certificate chains, with a foreign network with which it seeks to interoperate. Though such sharing can be implemented using several different mechanisms, ranging from manual to automated, the simplest and most modular way is to expose a REST endpoint that agents in foreign networks can reach. Further, this REST endpoint can be implemented as a standalone web application or it can be an extension of one or more of the existing client layer applications. (Multiple apps can expose the same endpoint serving the same information for redundancy.) We will demonstrate an example of this while leaving other implementation modes to the user.\nLet's say a Corda network consists of two nodes called ",(0,r.kt)("inlineCode",{parentName:"p"},"PartyA")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"PartyB"),", each running a client layer application with a web server whose URL prefixes are ",(0,r.kt)("inlineCode",{parentName:"p"},"http://partya.mynetwork.com:9000")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"http://partyb.mynetwork.com:9000")," respectively. Each app then can expose a REST endpoint (again, as an example) ",(0,r.kt)("inlineCode",{parentName:"p"},"http://partya.mynetwork.com:9000/node_sec_grp")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"http://partyb.mynetwork.com:9000/node_sec_grp")," respectively.\nAt each web server's backend, you need to implement logic to retrieve the node's ID and it's associated certificated chains. Sample code is given below for a Kotlin implementation built on ",(0,r.kt)("inlineCode",{parentName:"p"},"weaver-corda-sdk"),". You can use this code verbatim, except for some minor changes like ",(0,r.kt)("inlineCode",{parentName:"p"},"<path-to-root-corda-net-folder>"),", other parameters like security domain, and list of names of nodes as appropriate for your environment:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-kotlin"},'import com.weaver.corda.sdk.CredentialsCreator\nimport com.google.protobuf.util.JsonFormat\n\n\n@RestController\n@CrossOrigin\n@RequestMapping("/") // The paths for HTTP requests are relative to this base path.\nclass Controller {\n // Expose "node_sec_grp" endpoint using Rest Controller\n @RequestMapping(value = ["/node_sec_grp"], method = arrayOf(RequestMethod.GET), produces = arrayOf("application/json"))\n private fun GetNetworkConfig(): String {\n val jsonPrinter = JsonFormat.printer().includingDefaultValueFields()\n \n val credentialsCreator = CredentialsCreator(\n "<path-to-root-corda-net-folder>/build/nodes",\n "mynetwork", // security domain name\n ["PartyA", "PartyB"], // list of nodes \n "", \n ""\n )\n \n // Generate Membership\n val membership = credentialsCreator.createMembership()\n return jsonPrinter.print(membership)\n }\n}\n')),(0,r.kt)("p",null,"An agent from a foreign network can query either ",(0,r.kt)("inlineCode",{parentName:"p"},"http://partya.mynetwork.com:9000/sec_group")," or ",(0,r.kt)("inlineCode",{parentName:"p"},"http://partyb.mynetwork.com:9000/sec_group")," and obtain the security domain (or membership) configuration of the entire network."),(0,r.kt)("h4",{id:"for-data-sharing-1"},"For Data Sharing"),(0,r.kt)("p",null,"Consider a scenario inspired by the ",(0,r.kt)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/external/user-stories/global-trade"},"global trade use case")," where a letter of credit (L/C) management business logic is installed in the ",(0,r.kt)("inlineCode",{parentName:"p"},"trade-finance-network")," network, supports a flow named ",(0,r.kt)("inlineCode",{parentName:"p"},"UploadBillOfLading"),", which validates and records a bill of lading (B/L) supplied by a user via a UI. Weaver will enable such a B/L to be fetched from a different network ",(0,r.kt)("inlineCode",{parentName:"p"},"trade-logistics-network")," by querying the function ",(0,r.kt)("inlineCode",{parentName:"p"},"GetBillOfLading")," exposed by the chaincode ",(0,r.kt)("inlineCode",{parentName:"p"},"shipmentcc")," installed in the ",(0,r.kt)("inlineCode",{parentName:"p"},"tradelogisticschannel")," channel (",(0,r.kt)("em",{parentName:"p"},"The trade logistics network can be built on Corda as well. The steps for Weaver-enablement will mostly be the same, with the exception of view address creation logic. Here, for demonstration purposes, we assume that that counter-party network is built on Fabric"),")."),(0,r.kt)("p",null,"(In preparation, a suitable access control policy must be recorded on ",(0,r.kt)("inlineCode",{parentName:"p"},"tradelogisticschannel")," in ",(0,r.kt)("inlineCode",{parentName:"p"},"trade-logistics-network"),", and a suitable verification policy must be recorded in the vault of ",(0,r.kt)("inlineCode",{parentName:"p"},"trade-finance-network"),". We will see how to do this in the ",(0,r.kt)("a",{parentName:"p",href:"#startup-and-bootstrap-weaver-components"},"Startup and Bootstrap Weaver Components")," section later.)"),(0,r.kt)("p",null,"You will need to insert some code in the client layer application that accepts a B/L and submits a ",(0,r.kt)("inlineCode",{parentName:"p"},"UploadBillOfLading")," request in ",(0,r.kt)("inlineCode",{parentName:"p"},"trade-finance-network"),". (No code changes need to be made in any application in the other network.) The logic to accept a B/L should be replaced (or you can simply add an alternative) by a call to the ",(0,r.kt)("inlineCode",{parentName:"p"},"InteroperableHelper.interopFlow")," function offered by the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/packages/952245"},"weaver-corda-sdk")," library. The following code sample illustrates this:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-kt"},"import com.weaver.corda.sdk.InteroperableHelper\nimport com.mynetwork.flow.UploadBillOfLading\n\nval viewAddress = InteroperableHelper.createFabricViewAddress(\n 'trade-logistics-network', // Security Domain/Group\n <trade-logistics-relay-url[:<port>], // Replace with remote network's relay\n 'tradelogisticschannel', // Remote network's channel\n 'shipmentcc', // Remote network's cc\n 'GetBillOfLading', // Remote network's cc Fun\n [ <shipment-reference> ] // Replace <shipment-reference> with a value that can be used to look up the right B/L\n)\ntry {\n val response = InteroperableHelper.interopFlow(\n proxy, // CordaRPCOps instance to start flows\n viewAddress,\n <trade-finance-relay-url>[:<port>] // Replace with local network's relay address and port\n ).fold({\n println(\"Error in Interop Flow: ${it.message}\")\n }, {\n val linearId = it.toString()\n val BoLString = InteroperableHelper.getExternalStatePayloadString(\n proxy,\n linearId\n )\n val result = proxy.startFlow(::UploadBillOfLading, BoLString)\n println(\"$result\")\n }\n} catch (e: Exception) {\n println(\"Error: ${e.toString()}\")\n}\n")),(0,r.kt)("p",null,"Let us understand this code snippet better. The function ",(0,r.kt)("inlineCode",{parentName:"p"},"UploadBillOfLading")," expects one argument, the bill of lading contents. The ",(0,r.kt)("inlineCode",{parentName:"p"},"InteroperableHelper.createFabricViewAddress")," is used to create view address that is to passed to ",(0,r.kt)("inlineCode",{parentName:"p"},"InteroperableHelper.interopFlow")," function. The equivalent function to create a view address for a remote Corda network is ",(0,r.kt)("inlineCode",{parentName:"p"},"InteroperableHelper.createCordaViewAddress"),". "),(0,r.kt)("p",null,"The rest of the code ought to be self-explanatory. Values are hardcoded for explanation purposes."),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Enabling TLS"),":\nBy default, the TLS is set to false in ",(0,r.kt)("inlineCode",{parentName:"p"},"interopFlow"),", i.e. disabled. But if you want to enable TLS, can pass additional parameters to the ",(0,r.kt)("inlineCode",{parentName:"p"},"interopFlow")," function as follows:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-kt"},"val response = InteroperableHelper.interopFlow(\n proxy, // CordaRPCOps instance to start flows\n viewAddress,\n <trade-finance-relay-url>[:<port>], // Replace with local network's relay address and port\n 'trade-finance-network', // Local network name (destination)\n true, // Boolean indication TLS is enabled.\n <relayTlsTrustStorePath> // JKS file path containing relay server TLS CA certificates\n <relayTlsTrustStorePassword>, // password used to create the JKS file\n)\n")),(0,r.kt)("p",null,"OR"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-kt"},"val response = InteroperableHelper.interopFlow(\n proxy, // CordaRPCOps instance to start flows\n viewAddress,\n <trade-finance-relay-url>[:<port>], // Replace with local network's relay address and port\n 'trade-finance-network', // Local network name (destination)\n true, // Boolean indication TLS is enabled.\n <tlsCACertPathsForRelay>, // colon-separated list of CA certificate file paths\n)\n")),(0,r.kt)("h4",{id:"for-asset-exchange-1"},"For Asset exchange"),(0,r.kt)("p",null,"Let's take an example of asset exchange between ",(0,r.kt)("inlineCode",{parentName:"p"},"Alice")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"Bob"),", where Bob wants to purchase an asset of type ",(0,r.kt)("inlineCode",{parentName:"p"},"Gold")," with id ",(0,r.kt)("inlineCode",{parentName:"p"},"A123")," from ",(0,r.kt)("inlineCode",{parentName:"p"},"Alice")," in ",(0,r.kt)("inlineCode",{parentName:"p"},"BondNetwork")," in exchange for ",(0,r.kt)("inlineCode",{parentName:"p"},"200")," tokens of type ",(0,r.kt)("inlineCode",{parentName:"p"},"CBDC01")," in ",(0,r.kt)("inlineCode",{parentName:"p"},"TokenNetwork"),"."),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"Alice")," needs to select a secret text (say ",(0,r.kt)("inlineCode",{parentName:"p"},"s"),"), and hash it (say ",(0,r.kt)("inlineCode",{parentName:"p"},"H"),") using say ",(0,r.kt)("inlineCode",{parentName:"p"},"SHA512"),", which will be used to lock her asset in ",(0,r.kt)("inlineCode",{parentName:"p"},"BondNetwork"),". To lock the non-fungible asset using hash ",(0,r.kt)("inlineCode",{parentName:"p"},"H")," and timeout duration of 10 minutes, you need to add following code snippet in your application:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-kotlin"},'import com.weaver.corda.sdk.AssetManager\nimport com.weaver.corda.sdk.HashFunctions\n\nvar hash: HashFunctions.Hash = HashFunctions.SHA512\nhash.setSerializedHashBase64(H)\nval proxy = <CordaRPCOps-instance-created-using-credentials-of-Alice-in-BondNetwork>\nval issuer = <Issuer-party-in-BondNetwork>\nval recipient = <Bob-party-in-BondNetwork>\nval contractId = AssetManager.createHTLC(\n proxy, \n "Gold", // Type\n "A123", // ID\n recipient, \n hash, \n 10L, // Duration tmeout in secs, L denotes Long\n 1, // 1 if timeout is Duration, 0 if timeout is in absolute epochs\n "com.cordaSimpleApplication.flow.RetrieveStateAndRef", // full name of "Flow to get Asset State"\n AssetContract.Commands.Delete(), // Contract command for Asset to Burn/Delete the state\n issuer,\n observers // Optional parameter for list of observers for this transaction\n)\n')),(0,r.kt)("p",null,"Now ",(0,r.kt)("inlineCode",{parentName:"p"},"Bob")," will lock his tokens in ",(0,r.kt)("inlineCode",{parentName:"p"},"TokenNetwork"),". To lock the fungible asset using same hash ",(0,r.kt)("inlineCode",{parentName:"p"},"H")," and timeout of 5 minutes (half the timeout duration used by Alice in ",(0,r.kt)("inlineCode",{parentName:"p"},"BondNetwork"),"), add following code snippet in your application:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-kotlin"},'import com.weaver.corda.sdk.AssetManager\nimport com.weaver.corda.sdk.HashFunctions\n\nvar hash: HashFunctions.Hash = HashFunctions.SHA512\nhash.setSerializedHashBase64(H)\nval proxy = <CordaRPCOps-instance-created-using-credentials-of-Bob-in-TokenNetwork>\nval issuer = <Issuer-party-in-TokenNetwork>\nval recipient = <Alice-party-in-TokenNetwork>\nval contractId = AssetManager.createFungibleHTLC(\n proxy, \n "CBDC01", // Type\n "200", // Quantity\n recipient, \n hash, \n 5L, // Duration timeout in secs, L denotes Long\n 1, // 1 if timeout is Duration, 0 if timeout is in absolute epochs\n "com.cordaSimpleApplication.flow.RetrieveStateAndRef", // full name of "Flow to get Asset State"\n AssetContract.Commands.Delete(), // Contract command for Asset to Burn/Delete the state\n issuer,\n observers // Optional parameter for list of observers for this transaction\n)\n')),(0,r.kt)("p",null,"The above locks will return ",(0,r.kt)("inlineCode",{parentName:"p"},"contractId"),", that has to be stored and will be used in other HTLC functions."),(0,r.kt)("p",null,"To query whether the assets are locked or not in any network, use following query function:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-kotlin"},"val isLockedBoolean = AssetManager.isAssetLockedInHTLC(\n rpc.proxy, \n contractId\n)\n")),(0,r.kt)("p",null,"Now to claim the asset using the secret text (pre-image of hash) ",(0,r.kt)("inlineCode",{parentName:"p"},"s"),", add following code snippet:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-kotlin"},'var hash: HashFunctions.Hash = HashFunctions.SHA512()\nhash.setPreimage(s)\nval issuer = <Issuer-party>\nval proxu = <CordaRPCOps-instance-created-using-credentials-of-claiming-party>\nval res = AssetManager.claimAssetInHTLC(\n proxy, \n contractId, // ContractId obtained during lock\n hash,\n AssetContract.Commands.Issue(), // Contract command for issuing/minting asset\n "com.cordaSimpleApplication.flow.UpdateAssetOwnerFromPointer", // full name of flow to update owner in asset state\n issuer,\n observers // Optional parameter for list of observers for this transaction\n) \n// return value is boolean indicating success or failure of claim \n')),(0,r.kt)("p",null,"The above function can be adapted to both ",(0,r.kt)("inlineCode",{parentName:"p"},"BondNetwork")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"TokenNetwork"),"."),(0,r.kt)("p",null,"If the asset has to be unlocked, use following code snippet:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-kotlin"},"val issuer = <Issuer-party>\nval proxu = <CordaRPCOps-instance-created-using-credentials-of-locking-party>\nval res = AssetManager.reclaimAssetInHTLC(\n rpc.proxy, \n contractId, // ContractId obtained during lock\n AssetContract.Commands.Issue(), // Contract command for issuing/minting asset\n issuer,\n observers // Optional parameter for list of observers for this transaction\n) \n// return value is boolean indicating success or failure of claim \n")),(0,r.kt)("h4",{id:"for-asset-transfer-1"},"For Asset Transfer"),(0,r.kt)("p",null,(0,r.kt)("em",{parentName:"p"},"TBD")),(0,r.kt)("h2",{id:"pre-configuration-phase"},"Pre-Configuration Phase"),(0,r.kt)("p",null,"No changes are required in your network's pre-configuration process for Weaver enablement."),(0,r.kt)("p",null,"Typically, pre-configuration involves:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Generating node folders for each participating node in the network, which contains CorDapps, certificates, persistence db, etc sub directories. Using Gradle task ",(0,r.kt)("inlineCode",{parentName:"li"},"net.corda.plugins.Cordform")," or ",(0,r.kt)("inlineCode",{parentName:"li"},"net.corda.plugins.Dockerform"),", the folders get created under the directory ",(0,r.kt)("inlineCode",{parentName:"li"},"build/nodes")," (this path is used in above sample code for Identity Service).\n"),(0,r.kt)("li",{parentName:"ul"},"The RPC address, username and password specified in above task will be used to create an instance of ",(0,r.kt)("inlineCode",{parentName:"li"},"CordaRPCOps"),", which is the first argument for most ",(0,r.kt)("inlineCode",{parentName:"li"},"weaver-corda-sdk")," static functions as we saw in previous section. For example, one of them is ",(0,r.kt)("inlineCode",{parentName:"li"},"InteroperableHelper.interopFlow"),":")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-kotlin"},"val response = InteroperableHelper.interopFlow(\n proxy, // CordaRPCOps instance to start flows\n viewAddress,\n <trade-finance-relay-url>[:<port>], // Replace with local network's relay address and port\n)\n")),(0,r.kt)("p",null,"Also, the Corda Driver (which we will setup in the following sections) needs a specific RPC user to be created, so make sure to add that in the Gradle task above, and note the credentials."),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Sample ",(0,r.kt)("inlineCode",{parentName:"li"},"net.corda.plugins.Dockerform")," task:")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-groovy"},'task prepareDockerNodes(type: net.corda.plugins.Dockerform, dependsOn: [\'jar\']) {\n def HOST_ADDRESS = "0.0.0.0"\n nodeDefaults {\n projectCordapp {\n deploy = false\n }\n }\n node {\n name "O=Notary,L=London,C=GB"\n notary = [validating : true]\n p2pPort 10004\n rpcSettings {\n address("$HOST_ADDRESS:10003")\n adminAddress("$HOST_ADDRESS:10005")\n }\n cordapps.clear()\n }\n node {\n name "O=PartyA,L=London,C=GB"\n p2pPort 10007\n rpcSettings {\n address("$HOST_ADDRESS:10003")\n adminAddress("$HOST_ADDRESS:10005")\n }\n rpcUsers = [\n [ user: "user1", "password": "test", "permissions": ["ALL"]],\n [ user: "driverUser1", "password": "test", "permissions": ["ALL"]]] // <-- Driver RPC User\n }\n node {\n name "O=PartyB,L=London,C=GB"\n p2pPort 10009\n rpcSettings {\n address("$HOST_ADDRESS:10003")\n adminAddress("$HOST_ADDRESS:10005")\n }\n rpcUsers = [\n [ user: "user1", "password": "test", "permissions": ["ALL"]],\n [ user: "driverUser1", "password": "test", "permissions": ["ALL"]]] // <-- Driver RPC User\n }\n}\n')),(0,r.kt)("h2",{id:"startup-and-bootstrap-phase"},"Startup and Bootstrap Phase"),(0,r.kt)("p",null,"To launch a network using containerized components, you will typically use a Docker Compose or Kubernetes configuration file. No modifications are needed to the node's configurations. Sample instructions are given below for networks launched using Docker Compose; we leave it to the reader to adapt these to their custom launch processes."),(0,r.kt)("h3",{id:"for-asset-exchange-2"},"For Asset Exchange"),(0,r.kt)("p",null,"The asset exchange mode currently requires only the Interoperation CorDapp module from Weaver. Relays, drivers are not necessary. In the future, we expect to make the asset exchange protocol moe automated using these components; the instructions here will be updated appropriately."),(0,r.kt)("h3",{id:"install-interoperation-cordapp-on-nodes"},"Install Interoperation CorDapp on Nodes"),(0,r.kt)("p",null,"After bootstrapping the nodes folder, copy the following two CorDapps in ",(0,r.kt)("inlineCode",{parentName:"p"},"build/nodes/PartyA/cordapps")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"build/nodes/PartyB/cordapps")," folders (",(0,r.kt)("inlineCode",{parentName:"p"},"PartyA")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"PartyB")," node names are for example only):"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/packages/906215"},"com.weaver.corda.app.interop.interop-contracts")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/packages/906216"},"com.weaver.corda.app.interop.interop-workflows"))),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:"left"},"You can follow any installation process for this CorDapp, but make sure it is installed on all the nodes that maintain the states involved in cross-network operations in their vaults.")))),(0,r.kt)("h3",{id:"for-data-sharing-or-asset-transfer"},"For Data Sharing or Asset Transfer"),(0,r.kt)("p",null,"Both the data sharing and asset transfer modes require the Interoperation CorDapp, relays, and drivers, to be deployed."),(0,r.kt)("h4",{id:"install-interoperation-cordapp-on-nodes-1"},"Install Interoperation CorDapp on Nodes"),(0,r.kt)("p",null,"After bootstrapping the nodes folder, copy the following two CorDapps in ",(0,r.kt)("inlineCode",{parentName:"p"},"build/nodes/PartyA/cordapps")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"build/nodes/PartyB/cordapps")," folders (",(0,r.kt)("inlineCode",{parentName:"p"},"PartyA")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"PartyB")," node names are for example only):"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/packages/906215"},"com.weaver.corda.app.interop.interop-contracts")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/packages/906216"},"com.weaver.corda.app.interop.interop-workflows"))),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:"left"},"You can follow any installation process for this CorDapp, but make sure it is installed on all the nodes that maintain the states involved in cross-network operations in their vaults.")))),(0,r.kt)("h4",{id:"launch-relay"},"Launch Relay"),(0,r.kt)("p",null,"You need to run one or more relays for network-to-network communication. Here we provide instructions to run one relay running in a Docker container, which is sufficient for data sharing. (Later, we will provide instructions to run multiple relays, which will be useful from a failover perspective.)"),(0,r.kt)("p",null,"Weaver provides a ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/pkgs/container/weaver-relay-server"},"pre-built image")," for the relay. Before launching a container, you just need to customize its configuration for your Fabric network, which you can do by simply creating a folder (let's call it ",(0,r.kt)("inlineCode",{parentName:"p"},"relay_config"),") and configuring the following files in it:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"p"},".env"),": This sets suitable environment variables within the relay container. Copy the ",(0,r.kt)("inlineCode",{parentName:"p"},".env.template")," file ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/core/relay/.env.template"},"from the repository")," and customize it for your purposes, as indicated in the below sample:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},'PATH_TO_CONFIG=./config.toml\nRELAY_NAME=<"name" in config.toml>\nRELAY_PORT=<relay-server-port/"port" in config.toml>\nEXTERNAL_NETWORK=<docker-bridge-network>\nDOCKER_REGISTRY=ghcr.io/hyperledger-labs\nDOCKER_IMAGE_NAME=weaver-relay\nDOCKER_TAG=1.5.4\n')),(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"The ",(0,r.kt)("inlineCode",{parentName:"li"},"PATH_TO_CONFIG")," variable should point to the properties file typically named ",(0,r.kt)("inlineCode",{parentName:"li"},"config.toml")," (you can name this whatever you wish). See further below for instructions to write this file."),(0,r.kt)("li",{parentName:"ul"},"The ",(0,r.kt)("inlineCode",{parentName:"li"},"RELAY_NAME")," variable specifies a unique name for this relay. It should match what's specified in the ",(0,r.kt)("inlineCode",{parentName:"li"},"config.toml")," (more on that below)."),(0,r.kt)("li",{parentName:"ul"},"The ",(0,r.kt)("inlineCode",{parentName:"li"},"RELAY_PORT")," variable specifies the port this relay server will listen on. It should match what's specified in the ",(0,r.kt)("inlineCode",{parentName:"li"},"config.toml")," (more on that below)."),(0,r.kt)("li",{parentName:"ul"},"The ",(0,r.kt)("inlineCode",{parentName:"li"},"EXTERNAL_NETWORK")," variable should be set to the ",(0,r.kt)("a",{parentName:"li",href:"https://docs.docker.com/compose/networking/"},"name")," of your Fabric network."),(0,r.kt)("li",{parentName:"ul"},"The ",(0,r.kt)("inlineCode",{parentName:"li"},"DOCKER_*")," variables are used to specify the image on which the container will be built. Make sure you set ",(0,r.kt)("inlineCode",{parentName:"li"},"DOCKER_TAG")," to the latest version you see on ",(0,r.kt)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/pkgs/container/weaver-relay-server"},"Github"),".")),(0,r.kt)("p",{parentName:"li"},"For more details, see the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/core/relay/relay-docker.md"},"Relay Docker README"),' ("Relay Server Image" and "Running With Docker Compose" sections).')),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"p"},"config.toml"),": This is the file specified in the ",(0,r.kt)("inlineCode",{parentName:"p"},"PATH_TO_CONFIG")," variable in the ",(0,r.kt)("inlineCode",{parentName:"p"},".env"),". It specifies properties of this relay and the driver(s) it supports. A sample is given below:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-toml",metastring:"showLineNumbers",showLineNumbers:!0},'name=<relay-name>\nport=<relay-port>\nhost="0.0.0.0"\ndb_path="db/<relay-name>/requests"\nremote_db_path="db/<relay-name>/remote_request"\n\n# FOR TLS\ncert_path="credentials/fabric_cert.pem"\nkey_path="credentials/fabric_key"\ntls=<true/false>\n\n[networks]\n[networks.<network-name>]\nnetwork="<driver-name>"\n\n[relays]\n[relays.<foreign-relay-name>]\nhostname="<foreign-relay-hostname-or-ip-address>"\nport="<foreign-relay-port>"\n\n[drivers]\n[drivers.<driver-name>]\nhostname="<driver-hostname-or-ip-address>"\nport="<driver-port>"\n')),(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"<relay-name>")," should be a unique ID representing this relay; e.g., ",(0,r.kt)("inlineCode",{parentName:"li"},"my_network_relay"),". It should match the ",(0,r.kt)("inlineCode",{parentName:"li"},"RELAY_NAME")," value in ",(0,r.kt)("inlineCode",{parentName:"li"},".env"),"."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"<relay-port>")," is the port number the relay server will listen on. It should match the ",(0,r.kt)("inlineCode",{parentName:"li"},"RELAY_PORT")," value in ",(0,r.kt)("inlineCode",{parentName:"li"},".env"),"."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"db_path")," and ",(0,r.kt)("inlineCode",{parentName:"li"},"remote_db_path")," are used internally by the relay to store data. Replace ",(0,r.kt)("inlineCode",{parentName:"li"},"<relay-name>")," with the same value set for the ",(0,r.kt)("inlineCode",{parentName:"li"},"name")," parameter. (These can point to any filesystem paths in the relay's container.)"),(0,r.kt)("li",{parentName:"ul"},"If you set ",(0,r.kt)("inlineCode",{parentName:"li"},"tls")," to ",(0,r.kt)("inlineCode",{parentName:"li"},"true"),", the relay will enforce TLS communication. The ",(0,r.kt)("inlineCode",{parentName:"li"},"cert_path")," and ",(0,r.kt)("inlineCode",{parentName:"li"},"key_path")," should point to a Fabric TLS certificate and key respectively, such as those created using the ",(0,r.kt)("inlineCode",{parentName:"li"},"cryptogen")," tool."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"<network-name>")," is a unique identifier for your local network. You can set it to whatever value you wish."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"<driver-name>")," refers to the driver used by this relay to respond to requests. This also refers to one of the drivers's specifications in the ",(0,r.kt)("inlineCode",{parentName:"li"},"drivers")," section further below. In this code snippet, we have defined one driver. (The names in lines 14 and 22 must match.) In lines 23 and 24 respectively, you should specify the hostname and port for the driver (whose configuration we will handle later)."),(0,r.kt)("li",{parentName:"ul"},"The ",(0,r.kt)("inlineCode",{parentName:"li"},"relays")," section specifies all foreign relays this relay can connect to. The ",(0,r.kt)("inlineCode",{parentName:"li"},"<foreign-relay-name>")," value should be a unique ID for a given foreign relay, and this value will be used by your Layer-2 applications when constructing view addresses for data sharing requests. In lines 18 and 19, you should specify the hostname and port for the foreign relay."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"Enabling TLS"),":",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"You can make your relay accept TLS connections by specifying a TLS certificate file path and private key file path in ",(0,r.kt)("inlineCode",{parentName:"li"},"cert_path")," and ",(0,r.kt)("inlineCode",{parentName:"li"},"key_path")," respectively, and set ",(0,r.kt)("inlineCode",{parentName:"li"},"tls")," to ",(0,r.kt)("inlineCode",{parentName:"li"},"true"),"."),(0,r.kt)("li",{parentName:"ul"},"To communicate with a foreign relay using TLS, specify that relay's TLS CA certificate path in ",(0,r.kt)("inlineCode",{parentName:"li"},"tlsca_cert_path")," (currently only one certificate can be configured) and set ",(0,r.kt)("inlineCode",{parentName:"li"},"tls")," to ",(0,r.kt)("inlineCode",{parentName:"li"},"true")," by extending that relay's section as follows (",(0,r.kt)("em",{parentName:"li"},"Note"),": this CA certificate should match the one specified in the ",(0,r.kt)("inlineCode",{parentName:"li"},"cert_path")," property in the foreign relay's ",(0,r.kt)("inlineCode",{parentName:"li"},"config.toml")," file):",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-toml"},'[relays]\n[relays.<foreign-relay-name>]\nhostname="<foreign-relay-hostname-or-ip-address>"\nport="<foreign-relay-port>"\ntls=<true|false>\ntlsca_cert_path="<relay-tls-ca-certificate-path>"\n'))),(0,r.kt)("li",{parentName:"ul"},"To communicate with a driver using TLS, specify the driver's TLS CA certificate in ",(0,r.kt)("inlineCode",{parentName:"li"},"tlsca_cert_path")," (currently only one certificate can be configured) and set ",(0,r.kt)("inlineCode",{parentName:"li"},"tls")," to ",(0,r.kt)("inlineCode",{parentName:"li"},"true")," by extending that driver's section as follows (",(0,r.kt)("em",{parentName:"li"},"Note"),": this CA certificate must match the certificate used by the driver using the ",(0,r.kt)("inlineCode",{parentName:"li"},"DRIVER_TLS_CERT_PATH")," property in its ",(0,r.kt)("inlineCode",{parentName:"li"},".env")," configuration file, which we will examine later):",(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-toml"},'[drivers]\n[drivers.<driver-name>]\nhostname="<driver-hostname-or-ip-address>"\nport="<driver-port>"\ntls=<true|false>\ntlsca_cert_path="<driver-tls-ca-certificate-path>"\n')))))),(0,r.kt)("table",{parentName:"li"},(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:"left"},"You can specify more than one foreign relay instance in the ",(0,r.kt)("inlineCode",{parentName:"td"},"relays")," section.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:"left"},"You can specify more than one driver instance in the ",(0,r.kt)("inlineCode",{parentName:"td"},"drivers")," section."))))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"p"},"docker-compose.yaml"),": This specifies the properties of the relay container. You can use the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/core/relay/docker-compose.yaml"},"file in the repository")," verbatim."))),(0,r.kt)("p",null,"To start the relay server, navigate to the folder containing the above files and run the following:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"docker-compose up -d relay-server\n")),(0,r.kt)("h4",{id:"launch-driver"},"Launch Driver"),(0,r.kt)("p",null,"You need to run one or more drivers through which your relay can interact with your Corda network. Here we provide instructions to run one Corda driver running in a Docker container, which is sufficient for data sharing. (Later, we will provide instructions to run multiple drivers, which will be useful both from a failover perspective and to interact with different subsets of your Corda network.)"),(0,r.kt)("p",null,"Weaver provides a ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/pkgs/container/weaver-corda-driver"},"pre-built image")," for the Corda driver. Before launching a container, you just need to customize the container configuration for your Corda network, which you can do by simply configuring the following:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"p"},".env"),": This sets suitable environment variables within the driver container. Copy the ",(0,r.kt)("inlineCode",{parentName:"p"},".env.template")," file ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/core/relay/.env.template"},"from the repository")," and customize it for your purposes, as indicated in the below sample:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},"NETWORK_NAME=<container-name-suffix>\nDRIVER_PORT=<driver-server-port>\nDRIVER_RPC_USERNAME=<driver-rpc-username>\nDRIVER_RPC_PASSWORD=<driver-rpc-username>\nEXTERNAL_NETWORK=<docker-bridge-network>\nDOCKER_IMAGE_NAME=ghcr.io/hyperledger-labs/weaver-corda-driver\nDOCKER_TAG=1.2.13\nRELAY_TLS=<true|false>\nRELAY_TLSCA_TRUST_STORE=<truststore-jks-file-path>\nRELAY_TLSCA_TRUST_STORE_PASSWORD=<truststore-jks-file-password>\nRELAY_TLSCA_CERT_PATHS=<colon-separated-CA-cert-paths>\nDRIVER_TLS=<true|false>\nDRIVER_TLS_CERT_PATH=<cert-path>\nDRIVER_TLS_KEY_PATH=<private-key-path>\n")),(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"NETWORK_NAME")," is only used as suffix for container and has no other significance."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"DRIVER_PORT")," variable should be set to the port this driver will listen on."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"DRIVER_RPC_USERNAME")," variable should be set to rpc user created ",(0,r.kt)("a",{parentName:"li",href:"#pre-configuration"},"above")," for the driver."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"DRIVER_RPC_PASSWORD")," variable should be set to password of above rpc user."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"EXTERNAL_NETWORK")," variable should be set to the ",(0,r.kt)("a",{parentName:"li",href:"https://docs.docker.com/compose/networking/"},"name")," of your Corda network."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"Enabling TLS"),":",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"You can make your driver accept TLS connections by specifying ",(0,r.kt)("inlineCode",{parentName:"li"},"DRIVER_TLS")," as ",(0,r.kt)("inlineCode",{parentName:"li"},"true")," and specifying a TLS certificate file path and private key file path in ",(0,r.kt)("inlineCode",{parentName:"li"},"DRIVER_TLS_CERT_PATH")," and ",(0,r.kt)("inlineCode",{parentName:"li"},"DRIVER_TLS_KEY_PATH")," respectively. The same certificate should be specified in this driver's definition in the ",(0,r.kt)("inlineCode",{parentName:"li"},"drivers")," section in the ",(0,r.kt)("inlineCode",{parentName:"li"},"config.toml")," file of your relay in the ",(0,r.kt)("inlineCode",{parentName:"li"},"tlsca_cert_path")," property (see the earlier section on relay configuration)."),(0,r.kt)("li",{parentName:"ul"},"To communicate with your network' relay using TLS (i.e., if the relay is TLS-enabled), specify that relay's TLS CA certificate path in ",(0,r.kt)("inlineCode",{parentName:"li"},"RELAY_TLSCA_CERT_PATH")," (currently only one certificate can be configured) and set ",(0,r.kt)("inlineCode",{parentName:"li"},"RELAY_TLS")," to ",(0,r.kt)("inlineCode",{parentName:"li"},"true"),". This CA certificate should match the one specified in the ",(0,r.kt)("inlineCode",{parentName:"li"},"cert_path")," property in the relay's ",(0,r.kt)("inlineCode",{parentName:"li"},"config.toml")," file (see the earlier section on relay configuration):"),(0,r.kt)("li",{parentName:"ul"},"You can point to the folder in your host system containing the certificate and key using the ",(0,r.kt)("inlineCode",{parentName:"li"},"TLS_CREDENTIALS_DIR")," variable. (This folder will be synced to the ",(0,r.kt)("inlineCode",{parentName:"li"},"/corda-driver/credentials")," folder in the Fabric Driver container as specified in the ",(0,r.kt)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/core/drivers/fabric-driver/docker-compose.yml"},"docker-compose file"),".) Make sure you point to the right certificate and key file paths within the container using the ",(0,r.kt)("inlineCode",{parentName:"li"},"DRIVER_TLS_CERT_PATH"),", ",(0,r.kt)("inlineCode",{parentName:"li"},"DRIVER_TLS_KEY_PATH"),", and ",(0,r.kt)("inlineCode",{parentName:"li"},"RELAY_TLSCA_CERT_PATH")," variables."))))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"p"},"docker-compose.yaml"),": This specifies the properties of the driver container. You can use the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/core/drivers/corda-driver/docker-compose.yml"},"file in the repository")," verbatim."))),(0,r.kt)("p",null,"To start the driver, navigate to the folder containing the above files and run the following:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"docker-compose up -d\n")),(0,r.kt)("h4",{id:"vault-initialization"},"Vault Initialization"),(0,r.kt)("p",null,"To prepare your network for interoperation with a foreign network, you need to record the following to your vault using the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/packages/952245"},"Corda SDK")," (",(0,r.kt)("inlineCode",{parentName:"p"},"com.weaver.corda.sdk"),"):"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("strong",{parentName:"p"},"Access control policies"),":\nLet's take the example of the request made from ",(0,r.kt)("inlineCode",{parentName:"p"},"trade-finance-network")," to ",(0,r.kt)("inlineCode",{parentName:"p"},"trade-logistics-network")," for a B/L earlier in this document. ",(0,r.kt)("inlineCode",{parentName:"p"},"trade-logistics-network")," can have a policy of the following form permitting access to the ",(0,r.kt)("inlineCode",{parentName:"p"},"GetBillOfLading")," function from a client representing the ",(0,r.kt)("inlineCode",{parentName:"p"},"PartyA")," node in ",(0,r.kt)("inlineCode",{parentName:"p"},"trade-finance-network")," as follows:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-json"},'{\n "securityDomain":"trade-finance-network",\n "rules":\n [\n {\n "principal":"<PartyA-certificate-pem>",\n "principalType":"certificate",\n "resource":"exporternode:10003;carriernode:10003#com.mynetwork.flow.GetBillOfLading:*",\n "read":true\n }\n ]\n}\n')),(0,r.kt)("p",{parentName:"li"},"In this sample, a single rule is specified for requests coming from ",(0,r.kt)("inlineCode",{parentName:"p"},"trade-finance-network"),": it states that a workflow call to ",(0,r.kt)("inlineCode",{parentName:"p"},"com.mynetwork.flow.GetBillOfLading")," made to ",(0,r.kt)("inlineCode",{parentName:"p"},"exporter")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"carrier")," nodes of remote Corda network is permitted for a requestor whose certificate is specified in the ",(0,r.kt)("inlineCode",{parentName:"p"},"principal")," attribute. The ",(0,r.kt)("inlineCode",{parentName:"p"},"*")," at the end indicates that any arguments passed to the function will pass the access control check. The ",(0,r.kt)("inlineCode",{parentName:"p"},"exporternode:10003")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"carriernode:10003")," are of form ",(0,r.kt)("inlineCode",{parentName:"p"},"<hostname/IP>:<RPC_Port>"),", for ",(0,r.kt)("inlineCode",{parentName:"p"},"exporter")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"carrier")," nodes respectively in the remote Corda network."),(0,r.kt)("p",{parentName:"li"},"You need to record this policy rule on your Corda network's vault by invoking either the ",(0,r.kt)("inlineCode",{parentName:"p"},"AccessControlPolicyManager.createAccessControlPolicyState")," function or the ",(0,r.kt)("inlineCode",{parentName:"p"},"AccessControlPolicyManager.updateAccessControlPolicyState")," function on the ",(0,r.kt)("inlineCode",{parentName:"p"},"weaver-corda-sdk"),"; use the former if you are recording a set of rules for the given ",(0,r.kt)("inlineCode",{parentName:"p"},"securityDomain")," for the first time and the latter to overwrite a set of rules recorded earlier. The above JSON needs to be converted to protobuf object of ",(0,r.kt)("inlineCode",{parentName:"p"},"com.weaver.protos.common.access_control.AccessControl.AccessControlPolicy"),", using google's protobuf library, and the object is the second argument of above functions (first being the instance of CordaRPCOps).")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("strong",{parentName:"p"},"Verification policies"),":\nTaking the same example as above, an example of a verification policy for a B/L requested by the ",(0,r.kt)("inlineCode",{parentName:"p"},"trade-finance-network")," from the ",(0,r.kt)("inlineCode",{parentName:"p"},"trade-logistics-network")," is as follows:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-json"},'{\n "securityDomain":"trade-logistics-network",\n "identifiers":\n [\n {\n "pattern":"tradelogisticschannel:shipmentcc:GetBillOfLading:*",\n "policy":\n {\n "type":"Signature",\n "criteria":\n [\n "ExporterMSP",\n "CarrierMSP"\n ]\n }\n }\n ]\n}\n')),(0,r.kt)("p",{parentName:"li"},"In this sample, a single verification policy rule is specified for data views coming from ",(0,r.kt)("inlineCode",{parentName:"p"},"trade-logistics-network"),": it states that the data returned by the ",(0,r.kt)("inlineCode",{parentName:"p"},"GetBillOfLading")," query made to the ",(0,r.kt)("inlineCode",{parentName:"p"},"shipmentcc")," chaincode on the ",(0,r.kt)("inlineCode",{parentName:"p"},"tradelogisticschannel")," channel requires as proof two signatures, one from a peer in the organization whose MSP ID is ",(0,r.kt)("inlineCode",{parentName:"p"},"ExporterMSP")," and another from a peer in the organization whose MSP ID is ",(0,r.kt)("inlineCode",{parentName:"p"},"CarrierMSP"),"."),(0,r.kt)("table",{parentName:"li"},(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:"left"},"If the remote network is built on Corda, the resource specified in the access control policy can be used here as the ",(0,r.kt)("inlineCode",{parentName:"td"},"pattern"),", with different node names specified in the ",(0,r.kt)("inlineCode",{parentName:"td"},"criteria"),".")))),(0,r.kt)("p",{parentName:"li"},"You need to record this policy rule on your Corda network's vault by invoking Corda sdk's function ",(0,r.kt)("inlineCode",{parentName:"p"},"VerificationPolicyManager.createVerificationPolicyState(proxy, verificationPolicyProto)"),", where ",(0,r.kt)("inlineCode",{parentName:"p"},"proxy")," is an instance of ",(0,r.kt)("inlineCode",{parentName:"p"},"CordaRPCOps")," as described in previous sections, and ",(0,r.kt)("inlineCode",{parentName:"p"},"verificationPolicyProto")," is an object of protobuf ",(0,r.kt)("inlineCode",{parentName:"p"},"com.weaver.protos.common.verification_policy.VerificationPolicyOuterClass.VerificationPolicy"),". You can examine the full proto structure ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/common/protos/common/verification_policy.proto"},"here"),". (",(0,r.kt)("em",{parentName:"p"},"Google's protobuf library can be used to convert above JSON to protobuf object."),")"),(0,r.kt)("table",{parentName:"li"},(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:"left"},"For any cross-network data request, make sure an access control policy is recorded in the ",(0,r.kt)("em",{parentName:"td"},"source network")," (",(0,r.kt)("inlineCode",{parentName:"td"},"trade-logistics-network")," in the above example) and a corresponding verification policy is recorded in the ",(0,r.kt)("em",{parentName:"td"},"destination network")," (",(0,r.kt)("inlineCode",{parentName:"td"},"trade-finance-network")," in the above example) before any relay request is triggered."))))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("strong",{parentName:"p"},"Foreign network security domain (membership) configuration"),":\nRun the following procedure (pseudocode) to record security domain configuration for every foreign network you wish your Corda network to interoperate with (you will need to collect the identity service URLs for all the foreign networks first):"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},"for each foreign network:\n send an HTTP GET request to the network's identity service (using 'curl' or 'wget' from a shell script or equivalent programming language APIs).\n convert the response string to protobuf object of 'com.weaver.protos.common.membership.MembershipOuterClass.Membership'.\n invoke 'MembershipManager.createMembershipState(proxy, membershipProto)' or 'MembershipManager.updateMembershipState(proxy, membershipProto)' on Corda sdk.\n")),(0,r.kt)("p",{parentName:"li"},"As in the above two cases, use ",(0,r.kt)("inlineCode",{parentName:"p"},"createMembershipState")," to record a confiuration for the first time for a given ",(0,r.kt)("inlineCode",{parentName:"p"},"securityDomain")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"updateMembershipState")," to overwrite a configuration."),(0,r.kt)("table",{parentName:"li"},(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:"left"},"Security domain configurations (organization lists and their certificate chains) for any Fabric/Corda network are subject to change, so you should run the above procedure periodically in a loop.")))))),(0,r.kt)("p",null,"Your Corda network is now up and running with the necessary Weaver components, and your network's vault is bootstrapped with the initial configuration necessary for cross-network interactions!"))}m.isMDXComponent=!0},4610:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/corda-network-model-2e962213e430d787a71559bf2d647f88.png"},318:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/corda-weaver-model-8cd8e458ac29201d610bf4c5f2a99a8c.png"}}]); \ No newline at end of file diff --git a/assets/js/f0c74005.4262dd1c.js b/assets/js/f0c74005.4262dd1c.js new file mode 100644 index 000000000..2c42f529f --- /dev/null +++ b/assets/js/f0c74005.4262dd1c.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[8454],{5680:(e,n,a)=>{a.d(n,{xA:()=>d,yg:()=>y});var t=a(6540);function r(e,n,a){return n in e?Object.defineProperty(e,n,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[n]=a,e}function i(e,n){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var t=Object.getOwnPropertySymbols(e);n&&(t=t.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),a.push.apply(a,t)}return a}function o(e){for(var n=1;n<arguments.length;n++){var a=null!=arguments[n]?arguments[n]:{};n%2?i(Object(a),!0).forEach((function(n){r(e,n,a[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(a)):i(Object(a)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(a,n))}))}return e}function l(e,n){if(null==e)return{};var a,t,r=function(e,n){if(null==e)return{};var a,t,r={},i=Object.keys(e);for(t=0;t<i.length;t++)a=i[t],n.indexOf(a)>=0||(r[a]=e[a]);return r}(e,n);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(t=0;t<i.length;t++)a=i[t],n.indexOf(a)>=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var s=t.createContext({}),p=function(e){var n=t.useContext(s),a=n;return e&&(a="function"==typeof e?e(n):o(o({},n),e)),a},d=function(e){var n=p(e.components);return t.createElement(s.Provider,{value:n},e.children)},c="mdxType",g={inlineCode:"code",wrapper:function(e){var n=e.children;return t.createElement(t.Fragment,{},n)}},m=t.forwardRef((function(e,n){var a=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),c=p(a),m=r,y=c["".concat(s,".").concat(m)]||c[m]||g[m]||i;return a?t.createElement(y,o(o({ref:n},d),{},{components:a})):t.createElement(y,o({ref:n},d))}));function y(e,n){var a=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var i=a.length,o=new Array(i);o[0]=m;var l={};for(var s in n)hasOwnProperty.call(n,s)&&(l[s]=n[s]);l.originalType=e,l[c]="string"==typeof e?e:r,o[1]=l;for(var p=2;p<i;p++)o[p]=a[p];return t.createElement.apply(null,o)}return t.createElement.apply(null,a)}m.displayName="MDXCreateElement"},2051:(e,n,a)=>{a.r(n),a.d(n,{assets:()=>s,contentTitle:()=>o,default:()=>g,frontMatter:()=>i,metadata:()=>l,toc:()=>p});var t=a(8168),r=(a(6540),a(5680));const i={id:"corda",title:"Corda"},o=void 0,l={unversionedId:"external/getting-started/enabling-weaver-network/corda",id:"external/getting-started/enabling-weaver-network/corda",title:"Corda",description:"\x3c!--",source:"@site/docs/external/getting-started/enabling-weaver-network/corda.md",sourceDirName:"external/getting-started/enabling-weaver-network",slug:"/external/getting-started/enabling-weaver-network/corda",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/corda",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/getting-started/enabling-weaver-network/corda.md",tags:[],version:"current",frontMatter:{id:"corda",title:"Corda"},sidebar:"Documentation",previous:{title:"Hyperledger Fabric",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/fabric"},next:{title:"Hyperledger Besu",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/besu"}},s={},p=[{value:"Model",id:"model",level:2},{value:"Procedural Overview",id:"procedural-overview",level:2},{value:"Development Phase",id:"development-phase",level:2},{value:"CorDapp",id:"cordapp",level:3},{value:"For Data Sharing",id:"for-data-sharing",level:4},{value:"For Asset Exchange",id:"for-asset-exchange",level:4},{value:"For Asset Transfer",id:"for-asset-transfer",level:4},{value:"Contracts CorDapp",id:"contracts-cordapp",level:3},{value:"Client Layer applications",id:"client-layer-applications",level:2},{value:"For Identity Administration",id:"for-identity-administration",level:4},{value:"For Data Sharing",id:"for-data-sharing-1",level:4},{value:"For Asset exchange",id:"for-asset-exchange-1",level:4},{value:"For Asset Transfer",id:"for-asset-transfer-1",level:4},{value:"Pre-Configuration Phase",id:"pre-configuration-phase",level:2},{value:"Startup and Bootstrap Phase",id:"startup-and-bootstrap-phase",level:2},{value:"For Asset Exchange",id:"for-asset-exchange-2",level:3},{value:"Install Interoperation CorDapp on Nodes",id:"install-interoperation-cordapp-on-nodes",level:3},{value:"For Data Sharing or Asset Transfer",id:"for-data-sharing-or-asset-transfer",level:3},{value:"Install Interoperation CorDapp on Nodes",id:"install-interoperation-cordapp-on-nodes-1",level:4},{value:"Launch Relay",id:"launch-relay",level:4},{value:"Launch Driver",id:"launch-driver",level:4},{value:"Vault Initialization",id:"vault-initialization",level:4}],d={toc:p},c="wrapper";function g(e){let{components:n,...i}=e;return(0,r.yg)(c,(0,t.A)({},d,i,{components:n,mdxType:"MDXLayout"}),(0,r.yg)("p",null,"After testing the Weaver interoperation mechanisms on ",(0,r.yg)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/overview"},"basic sample networks"),", you may be interested in finding out how you can equip an existing real network, whether in development or in production, to exercise these mechanisms. In this document, we will demonstrate how to equip a Corda network and application with Weaver components and capabilities."),(0,r.yg)("h2",{id:"model"},"Model"),(0,r.yg)("p",null,"The figure below illustrates a typical Corda network. The infrastructure consists of a set of nodes (each maintaining its share of the global state in a local vault), notaries, and CAs. On the nodes are installed one or more CorDapps, representing shared business logic across subsets of those nodes. The core of a CorDapp consists of a collection of workflows (or flows) and contracts acting on states; we layer the flows above the contracts in thebelow image just to illustrate that flows represent transaction (state update) triggers, and contract validations occur during the executions of flows. Further up in the stack lie client applications associated with CorDapps that can are used to trigger flows (and by implication, contracts)."),(0,r.yg)("p",null,(0,r.yg)("img",{alt:"alt text",src:a(6559).A,width:"1255",height:"681"})),(0,r.yg)("p",null,"Such a network equipped with Weaver components and capabilities will look like the figure below. Legacy components are marked in grey and Weaver and bridging components in green."),(0,r.yg)("p",null,(0,r.yg)("img",{alt:"alt text",src:a(1645).A,width:"1791",height:"682"})),(0,r.yg)("p",null,"The relay and driver are the only additional infrastructure that need to be installed. One or more relays can be installed, as can one or more drivers. The drivers are illustrated in the client layer rather than in the bottom layer because, though they are coupled with relays, they trigger flows just like any client application does."),(0,r.yg)("p",null,"Existing CorDapp flows and contracts deployed on the network's nodes remain undisturbed. All that is required is the deployment of an Interoperation CorDapp (flows and contracts) on every node that needs to offer or consume state from foreign networks."),(0,r.yg)("p",null,"Client applications will need some additional code and configuration because the decisions to exercise interoperation mechanisms (relay queries for data sharing or atomic asset exchanges) are strictly part of business logic. But Weaver's Corda Interoperation Java-Kotlin SDK offers various helper functions to ease this process and keep the adaptation to a minimum, as we wil see later in this document. Finally, an ",(0,r.yg)("em",{parentName:"p"},"identity service")," must be offered by the network to expose its CAs' certificate chains to foreign networks, thereby laying the basis for interoperation. This service simply needs to offer a REST endpoint, and can be implemented as a standalone application or (more conveniently) as an augmentation of one or more of the existing client layer applications."),(0,r.yg)("h2",{id:"procedural-overview"},"Procedural Overview"),(0,r.yg)("p",null,"A Corda network is typically created in phases, in the following sequence:"),(0,r.yg)("ol",null,(0,r.yg)("li",{parentName:"ol"},(0,r.yg)("strong",{parentName:"li"},"Development"),": This involves writing CorDapp which consists of contracts and workflows, and client layer applications. The cordapp's deployment name/ID and its transaction API must be designed first, but subsequent development of the two layers of applications can then proceed parallelly."),(0,r.yg)("li",{parentName:"ol"},(0,r.yg)("strong",{parentName:"li"},"Pre-Configuration"),": This involves creating a desired specification (as a set of configuration diles) of the network topology and the ledgers it maintains."),(0,r.yg)("li",{parentName:"ol"},(0,r.yg)("strong",{parentName:"li"},"Startup and Bootstrap"),": This is the launch phase, in which the network components and applications are started and bootstrapped (i.e., configured with initial state and operating rules).")),(0,r.yg)("p",null,"Assuming that the reader is familiar with this procedure, we will walk through the changes required in each phase to make your network ready for interoperation using Weaver components and code templates. This will involve code addition and adaptation, deployment of additional modules, additional configuration, and creation of additional ledger state records. The requirements and effort will vary with the mode of interoperation you wish to support in your Fabric network."),(0,r.yg)("h2",{id:"development-phase"},"Development Phase"),(0,r.yg)("p",null,"A Corda distributed application's business logic code spans three layers as illustrated in the network model:"),(0,r.yg)("h3",{id:"cordapp"},"CorDapp"),(0,r.yg)("p",null,"CorDapps (Corda Distributed Applications) are distributed applications that run on the Corda platform. The goal of a CorDapp is to allow nodes to reach agreement on updates to the ledger. They achieve this goal by defining flows that Corda node owners can invoke over RPC."),(0,r.yg)("h4",{id:"for-data-sharing"},"For Data Sharing"),(0,r.yg)("p",null,"No code changes are required for Weaver enablement, because data sharing involves:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"View packaging (and optionally, encryption) logic and access control logic in a source network, and"),(0,r.yg)("li",{parentName:"ul"},"View validation logic in a destination network")),(0,r.yg)("p",null,"This logic is standard and independent of contract, workflow, and state, particulars. It is already implemented in the Interoperation CorDapp offered by Weaver. Hence you just need to deploy that CorDapp to exercise data sharing from, or to, your application CorDapp. Your application CorDapp can be oblivious of the Interoperation CorDapp's workings and of the view request-response protocol."),(0,r.yg)("h4",{id:"for-asset-exchange"},"For Asset Exchange"),(0,r.yg)("p",null,"To exchange an asset using Weaver, the asset's state on the ledger must be controlled in the following ways:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Locked in favor of a party"),(0,r.yg)("li",{parentName:"ul"},"Claimed by the party to whom the asset is pledged"),(0,r.yg)("li",{parentName:"ul"},"Returned to the original owner if it is not claimed within a given timeframe")),(0,r.yg)("p",null,"In addition, the state of the asset (i.e., whether it is locked), and its current and targeted owners, must be determinable by looking at the ledger records."),(0,r.yg)("p",null,"The bookkeeping logic required to maintain records of locks can be abstracted away from the particulars of a digital asset and its workflow. But as such assets and their properties (including ownership) can be, and are, encoded in an arbitrary number of ways, we cannot provide a one-size-fits all set of functions (like in the data sharing protocol) to exchange any kind of asset. Instead, we must rely on the application CorDapp managing an asset, as it knows precisely what the asset's properties are and how they can be updated and queried on the ledger."),(0,r.yg)("p",null,"What Weaver offers, therefore, is the following:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Lock management logic implemented in the Interoperation CorDapp that treats each asset as an abstract object (an instance of generic corda's ",(0,r.yg)("inlineCode",{parentName:"li"},"ContractState"),") and is agnostic of the assets' internals. It consumes (burns) the asset state and creates a new ",(0,r.yg)("inlineCode",{parentName:"li"},"HTLC")," state that indicates that the asset is locked, while in claim and unlock new asset state is created (minted) with appropriate owner while consuming ",(0,r.yg)("inlineCode",{parentName:"li"},"HTLC")," state. This logic can be exercised in by installing Interoperation CorDapp on the nodes."),(0,r.yg)("li",{parentName:"ul"},"A set of template functions with sample (and extensible) code that must be added to the application CorDapp to augment the above lock management functions.")),(0,r.yg)("p",null,"Below, we list the template functions with sample code that you, as a developer, must use and adapt within your CorDapp."),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Flow to get Asset State"),": For non-fungible assets, create a flow like:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-kotlin"},"class RetrieveStateAndRef(\n val type: String, \n val id: String\n): FlowLogic<StateAndRef<AssetState>>\n")),"And for fungible assets, create a flow like:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-kotlin"},"class RetrieveStateAndRef(\n val type: String, \n val quantity: Long\n): FlowLogic<StateAndRef<AssetState>>\n")),"The name of these flows can be anything, but the parameters should be same, and return type should ",(0,r.yg)("inlineCode",{parentName:"li"},"StateAndRef"),". These flows are supposed to get the ",(0,r.yg)("inlineCode",{parentName:"li"},"StateAndRef")," object to the asset state that has to be locked, which can be identified by ",(0,r.yg)("inlineCode",{parentName:"li"},"type")," and ",(0,r.yg)("inlineCode",{parentName:"li"},"id")," for non-fungible assets, and ",(0,r.yg)("inlineCode",{parentName:"li"},"type")," and ",(0,r.yg)("inlineCode",{parentName:"li"},"quantity")," for fungible assets."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Flow to update owner in asset state"),": Create a flow like:",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-kotlin"},"class UpdateOwnerFromPointer(\n val statePointer: StaticPointer<AssetState>\n) : FlowLogic<AssetState>()\n")),"Again the name can be anything but the function parameter should be same, i.e. take a ",(0,r.yg)("inlineCode",{parentName:"li"},"StaticPointer")," and return the ",(0,r.yg)("inlineCode",{parentName:"li"},"ContractState")," of the asset involved in asset exchange. This flow is supposed to resolve the ",(0,r.yg)("inlineCode",{parentName:"li"},"StaticPointer")," to actual asset, and update the owner of this asset to the caller of this flow.")),(0,r.yg)("h4",{id:"for-asset-transfer"},"For Asset Transfer"),(0,r.yg)("p",null,(0,r.yg)("em",{parentName:"p"},"TBD")),(0,r.yg)("h3",{id:"contracts-cordapp"},"Contracts CorDapp"),(0,r.yg)("p",null,"No code changes are required for Weaver enablement. For asset exchange, Weaver assumes that application CorDapp that manages assets must already have a asset creation (mint) contract command and asset deletion (burn) contract command, which can be invoked when ",(0,r.yg)("inlineCode",{parentName:"p"},"Issuer")," party is involved in the transaction."),(0,r.yg)("h2",{id:"client-layer-applications"},"Client Layer applications"),(0,r.yg)("p",null,"Weaver provides an SDK to help you adapt your applications to exercise the various interoperability modes. These are called out as ",(0,r.yg)("strong",{parentName:"p"},"SDK Helpers")," in the network model illustrated earlier. Your Corda network's Client layer applications have business logic embedded in them that, broadly speaking, accept data from users and other external agents and invoke workflows from CorDapp over RPC. When you use Weaver for network interoperability, other options can be added, namely requesting and accepting data from foreign networks, and triggering locks and claims for atomic exchanges spanning two networks. Weaver's Corda Interoperation SDK offers a library to exercise these options. But this will involve modification to the application's business logic.\nTo use Weaver's Corda SDK, you need to create a ",(0,r.yg)("a",{parentName:"p",href:"https://docs.github.com/en/github/authenticating-to-github/keeping-your-account-and-data-secure/creating-a-personal-access-token"},"personal access token")," with ",(0,r.yg)("inlineCode",{parentName:"p"},"read:packages")," access in GitHub, to access Weaver packages.\nYou also need to add the following to your application's ",(0,r.yg)("inlineCode",{parentName:"p"},"build.gradle")," file:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-groovy"},"repositories {\n maven {\n url https://maven.pkg.github.com/hyperledger-labs/weaver-dlt-interoperability\n credentials {\n username <github-email>\n password <github-personal-access-token>\n }\n }\n}\ndependencies {\n implementation(group: 'com.weaver.corda.sdk', name: 'weaver-corda-sdk', version: \"1.2.13\")\n implementation(group: 'com.weaver.corda.app.interop', name: 'interop-contracts', version: \"1.2.13\")\n implementation(group: 'com.weaver.corda.app.interop', name: 'interop-workflows', version: \"1.2.13\")\n implementation(group: 'com.weaver', name: 'protos-java-kt', version: \"1.5.7\")\n}\n")),(0,r.yg)("p",null,"(Or check out the ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/packages/952245"},"package website")," and select a different version.)"),(0,r.yg)("h4",{id:"for-identity-administration"},"For Identity Administration"),(0,r.yg)("p",null,"A Corda network needs to share its security domain (or membership) configuration, i.e., its nodes' CA certificate chains, with a foreign network with which it seeks to interoperate. Though such sharing can be implemented using several different mechanisms, ranging from manual to automated, the simplest and most modular way is to expose a REST endpoint that agents in foreign networks can reach. Further, this REST endpoint can be implemented as a standalone web application or it can be an extension of one or more of the existing client layer applications. (Multiple apps can expose the same endpoint serving the same information for redundancy.) We will demonstrate an example of this while leaving other implementation modes to the user.\nLet's say a Corda network consists of two nodes called ",(0,r.yg)("inlineCode",{parentName:"p"},"PartyA")," and ",(0,r.yg)("inlineCode",{parentName:"p"},"PartyB"),", each running a client layer application with a web server whose URL prefixes are ",(0,r.yg)("inlineCode",{parentName:"p"},"http://partya.mynetwork.com:9000")," and ",(0,r.yg)("inlineCode",{parentName:"p"},"http://partyb.mynetwork.com:9000")," respectively. Each app then can expose a REST endpoint (again, as an example) ",(0,r.yg)("inlineCode",{parentName:"p"},"http://partya.mynetwork.com:9000/node_sec_grp")," and ",(0,r.yg)("inlineCode",{parentName:"p"},"http://partyb.mynetwork.com:9000/node_sec_grp")," respectively.\nAt each web server's backend, you need to implement logic to retrieve the node's ID and it's associated certificated chains. Sample code is given below for a Kotlin implementation built on ",(0,r.yg)("inlineCode",{parentName:"p"},"weaver-corda-sdk"),". You can use this code verbatim, except for some minor changes like ",(0,r.yg)("inlineCode",{parentName:"p"},"<path-to-root-corda-net-folder>"),", other parameters like security domain, and list of names of nodes as appropriate for your environment:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-kotlin"},'import com.weaver.corda.sdk.CredentialsCreator\nimport com.google.protobuf.util.JsonFormat\n\n\n@RestController\n@CrossOrigin\n@RequestMapping("/") // The paths for HTTP requests are relative to this base path.\nclass Controller {\n // Expose "node_sec_grp" endpoint using Rest Controller\n @RequestMapping(value = ["/node_sec_grp"], method = arrayOf(RequestMethod.GET), produces = arrayOf("application/json"))\n private fun GetNetworkConfig(): String {\n val jsonPrinter = JsonFormat.printer().includingDefaultValueFields()\n \n val credentialsCreator = CredentialsCreator(\n "<path-to-root-corda-net-folder>/build/nodes",\n "mynetwork", // security domain name\n ["PartyA", "PartyB"], // list of nodes \n "", \n ""\n )\n \n // Generate Membership\n val membership = credentialsCreator.createMembership()\n return jsonPrinter.print(membership)\n }\n}\n')),(0,r.yg)("p",null,"An agent from a foreign network can query either ",(0,r.yg)("inlineCode",{parentName:"p"},"http://partya.mynetwork.com:9000/sec_group")," or ",(0,r.yg)("inlineCode",{parentName:"p"},"http://partyb.mynetwork.com:9000/sec_group")," and obtain the security domain (or membership) configuration of the entire network."),(0,r.yg)("h4",{id:"for-data-sharing-1"},"For Data Sharing"),(0,r.yg)("p",null,"Consider a scenario inspired by the ",(0,r.yg)("a",{parentName:"p",href:"/weaver-dlt-interoperability/docs/external/user-stories/global-trade"},"global trade use case")," where a letter of credit (L/C) management business logic is installed in the ",(0,r.yg)("inlineCode",{parentName:"p"},"trade-finance-network")," network, supports a flow named ",(0,r.yg)("inlineCode",{parentName:"p"},"UploadBillOfLading"),", which validates and records a bill of lading (B/L) supplied by a user via a UI. Weaver will enable such a B/L to be fetched from a different network ",(0,r.yg)("inlineCode",{parentName:"p"},"trade-logistics-network")," by querying the function ",(0,r.yg)("inlineCode",{parentName:"p"},"GetBillOfLading")," exposed by the chaincode ",(0,r.yg)("inlineCode",{parentName:"p"},"shipmentcc")," installed in the ",(0,r.yg)("inlineCode",{parentName:"p"},"tradelogisticschannel")," channel (",(0,r.yg)("em",{parentName:"p"},"The trade logistics network can be built on Corda as well. The steps for Weaver-enablement will mostly be the same, with the exception of view address creation logic. Here, for demonstration purposes, we assume that that counter-party network is built on Fabric"),")."),(0,r.yg)("p",null,"(In preparation, a suitable access control policy must be recorded on ",(0,r.yg)("inlineCode",{parentName:"p"},"tradelogisticschannel")," in ",(0,r.yg)("inlineCode",{parentName:"p"},"trade-logistics-network"),", and a suitable verification policy must be recorded in the vault of ",(0,r.yg)("inlineCode",{parentName:"p"},"trade-finance-network"),". We will see how to do this in the ",(0,r.yg)("a",{parentName:"p",href:"#startup-and-bootstrap-weaver-components"},"Startup and Bootstrap Weaver Components")," section later.)"),(0,r.yg)("p",null,"You will need to insert some code in the client layer application that accepts a B/L and submits a ",(0,r.yg)("inlineCode",{parentName:"p"},"UploadBillOfLading")," request in ",(0,r.yg)("inlineCode",{parentName:"p"},"trade-finance-network"),". (No code changes need to be made in any application in the other network.) The logic to accept a B/L should be replaced (or you can simply add an alternative) by a call to the ",(0,r.yg)("inlineCode",{parentName:"p"},"InteroperableHelper.interopFlow")," function offered by the ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/packages/952245"},"weaver-corda-sdk")," library. The following code sample illustrates this:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-kt"},"import com.weaver.corda.sdk.InteroperableHelper\nimport com.mynetwork.flow.UploadBillOfLading\n\nval viewAddress = InteroperableHelper.createFabricViewAddress(\n 'trade-logistics-network', // Security Domain/Group\n <trade-logistics-relay-url[:<port>], // Replace with remote network's relay\n 'tradelogisticschannel', // Remote network's channel\n 'shipmentcc', // Remote network's cc\n 'GetBillOfLading', // Remote network's cc Fun\n [ <shipment-reference> ] // Replace <shipment-reference> with a value that can be used to look up the right B/L\n)\ntry {\n val response = InteroperableHelper.interopFlow(\n proxy, // CordaRPCOps instance to start flows\n viewAddress,\n <trade-finance-relay-url>[:<port>] // Replace with local network's relay address and port\n ).fold({\n println(\"Error in Interop Flow: ${it.message}\")\n }, {\n val linearId = it.toString()\n val BoLString = InteroperableHelper.getExternalStatePayloadString(\n proxy,\n linearId\n )\n val result = proxy.startFlow(::UploadBillOfLading, BoLString)\n println(\"$result\")\n }\n} catch (e: Exception) {\n println(\"Error: ${e.toString()}\")\n}\n")),(0,r.yg)("p",null,"Let us understand this code snippet better. The function ",(0,r.yg)("inlineCode",{parentName:"p"},"UploadBillOfLading")," expects one argument, the bill of lading contents. The ",(0,r.yg)("inlineCode",{parentName:"p"},"InteroperableHelper.createFabricViewAddress")," is used to create view address that is to passed to ",(0,r.yg)("inlineCode",{parentName:"p"},"InteroperableHelper.interopFlow")," function. The equivalent function to create a view address for a remote Corda network is ",(0,r.yg)("inlineCode",{parentName:"p"},"InteroperableHelper.createCordaViewAddress"),". "),(0,r.yg)("p",null,"The rest of the code ought to be self-explanatory. Values are hardcoded for explanation purposes."),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},"Enabling TLS"),":\nBy default, the TLS is set to false in ",(0,r.yg)("inlineCode",{parentName:"p"},"interopFlow"),", i.e. disabled. But if you want to enable TLS, can pass additional parameters to the ",(0,r.yg)("inlineCode",{parentName:"p"},"interopFlow")," function as follows:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-kt"},"val response = InteroperableHelper.interopFlow(\n proxy, // CordaRPCOps instance to start flows\n viewAddress,\n <trade-finance-relay-url>[:<port>], // Replace with local network's relay address and port\n 'trade-finance-network', // Local network name (destination)\n true, // Boolean indication TLS is enabled.\n <relayTlsTrustStorePath> // JKS file path containing relay server TLS CA certificates\n <relayTlsTrustStorePassword>, // password used to create the JKS file\n)\n")),(0,r.yg)("p",null,"OR"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-kt"},"val response = InteroperableHelper.interopFlow(\n proxy, // CordaRPCOps instance to start flows\n viewAddress,\n <trade-finance-relay-url>[:<port>], // Replace with local network's relay address and port\n 'trade-finance-network', // Local network name (destination)\n true, // Boolean indication TLS is enabled.\n <tlsCACertPathsForRelay>, // colon-separated list of CA certificate file paths\n)\n")),(0,r.yg)("h4",{id:"for-asset-exchange-1"},"For Asset exchange"),(0,r.yg)("p",null,"Let's take an example of asset exchange between ",(0,r.yg)("inlineCode",{parentName:"p"},"Alice")," and ",(0,r.yg)("inlineCode",{parentName:"p"},"Bob"),", where Bob wants to purchase an asset of type ",(0,r.yg)("inlineCode",{parentName:"p"},"Gold")," with id ",(0,r.yg)("inlineCode",{parentName:"p"},"A123")," from ",(0,r.yg)("inlineCode",{parentName:"p"},"Alice")," in ",(0,r.yg)("inlineCode",{parentName:"p"},"BondNetwork")," in exchange for ",(0,r.yg)("inlineCode",{parentName:"p"},"200")," tokens of type ",(0,r.yg)("inlineCode",{parentName:"p"},"CBDC01")," in ",(0,r.yg)("inlineCode",{parentName:"p"},"TokenNetwork"),"."),(0,r.yg)("p",null,(0,r.yg)("inlineCode",{parentName:"p"},"Alice")," needs to select a secret text (say ",(0,r.yg)("inlineCode",{parentName:"p"},"s"),"), and hash it (say ",(0,r.yg)("inlineCode",{parentName:"p"},"H"),") using say ",(0,r.yg)("inlineCode",{parentName:"p"},"SHA512"),", which will be used to lock her asset in ",(0,r.yg)("inlineCode",{parentName:"p"},"BondNetwork"),". To lock the non-fungible asset using hash ",(0,r.yg)("inlineCode",{parentName:"p"},"H")," and timeout duration of 10 minutes, you need to add following code snippet in your application:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-kotlin"},'import com.weaver.corda.sdk.AssetManager\nimport com.weaver.corda.sdk.HashFunctions\n\nvar hash: HashFunctions.Hash = HashFunctions.SHA512\nhash.setSerializedHashBase64(H)\nval proxy = <CordaRPCOps-instance-created-using-credentials-of-Alice-in-BondNetwork>\nval issuer = <Issuer-party-in-BondNetwork>\nval recipient = <Bob-party-in-BondNetwork>\nval contractId = AssetManager.createHTLC(\n proxy, \n "Gold", // Type\n "A123", // ID\n recipient, \n hash, \n 10L, // Duration tmeout in secs, L denotes Long\n 1, // 1 if timeout is Duration, 0 if timeout is in absolute epochs\n "com.cordaSimpleApplication.flow.RetrieveStateAndRef", // full name of "Flow to get Asset State"\n AssetContract.Commands.Delete(), // Contract command for Asset to Burn/Delete the state\n issuer,\n observers // Optional parameter for list of observers for this transaction\n)\n')),(0,r.yg)("p",null,"Now ",(0,r.yg)("inlineCode",{parentName:"p"},"Bob")," will lock his tokens in ",(0,r.yg)("inlineCode",{parentName:"p"},"TokenNetwork"),". To lock the fungible asset using same hash ",(0,r.yg)("inlineCode",{parentName:"p"},"H")," and timeout of 5 minutes (half the timeout duration used by Alice in ",(0,r.yg)("inlineCode",{parentName:"p"},"BondNetwork"),"), add following code snippet in your application:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-kotlin"},'import com.weaver.corda.sdk.AssetManager\nimport com.weaver.corda.sdk.HashFunctions\n\nvar hash: HashFunctions.Hash = HashFunctions.SHA512\nhash.setSerializedHashBase64(H)\nval proxy = <CordaRPCOps-instance-created-using-credentials-of-Bob-in-TokenNetwork>\nval issuer = <Issuer-party-in-TokenNetwork>\nval recipient = <Alice-party-in-TokenNetwork>\nval contractId = AssetManager.createFungibleHTLC(\n proxy, \n "CBDC01", // Type\n "200", // Quantity\n recipient, \n hash, \n 5L, // Duration timeout in secs, L denotes Long\n 1, // 1 if timeout is Duration, 0 if timeout is in absolute epochs\n "com.cordaSimpleApplication.flow.RetrieveStateAndRef", // full name of "Flow to get Asset State"\n AssetContract.Commands.Delete(), // Contract command for Asset to Burn/Delete the state\n issuer,\n observers // Optional parameter for list of observers for this transaction\n)\n')),(0,r.yg)("p",null,"The above locks will return ",(0,r.yg)("inlineCode",{parentName:"p"},"contractId"),", that has to be stored and will be used in other HTLC functions."),(0,r.yg)("p",null,"To query whether the assets are locked or not in any network, use following query function:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-kotlin"},"val isLockedBoolean = AssetManager.isAssetLockedInHTLC(\n rpc.proxy, \n contractId\n)\n")),(0,r.yg)("p",null,"Now to claim the asset using the secret text (pre-image of hash) ",(0,r.yg)("inlineCode",{parentName:"p"},"s"),", add following code snippet:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-kotlin"},'var hash: HashFunctions.Hash = HashFunctions.SHA512()\nhash.setPreimage(s)\nval issuer = <Issuer-party>\nval proxu = <CordaRPCOps-instance-created-using-credentials-of-claiming-party>\nval res = AssetManager.claimAssetInHTLC(\n proxy, \n contractId, // ContractId obtained during lock\n hash,\n AssetContract.Commands.Issue(), // Contract command for issuing/minting asset\n "com.cordaSimpleApplication.flow.UpdateAssetOwnerFromPointer", // full name of flow to update owner in asset state\n issuer,\n observers // Optional parameter for list of observers for this transaction\n) \n// return value is boolean indicating success or failure of claim \n')),(0,r.yg)("p",null,"The above function can be adapted to both ",(0,r.yg)("inlineCode",{parentName:"p"},"BondNetwork")," and ",(0,r.yg)("inlineCode",{parentName:"p"},"TokenNetwork"),"."),(0,r.yg)("p",null,"If the asset has to be unlocked, use following code snippet:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-kotlin"},"val issuer = <Issuer-party>\nval proxu = <CordaRPCOps-instance-created-using-credentials-of-locking-party>\nval res = AssetManager.reclaimAssetInHTLC(\n rpc.proxy, \n contractId, // ContractId obtained during lock\n AssetContract.Commands.Issue(), // Contract command for issuing/minting asset\n issuer,\n observers // Optional parameter for list of observers for this transaction\n) \n// return value is boolean indicating success or failure of claim \n")),(0,r.yg)("h4",{id:"for-asset-transfer-1"},"For Asset Transfer"),(0,r.yg)("p",null,(0,r.yg)("em",{parentName:"p"},"TBD")),(0,r.yg)("h2",{id:"pre-configuration-phase"},"Pre-Configuration Phase"),(0,r.yg)("p",null,"No changes are required in your network's pre-configuration process for Weaver enablement."),(0,r.yg)("p",null,"Typically, pre-configuration involves:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Generating node folders for each participating node in the network, which contains CorDapps, certificates, persistence db, etc sub directories. Using Gradle task ",(0,r.yg)("inlineCode",{parentName:"li"},"net.corda.plugins.Cordform")," or ",(0,r.yg)("inlineCode",{parentName:"li"},"net.corda.plugins.Dockerform"),", the folders get created under the directory ",(0,r.yg)("inlineCode",{parentName:"li"},"build/nodes")," (this path is used in above sample code for Identity Service).\n"),(0,r.yg)("li",{parentName:"ul"},"The RPC address, username and password specified in above task will be used to create an instance of ",(0,r.yg)("inlineCode",{parentName:"li"},"CordaRPCOps"),", which is the first argument for most ",(0,r.yg)("inlineCode",{parentName:"li"},"weaver-corda-sdk")," static functions as we saw in previous section. For example, one of them is ",(0,r.yg)("inlineCode",{parentName:"li"},"InteroperableHelper.interopFlow"),":")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-kotlin"},"val response = InteroperableHelper.interopFlow(\n proxy, // CordaRPCOps instance to start flows\n viewAddress,\n <trade-finance-relay-url>[:<port>], // Replace with local network's relay address and port\n)\n")),(0,r.yg)("p",null,"Also, the Corda Driver (which we will setup in the following sections) needs a specific RPC user to be created, so make sure to add that in the Gradle task above, and note the credentials."),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Sample ",(0,r.yg)("inlineCode",{parentName:"li"},"net.corda.plugins.Dockerform")," task:")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-groovy"},'task prepareDockerNodes(type: net.corda.plugins.Dockerform, dependsOn: [\'jar\']) {\n def HOST_ADDRESS = "0.0.0.0"\n nodeDefaults {\n projectCordapp {\n deploy = false\n }\n }\n node {\n name "O=Notary,L=London,C=GB"\n notary = [validating : true]\n p2pPort 10004\n rpcSettings {\n address("$HOST_ADDRESS:10003")\n adminAddress("$HOST_ADDRESS:10005")\n }\n cordapps.clear()\n }\n node {\n name "O=PartyA,L=London,C=GB"\n p2pPort 10007\n rpcSettings {\n address("$HOST_ADDRESS:10003")\n adminAddress("$HOST_ADDRESS:10005")\n }\n rpcUsers = [\n [ user: "user1", "password": "test", "permissions": ["ALL"]],\n [ user: "driverUser1", "password": "test", "permissions": ["ALL"]]] // <-- Driver RPC User\n }\n node {\n name "O=PartyB,L=London,C=GB"\n p2pPort 10009\n rpcSettings {\n address("$HOST_ADDRESS:10003")\n adminAddress("$HOST_ADDRESS:10005")\n }\n rpcUsers = [\n [ user: "user1", "password": "test", "permissions": ["ALL"]],\n [ user: "driverUser1", "password": "test", "permissions": ["ALL"]]] // <-- Driver RPC User\n }\n}\n')),(0,r.yg)("h2",{id:"startup-and-bootstrap-phase"},"Startup and Bootstrap Phase"),(0,r.yg)("p",null,"To launch a network using containerized components, you will typically use a Docker Compose or Kubernetes configuration file. No modifications are needed to the node's configurations. Sample instructions are given below for networks launched using Docker Compose; we leave it to the reader to adapt these to their custom launch processes."),(0,r.yg)("h3",{id:"for-asset-exchange-2"},"For Asset Exchange"),(0,r.yg)("p",null,"The asset exchange mode currently requires only the Interoperation CorDapp module from Weaver. Relays and drivers are not necessary. In the future, we expect to make the asset exchange protocol moe automated using these components; the instructions here will be updated appropriately."),(0,r.yg)("h3",{id:"install-interoperation-cordapp-on-nodes"},"Install Interoperation CorDapp on Nodes"),(0,r.yg)("p",null,"After bootstrapping the nodes folder, copy the following two CorDapps in ",(0,r.yg)("inlineCode",{parentName:"p"},"build/nodes/PartyA/cordapps")," and ",(0,r.yg)("inlineCode",{parentName:"p"},"build/nodes/PartyB/cordapps")," folders (",(0,r.yg)("inlineCode",{parentName:"p"},"PartyA")," and ",(0,r.yg)("inlineCode",{parentName:"p"},"PartyB")," node names are for example only):"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/packages/906215"},"com.weaver.corda.app.interop.interop-contracts")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/packages/906216"},"com.weaver.corda.app.interop.interop-workflows"))),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:"left"},"You can follow any installation process for this CorDapp, but make sure it is installed on all the nodes that maintain the states involved in cross-network operations in their vaults.")))),(0,r.yg)("h3",{id:"for-data-sharing-or-asset-transfer"},"For Data Sharing or Asset Transfer"),(0,r.yg)("p",null,"Both the data sharing and asset transfer modes require the Interoperation CorDapp, relays, and drivers, to be deployed."),(0,r.yg)("h4",{id:"install-interoperation-cordapp-on-nodes-1"},"Install Interoperation CorDapp on Nodes"),(0,r.yg)("p",null,"After bootstrapping the nodes folder, copy the following two CorDapps in ",(0,r.yg)("inlineCode",{parentName:"p"},"build/nodes/PartyA/cordapps")," and ",(0,r.yg)("inlineCode",{parentName:"p"},"build/nodes/PartyB/cordapps")," folders (",(0,r.yg)("inlineCode",{parentName:"p"},"PartyA")," and ",(0,r.yg)("inlineCode",{parentName:"p"},"PartyB")," node names are for example only):"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/packages/906215"},"com.weaver.corda.app.interop.interop-contracts")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/packages/906216"},"com.weaver.corda.app.interop.interop-workflows"))),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:"left"},"You can follow any installation process for this CorDapp, but make sure it is installed on all the nodes that maintain the states involved in cross-network operations in their vaults.")))),(0,r.yg)("h4",{id:"launch-relay"},"Launch Relay"),(0,r.yg)("p",null,"You need to run one or more relays for network-to-network communication. Here we provide instructions to run one relay running in a Docker container, which is sufficient for data sharing. (Later, we will provide instructions to run multiple relays, which will be useful from a failover perspective.)"),(0,r.yg)("p",null,"Weaver provides a ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/pkgs/container/weaver-relay-server"},"pre-built image")," for the relay. Before launching a container, you just need to customize its configuration for your Fabric network, which you can do by simply creating a folder (let's call it ",(0,r.yg)("inlineCode",{parentName:"p"},"relay_config"),") and configuring the following files in it:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},(0,r.yg)("inlineCode",{parentName:"p"},".env"),": This sets suitable environment variables within the relay container. Copy the ",(0,r.yg)("inlineCode",{parentName:"p"},".env.template")," file ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/core/relay/.env.template"},"from the repository")," and customize it for your purposes, as indicated in the below sample:"),(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre"},'PATH_TO_CONFIG=./config.toml\nRELAY_NAME=<"name" in config.toml>\nRELAY_PORT=<relay-server-port/"port" in config.toml>\nEXTERNAL_NETWORK=<docker-bridge-network>\nDOCKER_REGISTRY=ghcr.io/hyperledger-labs\nDOCKER_IMAGE_NAME=weaver-relay\nDOCKER_TAG=1.5.4\n')),(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},"The ",(0,r.yg)("inlineCode",{parentName:"li"},"PATH_TO_CONFIG")," variable should point to the properties file typically named ",(0,r.yg)("inlineCode",{parentName:"li"},"config.toml")," (you can name this whatever you wish). See further below for instructions to write this file."),(0,r.yg)("li",{parentName:"ul"},"The ",(0,r.yg)("inlineCode",{parentName:"li"},"RELAY_NAME")," variable specifies a unique name for this relay. It should match what's specified in the ",(0,r.yg)("inlineCode",{parentName:"li"},"config.toml")," (more on that below)."),(0,r.yg)("li",{parentName:"ul"},"The ",(0,r.yg)("inlineCode",{parentName:"li"},"RELAY_PORT")," variable specifies the port this relay server will listen on. It should match what's specified in the ",(0,r.yg)("inlineCode",{parentName:"li"},"config.toml")," (more on that below)."),(0,r.yg)("li",{parentName:"ul"},"The ",(0,r.yg)("inlineCode",{parentName:"li"},"EXTERNAL_NETWORK")," variable should be set to the ",(0,r.yg)("a",{parentName:"li",href:"https://docs.docker.com/compose/networking/"},"name")," of your Fabric network."),(0,r.yg)("li",{parentName:"ul"},"The ",(0,r.yg)("inlineCode",{parentName:"li"},"DOCKER_*")," variables are used to specify the image on which the container will be built. Make sure you set ",(0,r.yg)("inlineCode",{parentName:"li"},"DOCKER_TAG")," to the latest version you see on ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/pkgs/container/weaver-relay-server"},"GitHub"),".")),(0,r.yg)("p",{parentName:"li"},"For more details, see the ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/core/relay/relay-docker.md"},"Relay Docker README"),' ("Relay Server Image" and "Running With Docker Compose" sections).')),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},(0,r.yg)("inlineCode",{parentName:"p"},"config.toml"),": This is the file specified in the ",(0,r.yg)("inlineCode",{parentName:"p"},"PATH_TO_CONFIG")," variable in the ",(0,r.yg)("inlineCode",{parentName:"p"},".env"),". It specifies properties of this relay and the driver(s) it supports. A sample is given below:"),(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-toml",metastring:"showLineNumbers",showLineNumbers:!0},'name=<relay-name>\nport=<relay-port>\nhost="0.0.0.0"\ndb_path="db/<relay-name>/requests"\nremote_db_path="db/<relay-name>/remote_request"\n\n# FOR TLS\ncert_path="credentials/fabric_cert.pem"\nkey_path="credentials/fabric_key"\ntls=<true/false>\n\n[networks]\n[networks.<network-name>]\nnetwork="<driver-name>"\n\n[relays]\n[relays.<foreign-relay-name>]\nhostname="<foreign-relay-hostname-or-ip-address>"\nport="<foreign-relay-port>"\n\n[drivers]\n[drivers.<driver-name>]\nhostname="<driver-hostname-or-ip-address>"\nport="<driver-port>"\n')),(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"<relay-name>")," should be a unique ID representing this relay; e.g., ",(0,r.yg)("inlineCode",{parentName:"li"},"my_network_relay"),". It should match the ",(0,r.yg)("inlineCode",{parentName:"li"},"RELAY_NAME")," value in ",(0,r.yg)("inlineCode",{parentName:"li"},".env"),"."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"<relay-port>")," is the port number the relay server will listen on. It should match the ",(0,r.yg)("inlineCode",{parentName:"li"},"RELAY_PORT")," value in ",(0,r.yg)("inlineCode",{parentName:"li"},".env"),"."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"db_path")," and ",(0,r.yg)("inlineCode",{parentName:"li"},"remote_db_path")," are used internally by the relay to store data. Replace ",(0,r.yg)("inlineCode",{parentName:"li"},"<relay-name>")," with the same value set for the ",(0,r.yg)("inlineCode",{parentName:"li"},"name")," parameter. (These can point to any filesystem paths in the relay's container.)"),(0,r.yg)("li",{parentName:"ul"},"If you set ",(0,r.yg)("inlineCode",{parentName:"li"},"tls")," to ",(0,r.yg)("inlineCode",{parentName:"li"},"true"),", the relay will enforce TLS communication. The ",(0,r.yg)("inlineCode",{parentName:"li"},"cert_path")," and ",(0,r.yg)("inlineCode",{parentName:"li"},"key_path")," should point to a Fabric TLS certificate and key respectively, such as those created using the ",(0,r.yg)("inlineCode",{parentName:"li"},"cryptogen")," tool."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"<network-name>")," is a unique identifier for your local network. You can set it to whatever value you wish."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"<driver-name>")," refers to the driver used by this relay to respond to requests. This also refers to one of the drivers's specifications in the ",(0,r.yg)("inlineCode",{parentName:"li"},"drivers")," section further below. In this code snippet, we have defined one driver. (The names in lines 14 and 22 must match.) In lines 23 and 24 respectively, you should specify the hostname and port for the driver (whose configuration we will handle later)."),(0,r.yg)("li",{parentName:"ul"},"The ",(0,r.yg)("inlineCode",{parentName:"li"},"relays")," section specifies all foreign relays this relay can connect to. The ",(0,r.yg)("inlineCode",{parentName:"li"},"<foreign-relay-name>")," value should be a unique ID for a given foreign relay, and this value will be used by your Layer-2 applications when constructing view addresses for data sharing requests. In lines 18 and 19, you should specify the hostname and port for the foreign relay."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Enabling TLS"),":",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},"You can make your relay accept TLS connections by specifying a TLS certificate file path and private key file path in ",(0,r.yg)("inlineCode",{parentName:"li"},"cert_path")," and ",(0,r.yg)("inlineCode",{parentName:"li"},"key_path")," respectively, and set ",(0,r.yg)("inlineCode",{parentName:"li"},"tls")," to ",(0,r.yg)("inlineCode",{parentName:"li"},"true"),"."),(0,r.yg)("li",{parentName:"ul"},"To communicate with a foreign relay using TLS, specify that relay's TLS CA certificate path in ",(0,r.yg)("inlineCode",{parentName:"li"},"tlsca_cert_path")," (currently only one certificate can be configured) and set ",(0,r.yg)("inlineCode",{parentName:"li"},"tls")," to ",(0,r.yg)("inlineCode",{parentName:"li"},"true")," by extending that relay's section as follows (",(0,r.yg)("em",{parentName:"li"},"Note"),": this CA certificate should match the one specified in the ",(0,r.yg)("inlineCode",{parentName:"li"},"cert_path")," property in the foreign relay's ",(0,r.yg)("inlineCode",{parentName:"li"},"config.toml")," file):",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-toml"},'[relays]\n[relays.<foreign-relay-name>]\nhostname="<foreign-relay-hostname-or-ip-address>"\nport="<foreign-relay-port>"\ntls=<true|false>\ntlsca_cert_path="<relay-tls-ca-certificate-path>"\n'))),(0,r.yg)("li",{parentName:"ul"},"To communicate with a driver using TLS, specify the driver's TLS CA certificate in ",(0,r.yg)("inlineCode",{parentName:"li"},"tlsca_cert_path")," (currently only one certificate can be configured) and set ",(0,r.yg)("inlineCode",{parentName:"li"},"tls")," to ",(0,r.yg)("inlineCode",{parentName:"li"},"true")," by extending that driver's section as follows (",(0,r.yg)("em",{parentName:"li"},"Note"),": this CA certificate must match the certificate used by the driver using the ",(0,r.yg)("inlineCode",{parentName:"li"},"DRIVER_TLS_CERT_PATH")," property in its ",(0,r.yg)("inlineCode",{parentName:"li"},".env")," configuration file, which we will examine later):",(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-toml"},'[drivers]\n[drivers.<driver-name>]\nhostname="<driver-hostname-or-ip-address>"\nport="<driver-port>"\ntls=<true|false>\ntlsca_cert_path="<driver-tls-ca-certificate-path>"\n')))))),(0,r.yg)("table",{parentName:"li"},(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:"left"},"You can specify more than one foreign relay instance in the ",(0,r.yg)("inlineCode",{parentName:"td"},"relays")," section.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:"left"},"You can specify more than one driver instance in the ",(0,r.yg)("inlineCode",{parentName:"td"},"drivers")," section."))))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},(0,r.yg)("inlineCode",{parentName:"p"},"docker-compose.yaml"),": This specifies the properties of the relay container. You can use the ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/core/relay/docker-compose.yaml"},"file in the repository")," verbatim."))),(0,r.yg)("p",null,"To start the relay server, navigate to the folder containing the above files and run the following:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"docker-compose up -d relay-server\n")),(0,r.yg)("h4",{id:"launch-driver"},"Launch Driver"),(0,r.yg)("p",null,"You need to run one or more drivers through which your relay can interact with your Corda network. Here we provide instructions to run one Corda driver running in a Docker container, which is sufficient for data sharing. (Later, we will provide instructions to run multiple drivers, which will be useful both from a failover perspective and to interact with different subsets of your Corda network.)"),(0,r.yg)("p",null,"Weaver provides a ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/pkgs/container/weaver-corda-driver"},"pre-built image")," for the Corda driver. Before launching a container, you just need to customize the container configuration for your Corda network, which you can do by simply configuring the following:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},(0,r.yg)("inlineCode",{parentName:"p"},".env"),": This sets suitable environment variables within the driver container. Copy the ",(0,r.yg)("inlineCode",{parentName:"p"},".env.template")," file ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/core/drivers/corda-driver/.env.docker.template"},"from the repository")," and customize it for your purposes, as indicated in the below sample:"),(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre"},"NETWORK_NAME=<container-name-suffix>\nDRIVER_PORT=<driver-server-port>\nDRIVER_RPC_USERNAME=<driver-rpc-username>\nDRIVER_RPC_PASSWORD=<driver-rpc-username>\nEXTERNAL_NETWORK=<docker-bridge-network>\nDOCKER_IMAGE_NAME=ghcr.io/hyperledger-labs/weaver-corda-driver\nDOCKER_TAG=1.2.13\nRELAY_TLS=<true|false>\nRELAY_TLSCA_TRUST_STORE=<truststore-jks-file-path>\nRELAY_TLSCA_TRUST_STORE_PASSWORD=<truststore-jks-file-password>\nRELAY_TLSCA_CERT_PATHS=<colon-separated-CA-cert-paths>\nDRIVER_TLS=<true|false>\nDRIVER_TLS_CERT_PATH=<cert-path>\nDRIVER_TLS_KEY_PATH=<private-key-path>\n")),(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"NETWORK_NAME")," is only used as suffix for container and has no other significance."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"DRIVER_PORT")," variable should be set to the port this driver will listen on."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"DRIVER_RPC_USERNAME")," variable should be set to rpc user created ",(0,r.yg)("a",{parentName:"li",href:"#pre-configuration"},"above")," for the driver."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"DRIVER_RPC_PASSWORD")," variable should be set to password of above rpc user."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"EXTERNAL_NETWORK")," variable should be set to the ",(0,r.yg)("a",{parentName:"li",href:"https://docs.docker.com/compose/networking/"},"name")," of your Corda network."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Enabling TLS"),":",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},"You can make your driver accept TLS connections by specifying ",(0,r.yg)("inlineCode",{parentName:"li"},"DRIVER_TLS")," as ",(0,r.yg)("inlineCode",{parentName:"li"},"true")," and specifying a TLS certificate file path and private key file path in ",(0,r.yg)("inlineCode",{parentName:"li"},"DRIVER_TLS_CERT_PATH")," and ",(0,r.yg)("inlineCode",{parentName:"li"},"DRIVER_TLS_KEY_PATH")," respectively. The same certificate should be specified in this driver's definition in the ",(0,r.yg)("inlineCode",{parentName:"li"},"drivers")," section in the ",(0,r.yg)("inlineCode",{parentName:"li"},"config.toml")," file of your relay in the ",(0,r.yg)("inlineCode",{parentName:"li"},"tlsca_cert_path")," property (see the earlier section on relay configuration)."),(0,r.yg)("li",{parentName:"ul"},"To communicate with your network' relay using TLS (i.e., if the relay is TLS-enabled), specify that relay's TLS CA certificate path in ",(0,r.yg)("inlineCode",{parentName:"li"},"RELAY_TLSCA_CERT_PATH")," (currently only one certificate can be configured) and set ",(0,r.yg)("inlineCode",{parentName:"li"},"RELAY_TLS")," to ",(0,r.yg)("inlineCode",{parentName:"li"},"true"),". This CA certificate should match the one specified in the ",(0,r.yg)("inlineCode",{parentName:"li"},"cert_path")," property in the relay's ",(0,r.yg)("inlineCode",{parentName:"li"},"config.toml")," file (see the earlier section on relay configuration):"),(0,r.yg)("li",{parentName:"ul"},"You can point to the folder in your host system containing the certificate and key using the ",(0,r.yg)("inlineCode",{parentName:"li"},"TLS_CREDENTIALS_DIR")," variable. (This folder will be synced to the ",(0,r.yg)("inlineCode",{parentName:"li"},"/corda-driver/credentials")," folder in the Fabric Driver container as specified in the ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/core/drivers/fabric-driver/docker-compose.yml"},"docker-compose file"),".) Make sure you point to the right certificate and key file paths within the container using the ",(0,r.yg)("inlineCode",{parentName:"li"},"DRIVER_TLS_CERT_PATH"),", ",(0,r.yg)("inlineCode",{parentName:"li"},"DRIVER_TLS_KEY_PATH"),", and ",(0,r.yg)("inlineCode",{parentName:"li"},"RELAY_TLSCA_CERT_PATH")," variables."))))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},(0,r.yg)("inlineCode",{parentName:"p"},"docker-compose.yaml"),": This specifies the properties of the driver container. You can use the ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/core/drivers/corda-driver/docker-compose.yml"},"file in the repository")," verbatim."))),(0,r.yg)("p",null,"To start the driver, navigate to the folder containing the above files and run the following:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"docker-compose up -d\n")),(0,r.yg)("h4",{id:"vault-initialization"},"Vault Initialization"),(0,r.yg)("p",null,"To prepare your network for interoperation with a foreign network, you need to record the following to your vault using the ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/packages/952245"},"Corda SDK")," (",(0,r.yg)("inlineCode",{parentName:"p"},"com.weaver.corda.sdk"),"):"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},(0,r.yg)("strong",{parentName:"p"},"Access control policies"),":\nLet's take the example of the request made from ",(0,r.yg)("inlineCode",{parentName:"p"},"trade-finance-network")," to ",(0,r.yg)("inlineCode",{parentName:"p"},"trade-logistics-network")," for a B/L earlier in this document. ",(0,r.yg)("inlineCode",{parentName:"p"},"trade-logistics-network")," can have a policy of the following form permitting access to the ",(0,r.yg)("inlineCode",{parentName:"p"},"GetBillOfLading")," function from a client representing the ",(0,r.yg)("inlineCode",{parentName:"p"},"PartyA")," node in ",(0,r.yg)("inlineCode",{parentName:"p"},"trade-finance-network")," as follows:"),(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-json"},'{\n "securityDomain":"trade-finance-network",\n "rules":\n [\n {\n "principal":"<PartyA-certificate-pem>",\n "principalType":"certificate",\n "resource":"exporternode:10003;carriernode:10003#com.mynetwork.flow.GetBillOfLading:*",\n "read":true\n }\n ]\n}\n')),(0,r.yg)("p",{parentName:"li"},"In this sample, a single rule is specified for requests coming from ",(0,r.yg)("inlineCode",{parentName:"p"},"trade-finance-network"),": it states that a workflow call to ",(0,r.yg)("inlineCode",{parentName:"p"},"com.mynetwork.flow.GetBillOfLading")," made to ",(0,r.yg)("inlineCode",{parentName:"p"},"exporter")," and ",(0,r.yg)("inlineCode",{parentName:"p"},"carrier")," nodes of remote Corda network is permitted for a requestor whose certificate is specified in the ",(0,r.yg)("inlineCode",{parentName:"p"},"principal")," attribute. The ",(0,r.yg)("inlineCode",{parentName:"p"},"*")," at the end indicates that any arguments passed to the function will pass the access control check. The ",(0,r.yg)("inlineCode",{parentName:"p"},"exporternode:10003")," and ",(0,r.yg)("inlineCode",{parentName:"p"},"carriernode:10003")," are of form ",(0,r.yg)("inlineCode",{parentName:"p"},"<hostname/IP>:<RPC_Port>"),", for ",(0,r.yg)("inlineCode",{parentName:"p"},"exporter")," and ",(0,r.yg)("inlineCode",{parentName:"p"},"carrier")," nodes respectively in the remote Corda network."),(0,r.yg)("p",{parentName:"li"},"You need to record this policy rule on your Corda network's vault by invoking either the ",(0,r.yg)("inlineCode",{parentName:"p"},"AccessControlPolicyManager.createAccessControlPolicyState")," function or the ",(0,r.yg)("inlineCode",{parentName:"p"},"AccessControlPolicyManager.updateAccessControlPolicyState")," function on the ",(0,r.yg)("inlineCode",{parentName:"p"},"weaver-corda-sdk"),"; use the former if you are recording a set of rules for the given ",(0,r.yg)("inlineCode",{parentName:"p"},"securityDomain")," for the first time and the latter to overwrite a set of rules recorded earlier. The above JSON needs to be converted to protobuf object of ",(0,r.yg)("inlineCode",{parentName:"p"},"com.weaver.protos.common.access_control.AccessControl.AccessControlPolicy"),", using google's protobuf library, and the object is the second argument of above functions (first being the instance of CordaRPCOps).")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},(0,r.yg)("strong",{parentName:"p"},"Verification policies"),":\nTaking the same example as above, an example of a verification policy for a B/L requested by the ",(0,r.yg)("inlineCode",{parentName:"p"},"trade-finance-network")," from the ",(0,r.yg)("inlineCode",{parentName:"p"},"trade-logistics-network")," is as follows:"),(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-json"},'{\n "securityDomain":"trade-logistics-network",\n "identifiers":\n [\n {\n "pattern":"tradelogisticschannel:shipmentcc:GetBillOfLading:*",\n "policy":\n {\n "type":"Signature",\n "criteria":\n [\n "ExporterMSP",\n "CarrierMSP"\n ]\n }\n }\n ]\n}\n')),(0,r.yg)("p",{parentName:"li"},"In this sample, a single verification policy rule is specified for data views coming from ",(0,r.yg)("inlineCode",{parentName:"p"},"trade-logistics-network"),": it states that the data returned by the ",(0,r.yg)("inlineCode",{parentName:"p"},"GetBillOfLading")," query made to the ",(0,r.yg)("inlineCode",{parentName:"p"},"shipmentcc")," chaincode on the ",(0,r.yg)("inlineCode",{parentName:"p"},"tradelogisticschannel")," channel requires as proof two signatures, one from a peer in the organization whose MSP ID is ",(0,r.yg)("inlineCode",{parentName:"p"},"ExporterMSP")," and another from a peer in the organization whose MSP ID is ",(0,r.yg)("inlineCode",{parentName:"p"},"CarrierMSP"),"."),(0,r.yg)("table",{parentName:"li"},(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:"left"},"If the remote network is built on Corda, the resource specified in the access control policy can be used here as the ",(0,r.yg)("inlineCode",{parentName:"td"},"pattern"),", with different node names specified in the ",(0,r.yg)("inlineCode",{parentName:"td"},"criteria"),".")))),(0,r.yg)("p",{parentName:"li"},"You need to record this policy rule on your Corda network's vault by invoking Corda sdk's function ",(0,r.yg)("inlineCode",{parentName:"p"},"VerificationPolicyManager.createVerificationPolicyState(proxy, verificationPolicyProto)"),", where ",(0,r.yg)("inlineCode",{parentName:"p"},"proxy")," is an instance of ",(0,r.yg)("inlineCode",{parentName:"p"},"CordaRPCOps")," as described in previous sections, and ",(0,r.yg)("inlineCode",{parentName:"p"},"verificationPolicyProto")," is an object of protobuf ",(0,r.yg)("inlineCode",{parentName:"p"},"com.weaver.protos.common.verification_policy.VerificationPolicyOuterClass.VerificationPolicy"),". You can examine the full proto structure ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/common/protos/common/verification_policy.proto"},"here"),". (",(0,r.yg)("em",{parentName:"p"},"Google's protobuf library can be used to convert above JSON to protobuf object."),")"),(0,r.yg)("table",{parentName:"li"},(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:"left"},"For any cross-network data request, make sure an access control policy is recorded in the ",(0,r.yg)("em",{parentName:"td"},"source network")," (",(0,r.yg)("inlineCode",{parentName:"td"},"trade-logistics-network")," in the above example) and a corresponding verification policy is recorded in the ",(0,r.yg)("em",{parentName:"td"},"destination network")," (",(0,r.yg)("inlineCode",{parentName:"td"},"trade-finance-network")," in the above example) before any relay request is triggered."))))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},(0,r.yg)("strong",{parentName:"p"},"Foreign network security domain (membership) configuration"),":\nRun the following procedure (pseudocode) to record security domain configuration for every foreign network you wish your Corda network to interoperate with (you will need to collect the identity service URLs for all the foreign networks first):"),(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre"},"for each foreign network:\n send an HTTP GET request to the network's identity service (using 'curl' or 'wget' from a shell script or equivalent programming language APIs).\n convert the response string to protobuf object of 'com.weaver.protos.common.membership.MembershipOuterClass.Membership'.\n invoke 'MembershipManager.createMembershipState(proxy, membershipProto)' or 'MembershipManager.updateMembershipState(proxy, membershipProto)' on Corda sdk.\n")),(0,r.yg)("p",{parentName:"li"},"As in the above two cases, use ",(0,r.yg)("inlineCode",{parentName:"p"},"createMembershipState")," to record a confiuration for the first time for a given ",(0,r.yg)("inlineCode",{parentName:"p"},"securityDomain")," and ",(0,r.yg)("inlineCode",{parentName:"p"},"updateMembershipState")," to overwrite a configuration."),(0,r.yg)("table",{parentName:"li"},(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:"left"},"Security domain configurations (organization lists and their certificate chains) for any Fabric/Corda network are subject to change, so you should run the above procedure periodically in a loop.")))))),(0,r.yg)("p",null,"Your Corda network is now up and running with the necessary Weaver components, and your network's vault is bootstrapped with the initial configuration necessary for cross-network interactions!"))}g.isMDXComponent=!0},6559:(e,n,a)=>{a.d(n,{A:()=>t});const t=a.p+"assets/images/corda-network-model-2e962213e430d787a71559bf2d647f88.png"},1645:(e,n,a)=>{a.d(n,{A:()=>t});const t=a.p+"assets/images/corda-weaver-model-8cd8e458ac29201d610bf4c5f2a99a8c.png"}}]); \ No newline at end of file diff --git a/assets/js/f1311735.501f6c98.js b/assets/js/f1311735.501f6c98.js deleted file mode 100644 index ff304c8d4..000000000 --- a/assets/js/f1311735.501f6c98.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[6664],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>u});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){i(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,a,i=function(e,t){if(null==e)return{};var n,a,i={},o=Object.keys(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var c=a.createContext({}),s=function(e){var t=a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},p=function(e){var t=s(e.components);return a.createElement(c.Provider,{value:t},e.children)},k="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,c=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),k=s(n),m=i,u=k["".concat(c,".").concat(m)]||k[m]||d[m]||o;return n?a.createElement(u,r(r({ref:t},p),{},{components:n})):a.createElement(u,r({ref:t},p))}));function u(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,r=new Array(o);r[0]=m;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l[k]="string"==typeof e?e:i,r[1]=l;for(var s=2;s<o;s++)r[s]=n[s];return a.createElement.apply(null,r)}return a.createElement.apply(null,n)}m.displayName="MDXCreateElement"},2846:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>r,default:()=>d,frontMatter:()=>o,metadata:()=>l,toc:()=>s});var a=n(7462),i=(n(7294),n(3905));const o={id:"besu-besu",title:"Asset Exchange: Besu with Besu",sidebar_label:"Besu with Besu",pagination_label:"Besu with Besu",pagination_prev:"external/getting-started/interop/asset-exchange/overview"},r=void 0,l={unversionedId:"external/getting-started/interop/asset-exchange/besu-besu",id:"external/getting-started/interop/asset-exchange/besu-besu",title:"Asset Exchange: Besu with Besu",description:"We divide this page into two sections, if you used default configuration in ledger initialization step, then go to section AliceERC721 with BobERC20, otherwise if you used hybrid tokens in network, then go to section AliceERC1155 with BobERC20",source:"@site/docs/external/getting-started/interop/asset-exchange/besu-besu.md",sourceDirName:"external/getting-started/interop/asset-exchange",slug:"/external/getting-started/interop/asset-exchange/besu-besu",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/besu-besu",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/getting-started/interop/asset-exchange/besu-besu.md",tags:[],version:"current",frontMatter:{id:"besu-besu",title:"Asset Exchange: Besu with Besu",sidebar_label:"Besu with Besu",pagination_label:"Besu with Besu",pagination_prev:"external/getting-started/interop/asset-exchange/overview"},sidebar:"Documentation",previous:{title:"Asset Exchange",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview"},next:{title:"Asset Transfer",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-transfer"}},c={},s=[{value:"AliceERC721 with BobERC20",id:"aliceerc721-with-boberc20",level:2},{value:"AliceERC1155 with BobERC20",id:"aliceerc1155-with-boberc20",level:2}],p={toc:s},k="wrapper";function d(e){let{components:t,...n}=e;return(0,i.kt)(k,(0,a.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"We divide this page into two sections, if you used default configuration in ledger initialization step, then go to section ",(0,i.kt)("a",{parentName:"p",href:"#aliceerc721-with-boberc20"},"AliceERC721 with BobERC20"),", otherwise if you used hybrid tokens in ",(0,i.kt)("inlineCode",{parentName:"p"},"network"),", then go to section ",(0,i.kt)("a",{parentName:"p",href:"#aliceerc1155-with-boberc20"},"AliceERC1155 with BobERC20")),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:"left"},"Notes"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"left"},"The hash used in following steps can be replaced by any valid ",(0,i.kt)("inlineCode",{parentName:"td"},"SHA256")," hash.")))),(0,i.kt)("h2",{id:"aliceerc721-with-boberc20"},"AliceERC721 with BobERC20"),(0,i.kt)("p",null,"One Besu network transfers an non-fungible ",(0,i.kt)("inlineCode",{parentName:"p"},"AliceERC721")," token with id ",(0,i.kt)("inlineCode",{parentName:"p"},"0")," from Alice to Bob in exchange for a transfer of ",(0,i.kt)("inlineCode",{parentName:"p"},"10 BobERC20")," tokens from Bob to Alice in the other network. We will use account ",(0,i.kt)("inlineCode",{parentName:"p"},"1")," for Alice and account ",(0,i.kt)("inlineCode",{parentName:"p"},"2")," for Bob in both networks."),(0,i.kt)("p",null,"Run the following steps:"),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},"Navigate to the ",(0,i.kt)("inlineCode",{parentName:"li"},"samples/besu/besu-cli")," folder in your clone of the Weaver repository."),(0,i.kt)("li",{parentName:"ol"},"Run the following to verify the status of the assets owned by ",(0,i.kt)("inlineCode",{parentName:"li"},"alice")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"bob")," in the two networks:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset get-balance --network=network1 --account=1\n./bin/besu-cli asset get-balance --network=network1 --account=2\n./bin/besu-cli asset get-balance --network=network2 --account=1\n./bin/besu-cli asset get-balance --network=network2 --account=2\n"))),(0,i.kt)("li",{parentName:"ol"},"Generate Secret-Hash Pair using following command (prints hash in base64):",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre"},"./bin/besu-cli hash --hash_fn=SHA256 secrettext\n"))),(0,i.kt)("li",{parentName:"ol"},"Run the following to trigger ",(0,i.kt)("inlineCode",{parentName:"li"},"alice")," locking ",(0,i.kt)("inlineCode",{parentName:"li"},"AliceERC721")," token with id ",(0,i.kt)("inlineCode",{parentName:"li"},"0")," for ",(0,i.kt)("inlineCode",{parentName:"li"},"bob")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"network1")," for 1 hour",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset lock --network=network1 --sender_account=1 --recipient_account=2 --token_id=0 --asset_type=ERC721 --timeout=3600 --hash_base64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs=\n")),"Value set to ",(0,i.kt)("inlineCode",{parentName:"li"},"hash_base64")," argument corresponds to what was generated in Step 3. Note the ",(0,i.kt)("inlineCode",{parentName:"li"},"contract-id")," printed as output in above command. The output line containing ",(0,i.kt)("inlineCode",{parentName:"li"},"contract-id")," (text in base64 after ",(0,i.kt)("inlineCode",{parentName:"li"},"Lock contract ID:"),") would like this:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"Lock contract ID: 48f59da2ac632117bf79b4aa986f5ece8a2439dc143d576965c17bc8275b0925\n"))),(0,i.kt)("li",{parentName:"ol"},"Run the following to verify ",(0,i.kt)("inlineCode",{parentName:"li"},"alice"),"'s lock, replacing ",(0,i.kt)("inlineCode",{parentName:"li"},"<contract-id>")," with actual ",(0,i.kt)("inlineCode",{parentName:"li"},"contract-id"),":",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset is-locked --network=network1 --lock_contract_id=<contract-id>\n"))),(0,i.kt)("li",{parentName:"ol"},"Run the following to trigger ",(0,i.kt)("inlineCode",{parentName:"li"},"bob")," locking ",(0,i.kt)("inlineCode",{parentName:"li"},"10")," units of ",(0,i.kt)("inlineCode",{parentName:"li"},"BobERC20")," tokens for ",(0,i.kt)("inlineCode",{parentName:"li"},"alice")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"network2")," for 30 mins:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset lock --network=network2 --sender_account=2 --recipient_account=1 --amount=10 --timeout=1800 --hash_base64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs=\n")),"Note the ",(0,i.kt)("inlineCode",{parentName:"li"},"contract-id")," again for this lock printed as output in above command. Let's refer it ",(0,i.kt)("inlineCode",{parentName:"li"},"<contract-id-2>")," for this demonstration."),(0,i.kt)("li",{parentName:"ol"},"Run the following to verify ",(0,i.kt)("inlineCode",{parentName:"li"},"bob"),"'s lock:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset is-locked --network=network2 --lock_contract_id=<contract-id-2>\n"))),(0,i.kt)("li",{parentName:"ol"},"Run the following to trigger ",(0,i.kt)("inlineCode",{parentName:"li"},"alice"),"'s claim for ",(0,i.kt)("inlineCode",{parentName:"li"},"10")," units of ",(0,i.kt)("inlineCode",{parentName:"li"},"BobERC20")," tokens locked by ",(0,i.kt)("inlineCode",{parentName:"li"},"bob")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"network2"),":",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset claim --network=network2 --recipient_account=1 --preimage=secrettext --lock_contract_id=<contract-id-2>\n"))),(0,i.kt)("li",{parentName:"ol"},"Run the following to trigger ",(0,i.kt)("inlineCode",{parentName:"li"},"bob"),"'s claim for ",(0,i.kt)("inlineCode",{parentName:"li"},"AliceERC721")," NFT with id ",(0,i.kt)("inlineCode",{parentName:"li"},"0")," locked by ",(0,i.kt)("inlineCode",{parentName:"li"},"alice")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"network1"),":",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset claim --network=network1 --recipient_account=2 --preimage=secrettext --token_id=0 --lock_contract_id=<contract-id>\n")))),(0,i.kt)("p",null,"The above steps complete a successful asset exchange between two Besu networks.\nIn addition to the above commands, following commands can be run if specified timeout has expired and the locked asset remains unclaimed."),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"If ",(0,i.kt)("inlineCode",{parentName:"li"},"alice")," wants to unlock the asset, run the following to trigger ",(0,i.kt)("inlineCode",{parentName:"li"},"alice"),"'s re-claim for ",(0,i.kt)("inlineCode",{parentName:"li"},"AliceERC721")," NFT with id ",(0,i.kt)("inlineCode",{parentName:"li"},"0")," locked in ",(0,i.kt)("inlineCode",{parentName:"li"},"network1"),":",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset unlock --network=network1 --lock_contract_id=<contract-id> --sender_account=1 --token_id=0\n"))),(0,i.kt)("li",{parentName:"ul"},"If ",(0,i.kt)("inlineCode",{parentName:"li"},"bob")," wants to unlock the token asset, run the following to trigger ",(0,i.kt)("inlineCode",{parentName:"li"},"bob"),"'s re-claim for ",(0,i.kt)("inlineCode",{parentName:"li"},"10 BobERC20")," tokens locked in ",(0,i.kt)("inlineCode",{parentName:"li"},"network2"),":",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset unlock --network=network2 --lock_contract_id=<contract-id-2> --sender_account=2\n")))),(0,i.kt)("h2",{id:"aliceerc1155-with-boberc20"},"AliceERC1155 with BobERC20"),(0,i.kt)("p",null,"One Besu network transfers an non-fungible ",(0,i.kt)("inlineCode",{parentName:"p"},"5 AliceERC1155")," tokens with id ",(0,i.kt)("inlineCode",{parentName:"p"},"0")," from Alice to Bob in exchange for a transfer of ",(0,i.kt)("inlineCode",{parentName:"p"},"50 BobERC20")," tokens from Bob to Alice in the other network. We will use account ",(0,i.kt)("inlineCode",{parentName:"p"},"1")," for Alice and account ",(0,i.kt)("inlineCode",{parentName:"p"},"2")," for Bob in both networks."),(0,i.kt)("p",null,"Run the following steps:"),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},"Navigate to the ",(0,i.kt)("inlineCode",{parentName:"li"},"samples/besu/besu-cli")," folder in your clone of the Weaver repository."),(0,i.kt)("li",{parentName:"ol"},"Run the following to verify the status of the assets owned by ",(0,i.kt)("inlineCode",{parentName:"li"},"alice")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"bob")," in the two networks:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset get-balance --network=network1 --account=1\n./bin/besu-cli asset get-balance --network=network1 --account=2\n./bin/besu-cli asset get-balance --network=network2 --account=1\n./bin/besu-cli asset get-balance --network=network2 --account=2\n"))),(0,i.kt)("li",{parentName:"ol"},"Generate Secret-Hash Pair using following command (prints hash in base64):",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre"},"./bin/besu-cli hash --hash_fn=SHA256 secrettext\n"))),(0,i.kt)("li",{parentName:"ol"},"Run the following to trigger ",(0,i.kt)("inlineCode",{parentName:"li"},"alice")," locking ",(0,i.kt)("inlineCode",{parentName:"li"},"5 AliceERC1155")," token with id ",(0,i.kt)("inlineCode",{parentName:"li"},"0")," for ",(0,i.kt)("inlineCode",{parentName:"li"},"bob")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"network1")," for 1 hour",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset lock --network=network1 --sender_account=1 --recipient_account=2 --amount=5 --token_id=0 --asset_type=ERC1155 --timeout=3600 --hash_base64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs=\n")),"Value set to ",(0,i.kt)("inlineCode",{parentName:"li"},"hash_base64")," argument corresponds to what was generated in Step 3. Note the ",(0,i.kt)("inlineCode",{parentName:"li"},"contract-id")," printed as output in above command. The output line containing ",(0,i.kt)("inlineCode",{parentName:"li"},"contract-id")," (text in base64 after ",(0,i.kt)("inlineCode",{parentName:"li"},"Lock contract ID:"),") would like this:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"Lock contract ID: 48f59da2ac632117bf79b4aa986f5ece8a2439dc143d576965c17bc8275b0925\n"))),(0,i.kt)("li",{parentName:"ol"},"Run the following to verify ",(0,i.kt)("inlineCode",{parentName:"li"},"alice"),"'s lock, replacing ",(0,i.kt)("inlineCode",{parentName:"li"},"<contract-id>")," with actual ",(0,i.kt)("inlineCode",{parentName:"li"},"contract-id"),":",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset is-locked --network=network1 --lock_contract_id=<contract-id>\n"))),(0,i.kt)("li",{parentName:"ol"},"Run the following to trigger ",(0,i.kt)("inlineCode",{parentName:"li"},"bob")," locking ",(0,i.kt)("inlineCode",{parentName:"li"},"50")," units of ",(0,i.kt)("inlineCode",{parentName:"li"},"BobERC20")," tokens for ",(0,i.kt)("inlineCode",{parentName:"li"},"alice")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"network2"),":",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset lock --network=network2 --sender_account=2 --recipient_account=1 --amount=50 --timeout=3600 --hash_base64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs=\n")),"Note the ",(0,i.kt)("inlineCode",{parentName:"li"},"contract-id")," again for this lock printed as output in above command. Let's refer it ",(0,i.kt)("inlineCode",{parentName:"li"},"<contract-id-2>")," for this demonstration."),(0,i.kt)("li",{parentName:"ol"},"Run the following to verify ",(0,i.kt)("inlineCode",{parentName:"li"},"bob"),"'s lock:",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset is-locked --network=network2 --lock_contract_id=<contract-id-2>\n"))),(0,i.kt)("li",{parentName:"ol"},"Run the following to trigger ",(0,i.kt)("inlineCode",{parentName:"li"},"alice"),"'s claim for ",(0,i.kt)("inlineCode",{parentName:"li"},"50")," units of ",(0,i.kt)("inlineCode",{parentName:"li"},"BobERC20")," tokens locked by ",(0,i.kt)("inlineCode",{parentName:"li"},"bob")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"network2"),":",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset claim --network=network2 --recipient_account=1 --preimage=secrettext --lock_contract_id=<contract-id-2>\n"))),(0,i.kt)("li",{parentName:"ol"},"Run the following to trigger ",(0,i.kt)("inlineCode",{parentName:"li"},"bob"),"'s claim for ",(0,i.kt)("inlineCode",{parentName:"li"},"5 AliceERC1155")," tokens with id ",(0,i.kt)("inlineCode",{parentName:"li"},"0")," locked by ",(0,i.kt)("inlineCode",{parentName:"li"},"alice")," in ",(0,i.kt)("inlineCode",{parentName:"li"},"network1"),":",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset claim --network=network1 --recipient_account=2 --preimage=secrettext --token_id=0 --lock_contract_id=<contract-id>\n")))),(0,i.kt)("p",null,"The above steps complete a successful asset exchange between two Besu networks.\nIn addition to the above commands, following commands can be run if specified timeout has expired and the locked asset remains unclaimed."),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"If ",(0,i.kt)("inlineCode",{parentName:"li"},"alice")," wants to unlock the asset, run the following to trigger ",(0,i.kt)("inlineCode",{parentName:"li"},"alice"),"'s re-claim for ",(0,i.kt)("inlineCode",{parentName:"li"},"5 AliceERC1155")," tokens with id ",(0,i.kt)("inlineCode",{parentName:"li"},"0")," locked in ",(0,i.kt)("inlineCode",{parentName:"li"},"network1"),":",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset unlock --network=network1 --lock_contract_id=<contract-id> --sender_account=1 --token_id=0\n"))),(0,i.kt)("li",{parentName:"ul"},"If ",(0,i.kt)("inlineCode",{parentName:"li"},"bob")," wants to unlock the token asset, run the following to trigger ",(0,i.kt)("inlineCode",{parentName:"li"},"bob"),"'s re-claim for ",(0,i.kt)("inlineCode",{parentName:"li"},"50 BobERC20")," tokens locked in ",(0,i.kt)("inlineCode",{parentName:"li"},"network2"),":",(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset unlock --network=network2 --lock_contract_id=<contract-id-2> --sender_account=2\n")))),(0,i.kt)("p",null,"Run the following to verify the status of the assets owned by ",(0,i.kt)("inlineCode",{parentName:"p"},"alice")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"bob")," in the two networks:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset get-balance --network=network1 --account=1\n./bin/besu-cli asset get-balance --network=network1 --account=2\n./bin/besu-cli asset get-balance --network=network2 --account=1\n./bin/besu-cli asset get-balance --network=network2 --account=2\n")))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/f1311735.70c3c239.js b/assets/js/f1311735.70c3c239.js new file mode 100644 index 000000000..07e0f8f01 --- /dev/null +++ b/assets/js/f1311735.70c3c239.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[8136],{5680:(e,n,t)=>{t.d(n,{xA:()=>g,yg:()=>u});var a=t(6540);function i(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function o(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function r(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?o(Object(t),!0).forEach((function(n){i(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):o(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function l(e,n){if(null==e)return{};var t,a,i=function(e,n){if(null==e)return{};var t,a,i={},o=Object.keys(e);for(a=0;a<o.length;a++)t=o[a],n.indexOf(t)>=0||(i[t]=e[t]);return i}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a<o.length;a++)t=o[a],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(i[t]=e[t])}return i}var c=a.createContext({}),s=function(e){var n=a.useContext(c),t=n;return e&&(t="function"==typeof e?e(n):r(r({},n),e)),t},g=function(e){var n=s(e.components);return a.createElement(c.Provider,{value:n},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},m=a.forwardRef((function(e,n){var t=e.components,i=e.mdxType,o=e.originalType,c=e.parentName,g=l(e,["components","mdxType","originalType","parentName"]),p=s(t),m=i,u=p["".concat(c,".").concat(m)]||p[m]||d[m]||o;return t?a.createElement(u,r(r({ref:n},g),{},{components:t})):a.createElement(u,r({ref:n},g))}));function u(e,n){var t=arguments,i=n&&n.mdxType;if("string"==typeof e||i){var o=t.length,r=new Array(o);r[0]=m;var l={};for(var c in n)hasOwnProperty.call(n,c)&&(l[c]=n[c]);l.originalType=e,l[p]="string"==typeof e?e:i,r[1]=l;for(var s=2;s<o;s++)r[s]=t[s];return a.createElement.apply(null,r)}return a.createElement.apply(null,t)}m.displayName="MDXCreateElement"},3621:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>r,default:()=>d,frontMatter:()=>o,metadata:()=>l,toc:()=>s});var a=t(8168),i=(t(6540),t(5680));const o={id:"besu-besu",title:"Asset Exchange: Besu with Besu",sidebar_label:"Besu with Besu",pagination_label:"Besu with Besu",pagination_prev:"external/getting-started/interop/asset-exchange/overview"},r=void 0,l={unversionedId:"external/getting-started/interop/asset-exchange/besu-besu",id:"external/getting-started/interop/asset-exchange/besu-besu",title:"Asset Exchange: Besu with Besu",description:"We divide this page into two sections, if you used default configuration in ledger initialization step, then go to section AliceERC721 with BobERC20, otherwise if you used hybrid tokens in network, then go to section AliceERC1155 with BobERC20",source:"@site/docs/external/getting-started/interop/asset-exchange/besu-besu.md",sourceDirName:"external/getting-started/interop/asset-exchange",slug:"/external/getting-started/interop/asset-exchange/besu-besu",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/besu-besu",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/getting-started/interop/asset-exchange/besu-besu.md",tags:[],version:"current",frontMatter:{id:"besu-besu",title:"Asset Exchange: Besu with Besu",sidebar_label:"Besu with Besu",pagination_label:"Besu with Besu",pagination_prev:"external/getting-started/interop/asset-exchange/overview"},sidebar:"Documentation",previous:{title:"Asset Exchange",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview"},next:{title:"Asset Transfer",permalink:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-transfer"}},c={},s=[{value:"AliceERC721 with BobERC20",id:"aliceerc721-with-boberc20",level:2},{value:"AliceERC1155 with BobERC20",id:"aliceerc1155-with-boberc20",level:2}],g={toc:s},p="wrapper";function d(e){let{components:n,...t}=e;return(0,i.yg)(p,(0,a.A)({},g,t,{components:n,mdxType:"MDXLayout"}),(0,i.yg)("p",null,"We divide this page into two sections, if you used default configuration in ledger initialization step, then go to section ",(0,i.yg)("a",{parentName:"p",href:"#aliceerc721-with-boberc20"},"AliceERC721 with BobERC20"),", otherwise if you used hybrid tokens in ",(0,i.yg)("inlineCode",{parentName:"p"},"network"),", then go to section ",(0,i.yg)("a",{parentName:"p",href:"#aliceerc1155-with-boberc20"},"AliceERC1155 with BobERC20")),(0,i.yg)("table",null,(0,i.yg)("thead",{parentName:"table"},(0,i.yg)("tr",{parentName:"thead"},(0,i.yg)("th",{parentName:"tr",align:"left"},"Notes"))),(0,i.yg)("tbody",{parentName:"table"},(0,i.yg)("tr",{parentName:"tbody"},(0,i.yg)("td",{parentName:"tr",align:"left"},"The hash used in following steps can be replaced by any valid ",(0,i.yg)("inlineCode",{parentName:"td"},"SHA256")," hash.")))),(0,i.yg)("h2",{id:"aliceerc721-with-boberc20"},"AliceERC721 with BobERC20"),(0,i.yg)("p",null,"One Besu network transfers an non-fungible ",(0,i.yg)("inlineCode",{parentName:"p"},"AliceERC721")," token with id ",(0,i.yg)("inlineCode",{parentName:"p"},"0")," from Alice to Bob in exchange for a transfer of ",(0,i.yg)("inlineCode",{parentName:"p"},"10 BobERC20")," tokens from Bob to Alice in the other network. We will use account ",(0,i.yg)("inlineCode",{parentName:"p"},"1")," for Alice and account ",(0,i.yg)("inlineCode",{parentName:"p"},"2")," for Bob in both networks."),(0,i.yg)("p",null,"Run the following steps:"),(0,i.yg)("ol",null,(0,i.yg)("li",{parentName:"ol"},"Navigate to the ",(0,i.yg)("inlineCode",{parentName:"li"},"samples/besu/besu-cli")," folder in your clone of the Weaver repository."),(0,i.yg)("li",{parentName:"ol"},"Run the following to verify the status of the assets owned by ",(0,i.yg)("inlineCode",{parentName:"li"},"alice")," and ",(0,i.yg)("inlineCode",{parentName:"li"},"bob")," in the two networks:",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset get-balance --network=network1 --account=1\n./bin/besu-cli asset get-balance --network=network1 --account=2\n./bin/besu-cli asset get-balance --network=network2 --account=1\n./bin/besu-cli asset get-balance --network=network2 --account=2\n"))),(0,i.yg)("li",{parentName:"ol"},"Generate Secret-Hash Pair using following command (prints hash in base64):",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre"},"./bin/besu-cli hash --hash_fn=SHA256 secrettext\n"))),(0,i.yg)("li",{parentName:"ol"},"Run the following to trigger ",(0,i.yg)("inlineCode",{parentName:"li"},"alice")," locking ",(0,i.yg)("inlineCode",{parentName:"li"},"AliceERC721")," token with id ",(0,i.yg)("inlineCode",{parentName:"li"},"0")," for ",(0,i.yg)("inlineCode",{parentName:"li"},"bob")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"network1")," for 1 hour",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset lock --network=network1 --sender_account=1 --recipient_account=2 --token_id=0 --asset_type=ERC721 --timeout=3600 --hash_base64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs=\n")),"Value set to ",(0,i.yg)("inlineCode",{parentName:"li"},"hash_base64")," argument corresponds to what was generated in Step 3. Note the ",(0,i.yg)("inlineCode",{parentName:"li"},"contract-id")," printed as output in above command. The output line containing ",(0,i.yg)("inlineCode",{parentName:"li"},"contract-id")," (text in base64 after ",(0,i.yg)("inlineCode",{parentName:"li"},"Lock contract ID:"),") would like this:",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"Lock contract ID: 48f59da2ac632117bf79b4aa986f5ece8a2439dc143d576965c17bc8275b0925\n"))),(0,i.yg)("li",{parentName:"ol"},"Run the following to verify ",(0,i.yg)("inlineCode",{parentName:"li"},"alice"),"'s lock, replacing ",(0,i.yg)("inlineCode",{parentName:"li"},"<contract-id>")," with actual ",(0,i.yg)("inlineCode",{parentName:"li"},"contract-id"),":",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset is-locked --network=network1 --lock_contract_id=<contract-id>\n"))),(0,i.yg)("li",{parentName:"ol"},"Run the following to trigger ",(0,i.yg)("inlineCode",{parentName:"li"},"bob")," locking ",(0,i.yg)("inlineCode",{parentName:"li"},"10")," units of ",(0,i.yg)("inlineCode",{parentName:"li"},"BobERC20")," tokens for ",(0,i.yg)("inlineCode",{parentName:"li"},"alice")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"network2")," for 30 mins:",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset lock --network=network2 --sender_account=2 --recipient_account=1 --amount=10 --timeout=1800 --hash_base64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs=\n")),"Note the ",(0,i.yg)("inlineCode",{parentName:"li"},"contract-id")," again for this lock printed as output in above command. Let's refer it ",(0,i.yg)("inlineCode",{parentName:"li"},"<contract-id-2>")," for this demonstration."),(0,i.yg)("li",{parentName:"ol"},"Run the following to verify ",(0,i.yg)("inlineCode",{parentName:"li"},"bob"),"'s lock:",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset is-locked --network=network2 --lock_contract_id=<contract-id-2>\n"))),(0,i.yg)("li",{parentName:"ol"},"Run the following to trigger ",(0,i.yg)("inlineCode",{parentName:"li"},"alice"),"'s claim for ",(0,i.yg)("inlineCode",{parentName:"li"},"10")," units of ",(0,i.yg)("inlineCode",{parentName:"li"},"BobERC20")," tokens locked by ",(0,i.yg)("inlineCode",{parentName:"li"},"bob")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"network2"),":",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset claim --network=network2 --recipient_account=1 --preimage=secrettext --lock_contract_id=<contract-id-2>\n"))),(0,i.yg)("li",{parentName:"ol"},"Run the following to trigger ",(0,i.yg)("inlineCode",{parentName:"li"},"bob"),"'s claim for ",(0,i.yg)("inlineCode",{parentName:"li"},"AliceERC721")," NFT with id ",(0,i.yg)("inlineCode",{parentName:"li"},"0")," locked by ",(0,i.yg)("inlineCode",{parentName:"li"},"alice")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"network1"),":",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset claim --network=network1 --recipient_account=2 --preimage=secrettext --token_id=0 --lock_contract_id=<contract-id>\n")))),(0,i.yg)("p",null,"The above steps complete a successful asset exchange between two Besu networks.\nIn addition to the above commands, following commands can be run if specified timeout has expired and the locked asset remains unclaimed."),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},"If ",(0,i.yg)("inlineCode",{parentName:"li"},"alice")," wants to unlock the asset, run the following to trigger ",(0,i.yg)("inlineCode",{parentName:"li"},"alice"),"'s re-claim for ",(0,i.yg)("inlineCode",{parentName:"li"},"AliceERC721")," NFT with id ",(0,i.yg)("inlineCode",{parentName:"li"},"0")," locked in ",(0,i.yg)("inlineCode",{parentName:"li"},"network1"),":",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset unlock --network=network1 --lock_contract_id=<contract-id> --sender_account=1 --token_id=0\n"))),(0,i.yg)("li",{parentName:"ul"},"If ",(0,i.yg)("inlineCode",{parentName:"li"},"bob")," wants to unlock the token asset, run the following to trigger ",(0,i.yg)("inlineCode",{parentName:"li"},"bob"),"'s re-claim for ",(0,i.yg)("inlineCode",{parentName:"li"},"10 BobERC20")," tokens locked in ",(0,i.yg)("inlineCode",{parentName:"li"},"network2"),":",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset unlock --network=network2 --lock_contract_id=<contract-id-2> --sender_account=2\n")))),(0,i.yg)("h2",{id:"aliceerc1155-with-boberc20"},"AliceERC1155 with BobERC20"),(0,i.yg)("p",null,"One Besu network transfers an non-fungible ",(0,i.yg)("inlineCode",{parentName:"p"},"5 AliceERC1155")," tokens with id ",(0,i.yg)("inlineCode",{parentName:"p"},"0")," from Alice to Bob in exchange for a transfer of ",(0,i.yg)("inlineCode",{parentName:"p"},"50 BobERC20")," tokens from Bob to Alice in the other network. We will use account ",(0,i.yg)("inlineCode",{parentName:"p"},"1")," for Alice and account ",(0,i.yg)("inlineCode",{parentName:"p"},"2")," for Bob in both networks."),(0,i.yg)("p",null,"Run the following steps:"),(0,i.yg)("ol",null,(0,i.yg)("li",{parentName:"ol"},"Navigate to the ",(0,i.yg)("inlineCode",{parentName:"li"},"samples/besu/besu-cli")," folder in your clone of the Weaver repository."),(0,i.yg)("li",{parentName:"ol"},"Run the following to verify the status of the assets owned by ",(0,i.yg)("inlineCode",{parentName:"li"},"alice")," and ",(0,i.yg)("inlineCode",{parentName:"li"},"bob")," in the two networks:",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset get-balance --network=network1 --account=1\n./bin/besu-cli asset get-balance --network=network1 --account=2\n./bin/besu-cli asset get-balance --network=network2 --account=1\n./bin/besu-cli asset get-balance --network=network2 --account=2\n"))),(0,i.yg)("li",{parentName:"ol"},"Generate Secret-Hash Pair using following command (prints hash in base64):",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre"},"./bin/besu-cli hash --hash_fn=SHA256 secrettext\n"))),(0,i.yg)("li",{parentName:"ol"},"Run the following to trigger ",(0,i.yg)("inlineCode",{parentName:"li"},"alice")," locking ",(0,i.yg)("inlineCode",{parentName:"li"},"5 AliceERC1155")," token with id ",(0,i.yg)("inlineCode",{parentName:"li"},"0")," for ",(0,i.yg)("inlineCode",{parentName:"li"},"bob")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"network1")," for 1 hour",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset lock --network=network1 --sender_account=1 --recipient_account=2 --amount=5 --token_id=0 --asset_type=ERC1155 --timeout=3600 --hash_base64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs=\n")),"Value set to ",(0,i.yg)("inlineCode",{parentName:"li"},"hash_base64")," argument corresponds to what was generated in Step 3. Note the ",(0,i.yg)("inlineCode",{parentName:"li"},"contract-id")," printed as output in above command. The output line containing ",(0,i.yg)("inlineCode",{parentName:"li"},"contract-id")," (text in base64 after ",(0,i.yg)("inlineCode",{parentName:"li"},"Lock contract ID:"),") would like this:",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"Lock contract ID: 48f59da2ac632117bf79b4aa986f5ece8a2439dc143d576965c17bc8275b0925\n"))),(0,i.yg)("li",{parentName:"ol"},"Run the following to verify ",(0,i.yg)("inlineCode",{parentName:"li"},"alice"),"'s lock, replacing ",(0,i.yg)("inlineCode",{parentName:"li"},"<contract-id>")," with actual ",(0,i.yg)("inlineCode",{parentName:"li"},"contract-id"),":",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset is-locked --network=network1 --lock_contract_id=<contract-id>\n"))),(0,i.yg)("li",{parentName:"ol"},"Run the following to trigger ",(0,i.yg)("inlineCode",{parentName:"li"},"bob")," locking ",(0,i.yg)("inlineCode",{parentName:"li"},"50")," units of ",(0,i.yg)("inlineCode",{parentName:"li"},"BobERC20")," tokens for ",(0,i.yg)("inlineCode",{parentName:"li"},"alice")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"network2"),":",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset lock --network=network2 --sender_account=2 --recipient_account=1 --amount=50 --timeout=3600 --hash_base64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs=\n")),"Note the ",(0,i.yg)("inlineCode",{parentName:"li"},"contract-id")," again for this lock printed as output in above command. Let's refer it ",(0,i.yg)("inlineCode",{parentName:"li"},"<contract-id-2>")," for this demonstration."),(0,i.yg)("li",{parentName:"ol"},"Run the following to verify ",(0,i.yg)("inlineCode",{parentName:"li"},"bob"),"'s lock:",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset is-locked --network=network2 --lock_contract_id=<contract-id-2>\n"))),(0,i.yg)("li",{parentName:"ol"},"Run the following to trigger ",(0,i.yg)("inlineCode",{parentName:"li"},"alice"),"'s claim for ",(0,i.yg)("inlineCode",{parentName:"li"},"50")," units of ",(0,i.yg)("inlineCode",{parentName:"li"},"BobERC20")," tokens locked by ",(0,i.yg)("inlineCode",{parentName:"li"},"bob")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"network2"),":",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset claim --network=network2 --recipient_account=1 --preimage=secrettext --lock_contract_id=<contract-id-2>\n"))),(0,i.yg)("li",{parentName:"ol"},"Run the following to trigger ",(0,i.yg)("inlineCode",{parentName:"li"},"bob"),"'s claim for ",(0,i.yg)("inlineCode",{parentName:"li"},"5 AliceERC1155")," tokens with id ",(0,i.yg)("inlineCode",{parentName:"li"},"0")," locked by ",(0,i.yg)("inlineCode",{parentName:"li"},"alice")," in ",(0,i.yg)("inlineCode",{parentName:"li"},"network1"),":",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset claim --network=network1 --recipient_account=2 --preimage=secrettext --token_id=0 --lock_contract_id=<contract-id>\n")))),(0,i.yg)("p",null,"The above steps complete a successful asset exchange between two Besu networks.\nIn addition to the above commands, following commands can be run if specified timeout has expired and the locked asset remains unclaimed."),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},"If ",(0,i.yg)("inlineCode",{parentName:"li"},"alice")," wants to unlock the asset, run the following to trigger ",(0,i.yg)("inlineCode",{parentName:"li"},"alice"),"'s re-claim for ",(0,i.yg)("inlineCode",{parentName:"li"},"5 AliceERC1155")," tokens with id ",(0,i.yg)("inlineCode",{parentName:"li"},"0")," locked in ",(0,i.yg)("inlineCode",{parentName:"li"},"network1"),":",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset unlock --network=network1 --lock_contract_id=<contract-id> --sender_account=1 --token_id=0\n"))),(0,i.yg)("li",{parentName:"ul"},"If ",(0,i.yg)("inlineCode",{parentName:"li"},"bob")," wants to unlock the token asset, run the following to trigger ",(0,i.yg)("inlineCode",{parentName:"li"},"bob"),"'s re-claim for ",(0,i.yg)("inlineCode",{parentName:"li"},"50 BobERC20")," tokens locked in ",(0,i.yg)("inlineCode",{parentName:"li"},"network2"),":",(0,i.yg)("pre",{parentName:"li"},(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset unlock --network=network2 --lock_contract_id=<contract-id-2> --sender_account=2\n")))),(0,i.yg)("p",null,"Run the following to verify the status of the assets owned by ",(0,i.yg)("inlineCode",{parentName:"p"},"alice")," and ",(0,i.yg)("inlineCode",{parentName:"p"},"bob")," in the two networks:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-bash"},"./bin/besu-cli asset get-balance --network=network1 --account=1\n./bin/besu-cli asset get-balance --network=network1 --account=2\n./bin/besu-cli asset get-balance --network=network2 --account=1\n./bin/besu-cli asset get-balance --network=network2 --account=2\n")))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/f5ed51a1.78c8cfe5.js b/assets/js/f5ed51a1.78c8cfe5.js new file mode 100644 index 000000000..2004b8926 --- /dev/null +++ b/assets/js/f5ed51a1.78c8cfe5.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[6559],{5680:(e,t,n)=>{n.d(t,{xA:()=>p,yg:()=>g});var r=n(6540);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?a(Object(n),!0).forEach((function(t){i(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):a(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,r,i=function(e,t){if(null==e)return{};var n,r,i={},a=Object.keys(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=r.createContext({}),c=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=c(e.components);return r.createElement(s.Provider,{value:t},e.children)},d="mdxType",y={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},u=r.forwardRef((function(e,t){var n=e.components,i=e.mdxType,a=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),d=c(n),u=i,g=d["".concat(s,".").concat(u)]||d[u]||y[u]||a;return n?r.createElement(g,o(o({ref:t},p),{},{components:n})):r.createElement(g,o({ref:t},p))}));function g(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var a=n.length,o=new Array(a);o[0]=u;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[d]="string"==typeof e?e:i,o[1]=l;for(var c=2;c<a;c++)o[c]=n[c];return r.createElement.apply(null,o)}return r.createElement.apply(null,n)}u.displayName="MDXCreateElement"},367:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>y,frontMatter:()=>a,metadata:()=>l,toc:()=>c});var r=n(8168),i=(n(6540),n(5680));const a={id:"levels-of-interoperability",title:"Levels of Interoperability"},o=void 0,l={unversionedId:"external/what-is-interoperability/levels-of-interoperability",id:"external/what-is-interoperability/levels-of-interoperability",title:"Levels of Interoperability",description:"\x3c!--",source:"@site/docs/external/what-is-interoperability/levels-of-interoperability.md",sourceDirName:"external/what-is-interoperability",slug:"/external/what-is-interoperability/levels-of-interoperability",permalink:"/weaver-dlt-interoperability/docs/external/what-is-interoperability/levels-of-interoperability",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/what-is-interoperability/levels-of-interoperability.md",tags:[],version:"current",frontMatter:{id:"levels-of-interoperability",title:"Levels of Interoperability"},sidebar:"Documentation",previous:{title:"Understanding Interoperability",permalink:"/weaver-dlt-interoperability/docs/external/what-is-interoperability/understanding-interoperability"},next:{title:"Integration Patterns",permalink:"/weaver-dlt-interoperability/docs/external/what-is-interoperability/integration-patterns"}},s={},c=[],p={toc:c},d="wrapper";function y(e){let{components:t,...a}=e;return(0,i.yg)(d,(0,r.A)({},p,a,{components:t,mdxType:"MDXLayout"}),(0,i.yg)("p",null,"Established models of information systems interoperability stratify interoperability concerns into multiple levels. This includes technical, syntactic, semantic and application levels as shown below. "),(0,i.yg)("p",null,"Above the protocol and application levels there are two additional levels that require careful attention when enabling interoperability. These cover governance and policy decisions when communicating state as well as the legal and regulatory implications of networks under different jurisdictions."),(0,i.yg)("p",null,(0,i.yg)("img",{src:n(9457).A,width:"1203",height:"584"})),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("p",{parentName:"li"},(0,i.yg)("strong",{parentName:"p"},"Technical"),": The technical level is a low-level concern that focuses on the underlying wire protocol used for communication. Examples of protocols at this level include gRPC, Apache Thrift, ASN.1 and CBOR. Protocols at this level are point-to-point and addresses additional concerns such as version negotiation and message delivery guarantees.")),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("p",{parentName:"li"},(0,i.yg)("strong",{parentName:"p"},"Syntactic"),": The syntactic level is concerned with the structure and format of the messages exchanged. This includes protocol elements such as keywords and types. Examples include protocols defined using Google's Protocol Buffers, JSON-RPC and ASN.1.")),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("p",{parentName:"li"},(0,i.yg)("strong",{parentName:"p"},"Semantic"),": The semantic level provides meaning to the messages exchanged. In the context of cross-chain communication, this includes messages that represent a data transfer or an asset exchange as well as other information such as validity proofs and actors involved.")),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("p",{parentName:"li"},(0,i.yg)("strong",{parentName:"p"},"Application"),": The application level addresses domain or use-case specific concerns. In this level, interoperability deals with industry standard data models (e.g. supply chain standards such as GS1) and business processes. This level is orthogonal to the technology concerns of interoperability.")),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("p",{parentName:"li"},(0,i.yg)("strong",{parentName:"p"},"Governance and Policies"),": The governing members of a ledger play a critical role in extending business processes to external systems. Interoperability necessitates that the governing bodies of the respective systems agree on the nature of their collaboration. The policies enforce these decisions and covers aspects such as access control and conditions for determining the validity of state proofs.")),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("p",{parentName:"li"},(0,i.yg)("strong",{parentName:"p"},"Legal and Regulation"),": Networks residing in different jurisdictions must be comply with existing laws and regulations when communicating state."))))}y.isMDXComponent=!0},9457:(e,t,n)=>{n.d(t,{A:()=>r});const r=n.p+"assets/images/levels-of-interoperability-9646e330e0bf206ef88eeefacc841185.jpg"}}]); \ No newline at end of file diff --git a/assets/js/f5ed51a1.b849efe5.js b/assets/js/f5ed51a1.b849efe5.js deleted file mode 100644 index e56886106..000000000 --- a/assets/js/f5ed51a1.b849efe5.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[8492],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>f});var r=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?a(Object(n),!0).forEach((function(t){i(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):a(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,r,i=function(e,t){if(null==e)return{};var n,r,i={},a=Object.keys(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=r.createContext({}),c=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=c(e.components);return r.createElement(s.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,i=e.mdxType,a=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),d=c(n),m=i,f=d["".concat(s,".").concat(m)]||d[m]||u[m]||a;return n?r.createElement(f,o(o({ref:t},p),{},{components:n})):r.createElement(f,o({ref:t},p))}));function f(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var a=n.length,o=new Array(a);o[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[d]="string"==typeof e?e:i,o[1]=l;for(var c=2;c<a;c++)o[c]=n[c];return r.createElement.apply(null,o)}return r.createElement.apply(null,n)}m.displayName="MDXCreateElement"},3005:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>u,frontMatter:()=>a,metadata:()=>l,toc:()=>c});var r=n(7462),i=(n(7294),n(3905));const a={id:"levels-of-interoperability",title:"Levels of Interoperability"},o=void 0,l={unversionedId:"external/what-is-interoperability/levels-of-interoperability",id:"external/what-is-interoperability/levels-of-interoperability",title:"Levels of Interoperability",description:"\x3c!--",source:"@site/docs/external/what-is-interoperability/levels-of-interoperability.md",sourceDirName:"external/what-is-interoperability",slug:"/external/what-is-interoperability/levels-of-interoperability",permalink:"/weaver-dlt-interoperability/docs/external/what-is-interoperability/levels-of-interoperability",draft:!1,editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/docs/external/what-is-interoperability/levels-of-interoperability.md",tags:[],version:"current",frontMatter:{id:"levels-of-interoperability",title:"Levels of Interoperability"},sidebar:"Documentation",previous:{title:"Understanding Interoperability",permalink:"/weaver-dlt-interoperability/docs/external/what-is-interoperability/understanding-interoperability"},next:{title:"Integration Patterns",permalink:"/weaver-dlt-interoperability/docs/external/what-is-interoperability/integration-patterns"}},s={},c=[],p={toc:c},d="wrapper";function u(e){let{components:t,...a}=e;return(0,i.kt)(d,(0,r.Z)({},p,a,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"Established models of information systems interoperability stratify interoperability concerns into multiple levels. This includes technical, syntactic, semantic and application levels as shown below. "),(0,i.kt)("p",null,"Above the protocol and application levels there are two additional levels that require careful attention when enabling interoperability. These cover governance and policy decisions when communicating state as well as the legal and regulatory implications of networks under different jurisdictions."),(0,i.kt)("p",null,(0,i.kt)("img",{src:n(3449).Z,width:"1203",height:"584"})),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},"Technical"),": The technical level is a low-level concern that focuses on the underlying wire protocol used for communication. Examples of protocols at this level include gRPC, Apache Thrift, ASN.1 and CBOR. Protocols at this level are point-to-point and addresses additional concerns such as version negotiation and message delivery guarantees.")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},"Syntactic"),": The syntactic level is concerned with the structure and format of the messages exchanged. This includes protocol elements such as keywords and types. Examples include protocols defined using Google's Protocol Buffers, JSON-RPC and ASN.1.")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},"Semantic"),": The semantic level provides meaning to the messages exchanged. In the context of cross-chain communication, this includes messages that represent a data transfer or an asset exchange as well as other information such as validity proofs and actors involved.")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},"Application"),": The application level addresses domain or use-case specific concerns. In this level, interoperability deals with industry standard data models (e.g. supply chain standards such as GS1) and business processes. This level is orthogonal to the technology concerns of interoperability.")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},"Governance and Policies"),": The governing members of a ledger play a critical role in extending business processes to external systems. Interoperability necessitates that the governing bodies of the respective systems agree on the nature of their collaboration. The policies enforce these decisions and covers aspects such as access control and conditions for determining the validity of state proofs.")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},"Legal and Regulation"),": Networks residing in different jurisdictions must be comply with existing laws and regulations when communicating state."))))}u.isMDXComponent=!0},3449:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/levels-of-interoperability-9646e330e0bf206ef88eeefacc841185.jpg"}}]); \ No newline at end of file diff --git a/assets/js/main.852d9073.js b/assets/js/main.852d9073.js deleted file mode 100644 index 7a9cb8b6e..000000000 --- a/assets/js/main.852d9073.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! For license information please see main.852d9073.js.LICENSE.txt */ -(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[179],{723:(e,t,n)=>{"use strict";n.d(t,{Z:()=>f});var r=n(7294),a=n(7462),i=n(8356),o=n.n(i),l=n(6887);const s={"071be86b":[()=>n.e(8922).then(n.bind(n,5316)),"@site/docs/external/user-stories/financial-markets.md",5316],13886346:[()=>n.e(231).then(n.bind(n,363)),"@site/docs/external/publications.md",363],"15bfa0c2":[()=>n.e(350).then(n.bind(n,6166)),"@site/docs/internal/development/cordapp-interop/cordapp-interop-rest-api.md",6166],"15db90ce":[()=>n.e(8039).then(n.bind(n,4517)),"@site/docs/external/getting-started/interop/asset-exchange/corda-besu.md",4517],17896441:[()=>Promise.all([n.e(532),n.e(2004),n.e(7918)]).then(n.bind(n,9055)),"@theme/DocItem",9055],"1be78505":[()=>Promise.all([n.e(532),n.e(9514)]).then(n.bind(n,9963)),"@theme/DocPage",9963],"20a6a7d9":[()=>n.e(4330).then(n.bind(n,2383)),"@site/docs/external/getting-started/guide.md",2383],"239a9e81":[()=>n.e(7900).then(n.bind(n,7827)),"@site/docs/external/getting-started/interop/overview.md",7827],"25e7257c":[()=>n.e(7376).then(n.bind(n,7532)),"@site/docs/external/getting-started/interop/asset-exchange/fabric-besu.md",7532],"27ea52af":[()=>n.e(3807).then(n.bind(n,4884)),"@site/docs/external/what-is-interoperability/integration-patterns.md",4884],"2b962623":[()=>n.e(9822).then(n.bind(n,3539)),"@site/docs/external/user-stories/overview.md",3539],"2e5dd55e":[()=>n.e(4010).then(n.bind(n,8854)),"@site/docs/external/getting-started/interop/asset-transfer.md",8854],"2e5ddf1e":[()=>n.e(2187).then(n.bind(n,2931)),"@site/docs/internal/activity-plan.md",2931],"2ec21c4a":[()=>n.e(3299).then(n.bind(n,7219)),"@site/docs/external/getting-started/test-network/advanced-configuration.md",7219],36367655:[()=>n.e(7736).then(n.bind(n,3059)),"@site/docs/external/getting-started/test-network/setup-local.md",3059],"378badfe":[()=>n.e(369).then(n.bind(n,7094)),"@site/blog/2021-01-21-cross-chain-asset.md",7094],"3d094f56":[()=>n.e(3278).then(n.bind(n,6599)),"@site/docs/external/user-stories/legacy-integration.md",6599],"3d5da5a5":[()=>n.e(9178).then(n.bind(n,6456)),"@site/blog/2021-01-21-emergence-enterprise-interoperability.md?truncated=true",6456],"3ec01bef":[()=>n.e(867).then(n.bind(n,9636)),"@site/docs/external/deployment-considerations/governance-and-policies.md",9636],"46d80676":[()=>n.e(9219).then(n.bind(n,2478)),"@site/docs/external/security-model/proofs-and-verification.md",2478],"53c981a7":[()=>n.e(3773).then(n.bind(n,2281)),"@site/docs/external/getting-started/test-network/setup-local-docker.md",2281],"56182e71":[()=>n.e(355).then(n.bind(n,6794)),"@site/blog/2021-01-21-emergence-enterprise-interoperability.md",6794],"591644de":[()=>n.e(7295).then(n.t.bind(n,5970,19)),"~blog/default/weaver-dlt-interoperability-blog-742.json",5970],59395140:[()=>n.e(8298).then(n.bind(n,8456)),"@site/docs/external/getting-started/interop/asset-exchange/overview.md",8456],"5c41994f":[()=>n.e(1637).then(n.bind(n,8411)),"@site/docs/external/getting-started/interop/asset-exchange/fabric-corda.md",8411],"5e9f5e1a":[()=>Promise.resolve().then(n.bind(n,6809)),"@generated/docusaurus.config",6809],"61becdbc":[()=>n.e(8340).then(n.t.bind(n,5745,19)),"/home/runner/work/weaver-dlt-interoperability/weaver-dlt-interoperability/docs/.docusaurus/docusaurus-plugin-content-pages/default/plugin-route-context-module-100.json",5745],"64b157a3":[()=>n.e(830).then(n.t.bind(n,9926,19)),"~blog/default/weaver-dlt-interoperability-blog-archive-7bd.json",9926],"6835b8cd":[()=>n.e(6445).then(n.bind(n,1626)),"@site/docs/external/specifications.md",1626],"7291aaef":[()=>n.e(1323).then(n.bind(n,5123)),"@site/docs/external/architecture-and-design/drivers.md",5123],"814f3328":[()=>n.e(2535).then(n.t.bind(n,5641,19)),"~blog/default/blog-post-list-prop-default.json",5641],"8379e623":[()=>n.e(3162).then(n.bind(n,8284)),"@site/docs/external/getting-started/enabling-weaver-network/overview.md",8284],"85de58a0":[()=>n.e(9530).then(n.bind(n,5680)),"@site/docs/external/interoperability-modes.md",5680],"8758c959":[()=>n.e(7459).then(n.bind(n,1288)),"@site/docs/external/architecture-and-design/decentralized-identity.md",1288],"8b2840ea":[()=>n.e(9935).then(n.bind(n,8568)),"@site/docs/external/getting-started/test-network/setup-packages.md",8568],"935bcf2a":[()=>n.e(3283).then(n.bind(n,3444)),"@site/docs/external/getting-started/interop/asset-exchange/corda-corda.md",3444],"935f2afb":[()=>n.e(53).then(n.t.bind(n,1109,19)),"~docs/default/version-current-metadata-prop-751.json",1109],"98ecfc99":[()=>n.e(3660).then(n.bind(n,9981)),"@site/docs/external/getting-started/enabling-weaver-network/fabric.md",9981],"99b332c9":[()=>n.e(1939).then(n.t.bind(n,3769,19)),"/home/runner/work/weaver-dlt-interoperability/weaver-dlt-interoperability/docs/.docusaurus/docusaurus-plugin-content-docs/default/plugin-route-context-module-100.json",3769],"9a814649":[()=>n.e(676).then(n.bind(n,1518)),"@site/docs/internal/development/cordapp-interop/cordapp-interop-api-assets.md",1518],"9e4087bc":[()=>n.e(3608).then(n.bind(n,3169)),"@theme/BlogArchivePage",3169],"9f52c9db":[()=>n.e(2435).then(n.bind(n,8540)),"@site/docs/external/deployment-considerations/deployment-patterns.md",8540],a3e47e5c:[()=>n.e(8995).then(n.bind(n,938)),"@site/docs/external/user-stories/global-trade.md",938],a50a7707:[()=>n.e(7195).then(n.bind(n,7644)),"@site/docs/external/security-model/end-to-end-security.md",7644],a6aa9e1f:[()=>Promise.all([n.e(532),n.e(2004),n.e(8218),n.e(3089)]).then(n.bind(n,3269)),"@theme/BlogListPage",3269],a6da3080:[()=>n.e(3145).then(n.bind(n,474)),"@site/docs/external/getting-started/interop/asset-exchange.md",474],a92192c3:[()=>n.e(87).then(n.bind(n,9673)),"@site/docs/external/security-model/authentication.md",9673],abd77f53:[()=>n.e(3214).then(n.bind(n,9879)),"@site/docs/internal/development/cordapp-interop/cordapp-interop-assets.md",9879],ac36c4b6:[()=>n.e(5622).then(n.bind(n,6277)),"@site/docs/external/roadmap.md",6277],b0f8195e:[()=>n.e(5398).then(n.bind(n,2674)),"@site/docs/external/getting-started/test-network/ledger-initialization.md",2674],b379f194:[()=>n.e(2136).then(n.bind(n,2895)),"@site/docs/external/architecture-and-design/overview.md",2895],b545330d:[()=>n.e(6610).then(n.bind(n,9270)),"@site/docs/external/getting-started/enabling-weaver-network/besu.md",9270],ba46e1b8:[()=>n.e(8214).then(n.bind(n,3527)),"@site/docs/external/introduction.md",3527],bdfaba9c:[()=>n.e(2981).then(n.bind(n,1339)),"@site/blog/2021-01-21-cross-chain-asset.md?truncated=true",1339],bf5dfefe:[()=>n.e(8362).then(n.bind(n,7192)),"@site/docs/external/getting-started/interop/asset-exchange/fabric-fabric.md",7192],c4f5d8e4:[()=>Promise.all([n.e(532),n.e(4195)]).then(n.bind(n,5239)),"@site/src/pages/index.js",5239],c9723ef0:[()=>n.e(9167).then(n.bind(n,3190)),"@site/docs/external/getting-started/test-network/setup-packages-docker.md",3190],c9886a33:[()=>n.e(5671).then(n.bind(n,2238)),"@site/docs/internal/documentation-guidelines.md",2238],ccc49370:[()=>Promise.all([n.e(532),n.e(2004),n.e(8218),n.e(6103)]).then(n.bind(n,5203)),"@theme/BlogPostPage",5203],cd2e0b0a:[()=>n.e(5261).then(n.bind(n,9805)),"@site/docs/internal/development/cordapp-interop/cordapp-interop.md",9805],ce7e6f90:[()=>n.e(9962).then(n.bind(n,5636)),"@site/docs/external/deployment-considerations/legal-and-regulation.md",5636],d85aeaf8:[()=>n.e(5651).then(n.bind(n,9402)),"@site/docs/internal/development/cordapp-interop/cordapp-interop-flows.md",9402],da157423:[()=>n.e(3395).then(n.bind(n,1253)),"@site/docs/external/getting-started/interop/data-sharing.md",1253],e0bf5ccd:[()=>n.e(881).then(n.bind(n,7820)),"@site/docs/external/design-principles.md",7820],e67be6b3:[()=>n.e(54).then(n.bind(n,8552)),"@site/docs/external/architecture-and-design/relay.md",8552],ec2d6a08:[()=>n.e(6896).then(n.bind(n,5592)),"@site/docs/external/getting-started/test-network/overview.md",5592],ec8cb05d:[()=>n.e(9856).then(n.bind(n,9561)),"@site/docs/external/architecture-and-design/weaver-dapps.md",9561],ee4141e0:[()=>n.e(2752).then(n.t.bind(n,4469,19)),"/home/runner/work/weaver-dlt-interoperability/weaver-dlt-interoperability/docs/.docusaurus/docusaurus-plugin-content-blog/default/plugin-route-context-module-100.json",4469],ee88fe61:[()=>n.e(1749).then(n.bind(n,8866)),"@site/docs/external/security-model/access-control.md",8866],eeaeeec1:[()=>n.e(2649).then(n.bind(n,898)),"@site/docs/external/what-is-interoperability/understanding-interoperability.md",898],eed74c9c:[()=>n.e(2238).then(n.bind(n,4563)),"@site/docs/internal/team.md",4563],f0c74005:[()=>n.e(457).then(n.bind(n,4682)),"@site/docs/external/getting-started/enabling-weaver-network/corda.md",4682],f1311735:[()=>n.e(6664).then(n.bind(n,2846)),"@site/docs/external/getting-started/interop/asset-exchange/besu-besu.md",2846],f5ed51a1:[()=>n.e(8492).then(n.bind(n,3005)),"@site/docs/external/what-is-interoperability/levels-of-interoperability.md",3005]};function c(e){let{error:t,retry:n,pastDelay:a}=e;return t?r.createElement("div",{style:{textAlign:"center",color:"#fff",backgroundColor:"#fa383e",borderColor:"#fa383e",borderStyle:"solid",borderRadius:"0.25rem",borderWidth:"1px",boxSizing:"border-box",display:"block",padding:"1rem",flex:"0 0 50%",marginLeft:"25%",marginRight:"25%",marginTop:"5rem",maxWidth:"50%",width:"100%"}},r.createElement("p",null,String(t)),r.createElement("div",null,r.createElement("button",{type:"button",onClick:n},"Retry"))):a?r.createElement("div",{style:{display:"flex",justifyContent:"center",alignItems:"center",height:"100vh"}},r.createElement("svg",{id:"loader",style:{width:128,height:110,position:"absolute",top:"calc(100vh - 64%)"},viewBox:"0 0 45 45",xmlns:"http://www.w3.org/2000/svg",stroke:"#61dafb"},r.createElement("g",{fill:"none",fillRule:"evenodd",transform:"translate(1 1)",strokeWidth:"2"},r.createElement("circle",{cx:"22",cy:"22",r:"6",strokeOpacity:"0"},r.createElement("animate",{attributeName:"r",begin:"1.5s",dur:"3s",values:"6;22",calcMode:"linear",repeatCount:"indefinite"}),r.createElement("animate",{attributeName:"stroke-opacity",begin:"1.5s",dur:"3s",values:"1;0",calcMode:"linear",repeatCount:"indefinite"}),r.createElement("animate",{attributeName:"stroke-width",begin:"1.5s",dur:"3s",values:"2;0",calcMode:"linear",repeatCount:"indefinite"})),r.createElement("circle",{cx:"22",cy:"22",r:"6",strokeOpacity:"0"},r.createElement("animate",{attributeName:"r",begin:"3s",dur:"3s",values:"6;22",calcMode:"linear",repeatCount:"indefinite"}),r.createElement("animate",{attributeName:"stroke-opacity",begin:"3s",dur:"3s",values:"1;0",calcMode:"linear",repeatCount:"indefinite"}),r.createElement("animate",{attributeName:"stroke-width",begin:"3s",dur:"3s",values:"2;0",calcMode:"linear",repeatCount:"indefinite"})),r.createElement("circle",{cx:"22",cy:"22",r:"8"},r.createElement("animate",{attributeName:"r",begin:"0s",dur:"1.5s",values:"6;1;2;3;4;5;6",calcMode:"linear",repeatCount:"indefinite"}))))):null}var u=n(9670),d=n(226);function p(e,t){if("*"===e)return o()({loading:c,loader:()=>n.e(4972).then(n.bind(n,4972)),modules:["@theme/NotFound"],webpack:()=>[4972],render(e,t){const n=e.default;return r.createElement(d.z,{value:{plugin:{name:"native",id:"default"}}},r.createElement(n,t))}});const i=l[`${e}-${t}`],p={},f=[],m=[],g=(0,u.Z)(i);return Object.entries(g).forEach((e=>{let[t,n]=e;const r=s[n];r&&(p[t]=r[0],f.push(r[1]),m.push(r[2]))})),o().Map({loading:c,loader:p,modules:f,webpack:()=>m,render(t,n){const o=JSON.parse(JSON.stringify(i));Object.entries(t).forEach((t=>{let[n,r]=t;const a=r.default;if(!a)throw new Error(`The page component at ${e} doesn't have a default export. This makes it impossible to render anything. Consider default-exporting a React component.`);"object"!=typeof a&&"function"!=typeof a||Object.keys(r).filter((e=>"default"!==e)).forEach((e=>{a[e]=r[e]}));let i=o;const l=n.split(".");l.slice(0,-1).forEach((e=>{i=i[e]})),i[l[l.length-1]]=a}));const l=o.__comp;delete o.__comp;const s=o.__context;return delete o.__context,r.createElement(d.z,{value:s},r.createElement(l,(0,a.Z)({},o,n)))}})}const f=[{path:"/weaver-dlt-interoperability/blog",component:p("/weaver-dlt-interoperability/blog","fba"),exact:!0},{path:"/weaver-dlt-interoperability/blog/2021/01/21/cross-chain-asset",component:p("/weaver-dlt-interoperability/blog/2021/01/21/cross-chain-asset","014"),exact:!0},{path:"/weaver-dlt-interoperability/blog/2021/01/21/emergence-enterprise-interoperability",component:p("/weaver-dlt-interoperability/blog/2021/01/21/emergence-enterprise-interoperability","e8d"),exact:!0},{path:"/weaver-dlt-interoperability/blog/archive",component:p("/weaver-dlt-interoperability/blog/archive","502"),exact:!0},{path:"/weaver-dlt-interoperability/docs",component:p("/weaver-dlt-interoperability/docs","25b"),routes:[{path:"/weaver-dlt-interoperability/docs/external/architecture-and-design/decentralized-identity",component:p("/weaver-dlt-interoperability/docs/external/architecture-and-design/decentralized-identity","999"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/architecture-and-design/drivers",component:p("/weaver-dlt-interoperability/docs/external/architecture-and-design/drivers","79c"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/architecture-and-design/overview",component:p("/weaver-dlt-interoperability/docs/external/architecture-and-design/overview","390"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/architecture-and-design/relay",component:p("/weaver-dlt-interoperability/docs/external/architecture-and-design/relay","db6"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/architecture-and-design/weaver-dapps",component:p("/weaver-dlt-interoperability/docs/external/architecture-and-design/weaver-dapps","52c"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/deployment-considerations/deployment-patterns",component:p("/weaver-dlt-interoperability/docs/external/deployment-considerations/deployment-patterns","22b"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/deployment-considerations/governance-and-policies",component:p("/weaver-dlt-interoperability/docs/external/deployment-considerations/governance-and-policies","d9a"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/deployment-considerations/legal-and-regulation",component:p("/weaver-dlt-interoperability/docs/external/deployment-considerations/legal-and-regulation","956"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/design-principles",component:p("/weaver-dlt-interoperability/docs/external/design-principles","9ec"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/besu",component:p("/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/besu","6b8"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/corda",component:p("/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/corda","a90"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/fabric",component:p("/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/fabric","8fd"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/overview",component:p("/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/overview","90e"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/getting-started/guide",component:p("/weaver-dlt-interoperability/docs/external/getting-started/guide","465"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange",component:p("/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange","8e9"),exact:!0},{path:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/besu-besu",component:p("/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/besu-besu","c57"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/corda-besu",component:p("/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/corda-besu","eea"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/corda-corda",component:p("/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/corda-corda","929"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-besu",component:p("/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-besu","51a"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-corda",component:p("/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-corda","752"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-fabric",component:p("/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-fabric","7fb"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview",component:p("/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview","332"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-transfer",component:p("/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-transfer","1df"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/getting-started/interop/data-sharing",component:p("/weaver-dlt-interoperability/docs/external/getting-started/interop/data-sharing","c36"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/getting-started/interop/overview",component:p("/weaver-dlt-interoperability/docs/external/getting-started/interop/overview","91f"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/advanced-configuration",component:p("/weaver-dlt-interoperability/docs/external/getting-started/test-network/advanced-configuration","93b"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/ledger-initialization",component:p("/weaver-dlt-interoperability/docs/external/getting-started/test-network/ledger-initialization","704"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/overview",component:p("/weaver-dlt-interoperability/docs/external/getting-started/test-network/overview","067"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-local",component:p("/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-local","b48"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-local-docker",component:p("/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-local-docker","a86"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-packages",component:p("/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-packages","452"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-packages-docker",component:p("/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-packages-docker","687"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/interoperability-modes",component:p("/weaver-dlt-interoperability/docs/external/interoperability-modes","3ac"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/introduction",component:p("/weaver-dlt-interoperability/docs/external/introduction","02e"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/publications",component:p("/weaver-dlt-interoperability/docs/external/publications","1c5"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/roadmap",component:p("/weaver-dlt-interoperability/docs/external/roadmap","877"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/security-model/access-control",component:p("/weaver-dlt-interoperability/docs/external/security-model/access-control","4cc"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/security-model/authentication",component:p("/weaver-dlt-interoperability/docs/external/security-model/authentication","5ea"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/security-model/end-to-end-security",component:p("/weaver-dlt-interoperability/docs/external/security-model/end-to-end-security","0a1"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/security-model/proofs-and-verification",component:p("/weaver-dlt-interoperability/docs/external/security-model/proofs-and-verification","095"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/specifications",component:p("/weaver-dlt-interoperability/docs/external/specifications","bd8"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/user-stories/financial-markets",component:p("/weaver-dlt-interoperability/docs/external/user-stories/financial-markets","168"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/user-stories/global-trade",component:p("/weaver-dlt-interoperability/docs/external/user-stories/global-trade","01e"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/user-stories/legacy-integration",component:p("/weaver-dlt-interoperability/docs/external/user-stories/legacy-integration","711"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/user-stories/overview",component:p("/weaver-dlt-interoperability/docs/external/user-stories/overview","1b3"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/what-is-interoperability/integration-patterns",component:p("/weaver-dlt-interoperability/docs/external/what-is-interoperability/integration-patterns","6e2"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/what-is-interoperability/levels-of-interoperability",component:p("/weaver-dlt-interoperability/docs/external/what-is-interoperability/levels-of-interoperability","541"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/what-is-interoperability/understanding-interoperability",component:p("/weaver-dlt-interoperability/docs/external/what-is-interoperability/understanding-interoperability","4c3"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/internal/activity-plan",component:p("/weaver-dlt-interoperability/docs/internal/activity-plan","790"),exact:!0},{path:"/weaver-dlt-interoperability/docs/internal/development/cordapp-interop/",component:p("/weaver-dlt-interoperability/docs/internal/development/cordapp-interop/","edc"),exact:!0},{path:"/weaver-dlt-interoperability/docs/internal/development/cordapp-interop/cordapp-interop-api-assets",component:p("/weaver-dlt-interoperability/docs/internal/development/cordapp-interop/cordapp-interop-api-assets","055"),exact:!0},{path:"/weaver-dlt-interoperability/docs/internal/development/cordapp-interop/cordapp-interop-assets",component:p("/weaver-dlt-interoperability/docs/internal/development/cordapp-interop/cordapp-interop-assets","02a"),exact:!0},{path:"/weaver-dlt-interoperability/docs/internal/development/cordapp-interop/cordapp-interop-flows",component:p("/weaver-dlt-interoperability/docs/internal/development/cordapp-interop/cordapp-interop-flows","810"),exact:!0},{path:"/weaver-dlt-interoperability/docs/internal/development/cordapp-interop/cordapp-interop-rest-api",component:p("/weaver-dlt-interoperability/docs/internal/development/cordapp-interop/cordapp-interop-rest-api","46e"),exact:!0},{path:"/weaver-dlt-interoperability/docs/internal/documentation-guidelines",component:p("/weaver-dlt-interoperability/docs/internal/documentation-guidelines","cae"),exact:!0},{path:"/weaver-dlt-interoperability/docs/internal/team",component:p("/weaver-dlt-interoperability/docs/internal/team","331"),exact:!0}]},{path:"/weaver-dlt-interoperability/",component:p("/weaver-dlt-interoperability/","6e4"),exact:!0},{path:"*",component:p("*")}]},8934:(e,t,n)=>{"use strict";n.d(t,{_:()=>a,t:()=>i});var r=n(7294);const a=r.createContext(!1);function i(e){let{children:t}=e;const[n,i]=(0,r.useState)(!1);return(0,r.useEffect)((()=>{i(!0)}),[]),r.createElement(a.Provider,{value:n},t)}},9383:(e,t,n)=>{"use strict";var r=n(7294),a=n(3935),i=n(3727),o=n(405),l=n(412);const s=[n(2497),n(3310),n(8320),n(2295)];var c=n(723),u=n(6550),d=n(8790);function p(e){let{children:t}=e;return r.createElement(r.Fragment,null,t)}var f=n(7462),m=n(5742),g=n(2263),h=n(4996),b=n(6668),v=n(1944),y=n(4711),w=n(9727),x=n(3320),k=n(197);function E(){const{i18n:{defaultLocale:e,localeConfigs:t}}=(0,g.Z)(),n=(0,y.l)();return r.createElement(m.Z,null,Object.entries(t).map((e=>{let[t,{htmlLang:a}]=e;return r.createElement("link",{key:t,rel:"alternate",href:n.createUrl({locale:t,fullyQualified:!0}),hrefLang:a})})),r.createElement("link",{rel:"alternate",href:n.createUrl({locale:e,fullyQualified:!0}),hrefLang:"x-default"}))}function S(e){let{permalink:t}=e;const{siteConfig:{url:n}}=(0,g.Z)(),a=function(){const{siteConfig:{url:e}}=(0,g.Z)(),{pathname:t}=(0,u.TH)();return e+(0,h.Z)(t)}(),i=t?`${n}${t}`:a;return r.createElement(m.Z,null,r.createElement("meta",{property:"og:url",content:i}),r.createElement("link",{rel:"canonical",href:i}))}function T(){const{i18n:{currentLocale:e}}=(0,g.Z)(),{metadata:t,image:n}=(0,b.L)();return r.createElement(r.Fragment,null,r.createElement(m.Z,null,r.createElement("meta",{name:"twitter:card",content:"summary_large_image"}),r.createElement("body",{className:w.h})),n&&r.createElement(v.d,{image:n}),r.createElement(S,null),r.createElement(E,null),r.createElement(k.Z,{tag:x.HX,locale:e}),r.createElement(m.Z,null,t.map(((e,t)=>r.createElement("meta",(0,f.Z)({key:t},e))))))}const _=new Map;function C(e){if(_.has(e.pathname))return{...e,pathname:_.get(e.pathname)};if((0,d.f)(c.Z,e.pathname).some((e=>{let{route:t}=e;return!0===t.exact})))return _.set(e.pathname,e.pathname),e;const t=e.pathname.trim().replace(/(?:\/index)?\.html$/,"")||"/";return _.set(e.pathname,t),{...e,pathname:t}}var A=n(8934),P=n(8940);function N(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),r=1;r<t;r++)n[r-1]=arguments[r];const a=s.map((t=>{const r=t.default?.[e]??t[e];return r?.(...n)}));return()=>a.forEach((e=>e?.()))}const O=function(e){let{children:t,location:n,previousLocation:a}=e;return(0,r.useLayoutEffect)((()=>{a!==n&&(a&&function(e){const{hash:t}=e;if(t){const e=decodeURIComponent(t.substring(1)),n=document.getElementById(e);n?.scrollIntoView()}else window.scrollTo(0,0)}(n),N("onRouteDidUpdate",{previousLocation:a,location:n}))}),[a,n]),t};function I(e){const t=Array.from(new Set([e,decodeURI(e)])).map((e=>(0,d.f)(c.Z,e))).flat();return Promise.all(t.map((e=>e.route.component.preload?.())))}class L extends r.Component{previousLocation;routeUpdateCleanupCb;constructor(e){super(e),this.previousLocation=null,this.routeUpdateCleanupCb=l.Z.canUseDOM?N("onRouteUpdate",{previousLocation:null,location:this.props.location}):()=>{},this.state={nextRouteHasLoaded:!0}}shouldComponentUpdate(e,t){if(e.location===this.props.location)return t.nextRouteHasLoaded;const n=e.location;return this.previousLocation=this.props.location,this.setState({nextRouteHasLoaded:!1}),this.routeUpdateCleanupCb=N("onRouteUpdate",{previousLocation:this.previousLocation,location:n}),I(n.pathname).then((()=>{this.routeUpdateCleanupCb(),this.setState({nextRouteHasLoaded:!0})})).catch((e=>{console.warn(e),window.location.reload()})),!1}render(){const{children:e,location:t}=this.props;return r.createElement(O,{previousLocation:this.previousLocation,location:t},r.createElement(u.AW,{location:t,render:()=>e}))}}const D=L,R="docusaurus-base-url-issue-banner-container",M="docusaurus-base-url-issue-banner",F="docusaurus-base-url-issue-banner-suggestion-container",B="__DOCUSAURUS_INSERT_BASEURL_BANNER";function $(e){return`\nwindow['${B}'] = true;\n\ndocument.addEventListener('DOMContentLoaded', maybeInsertBanner);\n\nfunction maybeInsertBanner() {\n var shouldInsert = window['${B}'];\n shouldInsert && insertBanner();\n}\n\nfunction insertBanner() {\n var bannerContainer = document.getElementById('${R}');\n if (!bannerContainer) {\n return;\n }\n var bannerHtml = ${JSON.stringify(function(e){return`\n<div id="${M}" style="border: thick solid red; background-color: rgb(255, 230, 179); margin: 20px; padding: 20px; font-size: 20px;">\n <p style="font-weight: bold; font-size: 30px;">Your Docusaurus site did not load properly.</p>\n <p>A very common reason is a wrong site <a href="https://docusaurus.io/docs/docusaurus.config.js/#baseurl" style="font-weight: bold;">baseUrl configuration</a>.</p>\n <p>Current configured baseUrl = <span style="font-weight: bold; color: red;">${e}</span> ${"/"===e?" (default value)":""}</p>\n <p>We suggest trying baseUrl = <span id="${F}" style="font-weight: bold; color: green;"></span></p>\n</div>\n`}(e)).replace(/</g,"\\<")};\n bannerContainer.innerHTML = bannerHtml;\n var suggestionContainer = document.getElementById('${F}');\n var actualHomePagePath = window.location.pathname;\n var suggestedBaseUrl = actualHomePagePath.substr(-1) === '/'\n ? actualHomePagePath\n : actualHomePagePath + '/';\n suggestionContainer.innerHTML = suggestedBaseUrl;\n}\n`}function z(){const{siteConfig:{baseUrl:e}}=(0,g.Z)();return(0,r.useLayoutEffect)((()=>{window[B]=!1}),[]),r.createElement(r.Fragment,null,!l.Z.canUseDOM&&r.createElement(m.Z,null,r.createElement("script",null,$(e))),r.createElement("div",{id:R}))}function U(){const{siteConfig:{baseUrl:e,baseUrlIssueBanner:t}}=(0,g.Z)(),{pathname:n}=(0,u.TH)();return t&&n===e?r.createElement(z,null):null}function j(){const{siteConfig:{favicon:e,title:t,noIndex:n},i18n:{currentLocale:a,localeConfigs:i}}=(0,g.Z)(),o=(0,h.Z)(e),{htmlLang:l,direction:s}=i[a];return r.createElement(m.Z,null,r.createElement("html",{lang:l,dir:s}),r.createElement("title",null,t),r.createElement("meta",{property:"og:title",content:t}),r.createElement("meta",{name:"viewport",content:"width=device-width, initial-scale=1.0"}),n&&r.createElement("meta",{name:"robots",content:"noindex, nofollow"}),e&&r.createElement("link",{rel:"icon",href:o}))}var Z=n(4763);function H(){const e=(0,d.H)(c.Z),t=(0,u.TH)();return r.createElement(Z.Z,null,r.createElement(P.M,null,r.createElement(A.t,null,r.createElement(p,null,r.createElement(j,null),r.createElement(T,null),r.createElement(U,null),r.createElement(D,{location:C(t)},e)))))}var W=n(6887);const V=function(e){try{return document.createElement("link").relList.supports(e)}catch{return!1}}("prefetch")?function(e){return new Promise(((t,n)=>{if("undefined"==typeof document)return void n();const r=document.createElement("link");r.setAttribute("rel","prefetch"),r.setAttribute("href",e),r.onload=()=>t(),r.onerror=()=>n();const a=document.getElementsByTagName("head")[0]??document.getElementsByName("script")[0]?.parentNode;a?.appendChild(r)}))}:function(e){return new Promise(((t,n)=>{const r=new XMLHttpRequest;r.open("GET",e,!0),r.withCredentials=!0,r.onload=()=>{200===r.status?t():n()},r.send(null)}))};var G=n(9670);const q=new Set,Y=new Set,K=()=>navigator.connection?.effectiveType.includes("2g")||navigator.connection?.saveData,Q={prefetch(e){if(!(e=>!K()&&!Y.has(e)&&!q.has(e))(e))return!1;q.add(e);const t=(0,d.f)(c.Z,e).flatMap((e=>{return t=e.route.path,Object.entries(W).filter((e=>{let[n]=e;return n.replace(/-[^-]+$/,"")===t})).flatMap((e=>{let[,t]=e;return Object.values((0,G.Z)(t))}));var t}));return Promise.all(t.map((e=>{const t=n.gca(e);return t&&!t.includes("undefined")?V(t).catch((()=>{})):Promise.resolve()})))},preload:e=>!!(e=>!K()&&!Y.has(e))(e)&&(Y.add(e),I(e))},X=Object.freeze(Q);if(l.Z.canUseDOM){window.docusaurus=X;const e=a.hydrate;I(window.location.pathname).then((()=>{e(r.createElement(o.B6,null,r.createElement(i.VK,null,r.createElement(H,null))),document.getElementById("__docusaurus"))}))}},8940:(e,t,n)=>{"use strict";n.d(t,{_:()=>u,M:()=>d});var r=n(7294),a=n(6809);const i=JSON.parse('{"docusaurus-plugin-content-docs":{"default":{"path":"/weaver-dlt-interoperability/docs","versions":[{"name":"current","label":"Next","isLast":true,"path":"/weaver-dlt-interoperability/docs","mainDocId":"external/introduction","docs":[{"id":"external/architecture-and-design/decentralized-identity","path":"/weaver-dlt-interoperability/docs/external/architecture-and-design/decentralized-identity","sidebar":"Documentation"},{"id":"external/architecture-and-design/drivers","path":"/weaver-dlt-interoperability/docs/external/architecture-and-design/drivers","sidebar":"Documentation"},{"id":"external/architecture-and-design/overview","path":"/weaver-dlt-interoperability/docs/external/architecture-and-design/overview","sidebar":"Documentation"},{"id":"external/architecture-and-design/relay","path":"/weaver-dlt-interoperability/docs/external/architecture-and-design/relay","sidebar":"Documentation"},{"id":"external/architecture-and-design/weaver-dapps","path":"/weaver-dlt-interoperability/docs/external/architecture-and-design/weaver-dapps","sidebar":"Documentation"},{"id":"external/deployment-considerations/deployment-patterns","path":"/weaver-dlt-interoperability/docs/external/deployment-considerations/deployment-patterns","sidebar":"Documentation"},{"id":"external/deployment-considerations/governance-and-policies","path":"/weaver-dlt-interoperability/docs/external/deployment-considerations/governance-and-policies","sidebar":"Documentation"},{"id":"external/deployment-considerations/legal-and-regulation","path":"/weaver-dlt-interoperability/docs/external/deployment-considerations/legal-and-regulation","sidebar":"Documentation"},{"id":"external/design-principles","path":"/weaver-dlt-interoperability/docs/external/design-principles","sidebar":"Documentation"},{"id":"external/getting-started/enabling-weaver-network/besu","path":"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/besu","sidebar":"Documentation"},{"id":"external/getting-started/enabling-weaver-network/corda","path":"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/corda","sidebar":"Documentation"},{"id":"external/getting-started/enabling-weaver-network/fabric","path":"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/fabric","sidebar":"Documentation"},{"id":"external/getting-started/enabling-weaver-network/overview","path":"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/overview","sidebar":"Documentation"},{"id":"external/getting-started/guide","path":"/weaver-dlt-interoperability/docs/external/getting-started/guide","sidebar":"Documentation"},{"id":"external/getting-started/interop/asset-exchange","path":"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange"},{"id":"external/getting-started/interop/asset-exchange/besu-besu","path":"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/besu-besu","sidebar":"Documentation"},{"id":"external/getting-started/interop/asset-exchange/corda-besu","path":"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/corda-besu","sidebar":"Documentation"},{"id":"external/getting-started/interop/asset-exchange/corda-corda","path":"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/corda-corda","sidebar":"Documentation"},{"id":"external/getting-started/interop/asset-exchange/fabric-besu","path":"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-besu","sidebar":"Documentation"},{"id":"external/getting-started/interop/asset-exchange/fabric-corda","path":"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-corda","sidebar":"Documentation"},{"id":"external/getting-started/interop/asset-exchange/fabric-fabric","path":"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-fabric","sidebar":"Documentation"},{"id":"external/getting-started/interop/asset-exchange/overview","path":"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview","sidebar":"Documentation"},{"id":"external/getting-started/interop/asset-transfer","path":"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-transfer","sidebar":"Documentation"},{"id":"external/getting-started/interop/data-sharing","path":"/weaver-dlt-interoperability/docs/external/getting-started/interop/data-sharing","sidebar":"Documentation"},{"id":"external/getting-started/interop/overview","path":"/weaver-dlt-interoperability/docs/external/getting-started/interop/overview","sidebar":"Documentation"},{"id":"external/getting-started/test-network/advanced-configuration","path":"/weaver-dlt-interoperability/docs/external/getting-started/test-network/advanced-configuration","sidebar":"Documentation"},{"id":"external/getting-started/test-network/ledger-initialization","path":"/weaver-dlt-interoperability/docs/external/getting-started/test-network/ledger-initialization","sidebar":"Documentation"},{"id":"external/getting-started/test-network/overview","path":"/weaver-dlt-interoperability/docs/external/getting-started/test-network/overview","sidebar":"Documentation"},{"id":"external/getting-started/test-network/setup-local","path":"/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-local","sidebar":"Documentation"},{"id":"external/getting-started/test-network/setup-local-docker","path":"/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-local-docker","sidebar":"Documentation"},{"id":"external/getting-started/test-network/setup-packages","path":"/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-packages","sidebar":"Documentation"},{"id":"external/getting-started/test-network/setup-packages-docker","path":"/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-packages-docker","sidebar":"Documentation"},{"id":"external/interoperability-modes","path":"/weaver-dlt-interoperability/docs/external/interoperability-modes","sidebar":"Documentation"},{"id":"external/introduction","path":"/weaver-dlt-interoperability/docs/external/introduction","sidebar":"Documentation"},{"id":"external/publications","path":"/weaver-dlt-interoperability/docs/external/publications","sidebar":"Documentation"},{"id":"external/roadmap","path":"/weaver-dlt-interoperability/docs/external/roadmap","sidebar":"Documentation"},{"id":"external/security-model/access-control","path":"/weaver-dlt-interoperability/docs/external/security-model/access-control","sidebar":"Documentation"},{"id":"external/security-model/authentication","path":"/weaver-dlt-interoperability/docs/external/security-model/authentication","sidebar":"Documentation"},{"id":"external/security-model/end-to-end-security","path":"/weaver-dlt-interoperability/docs/external/security-model/end-to-end-security","sidebar":"Documentation"},{"id":"external/security-model/proofs-and-verification","path":"/weaver-dlt-interoperability/docs/external/security-model/proofs-and-verification","sidebar":"Documentation"},{"id":"external/specifications","path":"/weaver-dlt-interoperability/docs/external/specifications","sidebar":"Documentation"},{"id":"external/user-stories/financial-markets","path":"/weaver-dlt-interoperability/docs/external/user-stories/financial-markets","sidebar":"Documentation"},{"id":"external/user-stories/global-trade","path":"/weaver-dlt-interoperability/docs/external/user-stories/global-trade","sidebar":"Documentation"},{"id":"external/user-stories/legacy-integration","path":"/weaver-dlt-interoperability/docs/external/user-stories/legacy-integration","sidebar":"Documentation"},{"id":"external/user-stories/overview","path":"/weaver-dlt-interoperability/docs/external/user-stories/overview","sidebar":"Documentation"},{"id":"external/what-is-interoperability/integration-patterns","path":"/weaver-dlt-interoperability/docs/external/what-is-interoperability/integration-patterns","sidebar":"Documentation"},{"id":"external/what-is-interoperability/levels-of-interoperability","path":"/weaver-dlt-interoperability/docs/external/what-is-interoperability/levels-of-interoperability","sidebar":"Documentation"},{"id":"external/what-is-interoperability/understanding-interoperability","path":"/weaver-dlt-interoperability/docs/external/what-is-interoperability/understanding-interoperability","sidebar":"Documentation"},{"id":"internal/activity-plan","path":"/weaver-dlt-interoperability/docs/internal/activity-plan"},{"id":"internal/development/cordapp-interop/cordapp-interop","path":"/weaver-dlt-interoperability/docs/internal/development/cordapp-interop/"},{"id":"internal/development/cordapp-interop/cordapp-interop-api-assets","path":"/weaver-dlt-interoperability/docs/internal/development/cordapp-interop/cordapp-interop-api-assets"},{"id":"internal/development/cordapp-interop/cordapp-interop-assets","path":"/weaver-dlt-interoperability/docs/internal/development/cordapp-interop/cordapp-interop-assets"},{"id":"internal/development/cordapp-interop/cordapp-interop-flows","path":"/weaver-dlt-interoperability/docs/internal/development/cordapp-interop/cordapp-interop-flows"},{"id":"internal/development/cordapp-interop/cordapp-interop-rest-api","path":"/weaver-dlt-interoperability/docs/internal/development/cordapp-interop/cordapp-interop-rest-api"},{"id":"internal/documentation-guidelines","path":"/weaver-dlt-interoperability/docs/internal/documentation-guidelines"},{"id":"internal/team","path":"/weaver-dlt-interoperability/docs/internal/team"}],"draftIds":[],"sidebars":{"Documentation":{"link":{"path":"/weaver-dlt-interoperability/docs/external/introduction","label":"external/introduction"}}}}],"breadcrumbs":true}}}'),o=JSON.parse('{"defaultLocale":"en","locales":["en"],"path":"i18n","currentLocale":"en","localeConfigs":{"en":{"label":"English","direction":"ltr","htmlLang":"en","calendar":"gregory","path":"en"}}}');var l=n(7529);const s=JSON.parse('{"docusaurusVersion":"2.2.0","siteVersion":"0.0.0","pluginVersions":{"docusaurus-plugin-content-docs":{"type":"package","name":"@docusaurus/plugin-content-docs","version":"2.2.0"},"docusaurus-plugin-content-blog":{"type":"package","name":"@docusaurus/plugin-content-blog","version":"2.2.0"},"docusaurus-plugin-content-pages":{"type":"package","name":"@docusaurus/plugin-content-pages","version":"2.2.0"},"docusaurus-plugin-sitemap":{"type":"package","name":"@docusaurus/plugin-sitemap","version":"2.2.0"},"docusaurus-theme-classic":{"type":"package","name":"@docusaurus/theme-classic","version":"2.2.0"}}}'),c={siteConfig:a.default,siteMetadata:s,globalData:i,i18n:o,codeTranslations:l},u=r.createContext(c);function d(e){let{children:t}=e;return r.createElement(u.Provider,{value:c},t)}},4763:(e,t,n)=>{"use strict";n.d(t,{Z:()=>u});var r=n(7294),a=n(412),i=n(5742),o=n(3285);function l(e){let{error:t,tryAgain:n}=e;return r.createElement("div",{style:{display:"flex",flexDirection:"column",justifyContent:"center",alignItems:"center",height:"50vh",width:"100%",fontSize:"20px"}},r.createElement("h1",null,"This page crashed."),r.createElement("p",null,t.message),r.createElement("button",{type:"button",onClick:n},"Try again"))}function s(e){let{error:t,tryAgain:n}=e;return r.createElement(u,{fallback:()=>r.createElement(l,{error:t,tryAgain:n})},r.createElement(i.Z,null,r.createElement("title",null,"Page Error")),r.createElement(o.Z,null,r.createElement(l,{error:t,tryAgain:n})))}const c=e=>r.createElement(s,e);class u extends r.Component{constructor(e){super(e),this.state={error:null}}componentDidCatch(e){a.Z.canUseDOM&&this.setState({error:e})}render(){const{children:e}=this.props,{error:t}=this.state;if(t){const e={error:t,tryAgain:()=>this.setState({error:null})};return(this.props.fallback??c)(e)}return e??null}}},412:(e,t,n)=>{"use strict";n.d(t,{Z:()=>a});const r="undefined"!=typeof window&&"document"in window&&"createElement"in window.document,a={canUseDOM:r,canUseEventListeners:r&&("addEventListener"in window||"attachEvent"in window),canUseIntersectionObserver:r&&"IntersectionObserver"in window,canUseViewport:r&&"screen"in window}},5742:(e,t,n)=>{"use strict";n.d(t,{Z:()=>i});var r=n(7294),a=n(405);function i(e){return r.createElement(a.ql,e)}},9960:(e,t,n)=>{"use strict";n.d(t,{Z:()=>f});var r=n(7462),a=n(7294),i=n(3727),o=n(8780),l=n(2263),s=n(3919),c=n(412);const u=a.createContext({collectLink:()=>{}});var d=n(4996);function p(e,t){let{isNavLink:n,to:p,href:f,activeClassName:m,isActive:g,"data-noBrokenLinkCheck":h,autoAddBaseUrl:b=!0,...v}=e;const{siteConfig:{trailingSlash:y,baseUrl:w}}=(0,l.Z)(),{withBaseUrl:x}=(0,d.C)(),k=(0,a.useContext)(u),E=(0,a.useRef)(null);(0,a.useImperativeHandle)(t,(()=>E.current));const S=p||f;const T=(0,s.Z)(S),_=S?.replace("pathname://","");let C=void 0!==_?(A=_,b&&(e=>e.startsWith("/"))(A)?x(A):A):void 0;var A;C&&T&&(C=(0,o.applyTrailingSlash)(C,{trailingSlash:y,baseUrl:w}));const P=(0,a.useRef)(!1),N=n?i.OL:i.rU,O=c.Z.canUseIntersectionObserver,I=(0,a.useRef)(),L=()=>{P.current||null==C||(window.docusaurus.preload(C),P.current=!0)};(0,a.useEffect)((()=>(!O&&T&&null!=C&&window.docusaurus.prefetch(C),()=>{O&&I.current&&I.current.disconnect()})),[I,C,O,T]);const D=C?.startsWith("#")??!1,R=!C||!T||D;return R||h||k.collectLink(C),R?a.createElement("a",(0,r.Z)({ref:E,href:C},S&&!T&&{target:"_blank",rel:"noopener noreferrer"},v)):a.createElement(N,(0,r.Z)({},v,{onMouseEnter:L,onTouchStart:L,innerRef:e=>{E.current=e,O&&e&&T&&(I.current=new window.IntersectionObserver((t=>{t.forEach((t=>{e===t.target&&(t.isIntersecting||t.intersectionRatio>0)&&(I.current.unobserve(e),I.current.disconnect(),null!=C&&window.docusaurus.prefetch(C))}))})),I.current.observe(e))},to:C},n&&{isActive:g,activeClassName:m}))}const f=a.forwardRef(p)},1875:(e,t,n)=>{"use strict";n.d(t,{Z:()=>r});const r=()=>null},5999:(e,t,n)=>{"use strict";n.d(t,{Z:()=>s,I:()=>l});var r=n(7294);function a(e,t){const n=e.split(/(\{\w+\})/).map(((e,n)=>{if(n%2==1){const n=t?.[e.slice(1,-1)];if(void 0!==n)return n}return e}));return n.some((e=>(0,r.isValidElement)(e)))?n.map(((e,t)=>(0,r.isValidElement)(e)?r.cloneElement(e,{key:t}):e)).filter((e=>""!==e)):n.join("")}var i=n(7529);function o(e){let{id:t,message:n}=e;if(void 0===t&&void 0===n)throw new Error("Docusaurus translation declarations must have at least a translation id or a default translation message");return i[t??n]??n??t}function l(e,t){let{message:n,id:r}=e;return a(o({message:n,id:r}),t)}function s(e){let{children:t,id:n,values:i}=e;if(t&&"string"!=typeof t)throw console.warn("Illegal <Translate> children",t),new Error("The Docusaurus <Translate> component only accept simple string values");const l=o({message:t,id:n});return r.createElement(r.Fragment,null,a(l,i))}},9935:(e,t,n)=>{"use strict";n.d(t,{m:()=>r});const r="default"},3919:(e,t,n)=>{"use strict";function r(e){return/^(?:\w*:|\/\/)/.test(e)}function a(e){return void 0!==e&&!r(e)}n.d(t,{Z:()=>a,b:()=>r})},4996:(e,t,n)=>{"use strict";n.d(t,{C:()=>i,Z:()=>o});var r=n(2263),a=n(3919);function i(){const{siteConfig:{baseUrl:e,url:t}}=(0,r.Z)();return{withBaseUrl:(n,r)=>function(e,t,n,r){let{forcePrependBaseUrl:i=!1,absolute:o=!1}=void 0===r?{}:r;if(!n||n.startsWith("#")||(0,a.b)(n))return n;if(i)return t+n.replace(/^\//,"");if(n===t.replace(/\/$/,""))return t;const l=n.startsWith(t)?n:t+n.replace(/^\//,"");return o?e+l:l}(t,e,n,r)}}function o(e,t){void 0===t&&(t={});const{withBaseUrl:n}=i();return n(e,t)}},2263:(e,t,n)=>{"use strict";n.d(t,{Z:()=>i});var r=n(7294),a=n(8940);function i(){return(0,r.useContext)(a._)}},2389:(e,t,n)=>{"use strict";n.d(t,{Z:()=>i});var r=n(7294),a=n(8934);function i(){return(0,r.useContext)(a._)}},9670:(e,t,n)=>{"use strict";n.d(t,{Z:()=>a});const r=e=>"object"==typeof e&&!!e&&Object.keys(e).length>0;function a(e){const t={};return function e(n,a){Object.entries(n).forEach((n=>{let[i,o]=n;const l=a?`${a}.${i}`:i;r(o)?e(o,l):t[l]=o}))}(e),t}},226:(e,t,n)=>{"use strict";n.d(t,{_:()=>a,z:()=>i});var r=n(7294);const a=r.createContext(null);function i(e){let{children:t,value:n}=e;const i=r.useContext(a),o=(0,r.useMemo)((()=>function(e){let{parent:t,value:n}=e;if(!t){if(!n)throw new Error("Unexpected: no Docusaurus route context found");if(!("plugin"in n))throw new Error("Unexpected: Docusaurus topmost route context has no `plugin` attribute");return n}const r={...t.data,...n?.data};return{plugin:t.plugin,data:r}}({parent:i,value:n})),[i,n]);return r.createElement(a.Provider,{value:o},t)}},143:(e,t,n)=>{"use strict";n.d(t,{Iw:()=>g,gA:()=>p,_r:()=>u,Jo:()=>h,zh:()=>d,yW:()=>m,gB:()=>f});var r=n(6550),a=n(2263),i=n(9935);function o(e,t){void 0===t&&(t={});const n=function(){const{globalData:e}=(0,a.Z)();return e}()[e];if(!n&&t.failfast)throw new Error(`Docusaurus plugin global data not found for "${e}" plugin.`);return n}const l=e=>e.versions.find((e=>e.isLast));function s(e,t){const n=function(e,t){const n=l(e);return[...e.versions.filter((e=>e!==n)),n].find((e=>!!(0,r.LX)(t,{path:e.path,exact:!1,strict:!1})))}(e,t),a=n?.docs.find((e=>!!(0,r.LX)(t,{path:e.path,exact:!0,strict:!1})));return{activeVersion:n,activeDoc:a,alternateDocVersions:a?function(t){const n={};return e.versions.forEach((e=>{e.docs.forEach((r=>{r.id===t&&(n[e.name]=r)}))})),n}(a.id):{}}}const c={},u=()=>o("docusaurus-plugin-content-docs")??c,d=e=>function(e,t,n){void 0===t&&(t=i.m),void 0===n&&(n={});const r=o(e),a=r?.[t];if(!a&&n.failfast)throw new Error(`Docusaurus plugin global data not found for "${e}" plugin with id "${t}".`);return a}("docusaurus-plugin-content-docs",e,{failfast:!0});function p(e){void 0===e&&(e={});const t=u(),{pathname:n}=(0,r.TH)();return function(e,t,n){void 0===n&&(n={});const a=Object.entries(e).sort(((e,t)=>t[1].path.localeCompare(e[1].path))).find((e=>{let[,n]=e;return!!(0,r.LX)(t,{path:n.path,exact:!1,strict:!1})})),i=a?{pluginId:a[0],pluginData:a[1]}:void 0;if(!i&&n.failfast)throw new Error(`Can't find active docs plugin for "${t}" pathname, while it was expected to be found. Maybe you tried to use a docs feature that can only be used on a docs-related page? Existing docs plugin paths are: ${Object.values(e).map((e=>e.path)).join(", ")}`);return i}(t,n,e)}function f(e){return d(e).versions}function m(e){const t=d(e);return l(t)}function g(e){const t=d(e),{pathname:n}=(0,r.TH)();return s(t,n)}function h(e){const t=d(e),{pathname:n}=(0,r.TH)();return function(e,t){const n=l(e);return{latestDocSuggestion:s(e,t).alternateDocVersions[n.name],latestVersionSuggestion:n}}(t,n)}},8320:(e,t,n)=>{"use strict";n.r(t),n.d(t,{default:()=>i});var r=n(4865),a=n.n(r);a().configure({showSpinner:!1});const i={onRouteUpdate(e){let{location:t,previousLocation:n}=e;if(n&&t.pathname!==n.pathname){const e=window.setTimeout((()=>{a().start()}),200);return()=>window.clearTimeout(e)}},onRouteDidUpdate(){a().done()}}},3310:(e,t,n)=>{"use strict";n.r(t);var r=n(7410),a=n(6809);!function(e){const{themeConfig:{prism:t}}=a.default,{additionalLanguages:r}=t;globalThis.Prism=e,r.forEach((e=>{n(7665)(`./prism-${e}`)})),delete globalThis.Prism}(r.Z)},9471:(e,t,n)=>{"use strict";n.d(t,{Z:()=>i});var r=n(7294);const a={iconExternalLink:"iconExternalLink_nPIU"};function i(e){let{width:t=13.5,height:n=13.5}=e;return r.createElement("svg",{width:t,height:n,"aria-hidden":"true",viewBox:"0 0 24 24",className:a.iconExternalLink},r.createElement("path",{fill:"currentColor",d:"M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"}))}},3285:(e,t,n)=>{"use strict";n.d(t,{Z:()=>st});var r=n(7294),a=n(6010),i=n(4763),o=n(1944),l=n(7462),s=n(6550),c=n(5999),u=n(5936);const d="docusaurus_skipToContent_fallback";function p(e){e.setAttribute("tabindex","-1"),e.focus(),e.removeAttribute("tabindex")}function f(){const e=(0,r.useRef)(null),{action:t}=(0,s.k6)(),n=(0,r.useCallback)((e=>{e.preventDefault();const t=document.querySelector("main:first-of-type")??document.getElementById(d);t&&p(t)}),[]);return(0,u.S)((n=>{let{location:r}=n;e.current&&!r.hash&&"PUSH"===t&&p(e.current)})),{containerRef:e,onClick:n}}const m=(0,c.I)({id:"theme.common.skipToMainContent",description:"The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation",message:"Skip to main content"});function g(e){const t=e.children??m,{containerRef:n,onClick:a}=f();return r.createElement("div",{ref:n,role:"region","aria-label":m},r.createElement("a",(0,l.Z)({},e,{href:`#${d}`,onClick:a}),t))}var h=n(5281),b=n(9727);const v={skipToContent:"skipToContent_fXgn"};function y(){return r.createElement(g,{className:v.skipToContent})}var w=n(6668),x=n(9689);function k(e){let{width:t=21,height:n=21,color:a="currentColor",strokeWidth:i=1.2,className:o,...s}=e;return r.createElement("svg",(0,l.Z)({viewBox:"0 0 15 15",width:t,height:n},s),r.createElement("g",{stroke:a,strokeWidth:i},r.createElement("path",{d:"M.75.75l13.5 13.5M14.25.75L.75 14.25"})))}const E={closeButton:"closeButton_CVFx"};function S(e){return r.createElement("button",(0,l.Z)({type:"button","aria-label":(0,c.I)({id:"theme.AnnouncementBar.closeButtonAriaLabel",message:"Close",description:"The ARIA label for close button of announcement bar"})},e,{className:(0,a.Z)("clean-btn close",E.closeButton,e.className)}),r.createElement(k,{width:14,height:14,strokeWidth:3.1}))}const T={content:"content_knG7"};function _(e){const{announcementBar:t}=(0,w.L)(),{content:n}=t;return r.createElement("div",(0,l.Z)({},e,{className:(0,a.Z)(T.content,e.className),dangerouslySetInnerHTML:{__html:n}}))}const C={announcementBar:"announcementBar_mb4j",announcementBarPlaceholder:"announcementBarPlaceholder_vyr4",announcementBarClose:"announcementBarClose_gvF7",announcementBarContent:"announcementBarContent_xLdY"};function A(){const{announcementBar:e}=(0,w.L)(),{isActive:t,close:n}=(0,x.nT)();if(!t)return null;const{backgroundColor:a,textColor:i,isCloseable:o}=e;return r.createElement("div",{className:C.announcementBar,style:{backgroundColor:a,color:i},role:"banner"},o&&r.createElement("div",{className:C.announcementBarPlaceholder}),r.createElement(_,{className:C.announcementBarContent}),o&&r.createElement(S,{onClick:n,className:C.announcementBarClose}))}var P=n(2961),N=n(2466);var O=n(902),I=n(3102);const L=r.createContext(null);function D(e){let{children:t}=e;const n=function(){const e=(0,P.e)(),t=(0,I.HY)(),[n,a]=(0,r.useState)(!1),i=null!==t.component,o=(0,O.D9)(i);return(0,r.useEffect)((()=>{i&&!o&&a(!0)}),[i,o]),(0,r.useEffect)((()=>{i?e.shown||a(!0):a(!1)}),[e.shown,i]),(0,r.useMemo)((()=>[n,a]),[n])}();return r.createElement(L.Provider,{value:n},t)}function R(e){if(e.component){const t=e.component;return r.createElement(t,e.props)}}function M(){const e=(0,r.useContext)(L);if(!e)throw new O.i6("NavbarSecondaryMenuDisplayProvider");const[t,n]=e,a=(0,r.useCallback)((()=>n(!1)),[n]),i=(0,I.HY)();return(0,r.useMemo)((()=>({shown:t,hide:a,content:R(i)})),[a,i,t])}function F(e){let{header:t,primaryMenu:n,secondaryMenu:i}=e;const{shown:o}=M();return r.createElement("div",{className:"navbar-sidebar"},t,r.createElement("div",{className:(0,a.Z)("navbar-sidebar__items",{"navbar-sidebar__items--show-secondary":o})},r.createElement("div",{className:"navbar-sidebar__item menu"},n),r.createElement("div",{className:"navbar-sidebar__item menu"},i)))}var B=n(2949),$=n(2389);function z(e){return r.createElement("svg",(0,l.Z)({viewBox:"0 0 24 24",width:24,height:24},e),r.createElement("path",{fill:"currentColor",d:"M12,9c1.65,0,3,1.35,3,3s-1.35,3-3,3s-3-1.35-3-3S10.35,9,12,9 M12,7c-2.76,0-5,2.24-5,5s2.24,5,5,5s5-2.24,5-5 S14.76,7,12,7L12,7z M2,13l2,0c0.55,0,1-0.45,1-1s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S1.45,13,2,13z M20,13l2,0c0.55,0,1-0.45,1-1 s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S19.45,13,20,13z M11,2v2c0,0.55,0.45,1,1,1s1-0.45,1-1V2c0-0.55-0.45-1-1-1S11,1.45,11,2z M11,20v2c0,0.55,0.45,1,1,1s1-0.45,1-1v-2c0-0.55-0.45-1-1-1C11.45,19,11,19.45,11,20z M5.99,4.58c-0.39-0.39-1.03-0.39-1.41,0 c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0s0.39-1.03,0-1.41L5.99,4.58z M18.36,16.95 c-0.39-0.39-1.03-0.39-1.41,0c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0c0.39-0.39,0.39-1.03,0-1.41 L18.36,16.95z M19.42,5.99c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06c-0.39,0.39-0.39,1.03,0,1.41 s1.03,0.39,1.41,0L19.42,5.99z M7.05,18.36c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06 c-0.39,0.39-0.39,1.03,0,1.41s1.03,0.39,1.41,0L7.05,18.36z"}))}function U(e){return r.createElement("svg",(0,l.Z)({viewBox:"0 0 24 24",width:24,height:24},e),r.createElement("path",{fill:"currentColor",d:"M9.37,5.51C9.19,6.15,9.1,6.82,9.1,7.5c0,4.08,3.32,7.4,7.4,7.4c0.68,0,1.35-0.09,1.99-0.27C17.45,17.19,14.93,19,12,19 c-3.86,0-7-3.14-7-7C5,9.07,6.81,6.55,9.37,5.51z M12,3c-4.97,0-9,4.03-9,9s4.03,9,9,9s9-4.03,9-9c0-0.46-0.04-0.92-0.1-1.36 c-0.98,1.37-2.58,2.26-4.4,2.26c-2.98,0-5.4-2.42-5.4-5.4c0-1.81,0.89-3.42,2.26-4.4C12.92,3.04,12.46,3,12,3L12,3z"}))}const j={toggle:"toggle_vylO",toggleButton:"toggleButton_gllP",darkToggleIcon:"darkToggleIcon_wfgR",lightToggleIcon:"lightToggleIcon_pyhR",toggleButtonDisabled:"toggleButtonDisabled_aARS"};function Z(e){let{className:t,value:n,onChange:i}=e;const o=(0,$.Z)(),l=(0,c.I)({message:"Switch between dark and light mode (currently {mode})",id:"theme.colorToggle.ariaLabel",description:"The ARIA label for the navbar color mode toggle"},{mode:"dark"===n?(0,c.I)({message:"dark mode",id:"theme.colorToggle.ariaLabel.mode.dark",description:"The name for the dark color mode"}):(0,c.I)({message:"light mode",id:"theme.colorToggle.ariaLabel.mode.light",description:"The name for the light color mode"})});return r.createElement("div",{className:(0,a.Z)(j.toggle,t)},r.createElement("button",{className:(0,a.Z)("clean-btn",j.toggleButton,!o&&j.toggleButtonDisabled),type:"button",onClick:()=>i("dark"===n?"light":"dark"),disabled:!o,title:l,"aria-label":l,"aria-live":"polite"},r.createElement(z,{className:(0,a.Z)(j.toggleIcon,j.lightToggleIcon)}),r.createElement(U,{className:(0,a.Z)(j.toggleIcon,j.darkToggleIcon)})))}const H=r.memo(Z);function W(e){let{className:t}=e;const n=(0,w.L)().colorMode.disableSwitch,{colorMode:a,setColorMode:i}=(0,B.I)();return n?null:r.createElement(H,{className:t,value:a,onChange:i})}var V=n(1327);function G(){return r.createElement(V.Z,{className:"navbar__brand",imageClassName:"navbar__logo",titleClassName:"navbar__title text--truncate"})}function q(){const e=(0,P.e)();return r.createElement("button",{type:"button","aria-label":(0,c.I)({id:"theme.docs.sidebar.closeSidebarButtonAriaLabel",message:"Close navigation bar",description:"The ARIA label for close button of mobile sidebar"}),className:"clean-btn navbar-sidebar__close",onClick:()=>e.toggle()},r.createElement(k,{color:"var(--ifm-color-emphasis-600)"}))}function Y(){return r.createElement("div",{className:"navbar-sidebar__brand"},r.createElement(G,null),r.createElement(W,{className:"margin-right--md"}),r.createElement(q,null))}var K=n(9960),Q=n(4996),X=n(3919);function J(e,t){return void 0!==e&&void 0!==t&&new RegExp(e,"gi").test(t)}var ee=n(9471);function te(e){let{activeBasePath:t,activeBaseRegex:n,to:a,href:i,label:o,html:s,isDropdownLink:c,prependBaseUrlToHref:u,...d}=e;const p=(0,Q.Z)(a),f=(0,Q.Z)(t),m=(0,Q.Z)(i,{forcePrependBaseUrl:!0}),g=o&&i&&!(0,X.Z)(i),h=s?{dangerouslySetInnerHTML:{__html:s}}:{children:r.createElement(r.Fragment,null,o,g&&r.createElement(ee.Z,c&&{width:12,height:12}))};return i?r.createElement(K.Z,(0,l.Z)({href:u?m:i},d,h)):r.createElement(K.Z,(0,l.Z)({to:p,isNavLink:!0},(t||n)&&{isActive:(e,t)=>n?J(n,t.pathname):t.pathname.startsWith(f)},d,h))}function ne(e){let{className:t,isDropdownItem:n=!1,...i}=e;const o=r.createElement(te,(0,l.Z)({className:(0,a.Z)(n?"dropdown__link":"navbar__item navbar__link",t),isDropdownLink:n},i));return n?r.createElement("li",null,o):o}function re(e){let{className:t,isDropdownItem:n,...i}=e;return r.createElement("li",{className:"menu__list-item"},r.createElement(te,(0,l.Z)({className:(0,a.Z)("menu__link",t)},i)))}function ae(e){let{mobile:t=!1,position:n,...a}=e;const i=t?re:ne;return r.createElement(i,(0,l.Z)({},a,{activeClassName:a.activeClassName??(t?"menu__link--active":"navbar__link--active")}))}var ie=n(6043),oe=n(8596),le=n(2263);function se(e,t){return e.some((e=>function(e,t){return!!(0,oe.Mg)(e.to,t)||!!J(e.activeBaseRegex,t)||!(!e.activeBasePath||!t.startsWith(e.activeBasePath))}(e,t)))}function ce(e){let{items:t,position:n,className:i,onClick:o,...s}=e;const c=(0,r.useRef)(null),[u,d]=(0,r.useState)(!1);return(0,r.useEffect)((()=>{const e=e=>{c.current&&!c.current.contains(e.target)&&d(!1)};return document.addEventListener("mousedown",e),document.addEventListener("touchstart",e),()=>{document.removeEventListener("mousedown",e),document.removeEventListener("touchstart",e)}}),[c]),r.createElement("div",{ref:c,className:(0,a.Z)("navbar__item","dropdown","dropdown--hoverable",{"dropdown--right":"right"===n,"dropdown--show":u})},r.createElement(te,(0,l.Z)({"aria-haspopup":"true","aria-expanded":u,role:"button",href:s.to?void 0:"#",className:(0,a.Z)("navbar__link",i)},s,{onClick:s.to?void 0:e=>e.preventDefault(),onKeyDown:e=>{"Enter"===e.key&&(e.preventDefault(),d(!u))}}),s.children??s.label),r.createElement("ul",{className:"dropdown__menu"},t.map(((e,n)=>r.createElement(Ee,(0,l.Z)({isDropdownItem:!0,onKeyDown:e=>{if(n===t.length-1&&"Tab"===e.key){e.preventDefault(),d(!1);const t=c.current.nextElementSibling;if(t){(t instanceof HTMLAnchorElement?t:t.querySelector("a")).focus()}}},activeClassName:"dropdown__link--active"},e,{key:n}))))))}function ue(e){let{items:t,className:n,position:i,onClick:o,...c}=e;const u=function(){const{siteConfig:{baseUrl:e}}=(0,le.Z)(),{pathname:t}=(0,s.TH)();return t.replace(e,"/")}(),d=se(t,u),{collapsed:p,toggleCollapsed:f,setCollapsed:m}=(0,ie.u)({initialState:()=>!d});return(0,r.useEffect)((()=>{d&&m(!d)}),[u,d,m]),r.createElement("li",{className:(0,a.Z)("menu__list-item",{"menu__list-item--collapsed":p})},r.createElement(te,(0,l.Z)({role:"button",className:(0,a.Z)("menu__link menu__link--sublist menu__link--sublist-caret",n)},c,{onClick:e=>{e.preventDefault(),f()}}),c.children??c.label),r.createElement(ie.z,{lazy:!0,as:"ul",className:"menu__list",collapsed:p},t.map(((e,t)=>r.createElement(Ee,(0,l.Z)({mobile:!0,isDropdownItem:!0,onClick:o,activeClassName:"menu__link--active"},e,{key:t}))))))}function de(e){let{mobile:t=!1,...n}=e;const a=t?ue:ce;return r.createElement(a,n)}var pe=n(4711);function fe(e){let{width:t=20,height:n=20,...a}=e;return r.createElement("svg",(0,l.Z)({viewBox:"0 0 24 24",width:t,height:n,"aria-hidden":!0},a),r.createElement("path",{fill:"currentColor",d:"M12.87 15.07l-2.54-2.51.03-.03c1.74-1.94 2.98-4.17 3.71-6.53H17V4h-7V2H8v2H1v1.99h11.17C11.5 7.92 10.44 9.75 9 11.35 8.07 10.32 7.3 9.19 6.69 8h-2c.73 1.63 1.73 3.17 2.98 4.56l-5.09 5.02L4 19l5-5 3.11 3.11.76-2.04zM18.5 10h-2L12 22h2l1.12-3h4.75L21 22h2l-4.5-12zm-2.62 7l1.62-4.33L19.12 17h-3.24z"}))}const me="iconLanguage_nlXk";var ge=n(1875);const he={searchBox:"searchBox_ZlJk"};function be(e){let{children:t,className:n}=e;return r.createElement("div",{className:(0,a.Z)(n,he.searchBox)},t)}var ve=n(143),ye=n(2802);var we=n(373);const xe=e=>e.docs.find((t=>t.id===e.mainDocId));const ke={default:ae,localeDropdown:function(e){let{mobile:t,dropdownItemsBefore:n,dropdownItemsAfter:a,...i}=e;const{i18n:{currentLocale:o,locales:u,localeConfigs:d}}=(0,le.Z)(),p=(0,pe.l)(),{search:f,hash:m}=(0,s.TH)(),g=[...n,...u.map((e=>{const n=`${`pathname://${p.createUrl({locale:e,fullyQualified:!1})}`}${f}${m}`;return{label:d[e].label,lang:d[e].htmlLang,to:n,target:"_self",autoAddBaseUrl:!1,className:e===o?t?"menu__link--active":"dropdown__link--active":""}})),...a],h=t?(0,c.I)({message:"Languages",id:"theme.navbar.mobileLanguageDropdown.label",description:"The label for the mobile language switcher dropdown"}):d[o].label;return r.createElement(de,(0,l.Z)({},i,{mobile:t,label:r.createElement(r.Fragment,null,r.createElement(fe,{className:me}),h),items:g}))},search:function(e){let{mobile:t,className:n}=e;return t?null:r.createElement(be,{className:n},r.createElement(ge.Z,null))},dropdown:de,html:function(e){let{value:t,className:n,mobile:i=!1,isDropdownItem:o=!1}=e;const l=o?"li":"div";return r.createElement(l,{className:(0,a.Z)({navbar__item:!i&&!o,"menu__list-item":i},n),dangerouslySetInnerHTML:{__html:t}})},doc:function(e){let{docId:t,label:n,docsPluginId:a,...i}=e;const{activeDoc:o}=(0,ve.Iw)(a),s=(0,ye.vY)(t,a);return null===s?null:r.createElement(ae,(0,l.Z)({exact:!0},i,{isActive:()=>o?.path===s.path||!!o?.sidebar&&o.sidebar===s.sidebar,label:n??s.id,to:s.path}))},docSidebar:function(e){let{sidebarId:t,label:n,docsPluginId:a,...i}=e;const{activeDoc:o}=(0,ve.Iw)(a),s=(0,ye.oz)(t,a).link;if(!s)throw new Error(`DocSidebarNavbarItem: Sidebar with ID "${t}" doesn't have anything to be linked to.`);return r.createElement(ae,(0,l.Z)({exact:!0},i,{isActive:()=>o?.sidebar===t,label:n??s.label,to:s.path}))},docsVersion:function(e){let{label:t,to:n,docsPluginId:a,...i}=e;const o=(0,ye.lO)(a)[0],s=t??o.label,c=n??(e=>e.docs.find((t=>t.id===e.mainDocId)))(o).path;return r.createElement(ae,(0,l.Z)({},i,{label:s,to:c}))},docsVersionDropdown:function(e){let{mobile:t,docsPluginId:n,dropdownActiveClassDisabled:a,dropdownItemsBefore:i,dropdownItemsAfter:o,...u}=e;const{search:d,hash:p}=(0,s.TH)(),f=(0,ve.Iw)(n),m=(0,ve.gB)(n),{savePreferredVersionName:g}=(0,we.J)(n),h=[...i,...m.map((e=>{const t=f.alternateDocVersions[e.name]??xe(e);return{label:e.label,to:`${t.path}${d}${p}`,isActive:()=>e===f.activeVersion,onClick:()=>g(e.name)}})),...o],b=(0,ye.lO)(n)[0],v=t&&h.length>1?(0,c.I)({id:"theme.navbar.mobileVersionsDropdown.label",message:"Versions",description:"The label for the navbar versions dropdown on mobile view"}):b.label,y=t&&h.length>1?void 0:xe(b).path;return h.length<=1?r.createElement(ae,(0,l.Z)({},u,{mobile:t,label:v,to:y,isActive:a?()=>!1:void 0})):r.createElement(de,(0,l.Z)({},u,{mobile:t,label:v,to:y,items:h,isActive:a?()=>!1:void 0}))}};function Ee(e){let{type:t,...n}=e;const a=function(e,t){return e&&"default"!==e?e:"items"in t?"dropdown":"default"}(t,n),i=ke[a];if(!i)throw new Error(`No NavbarItem component found for type "${t}".`);return r.createElement(i,n)}function Se(){const e=(0,P.e)(),t=(0,w.L)().navbar.items;return r.createElement("ul",{className:"menu__list"},t.map(((t,n)=>r.createElement(Ee,(0,l.Z)({mobile:!0},t,{onClick:()=>e.toggle(),key:n})))))}function Te(e){return r.createElement("button",(0,l.Z)({},e,{type:"button",className:"clean-btn navbar-sidebar__back"}),r.createElement(c.Z,{id:"theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel",description:"The label of the back button to return to main menu, inside the mobile navbar sidebar secondary menu (notably used to display the docs sidebar)"},"\u2190 Back to main menu"))}function _e(){const e=0===(0,w.L)().navbar.items.length,t=M();return r.createElement(r.Fragment,null,!e&&r.createElement(Te,{onClick:()=>t.hide()}),t.content)}function Ce(){const e=(0,P.e)();var t;return void 0===(t=e.shown)&&(t=!0),(0,r.useEffect)((()=>(document.body.style.overflow=t?"hidden":"visible",()=>{document.body.style.overflow="visible"})),[t]),e.shouldRender?r.createElement(F,{header:r.createElement(Y,null),primaryMenu:r.createElement(Se,null),secondaryMenu:r.createElement(_e,null)}):null}const Ae={navbarHideable:"navbarHideable_m1mJ",navbarHidden:"navbarHidden_jGov"};function Pe(e){return r.createElement("div",(0,l.Z)({role:"presentation"},e,{className:(0,a.Z)("navbar-sidebar__backdrop",e.className)}))}function Ne(e){let{children:t}=e;const{navbar:{hideOnScroll:n,style:i}}=(0,w.L)(),o=(0,P.e)(),{navbarRef:l,isNavbarVisible:s}=function(e){const[t,n]=(0,r.useState)(e),a=(0,r.useRef)(!1),i=(0,r.useRef)(0),o=(0,r.useCallback)((e=>{null!==e&&(i.current=e.getBoundingClientRect().height)}),[]);return(0,N.RF)(((t,r)=>{let{scrollY:o}=t;if(!e)return;if(o<i.current)return void n(!0);if(a.current)return void(a.current=!1);const l=r?.scrollY,s=document.documentElement.scrollHeight-i.current,c=window.innerHeight;l&&o>=l?n(!1):o+c<s&&n(!0)})),(0,u.S)((t=>{if(!e)return;const r=t.location.hash;if(r?document.getElementById(r.substring(1)):void 0)return a.current=!0,void n(!1);n(!0)})),{navbarRef:o,isNavbarVisible:t}}(n);return r.createElement("nav",{ref:l,className:(0,a.Z)("navbar","navbar--fixed-top",n&&[Ae.navbarHideable,!s&&Ae.navbarHidden],{"navbar--dark":"dark"===i,"navbar--primary":"primary"===i,"navbar-sidebar--show":o.shown})},t,r.createElement(Pe,{onClick:o.toggle}),r.createElement(Ce,null))}const Oe="right";function Ie(e){let{width:t=30,height:n=30,className:a,...i}=e;return r.createElement("svg",(0,l.Z)({className:a,width:t,height:n,viewBox:"0 0 30 30","aria-hidden":"true"},i),r.createElement("path",{stroke:"currentColor",strokeLinecap:"round",strokeMiterlimit:"10",strokeWidth:"2",d:"M4 7h22M4 15h22M4 23h22"}))}function Le(){const{toggle:e,shown:t}=(0,P.e)();return r.createElement("button",{onClick:e,"aria-label":(0,c.I)({id:"theme.docs.sidebar.toggleSidebarButtonAriaLabel",message:"Toggle navigation bar",description:"The ARIA label for hamburger menu button of mobile navigation"}),"aria-expanded":t,className:"navbar__toggle clean-btn",type:"button"},r.createElement(Ie,null))}const De={colorModeToggle:"colorModeToggle_DEke"};function Re(e){let{items:t}=e;return r.createElement(r.Fragment,null,t.map(((e,t)=>r.createElement(Ee,(0,l.Z)({},e,{key:t})))))}function Me(e){let{left:t,right:n}=e;return r.createElement("div",{className:"navbar__inner"},r.createElement("div",{className:"navbar__items"},t),r.createElement("div",{className:"navbar__items navbar__items--right"},n))}function Fe(){const e=(0,P.e)(),t=(0,w.L)().navbar.items,[n,a]=function(e){function t(e){return"left"===(e.position??Oe)}return[e.filter(t),e.filter((e=>!t(e)))]}(t),i=t.find((e=>"search"===e.type));return r.createElement(Me,{left:r.createElement(r.Fragment,null,!e.disabled&&r.createElement(Le,null),r.createElement(G,null),r.createElement(Re,{items:n})),right:r.createElement(r.Fragment,null,r.createElement(Re,{items:a}),r.createElement(W,{className:De.colorModeToggle}),!i&&r.createElement(be,null,r.createElement(ge.Z,null)))})}function Be(){return r.createElement(Ne,null,r.createElement(Fe,null))}function $e(e){let{item:t}=e;const{to:n,href:a,label:i,prependBaseUrlToHref:o,...s}=t,c=(0,Q.Z)(n),u=(0,Q.Z)(a,{forcePrependBaseUrl:!0});return r.createElement(K.Z,(0,l.Z)({className:"footer__link-item"},a?{href:o?u:a}:{to:c},s),i,a&&!(0,X.Z)(a)&&r.createElement(ee.Z,null))}function ze(e){let{item:t}=e;return t.html?r.createElement("li",{className:"footer__item",dangerouslySetInnerHTML:{__html:t.html}}):r.createElement("li",{key:t.href??t.to,className:"footer__item"},r.createElement($e,{item:t}))}function Ue(e){let{column:t}=e;return r.createElement("div",{className:"col footer__col"},r.createElement("div",{className:"footer__title"},t.title),r.createElement("ul",{className:"footer__items clean-list"},t.items.map(((e,t)=>r.createElement(ze,{key:t,item:e})))))}function je(e){let{columns:t}=e;return r.createElement("div",{className:"row footer__links"},t.map(((e,t)=>r.createElement(Ue,{key:t,column:e}))))}function Ze(){return r.createElement("span",{className:"footer__link-separator"},"\xb7")}function He(e){let{item:t}=e;return t.html?r.createElement("span",{className:"footer__link-item",dangerouslySetInnerHTML:{__html:t.html}}):r.createElement($e,{item:t})}function We(e){let{links:t}=e;return r.createElement("div",{className:"footer__links text--center"},r.createElement("div",{className:"footer__links"},t.map(((e,n)=>r.createElement(r.Fragment,{key:n},r.createElement(He,{item:e}),t.length!==n+1&&r.createElement(Ze,null))))))}function Ve(e){let{links:t}=e;return function(e){return"title"in e[0]}(t)?r.createElement(je,{columns:t}):r.createElement(We,{links:t})}var Ge=n(941);const qe={footerLogoLink:"footerLogoLink_BH7S"};function Ye(e){let{logo:t}=e;const{withBaseUrl:n}=(0,Q.C)(),i={light:n(t.src),dark:n(t.srcDark??t.src)};return r.createElement(Ge.Z,{className:(0,a.Z)("footer__logo",t.className),alt:t.alt,sources:i,width:t.width,height:t.height,style:t.style})}function Ke(e){let{logo:t}=e;return t.href?r.createElement(K.Z,{href:t.href,className:qe.footerLogoLink,target:t.target},r.createElement(Ye,{logo:t})):r.createElement(Ye,{logo:t})}function Qe(e){let{copyright:t}=e;return r.createElement("div",{className:"footer__copyright",dangerouslySetInnerHTML:{__html:t}})}function Xe(e){let{style:t,links:n,logo:i,copyright:o}=e;return r.createElement("footer",{className:(0,a.Z)("footer",{"footer--dark":"dark"===t})},r.createElement("div",{className:"container container-fluid"},n,(i||o)&&r.createElement("div",{className:"footer__bottom text--center"},i&&r.createElement("div",{className:"margin-bottom--sm"},i),o)))}function Je(){const{footer:e}=(0,w.L)();if(!e)return null;const{copyright:t,links:n,logo:a,style:i}=e;return r.createElement(Xe,{style:i,links:n&&n.length>0&&r.createElement(Ve,{links:n}),logo:a&&r.createElement(Ke,{logo:a}),copyright:t&&r.createElement(Qe,{copyright:t})})}const et=r.memo(Je);var tt=n(12);const nt="docusaurus.tab.",rt=r.createContext(void 0);const at=(0,O.Qc)([B.S,x.pl,function(e){let{children:t}=e;const n=function(){const[e,t]=(0,r.useState)({}),n=(0,r.useCallback)(((e,t)=>{(0,tt.W)(`${nt}${e}`).set(t)}),[]);(0,r.useEffect)((()=>{try{const e={};(0,tt._)().forEach((t=>{if(t.startsWith(nt)){const n=t.substring(nt.length);e[n]=(0,tt.W)(t).get()}})),t(e)}catch(e){console.error(e)}}),[]);const a=(0,r.useCallback)(((e,r)=>{t((t=>({...t,[e]:r}))),n(e,r)}),[n]);return(0,r.useMemo)((()=>({tabGroupChoices:e,setTabGroupChoices:a})),[e,a])}();return r.createElement(rt.Provider,{value:n},t)},N.OC,we.L5,o.VC,function(e){let{children:t}=e;return r.createElement(I.n2,null,r.createElement(P.M,null,r.createElement(D,null,t)))}]);function it(e){let{children:t}=e;return r.createElement(at,null,t)}function ot(e){let{error:t,tryAgain:n}=e;return r.createElement("main",{className:"container margin-vert--xl"},r.createElement("div",{className:"row"},r.createElement("div",{className:"col col--6 col--offset-3"},r.createElement("h1",{className:"hero__title"},r.createElement(c.Z,{id:"theme.ErrorPageContent.title",description:"The title of the fallback page when the page crashed"},"This page crashed.")),r.createElement("p",null,t.message),r.createElement("div",null,r.createElement("button",{type:"button",onClick:n},r.createElement(c.Z,{id:"theme.ErrorPageContent.tryAgain",description:"The label of the button to try again when the page crashed"},"Try again"))))))}const lt={mainWrapper:"mainWrapper_z2l0"};function st(e){const{children:t,noFooter:n,wrapperClassName:l,title:s,description:c}=e;return(0,b.t)(),r.createElement(it,null,r.createElement(o.d,{title:s,description:c}),r.createElement(y,null),r.createElement(A,null),r.createElement(Be,null),r.createElement("div",{id:d,className:(0,a.Z)(h.k.wrapper.main,lt.mainWrapper,l)},r.createElement(i.Z,{fallback:e=>r.createElement(ot,e)},t)),!n&&r.createElement(et,null))}},1327:(e,t,n)=>{"use strict";n.d(t,{Z:()=>d});var r=n(7462),a=n(7294),i=n(9960),o=n(4996),l=n(2263),s=n(6668),c=n(941);function u(e){let{logo:t,alt:n,imageClassName:r}=e;const i={light:(0,o.Z)(t.src),dark:(0,o.Z)(t.srcDark||t.src)},l=a.createElement(c.Z,{className:t.className,sources:i,height:t.height,width:t.width,alt:n,style:t.style});return r?a.createElement("div",{className:r},l):l}function d(e){const{siteConfig:{title:t}}=(0,l.Z)(),{navbar:{title:n,logo:c}}=(0,s.L)(),{imageClassName:d,titleClassName:p,...f}=e,m=(0,o.Z)(c?.href||"/"),g=n?"":t,h=c?.alt??g;return a.createElement(i.Z,(0,r.Z)({to:m},f,c?.target&&{target:c.target}),c&&a.createElement(u,{logo:c,alt:h,imageClassName:d}),null!=n&&a.createElement("b",{className:p},n))}},197:(e,t,n)=>{"use strict";n.d(t,{Z:()=>i});var r=n(7294),a=n(5742);function i(e){let{locale:t,version:n,tag:i}=e;const o=t;return r.createElement(a.Z,null,t&&r.createElement("meta",{name:"docusaurus_locale",content:t}),n&&r.createElement("meta",{name:"docusaurus_version",content:n}),i&&r.createElement("meta",{name:"docusaurus_tag",content:i}),o&&r.createElement("meta",{name:"docsearch:language",content:o}),n&&r.createElement("meta",{name:"docsearch:version",content:n}),i&&r.createElement("meta",{name:"docsearch:docusaurus_tag",content:i}))}},941:(e,t,n)=>{"use strict";n.d(t,{Z:()=>c});var r=n(7462),a=n(7294),i=n(6010),o=n(2389),l=n(2949);const s={themedImage:"themedImage_ToTc","themedImage--light":"themedImage--light_HNdA","themedImage--dark":"themedImage--dark_i4oU"};function c(e){const t=(0,o.Z)(),{colorMode:n}=(0,l.I)(),{sources:c,className:u,alt:d,...p}=e,f=t?"dark"===n?["dark"]:["light"]:["light","dark"];return a.createElement(a.Fragment,null,f.map((e=>a.createElement("img",(0,r.Z)({key:e,src:c[e],alt:d,className:(0,i.Z)(s.themedImage,s[`themedImage--${e}`],u)},p)))))}},6043:(e,t,n)=>{"use strict";n.d(t,{u:()=>l,z:()=>g});var r=n(7462),a=n(7294),i=n(412);const o="ease-in-out";function l(e){let{initialState:t}=e;const[n,r]=(0,a.useState)(t??!1),i=(0,a.useCallback)((()=>{r((e=>!e))}),[]);return{collapsed:n,setCollapsed:r,toggleCollapsed:i}}const s={display:"none",overflow:"hidden",height:"0px"},c={display:"block",overflow:"visible",height:"auto"};function u(e,t){const n=t?s:c;e.style.display=n.display,e.style.overflow=n.overflow,e.style.height=n.height}function d(e){let{collapsibleRef:t,collapsed:n,animation:r}=e;const i=(0,a.useRef)(!1);(0,a.useEffect)((()=>{const e=t.current;function a(){const t=e.scrollHeight,n=r?.duration??function(e){const t=e/36;return Math.round(10*(4+15*t**.25+t/5))}(t);return{transition:`height ${n}ms ${r?.easing??o}`,height:`${t}px`}}function l(){const t=a();e.style.transition=t.transition,e.style.height=t.height}if(!i.current)return u(e,n),void(i.current=!0);return e.style.willChange="height",function(){const t=requestAnimationFrame((()=>{n?(l(),requestAnimationFrame((()=>{e.style.height=s.height,e.style.overflow=s.overflow}))):(e.style.display="block",requestAnimationFrame((()=>{l()})))}));return()=>cancelAnimationFrame(t)}()}),[t,n,r])}function p(e){if(!i.Z.canUseDOM)return e?s:c}function f(e){let{as:t="div",collapsed:n,children:r,animation:i,onCollapseTransitionEnd:o,className:l,disableSSRStyle:s}=e;const c=(0,a.useRef)(null);return d({collapsibleRef:c,collapsed:n,animation:i}),a.createElement(t,{ref:c,style:s?void 0:p(n),onTransitionEnd:e=>{"height"===e.propertyName&&(u(c.current,n),o?.(n))},className:l},r)}function m(e){let{collapsed:t,...n}=e;const[i,o]=(0,a.useState)(!t),[l,s]=(0,a.useState)(t);return(0,a.useLayoutEffect)((()=>{t||o(!0)}),[t]),(0,a.useLayoutEffect)((()=>{i&&s(t)}),[i,t]),i?a.createElement(f,(0,r.Z)({},n,{collapsed:l})):null}function g(e){let{lazy:t,...n}=e;const r=t?m:f;return a.createElement(r,n)}},9689:(e,t,n)=>{"use strict";n.d(t,{nT:()=>m,pl:()=>f});var r=n(7294),a=n(2389),i=n(12),o=n(902),l=n(6668);const s=(0,i.W)("docusaurus.announcement.dismiss"),c=(0,i.W)("docusaurus.announcement.id"),u=()=>"true"===s.get(),d=e=>s.set(String(e)),p=r.createContext(null);function f(e){let{children:t}=e;const n=function(){const{announcementBar:e}=(0,l.L)(),t=(0,a.Z)(),[n,i]=(0,r.useState)((()=>!!t&&u()));(0,r.useEffect)((()=>{i(u())}),[]);const o=(0,r.useCallback)((()=>{d(!0),i(!0)}),[]);return(0,r.useEffect)((()=>{if(!e)return;const{id:t}=e;let n=c.get();"annoucement-bar"===n&&(n="announcement-bar");const r=t!==n;c.set(t),r&&d(!1),!r&&u()||i(!1)}),[e]),(0,r.useMemo)((()=>({isActive:!!e&&!n,close:o})),[e,n,o])}();return r.createElement(p.Provider,{value:n},t)}function m(){const e=(0,r.useContext)(p);if(!e)throw new o.i6("AnnouncementBarProvider");return e}},2949:(e,t,n)=>{"use strict";n.d(t,{I:()=>h,S:()=>g});var r=n(7294),a=n(412),i=n(902),o=n(12),l=n(6668);const s=r.createContext(void 0),c="theme",u=(0,o.W)(c),d={light:"light",dark:"dark"},p=e=>e===d.dark?d.dark:d.light,f=e=>a.Z.canUseDOM?p(document.documentElement.getAttribute("data-theme")):p(e),m=e=>{u.set(p(e))};function g(e){let{children:t}=e;const n=function(){const{colorMode:{defaultMode:e,disableSwitch:t,respectPrefersColorScheme:n}}=(0,l.L)(),[a,i]=(0,r.useState)(f(e));(0,r.useEffect)((()=>{t&&u.del()}),[t]);const o=(0,r.useCallback)((function(t,r){void 0===r&&(r={});const{persist:a=!0}=r;t?(i(t),a&&m(t)):(i(n?window.matchMedia("(prefers-color-scheme: dark)").matches?d.dark:d.light:e),u.del())}),[n,e]);(0,r.useEffect)((()=>{document.documentElement.setAttribute("data-theme",p(a))}),[a]),(0,r.useEffect)((()=>{if(t)return;const e=e=>{if(e.key!==c)return;const t=u.get();null!==t&&o(p(t))};return window.addEventListener("storage",e),()=>window.removeEventListener("storage",e)}),[t,o]);const s=(0,r.useRef)(!1);return(0,r.useEffect)((()=>{if(t&&!n)return;const e=window.matchMedia("(prefers-color-scheme: dark)"),r=()=>{window.matchMedia("print").matches||s.current?s.current=window.matchMedia("print").matches:o(null)};return e.addListener(r),()=>e.removeListener(r)}),[o,t,n]),(0,r.useMemo)((()=>({colorMode:a,setColorMode:o,get isDarkTheme(){return a===d.dark},setLightTheme(){o(d.light)},setDarkTheme(){o(d.dark)}})),[a,o])}();return r.createElement(s.Provider,{value:n},t)}function h(){const e=(0,r.useContext)(s);if(null==e)throw new i.i6("ColorModeProvider","Please see https://docusaurus.io/docs/api/themes/configuration#use-color-mode.");return e}},373:(e,t,n)=>{"use strict";n.d(t,{J:()=>v,L5:()=>h});var r=n(7294),a=n(143),i=n(9935),o=n(6668),l=n(2802),s=n(902),c=n(12);const u=e=>`docs-preferred-version-${e}`,d={save:(e,t,n)=>{(0,c.W)(u(e),{persistence:t}).set(n)},read:(e,t)=>(0,c.W)(u(e),{persistence:t}).get(),clear:(e,t)=>{(0,c.W)(u(e),{persistence:t}).del()}},p=e=>Object.fromEntries(e.map((e=>[e,{preferredVersionName:null}])));const f=r.createContext(null);function m(){const e=(0,a._r)(),t=(0,o.L)().docs.versionPersistence,n=(0,r.useMemo)((()=>Object.keys(e)),[e]),[i,l]=(0,r.useState)((()=>p(n)));(0,r.useEffect)((()=>{l(function(e){let{pluginIds:t,versionPersistence:n,allDocsData:r}=e;function a(e){const t=d.read(e,n);return r[e].versions.some((e=>e.name===t))?{preferredVersionName:t}:(d.clear(e,n),{preferredVersionName:null})}return Object.fromEntries(t.map((e=>[e,a(e)])))}({allDocsData:e,versionPersistence:t,pluginIds:n}))}),[e,t,n]);return[i,(0,r.useMemo)((()=>({savePreferredVersion:function(e,n){d.save(e,t,n),l((t=>({...t,[e]:{preferredVersionName:n}})))}})),[t])]}function g(e){let{children:t}=e;const n=m();return r.createElement(f.Provider,{value:n},t)}function h(e){let{children:t}=e;return l.cE?r.createElement(g,null,t):r.createElement(r.Fragment,null,t)}function b(){const e=(0,r.useContext)(f);if(!e)throw new s.i6("DocsPreferredVersionContextProvider");return e}function v(e){void 0===e&&(e=i.m);const t=(0,a.zh)(e),[n,o]=b(),{preferredVersionName:l}=n[e];return{preferredVersion:t.versions.find((e=>e.name===l))??null,savePreferredVersionName:(0,r.useCallback)((t=>{o.savePreferredVersion(e,t)}),[o,e])}}},1116:(e,t,n)=>{"use strict";n.d(t,{V:()=>s,b:()=>l});var r=n(7294),a=n(902);const i=Symbol("EmptyContext"),o=r.createContext(i);function l(e){let{children:t,name:n,items:a}=e;const i=(0,r.useMemo)((()=>n&&a?{name:n,items:a}:null),[n,a]);return r.createElement(o.Provider,{value:i},t)}function s(){const e=(0,r.useContext)(o);if(e===i)throw new a.i6("DocsSidebarProvider");return e}},2961:(e,t,n)=>{"use strict";n.d(t,{M:()=>p,e:()=>f});var r=n(7294),a=n(3102),i=n(7524),o=n(6550),l=n(902);function s(e){!function(e){const t=(0,o.k6)(),n=(0,l.zX)(e);(0,r.useEffect)((()=>t.block(((e,t)=>n(e,t)))),[t,n])}(((t,n)=>{if("POP"===n)return e(t,n)}))}var c=n(6668);const u=r.createContext(void 0);function d(){const e=function(){const e=(0,a.HY)(),{items:t}=(0,c.L)().navbar;return 0===t.length&&!e.component}(),t=(0,i.i)(),n=!e&&"mobile"===t,[o,l]=(0,r.useState)(!1);s((()=>{if(o)return l(!1),!1}));const u=(0,r.useCallback)((()=>{l((e=>!e))}),[]);return(0,r.useEffect)((()=>{"desktop"===t&&l(!1)}),[t]),(0,r.useMemo)((()=>({disabled:e,shouldRender:n,toggle:u,shown:o})),[e,n,u,o])}function p(e){let{children:t}=e;const n=d();return r.createElement(u.Provider,{value:n},t)}function f(){const e=r.useContext(u);if(void 0===e)throw new l.i6("NavbarMobileSidebarProvider");return e}},3102:(e,t,n)=>{"use strict";n.d(t,{HY:()=>l,Zo:()=>s,n2:()=>o});var r=n(7294),a=n(902);const i=r.createContext(null);function o(e){let{children:t}=e;const n=(0,r.useState)({component:null,props:null});return r.createElement(i.Provider,{value:n},t)}function l(){const e=(0,r.useContext)(i);if(!e)throw new a.i6("NavbarSecondaryMenuContentProvider");return e[0]}function s(e){let{component:t,props:n}=e;const o=(0,r.useContext)(i);if(!o)throw new a.i6("NavbarSecondaryMenuContentProvider");const[,l]=o,s=(0,a.Ql)(n);return(0,r.useEffect)((()=>{l({component:t,props:s})}),[l,t,s]),(0,r.useEffect)((()=>()=>l({component:null,props:null})),[l]),null}},9727:(e,t,n)=>{"use strict";n.d(t,{h:()=>a,t:()=>i});var r=n(7294);const a="navigation-with-keyboard";function i(){(0,r.useEffect)((()=>{function e(e){"keydown"===e.type&&"Tab"===e.key&&document.body.classList.add(a),"mousedown"===e.type&&document.body.classList.remove(a)}return document.addEventListener("keydown",e),document.addEventListener("mousedown",e),()=>{document.body.classList.remove(a),document.removeEventListener("keydown",e),document.removeEventListener("mousedown",e)}}),[])}},7524:(e,t,n)=>{"use strict";n.d(t,{i:()=>c});var r=n(7294),a=n(412);const i={desktop:"desktop",mobile:"mobile",ssr:"ssr"},o=996;function l(){return a.Z.canUseDOM?window.innerWidth>o?i.desktop:i.mobile:i.ssr}const s=!1;function c(){const[e,t]=(0,r.useState)((()=>s?"ssr":l()));return(0,r.useEffect)((()=>{function e(){t(l())}const n=s?window.setTimeout(e,1e3):void 0;return window.addEventListener("resize",e),()=>{window.removeEventListener("resize",e),clearTimeout(n)}}),[]),e}},5281:(e,t,n)=>{"use strict";n.d(t,{k:()=>r});const r={page:{blogListPage:"blog-list-page",blogPostPage:"blog-post-page",blogTagsListPage:"blog-tags-list-page",blogTagPostListPage:"blog-tags-post-list-page",docsDocPage:"docs-doc-page",docsTagsListPage:"docs-tags-list-page",docsTagDocListPage:"docs-tags-doc-list-page",mdxPage:"mdx-page"},wrapper:{main:"main-wrapper",blogPages:"blog-wrapper",docsPages:"docs-wrapper",mdxPages:"mdx-wrapper"},common:{editThisPage:"theme-edit-this-page",lastUpdated:"theme-last-updated",backToTopButton:"theme-back-to-top-button",codeBlock:"theme-code-block",admonition:"theme-admonition",admonitionType:e=>`theme-admonition-${e}`},layout:{},docs:{docVersionBanner:"theme-doc-version-banner",docVersionBadge:"theme-doc-version-badge",docBreadcrumbs:"theme-doc-breadcrumbs",docMarkdown:"theme-doc-markdown",docTocMobile:"theme-doc-toc-mobile",docTocDesktop:"theme-doc-toc-desktop",docFooter:"theme-doc-footer",docFooterTagsRow:"theme-doc-footer-tags-row",docFooterEditMetaRow:"theme-doc-footer-edit-meta-row",docSidebarContainer:"theme-doc-sidebar-container",docSidebarMenu:"theme-doc-sidebar-menu",docSidebarItemCategory:"theme-doc-sidebar-item-category",docSidebarItemLink:"theme-doc-sidebar-item-link",docSidebarItemCategoryLevel:e=>`theme-doc-sidebar-item-category-level-${e}`,docSidebarItemLinkLevel:e=>`theme-doc-sidebar-item-link-level-${e}`},blog:{}}},2802:(e,t,n)=>{"use strict";n.d(t,{Wl:()=>p,_F:()=>g,cE:()=>d,hI:()=>x,lO:()=>v,vY:()=>w,oz:()=>y,s1:()=>b});var r=n(7294),a=n(6550),i=n(8790),o=n(143),l=n(373),s=n(1116);function c(e){return Array.from(new Set(e))}var u=n(8596);const d=!!o._r;function p(e){if(e.href)return e.href;for(const t of e.items){if("link"===t.type)return t.href;if("category"===t.type){const e=p(t);if(e)return e}}}const f=(e,t)=>void 0!==e&&(0,u.Mg)(e,t),m=(e,t)=>e.some((e=>g(e,t)));function g(e,t){return"link"===e.type?f(e.href,t):"category"===e.type&&(f(e.href,t)||m(e.items,t))}function h(e){let{sidebarItems:t,pathname:n,onlyCategories:r=!1}=e;const a=[];return function e(t){for(const i of t)if("category"===i.type&&((0,u.Mg)(i.href,n)||e(i.items))||"link"===i.type&&(0,u.Mg)(i.href,n)){return r&&"category"!==i.type||a.unshift(i),!0}return!1}(t),a}function b(){const e=(0,s.V)(),{pathname:t}=(0,a.TH)(),n=(0,o.gA)()?.pluginData.breadcrumbs;return!1!==n&&e?h({sidebarItems:e.items,pathname:t}):null}function v(e){const{activeVersion:t}=(0,o.Iw)(e),{preferredVersion:n}=(0,l.J)(e),a=(0,o.yW)(e);return(0,r.useMemo)((()=>c([t,n,a].filter(Boolean))),[t,n,a])}function y(e,t){const n=v(t);return(0,r.useMemo)((()=>{const t=n.flatMap((e=>e.sidebars?Object.entries(e.sidebars):[])),r=t.find((t=>t[0]===e));if(!r)throw new Error(`Can't find any sidebar with id "${e}" in version${n.length>1?"s":""} ${n.map((e=>e.name)).join(", ")}".\n Available sidebar ids are:\n - ${Object.keys(t).join("\n- ")}`);return r[1]}),[e,n])}function w(e,t){const n=v(t);return(0,r.useMemo)((()=>{const t=n.flatMap((e=>e.docs)),r=t.find((t=>t.id===e));if(!r){if(n.flatMap((e=>e.draftIds)).includes(e))return null;throw new Error(`DocNavbarItem: couldn't find any doc with id "${e}" in version${n.length>1?"s":""} ${n.map((e=>e.name)).join(", ")}".\nAvailable doc ids are:\n- ${c(t.map((e=>e.id))).join("\n- ")}`)}return r}),[e,n])}function x(e){let{route:t,versionMetadata:n}=e;const r=(0,a.TH)(),o=t.routes,l=o.find((e=>(0,a.LX)(r.pathname,e)));if(!l)return null;const s=l.sidebar,c=s?n.docsSidebars[s]:void 0;return{docElement:(0,i.H)(o),sidebarName:s,sidebarItems:c}}},1944:(e,t,n)=>{"use strict";n.d(t,{FG:()=>p,d:()=>u,VC:()=>f});var r=n(7294),a=n(6010),i=n(5742),o=n(226);function l(){const e=r.useContext(o._);if(!e)throw new Error("Unexpected: no Docusaurus route context found");return e}var s=n(4996),c=n(2263);function u(e){let{title:t,description:n,keywords:a,image:o,children:l}=e;const u=function(e){const{siteConfig:t}=(0,c.Z)(),{title:n,titleDelimiter:r}=t;return e?.trim().length?`${e.trim()} ${r} ${n}`:n}(t),{withBaseUrl:d}=(0,s.C)(),p=o?d(o,{absolute:!0}):void 0;return r.createElement(i.Z,null,t&&r.createElement("title",null,u),t&&r.createElement("meta",{property:"og:title",content:u}),n&&r.createElement("meta",{name:"description",content:n}),n&&r.createElement("meta",{property:"og:description",content:n}),a&&r.createElement("meta",{name:"keywords",content:Array.isArray(a)?a.join(","):a}),p&&r.createElement("meta",{property:"og:image",content:p}),p&&r.createElement("meta",{name:"twitter:image",content:p}),l)}const d=r.createContext(void 0);function p(e){let{className:t,children:n}=e;const o=r.useContext(d),l=(0,a.Z)(o,t);return r.createElement(d.Provider,{value:l},r.createElement(i.Z,null,r.createElement("html",{className:l})),n)}function f(e){let{children:t}=e;const n=l(),i=`plugin-${n.plugin.name.replace(/docusaurus-(?:plugin|theme)-(?:content-)?/gi,"")}`;const o=`plugin-id-${n.plugin.id}`;return r.createElement(p,{className:(0,a.Z)(i,o)},t)}},902:(e,t,n)=>{"use strict";n.d(t,{D9:()=>o,Qc:()=>c,Ql:()=>s,i6:()=>l,zX:()=>i});var r=n(7294);const a=n(412).Z.canUseDOM?r.useLayoutEffect:r.useEffect;function i(e){const t=(0,r.useRef)(e);return a((()=>{t.current=e}),[e]),(0,r.useCallback)((function(){return t.current(...arguments)}),[])}function o(e){const t=(0,r.useRef)();return a((()=>{t.current=e})),t.current}class l extends Error{constructor(e,t){super(),this.name="ReactContextError",this.message=`Hook ${this.stack?.split("\n")[1]?.match(/at (?:\w+\.)?(?<name>\w+)/)?.groups.name??""} is called outside the <${e}>. ${t??""}`}}function s(e){const t=Object.entries(e);return t.sort(((e,t)=>e[0].localeCompare(t[0]))),(0,r.useMemo)((()=>e),t.flat())}function c(e){return t=>{let{children:n}=t;return r.createElement(r.Fragment,null,e.reduceRight(((e,t)=>r.createElement(t,null,e)),n))}}},8596:(e,t,n)=>{"use strict";n.d(t,{Mg:()=>o,Ns:()=>l});var r=n(7294),a=n(723),i=n(2263);function o(e,t){const n=e=>(!e||e.endsWith("/")?e:`${e}/`)?.toLowerCase();return n(e)===n(t)}function l(){const{baseUrl:e}=(0,i.Z)().siteConfig;return(0,r.useMemo)((()=>function(e){let{baseUrl:t,routes:n}=e;function r(e){return e.path===t&&!0===e.exact}function a(e){return e.path===t&&!e.exact}return function e(t){if(0===t.length)return;return t.find(r)||e(t.filter(a).flatMap((e=>e.routes??[])))}(n)}({routes:a.Z,baseUrl:e})),[e])}},2466:(e,t,n)=>{"use strict";n.d(t,{Ct:()=>p,OC:()=>s,RF:()=>d});var r=n(7294),a=n(412),i=n(2389),o=n(902);const l=r.createContext(void 0);function s(e){let{children:t}=e;const n=function(){const e=(0,r.useRef)(!0);return(0,r.useMemo)((()=>({scrollEventsEnabledRef:e,enableScrollEvents:()=>{e.current=!0},disableScrollEvents:()=>{e.current=!1}})),[])}();return r.createElement(l.Provider,{value:n},t)}function c(){const e=(0,r.useContext)(l);if(null==e)throw new o.i6("ScrollControllerProvider");return e}const u=()=>a.Z.canUseDOM?{scrollX:window.pageXOffset,scrollY:window.pageYOffset}:null;function d(e,t){void 0===t&&(t=[]);const{scrollEventsEnabledRef:n}=c(),a=(0,r.useRef)(u()),i=(0,o.zX)(e);(0,r.useEffect)((()=>{const e=()=>{if(!n.current)return;const e=u();i(e,a.current),a.current=e},t={passive:!0};return e(),window.addEventListener("scroll",e,t),()=>window.removeEventListener("scroll",e,t)}),[i,n,...t])}function p(){const e=(0,r.useRef)(null),t=(0,i.Z)()&&"smooth"===getComputedStyle(document.documentElement).scrollBehavior;return{startScroll:n=>{e.current=t?function(e){return window.scrollTo({top:e,behavior:"smooth"}),()=>{}}(n):function(e){let t=null;const n=document.documentElement.scrollTop>e;return function r(){const a=document.documentElement.scrollTop;(n&&a>e||!n&&a<e)&&(t=requestAnimationFrame(r),window.scrollTo(0,Math.floor(.85*(a-e))+e))}(),()=>t&&cancelAnimationFrame(t)}(n)},cancelScroll:()=>e.current?.()}}},3320:(e,t,n)=>{"use strict";n.d(t,{HX:()=>r,os:()=>a});n(2263);const r="default";function a(e,t){return`docs-${e}-${t}`}},12:(e,t,n)=>{"use strict";n.d(t,{W:()=>l,_:()=>s});const r="localStorage";function a(e){if(void 0===e&&(e=r),"undefined"==typeof window)throw new Error("Browser storage is not available on Node.js/Docusaurus SSR process.");if("none"===e)return null;try{return window[e]}catch(n){return t=n,i||(console.warn("Docusaurus browser storage is not available.\nPossible reasons: running Docusaurus in an iframe, in an incognito browser session, or using too strict browser privacy settings.",t),i=!0),null}var t}let i=!1;const o={get:()=>null,set:()=>{},del:()=>{}};function l(e,t){if("undefined"==typeof window)return function(e){function t(){throw new Error(`Illegal storage API usage for storage key "${e}".\nDocusaurus storage APIs are not supposed to be called on the server-rendering process.\nPlease only call storage APIs in effects and event handlers.`)}return{get:t,set:t,del:t}}(e);const n=a(t?.persistence);return null===n?o:{get:()=>{try{return n.getItem(e)}catch(t){return console.error(`Docusaurus storage error, can't get key=${e}`,t),null}},set:t=>{try{n.setItem(e,t)}catch(r){console.error(`Docusaurus storage error, can't set ${e}=${t}`,r)}},del:()=>{try{n.removeItem(e)}catch(t){console.error(`Docusaurus storage error, can't delete key=${e}`,t)}}}}function s(e){void 0===e&&(e=r);const t=a(e);if(!t)return[];const n=[];for(let r=0;r<t.length;r+=1){const e=t.key(r);null!==e&&n.push(e)}return n}},4711:(e,t,n)=>{"use strict";n.d(t,{l:()=>i});var r=n(2263),a=n(6550);function i(){const{siteConfig:{baseUrl:e,url:t},i18n:{defaultLocale:n,currentLocale:i}}=(0,r.Z)(),{pathname:o}=(0,a.TH)(),l=i===n?e:e.replace(`/${i}/`,"/"),s=o.replace(e,"");return{createUrl:function(e){let{locale:r,fullyQualified:a}=e;return`${a?t:""}${function(e){return e===n?`${l}`:`${l}${e}/`}(r)}${s}`}}}},5936:(e,t,n)=>{"use strict";n.d(t,{S:()=>o});var r=n(7294),a=n(6550),i=n(902);function o(e){const t=(0,a.TH)(),n=(0,i.D9)(t),o=(0,i.zX)(e);(0,r.useEffect)((()=>{n&&t!==n&&o({location:t,previousLocation:n})}),[o,t,n])}},6668:(e,t,n)=>{"use strict";n.d(t,{L:()=>a});var r=n(2263);function a(){return(0,r.Z)().siteConfig.themeConfig}},8802:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e,t){const{trailingSlash:n,baseUrl:r}=t;if(e.startsWith("#"))return e;if(void 0===n)return e;const[a]=e.split(/[#?]/),i="/"===a||a===r?a:(o=a,n?function(e){return e.endsWith("/")?e:`${e}/`}(o):function(e){return e.endsWith("/")?e.slice(0,-1):e}(o));var o;return e.replace(a,i)}},8780:function(e,t,n){"use strict";var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.applyTrailingSlash=t.blogPostContainerID=void 0,t.blogPostContainerID="post-content";var a=n(8802);Object.defineProperty(t,"applyTrailingSlash",{enumerable:!0,get:function(){return r(a).default}})},6010:(e,t,n)=>{"use strict";function r(e){var t,n,a="";if("string"==typeof e||"number"==typeof e)a+=e;else if("object"==typeof e)if(Array.isArray(e))for(t=0;t<e.length;t++)e[t]&&(n=r(e[t]))&&(a&&(a+=" "),a+=n);else for(t in e)e[t]&&(a&&(a+=" "),a+=t);return a}n.d(t,{Z:()=>a});const a=function(){for(var e,t,n=0,a="";n<arguments.length;)(e=arguments[n++])&&(t=r(e))&&(a&&(a+=" "),a+=t);return a}},9318:(e,t,n)=>{"use strict";n.d(t,{lX:()=>w,q_:()=>_,ob:()=>f,PP:()=>A,Ep:()=>p});var r=n(7462);function a(e){return"/"===e.charAt(0)}function i(e,t){for(var n=t,r=n+1,a=e.length;r<a;n+=1,r+=1)e[n]=e[r];e.pop()}const o=function(e,t){void 0===t&&(t="");var n,r=e&&e.split("/")||[],o=t&&t.split("/")||[],l=e&&a(e),s=t&&a(t),c=l||s;if(e&&a(e)?o=r:r.length&&(o.pop(),o=o.concat(r)),!o.length)return"/";if(o.length){var u=o[o.length-1];n="."===u||".."===u||""===u}else n=!1;for(var d=0,p=o.length;p>=0;p--){var f=o[p];"."===f?i(o,p):".."===f?(i(o,p),d++):d&&(i(o,p),d--)}if(!c)for(;d--;d)o.unshift("..");!c||""===o[0]||o[0]&&a(o[0])||o.unshift("");var m=o.join("/");return n&&"/"!==m.substr(-1)&&(m+="/"),m};var l=n(8776);function s(e){return"/"===e.charAt(0)?e:"/"+e}function c(e){return"/"===e.charAt(0)?e.substr(1):e}function u(e,t){return function(e,t){return 0===e.toLowerCase().indexOf(t.toLowerCase())&&-1!=="/?#".indexOf(e.charAt(t.length))}(e,t)?e.substr(t.length):e}function d(e){return"/"===e.charAt(e.length-1)?e.slice(0,-1):e}function p(e){var t=e.pathname,n=e.search,r=e.hash,a=t||"/";return n&&"?"!==n&&(a+="?"===n.charAt(0)?n:"?"+n),r&&"#"!==r&&(a+="#"===r.charAt(0)?r:"#"+r),a}function f(e,t,n,a){var i;"string"==typeof e?(i=function(e){var t=e||"/",n="",r="",a=t.indexOf("#");-1!==a&&(r=t.substr(a),t=t.substr(0,a));var i=t.indexOf("?");return-1!==i&&(n=t.substr(i),t=t.substr(0,i)),{pathname:t,search:"?"===n?"":n,hash:"#"===r?"":r}}(e),i.state=t):(void 0===(i=(0,r.Z)({},e)).pathname&&(i.pathname=""),i.search?"?"!==i.search.charAt(0)&&(i.search="?"+i.search):i.search="",i.hash?"#"!==i.hash.charAt(0)&&(i.hash="#"+i.hash):i.hash="",void 0!==t&&void 0===i.state&&(i.state=t));try{i.pathname=decodeURI(i.pathname)}catch(l){throw l instanceof URIError?new URIError('Pathname "'+i.pathname+'" could not be decoded. This is likely caused by an invalid percent-encoding.'):l}return n&&(i.key=n),a?i.pathname?"/"!==i.pathname.charAt(0)&&(i.pathname=o(i.pathname,a.pathname)):i.pathname=a.pathname:i.pathname||(i.pathname="/"),i}function m(){var e=null;var t=[];return{setPrompt:function(t){return e=t,function(){e===t&&(e=null)}},confirmTransitionTo:function(t,n,r,a){if(null!=e){var i="function"==typeof e?e(t,n):e;"string"==typeof i?"function"==typeof r?r(i,a):a(!0):a(!1!==i)}else a(!0)},appendListener:function(e){var n=!0;function r(){n&&e.apply(void 0,arguments)}return t.push(r),function(){n=!1,t=t.filter((function(e){return e!==r}))}},notifyListeners:function(){for(var e=arguments.length,n=new Array(e),r=0;r<e;r++)n[r]=arguments[r];t.forEach((function(e){return e.apply(void 0,n)}))}}}var g=!("undefined"==typeof window||!window.document||!window.document.createElement);function h(e,t){t(window.confirm(e))}var b="popstate",v="hashchange";function y(){try{return window.history.state||{}}catch(e){return{}}}function w(e){void 0===e&&(e={}),g||(0,l.Z)(!1);var t,n=window.history,a=(-1===(t=window.navigator.userAgent).indexOf("Android 2.")&&-1===t.indexOf("Android 4.0")||-1===t.indexOf("Mobile Safari")||-1!==t.indexOf("Chrome")||-1!==t.indexOf("Windows Phone"))&&window.history&&"pushState"in window.history,i=!(-1===window.navigator.userAgent.indexOf("Trident")),o=e,c=o.forceRefresh,w=void 0!==c&&c,x=o.getUserConfirmation,k=void 0===x?h:x,E=o.keyLength,S=void 0===E?6:E,T=e.basename?d(s(e.basename)):"";function _(e){var t=e||{},n=t.key,r=t.state,a=window.location,i=a.pathname+a.search+a.hash;return T&&(i=u(i,T)),f(i,r,n)}function C(){return Math.random().toString(36).substr(2,S)}var A=m();function P(e){(0,r.Z)(U,e),U.length=n.length,A.notifyListeners(U.location,U.action)}function N(e){(function(e){return void 0===e.state&&-1===navigator.userAgent.indexOf("CriOS")})(e)||L(_(e.state))}function O(){L(_(y()))}var I=!1;function L(e){if(I)I=!1,P();else{A.confirmTransitionTo(e,"POP",k,(function(t){t?P({action:"POP",location:e}):function(e){var t=U.location,n=R.indexOf(t.key);-1===n&&(n=0);var r=R.indexOf(e.key);-1===r&&(r=0);var a=n-r;a&&(I=!0,F(a))}(e)}))}}var D=_(y()),R=[D.key];function M(e){return T+p(e)}function F(e){n.go(e)}var B=0;function $(e){1===(B+=e)&&1===e?(window.addEventListener(b,N),i&&window.addEventListener(v,O)):0===B&&(window.removeEventListener(b,N),i&&window.removeEventListener(v,O))}var z=!1;var U={length:n.length,action:"POP",location:D,createHref:M,push:function(e,t){var r="PUSH",i=f(e,t,C(),U.location);A.confirmTransitionTo(i,r,k,(function(e){if(e){var t=M(i),o=i.key,l=i.state;if(a)if(n.pushState({key:o,state:l},null,t),w)window.location.href=t;else{var s=R.indexOf(U.location.key),c=R.slice(0,s+1);c.push(i.key),R=c,P({action:r,location:i})}else window.location.href=t}}))},replace:function(e,t){var r="REPLACE",i=f(e,t,C(),U.location);A.confirmTransitionTo(i,r,k,(function(e){if(e){var t=M(i),o=i.key,l=i.state;if(a)if(n.replaceState({key:o,state:l},null,t),w)window.location.replace(t);else{var s=R.indexOf(U.location.key);-1!==s&&(R[s]=i.key),P({action:r,location:i})}else window.location.replace(t)}}))},go:F,goBack:function(){F(-1)},goForward:function(){F(1)},block:function(e){void 0===e&&(e=!1);var t=A.setPrompt(e);return z||($(1),z=!0),function(){return z&&(z=!1,$(-1)),t()}},listen:function(e){var t=A.appendListener(e);return $(1),function(){$(-1),t()}}};return U}var x="hashchange",k={hashbang:{encodePath:function(e){return"!"===e.charAt(0)?e:"!/"+c(e)},decodePath:function(e){return"!"===e.charAt(0)?e.substr(1):e}},noslash:{encodePath:c,decodePath:s},slash:{encodePath:s,decodePath:s}};function E(e){var t=e.indexOf("#");return-1===t?e:e.slice(0,t)}function S(){var e=window.location.href,t=e.indexOf("#");return-1===t?"":e.substring(t+1)}function T(e){window.location.replace(E(window.location.href)+"#"+e)}function _(e){void 0===e&&(e={}),g||(0,l.Z)(!1);var t=window.history,n=(window.navigator.userAgent.indexOf("Firefox"),e),a=n.getUserConfirmation,i=void 0===a?h:a,o=n.hashType,c=void 0===o?"slash":o,b=e.basename?d(s(e.basename)):"",v=k[c],y=v.encodePath,w=v.decodePath;function _(){var e=w(S());return b&&(e=u(e,b)),f(e)}var C=m();function A(e){(0,r.Z)(z,e),z.length=t.length,C.notifyListeners(z.location,z.action)}var P=!1,N=null;function O(){var e,t,n=S(),r=y(n);if(n!==r)T(r);else{var a=_(),o=z.location;if(!P&&(t=a,(e=o).pathname===t.pathname&&e.search===t.search&&e.hash===t.hash))return;if(N===p(a))return;N=null,function(e){if(P)P=!1,A();else{var t="POP";C.confirmTransitionTo(e,t,i,(function(n){n?A({action:t,location:e}):function(e){var t=z.location,n=R.lastIndexOf(p(t));-1===n&&(n=0);var r=R.lastIndexOf(p(e));-1===r&&(r=0);var a=n-r;a&&(P=!0,M(a))}(e)}))}}(a)}}var I=S(),L=y(I);I!==L&&T(L);var D=_(),R=[p(D)];function M(e){t.go(e)}var F=0;function B(e){1===(F+=e)&&1===e?window.addEventListener(x,O):0===F&&window.removeEventListener(x,O)}var $=!1;var z={length:t.length,action:"POP",location:D,createHref:function(e){var t=document.querySelector("base"),n="";return t&&t.getAttribute("href")&&(n=E(window.location.href)),n+"#"+y(b+p(e))},push:function(e,t){var n="PUSH",r=f(e,void 0,void 0,z.location);C.confirmTransitionTo(r,n,i,(function(e){if(e){var t=p(r),a=y(b+t);if(S()!==a){N=t,function(e){window.location.hash=e}(a);var i=R.lastIndexOf(p(z.location)),o=R.slice(0,i+1);o.push(t),R=o,A({action:n,location:r})}else A()}}))},replace:function(e,t){var n="REPLACE",r=f(e,void 0,void 0,z.location);C.confirmTransitionTo(r,n,i,(function(e){if(e){var t=p(r),a=y(b+t);S()!==a&&(N=t,T(a));var i=R.indexOf(p(z.location));-1!==i&&(R[i]=t),A({action:n,location:r})}}))},go:M,goBack:function(){M(-1)},goForward:function(){M(1)},block:function(e){void 0===e&&(e=!1);var t=C.setPrompt(e);return $||(B(1),$=!0),function(){return $&&($=!1,B(-1)),t()}},listen:function(e){var t=C.appendListener(e);return B(1),function(){B(-1),t()}}};return z}function C(e,t,n){return Math.min(Math.max(e,t),n)}function A(e){void 0===e&&(e={});var t=e,n=t.getUserConfirmation,a=t.initialEntries,i=void 0===a?["/"]:a,o=t.initialIndex,l=void 0===o?0:o,s=t.keyLength,c=void 0===s?6:s,u=m();function d(e){(0,r.Z)(w,e),w.length=w.entries.length,u.notifyListeners(w.location,w.action)}function g(){return Math.random().toString(36).substr(2,c)}var h=C(l,0,i.length-1),b=i.map((function(e){return f(e,void 0,"string"==typeof e?g():e.key||g())})),v=p;function y(e){var t=C(w.index+e,0,w.entries.length-1),r=w.entries[t];u.confirmTransitionTo(r,"POP",n,(function(e){e?d({action:"POP",location:r,index:t}):d()}))}var w={length:b.length,action:"POP",location:b[h],index:h,entries:b,createHref:v,push:function(e,t){var r="PUSH",a=f(e,t,g(),w.location);u.confirmTransitionTo(a,r,n,(function(e){if(e){var t=w.index+1,n=w.entries.slice(0);n.length>t?n.splice(t,n.length-t,a):n.push(a),d({action:r,location:a,index:t,entries:n})}}))},replace:function(e,t){var r="REPLACE",a=f(e,t,g(),w.location);u.confirmTransitionTo(a,r,n,(function(e){e&&(w.entries[w.index]=a,d({action:r,location:a}))}))},go:y,goBack:function(){y(-1)},goForward:function(){y(1)},canGo:function(e){var t=w.index+e;return t>=0&&t<w.entries.length},block:function(e){return void 0===e&&(e=!1),u.setPrompt(e)},listen:function(e){return u.appendListener(e)}};return w}},8679:(e,t,n)=>{"use strict";var r=n(9864),a={childContextTypes:!0,contextType:!0,contextTypes:!0,defaultProps:!0,displayName:!0,getDefaultProps:!0,getDerivedStateFromError:!0,getDerivedStateFromProps:!0,mixins:!0,propTypes:!0,type:!0},i={name:!0,length:!0,prototype:!0,caller:!0,callee:!0,arguments:!0,arity:!0},o={$$typeof:!0,compare:!0,defaultProps:!0,displayName:!0,propTypes:!0,type:!0},l={};function s(e){return r.isMemo(e)?o:l[e.$$typeof]||a}l[r.ForwardRef]={$$typeof:!0,render:!0,defaultProps:!0,displayName:!0,propTypes:!0},l[r.Memo]=o;var c=Object.defineProperty,u=Object.getOwnPropertyNames,d=Object.getOwnPropertySymbols,p=Object.getOwnPropertyDescriptor,f=Object.getPrototypeOf,m=Object.prototype;e.exports=function e(t,n,r){if("string"!=typeof n){if(m){var a=f(n);a&&a!==m&&e(t,a,r)}var o=u(n);d&&(o=o.concat(d(n)));for(var l=s(t),g=s(n),h=0;h<o.length;++h){var b=o[h];if(!(i[b]||r&&r[b]||g&&g[b]||l&&l[b])){var v=p(n,b);try{c(t,b,v)}catch(y){}}}}return t}},1143:e=>{"use strict";e.exports=function(e,t,n,r,a,i,o,l){if(!e){var s;if(void 0===t)s=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var c=[n,r,a,i,o,l],u=0;(s=new Error(t.replace(/%s/g,(function(){return c[u++]})))).name="Invariant Violation"}throw s.framesToPop=1,s}}},5826:e=>{e.exports=Array.isArray||function(e){return"[object Array]"==Object.prototype.toString.call(e)}},2497:(e,t,n)=>{"use strict";n.r(t)},2295:(e,t,n)=>{"use strict";n.r(t)},4865:function(e,t,n){var r,a;r=function(){var e,t,n={version:"0.2.0"},r=n.settings={minimum:.08,easing:"ease",positionUsing:"",speed:200,trickle:!0,trickleRate:.02,trickleSpeed:800,showSpinner:!0,barSelector:'[role="bar"]',spinnerSelector:'[role="spinner"]',parent:"body",template:'<div class="bar" role="bar"><div class="peg"></div></div><div class="spinner" role="spinner"><div class="spinner-icon"></div></div>'};function a(e,t,n){return e<t?t:e>n?n:e}function i(e){return 100*(-1+e)}function o(e,t,n){var a;return(a="translate3d"===r.positionUsing?{transform:"translate3d("+i(e)+"%,0,0)"}:"translate"===r.positionUsing?{transform:"translate("+i(e)+"%,0)"}:{"margin-left":i(e)+"%"}).transition="all "+t+"ms "+n,a}n.configure=function(e){var t,n;for(t in e)void 0!==(n=e[t])&&e.hasOwnProperty(t)&&(r[t]=n);return this},n.status=null,n.set=function(e){var t=n.isStarted();e=a(e,r.minimum,1),n.status=1===e?null:e;var i=n.render(!t),c=i.querySelector(r.barSelector),u=r.speed,d=r.easing;return i.offsetWidth,l((function(t){""===r.positionUsing&&(r.positionUsing=n.getPositioningCSS()),s(c,o(e,u,d)),1===e?(s(i,{transition:"none",opacity:1}),i.offsetWidth,setTimeout((function(){s(i,{transition:"all "+u+"ms linear",opacity:0}),setTimeout((function(){n.remove(),t()}),u)}),u)):setTimeout(t,u)})),this},n.isStarted=function(){return"number"==typeof n.status},n.start=function(){n.status||n.set(0);var e=function(){setTimeout((function(){n.status&&(n.trickle(),e())}),r.trickleSpeed)};return r.trickle&&e(),this},n.done=function(e){return e||n.status?n.inc(.3+.5*Math.random()).set(1):this},n.inc=function(e){var t=n.status;return t?("number"!=typeof e&&(e=(1-t)*a(Math.random()*t,.1,.95)),t=a(t+e,0,.994),n.set(t)):n.start()},n.trickle=function(){return n.inc(Math.random()*r.trickleRate)},e=0,t=0,n.promise=function(r){return r&&"resolved"!==r.state()?(0===t&&n.start(),e++,t++,r.always((function(){0==--t?(e=0,n.done()):n.set((e-t)/e)})),this):this},n.render=function(e){if(n.isRendered())return document.getElementById("nprogress");u(document.documentElement,"nprogress-busy");var t=document.createElement("div");t.id="nprogress",t.innerHTML=r.template;var a,o=t.querySelector(r.barSelector),l=e?"-100":i(n.status||0),c=document.querySelector(r.parent);return s(o,{transition:"all 0 linear",transform:"translate3d("+l+"%,0,0)"}),r.showSpinner||(a=t.querySelector(r.spinnerSelector))&&f(a),c!=document.body&&u(c,"nprogress-custom-parent"),c.appendChild(t),t},n.remove=function(){d(document.documentElement,"nprogress-busy"),d(document.querySelector(r.parent),"nprogress-custom-parent");var e=document.getElementById("nprogress");e&&f(e)},n.isRendered=function(){return!!document.getElementById("nprogress")},n.getPositioningCSS=function(){var e=document.body.style,t="WebkitTransform"in e?"Webkit":"MozTransform"in e?"Moz":"msTransform"in e?"ms":"OTransform"in e?"O":"";return t+"Perspective"in e?"translate3d":t+"Transform"in e?"translate":"margin"};var l=function(){var e=[];function t(){var n=e.shift();n&&n(t)}return function(n){e.push(n),1==e.length&&t()}}(),s=function(){var e=["Webkit","O","Moz","ms"],t={};function n(e){return e.replace(/^-ms-/,"ms-").replace(/-([\da-z])/gi,(function(e,t){return t.toUpperCase()}))}function r(t){var n=document.body.style;if(t in n)return t;for(var r,a=e.length,i=t.charAt(0).toUpperCase()+t.slice(1);a--;)if((r=e[a]+i)in n)return r;return t}function a(e){return e=n(e),t[e]||(t[e]=r(e))}function i(e,t,n){t=a(t),e.style[t]=n}return function(e,t){var n,r,a=arguments;if(2==a.length)for(n in t)void 0!==(r=t[n])&&t.hasOwnProperty(n)&&i(e,n,r);else i(e,a[1],a[2])}}();function c(e,t){return("string"==typeof e?e:p(e)).indexOf(" "+t+" ")>=0}function u(e,t){var n=p(e),r=n+t;c(n,t)||(e.className=r.substring(1))}function d(e,t){var n,r=p(e);c(e,t)&&(n=r.replace(" "+t+" "," "),e.className=n.substring(1,n.length-1))}function p(e){return(" "+(e.className||"")+" ").replace(/\s+/gi," ")}function f(e){e&&e.parentNode&&e.parentNode.removeChild(e)}return n},void 0===(a="function"==typeof r?r.call(t,n,t,e):r)||(e.exports=a)},7418:e=>{"use strict";var t=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,r=Object.prototype.propertyIsEnumerable;e.exports=function(){try{if(!Object.assign)return!1;var e=new String("abc");if(e[5]="de","5"===Object.getOwnPropertyNames(e)[0])return!1;for(var t={},n=0;n<10;n++)t["_"+String.fromCharCode(n)]=n;if("0123456789"!==Object.getOwnPropertyNames(t).map((function(e){return t[e]})).join(""))return!1;var r={};return"abcdefghijklmnopqrst".split("").forEach((function(e){r[e]=e})),"abcdefghijklmnopqrst"===Object.keys(Object.assign({},r)).join("")}catch(a){return!1}}()?Object.assign:function(e,a){for(var i,o,l=function(e){if(null==e)throw new TypeError("Object.assign cannot be called with null or undefined");return Object(e)}(e),s=1;s<arguments.length;s++){for(var c in i=Object(arguments[s]))n.call(i,c)&&(l[c]=i[c]);if(t){o=t(i);for(var u=0;u<o.length;u++)r.call(i,o[u])&&(l[o[u]]=i[o[u]])}}return l}},4779:(e,t,n)=>{var r=n(5826);e.exports=f,e.exports.parse=i,e.exports.compile=function(e,t){return l(i(e,t),t)},e.exports.tokensToFunction=l,e.exports.tokensToRegExp=p;var a=new RegExp(["(\\\\.)","([\\/.])?(?:(?:\\:(\\w+)(?:\\(((?:\\\\.|[^\\\\()])+)\\))?|\\(((?:\\\\.|[^\\\\()])+)\\))([+*?])?|(\\*))"].join("|"),"g");function i(e,t){for(var n,r=[],i=0,o=0,l="",u=t&&t.delimiter||"/";null!=(n=a.exec(e));){var d=n[0],p=n[1],f=n.index;if(l+=e.slice(o,f),o=f+d.length,p)l+=p[1];else{var m=e[o],g=n[2],h=n[3],b=n[4],v=n[5],y=n[6],w=n[7];l&&(r.push(l),l="");var x=null!=g&&null!=m&&m!==g,k="+"===y||"*"===y,E="?"===y||"*"===y,S=n[2]||u,T=b||v;r.push({name:h||i++,prefix:g||"",delimiter:S,optional:E,repeat:k,partial:x,asterisk:!!w,pattern:T?c(T):w?".*":"[^"+s(S)+"]+?"})}}return o<e.length&&(l+=e.substr(o)),l&&r.push(l),r}function o(e){return encodeURI(e).replace(/[\/?#]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}function l(e,t){for(var n=new Array(e.length),a=0;a<e.length;a++)"object"==typeof e[a]&&(n[a]=new RegExp("^(?:"+e[a].pattern+")$",d(t)));return function(t,a){for(var i="",l=t||{},s=(a||{}).pretty?o:encodeURIComponent,c=0;c<e.length;c++){var u=e[c];if("string"!=typeof u){var d,p=l[u.name];if(null==p){if(u.optional){u.partial&&(i+=u.prefix);continue}throw new TypeError('Expected "'+u.name+'" to be defined')}if(r(p)){if(!u.repeat)throw new TypeError('Expected "'+u.name+'" to not repeat, but received `'+JSON.stringify(p)+"`");if(0===p.length){if(u.optional)continue;throw new TypeError('Expected "'+u.name+'" to not be empty')}for(var f=0;f<p.length;f++){if(d=s(p[f]),!n[c].test(d))throw new TypeError('Expected all "'+u.name+'" to match "'+u.pattern+'", but received `'+JSON.stringify(d)+"`");i+=(0===f?u.prefix:u.delimiter)+d}}else{if(d=u.asterisk?encodeURI(p).replace(/[?#]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()})):s(p),!n[c].test(d))throw new TypeError('Expected "'+u.name+'" to match "'+u.pattern+'", but received "'+d+'"');i+=u.prefix+d}}else i+=u}return i}}function s(e){return e.replace(/([.+*?=^!:${}()[\]|\/\\])/g,"\\$1")}function c(e){return e.replace(/([=!:$\/()])/g,"\\$1")}function u(e,t){return e.keys=t,e}function d(e){return e&&e.sensitive?"":"i"}function p(e,t,n){r(t)||(n=t||n,t=[]);for(var a=(n=n||{}).strict,i=!1!==n.end,o="",l=0;l<e.length;l++){var c=e[l];if("string"==typeof c)o+=s(c);else{var p=s(c.prefix),f="(?:"+c.pattern+")";t.push(c),c.repeat&&(f+="(?:"+p+f+")*"),o+=f=c.optional?c.partial?p+"("+f+")?":"(?:"+p+"("+f+"))?":p+"("+f+")"}}var m=s(n.delimiter||"/"),g=o.slice(-m.length)===m;return a||(o=(g?o.slice(0,-m.length):o)+"(?:"+m+"(?=$))?"),o+=i?"$":a&&g?"":"(?="+m+"|$)",u(new RegExp("^"+o,d(n)),t)}function f(e,t,n){return r(t)||(n=t||n,t=[]),n=n||{},e instanceof RegExp?function(e,t){var n=e.source.match(/\((?!\?)/g);if(n)for(var r=0;r<n.length;r++)t.push({name:r,prefix:null,delimiter:null,optional:!1,repeat:!1,partial:!1,asterisk:!1,pattern:null});return u(e,t)}(e,t):r(e)?function(e,t,n){for(var r=[],a=0;a<e.length;a++)r.push(f(e[a],t,n).source);return u(new RegExp("(?:"+r.join("|")+")",d(n)),t)}(e,t,n):function(e,t,n){return p(i(e,n),t,n)}(e,t,n)}},7410:(e,t,n)=>{"use strict";n.d(t,{Z:()=>i});var r=function(){var e=/(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i,t=0,n={},r={util:{encode:function e(t){return t instanceof a?new a(t.type,e(t.content),t.alias):Array.isArray(t)?t.map(e):t.replace(/&/g,"&").replace(/</g,"<").replace(/\u00a0/g," ")},type:function(e){return Object.prototype.toString.call(e).slice(8,-1)},objId:function(e){return e.__id||Object.defineProperty(e,"__id",{value:++t}),e.__id},clone:function e(t,n){var a,i;switch(n=n||{},r.util.type(t)){case"Object":if(i=r.util.objId(t),n[i])return n[i];for(var o in a={},n[i]=a,t)t.hasOwnProperty(o)&&(a[o]=e(t[o],n));return a;case"Array":return i=r.util.objId(t),n[i]?n[i]:(a=[],n[i]=a,t.forEach((function(t,r){a[r]=e(t,n)})),a);default:return t}},getLanguage:function(t){for(;t;){var n=e.exec(t.className);if(n)return n[1].toLowerCase();t=t.parentElement}return"none"},setLanguage:function(t,n){t.className=t.className.replace(RegExp(e,"gi"),""),t.classList.add("language-"+n)},isActive:function(e,t,n){for(var r="no-"+t;e;){var a=e.classList;if(a.contains(t))return!0;if(a.contains(r))return!1;e=e.parentElement}return!!n}},languages:{plain:n,plaintext:n,text:n,txt:n,extend:function(e,t){var n=r.util.clone(r.languages[e]);for(var a in t)n[a]=t[a];return n},insertBefore:function(e,t,n,a){var i=(a=a||r.languages)[e],o={};for(var l in i)if(i.hasOwnProperty(l)){if(l==t)for(var s in n)n.hasOwnProperty(s)&&(o[s]=n[s]);n.hasOwnProperty(l)||(o[l]=i[l])}var c=a[e];return a[e]=o,r.languages.DFS(r.languages,(function(t,n){n===c&&t!=e&&(this[t]=o)})),o},DFS:function e(t,n,a,i){i=i||{};var o=r.util.objId;for(var l in t)if(t.hasOwnProperty(l)){n.call(t,l,t[l],a||l);var s=t[l],c=r.util.type(s);"Object"!==c||i[o(s)]?"Array"!==c||i[o(s)]||(i[o(s)]=!0,e(s,n,l,i)):(i[o(s)]=!0,e(s,n,null,i))}}},plugins:{},highlight:function(e,t,n){var i={code:e,grammar:t,language:n};return r.hooks.run("before-tokenize",i),i.tokens=r.tokenize(i.code,i.grammar),r.hooks.run("after-tokenize",i),a.stringify(r.util.encode(i.tokens),i.language)},tokenize:function(e,t){var n=t.rest;if(n){for(var r in n)t[r]=n[r];delete t.rest}var a=new l;return s(a,a.head,e),o(e,a,t,a.head,0),function(e){var t=[],n=e.head.next;for(;n!==e.tail;)t.push(n.value),n=n.next;return t}(a)},hooks:{all:{},add:function(e,t){var n=r.hooks.all;n[e]=n[e]||[],n[e].push(t)},run:function(e,t){var n=r.hooks.all[e];if(n&&n.length)for(var a,i=0;a=n[i++];)a(t)}},Token:a};function a(e,t,n,r){this.type=e,this.content=t,this.alias=n,this.length=0|(r||"").length}function i(e,t,n,r){e.lastIndex=t;var a=e.exec(n);if(a&&r&&a[1]){var i=a[1].length;a.index+=i,a[0]=a[0].slice(i)}return a}function o(e,t,n,l,u,d){for(var p in n)if(n.hasOwnProperty(p)&&n[p]){var f=n[p];f=Array.isArray(f)?f:[f];for(var m=0;m<f.length;++m){if(d&&d.cause==p+","+m)return;var g=f[m],h=g.inside,b=!!g.lookbehind,v=!!g.greedy,y=g.alias;if(v&&!g.pattern.global){var w=g.pattern.toString().match(/[imsuy]*$/)[0];g.pattern=RegExp(g.pattern.source,w+"g")}for(var x=g.pattern||g,k=l.next,E=u;k!==t.tail&&!(d&&E>=d.reach);E+=k.value.length,k=k.next){var S=k.value;if(t.length>e.length)return;if(!(S instanceof a)){var T,_=1;if(v){if(!(T=i(x,E,e,b))||T.index>=e.length)break;var C=T.index,A=T.index+T[0].length,P=E;for(P+=k.value.length;C>=P;)P+=(k=k.next).value.length;if(E=P-=k.value.length,k.value instanceof a)continue;for(var N=k;N!==t.tail&&(P<A||"string"==typeof N.value);N=N.next)_++,P+=N.value.length;_--,S=e.slice(E,P),T.index-=E}else if(!(T=i(x,0,S,b)))continue;C=T.index;var O=T[0],I=S.slice(0,C),L=S.slice(C+O.length),D=E+S.length;d&&D>d.reach&&(d.reach=D);var R=k.prev;if(I&&(R=s(t,R,I),E+=I.length),c(t,R,_),k=s(t,R,new a(p,h?r.tokenize(O,h):O,y,O)),L&&s(t,k,L),_>1){var M={cause:p+","+m,reach:D};o(e,t,n,k.prev,E,M),d&&M.reach>d.reach&&(d.reach=M.reach)}}}}}}function l(){var e={value:null,prev:null,next:null},t={value:null,prev:e,next:null};e.next=t,this.head=e,this.tail=t,this.length=0}function s(e,t,n){var r=t.next,a={value:n,prev:t,next:r};return t.next=a,r.prev=a,e.length++,a}function c(e,t,n){for(var r=t.next,a=0;a<n&&r!==e.tail;a++)r=r.next;t.next=r,r.prev=t,e.length-=a}return a.stringify=function e(t,n){if("string"==typeof t)return t;if(Array.isArray(t)){var a="";return t.forEach((function(t){a+=e(t,n)})),a}var i={type:t.type,content:e(t.content,n),tag:"span",classes:["token",t.type],attributes:{},language:n},o=t.alias;o&&(Array.isArray(o)?Array.prototype.push.apply(i.classes,o):i.classes.push(o)),r.hooks.run("wrap",i);var l="";for(var s in i.attributes)l+=" "+s+'="'+(i.attributes[s]||"").replace(/"/g,""")+'"';return"<"+i.tag+' class="'+i.classes.join(" ")+'"'+l+">"+i.content+"</"+i.tag+">"},r}(),a=r;r.default=r,a.languages.markup={comment:{pattern:/<!--(?:(?!<!--)[\s\S])*?-->/,greedy:!0},prolog:{pattern:/<\?[\s\S]+?\?>/,greedy:!0},doctype:{pattern:/<!DOCTYPE(?:[^>"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|<!--(?:[^-]|-(?!->))*-->)*\]\s*)?>/i,greedy:!0,inside:{"internal-subset":{pattern:/(^[^\[]*\[)[\s\S]+(?=\]>$)/,lookbehind:!0,greedy:!0,inside:null},string:{pattern:/"[^"]*"|'[^']*'/,greedy:!0},punctuation:/^<!|>$|[[\]]/,"doctype-tag":/^DOCTYPE/i,name:/[^\s<>'"]+/}},cdata:{pattern:/<!\[CDATA\[[\s\S]*?\]\]>/i,greedy:!0},tag:{pattern:/<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/,greedy:!0,inside:{tag:{pattern:/^<\/?[^\s>\/]+/,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"special-attr":[],"attr-value":{pattern:/=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,inside:{punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:[{pattern:/&[\da-z]{1,8};/i,alias:"named-entity"},/&#x?[\da-f]{1,8};/i]},a.languages.markup.tag.inside["attr-value"].inside.entity=a.languages.markup.entity,a.languages.markup.doctype.inside["internal-subset"].inside=a.languages.markup,a.hooks.add("wrap",(function(e){"entity"===e.type&&(e.attributes.title=e.content.replace(/&/,"&"))})),Object.defineProperty(a.languages.markup.tag,"addInlined",{value:function(e,t){var n={};n["language-"+t]={pattern:/(^<!\[CDATA\[)[\s\S]+?(?=\]\]>$)/i,lookbehind:!0,inside:a.languages[t]},n.cdata=/^<!\[CDATA\[|\]\]>$/i;var r={"included-cdata":{pattern:/<!\[CDATA\[[\s\S]*?\]\]>/i,inside:n}};r["language-"+t]={pattern:/[\s\S]+/,inside:a.languages[t]};var i={};i[e]={pattern:RegExp(/(<__[^>]*>)(?:<!\[CDATA\[(?:[^\]]|\](?!\]>))*\]\]>|(?!<!\[CDATA\[)[\s\S])*?(?=<\/__>)/.source.replace(/__/g,(function(){return e})),"i"),lookbehind:!0,greedy:!0,inside:r},a.languages.insertBefore("markup","cdata",i)}}),Object.defineProperty(a.languages.markup.tag,"addAttribute",{value:function(e,t){a.languages.markup.tag.inside["special-attr"].push({pattern:RegExp(/(^|["'\s])/.source+"(?:"+e+")"+/\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))/.source,"i"),lookbehind:!0,inside:{"attr-name":/^[^\s=]+/,"attr-value":{pattern:/=[\s\S]+/,inside:{value:{pattern:/(^=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/,lookbehind:!0,alias:[t,"language-"+t],inside:a.languages[t]},punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}}}})}}),a.languages.html=a.languages.markup,a.languages.mathml=a.languages.markup,a.languages.svg=a.languages.markup,a.languages.xml=a.languages.extend("markup",{}),a.languages.ssml=a.languages.xml,a.languages.atom=a.languages.xml,a.languages.rss=a.languages.xml,function(e){var t="\\b(?:BASH|BASHOPTS|BASH_ALIASES|BASH_ARGC|BASH_ARGV|BASH_CMDS|BASH_COMPLETION_COMPAT_DIR|BASH_LINENO|BASH_REMATCH|BASH_SOURCE|BASH_VERSINFO|BASH_VERSION|COLORTERM|COLUMNS|COMP_WORDBREAKS|DBUS_SESSION_BUS_ADDRESS|DEFAULTS_PATH|DESKTOP_SESSION|DIRSTACK|DISPLAY|EUID|GDMSESSION|GDM_LANG|GNOME_KEYRING_CONTROL|GNOME_KEYRING_PID|GPG_AGENT_INFO|GROUPS|HISTCONTROL|HISTFILE|HISTFILESIZE|HISTSIZE|HOME|HOSTNAME|HOSTTYPE|IFS|INSTANCE|JOB|LANG|LANGUAGE|LC_ADDRESS|LC_ALL|LC_IDENTIFICATION|LC_MEASUREMENT|LC_MONETARY|LC_NAME|LC_NUMERIC|LC_PAPER|LC_TELEPHONE|LC_TIME|LESSCLOSE|LESSOPEN|LINES|LOGNAME|LS_COLORS|MACHTYPE|MAILCHECK|MANDATORY_PATH|NO_AT_BRIDGE|OLDPWD|OPTERR|OPTIND|ORBIT_SOCKETDIR|OSTYPE|PAPERSIZE|PATH|PIPESTATUS|PPID|PS1|PS2|PS3|PS4|PWD|RANDOM|REPLY|SECONDS|SELINUX_INIT|SESSION|SESSIONTYPE|SESSION_MANAGER|SHELL|SHELLOPTS|SHLVL|SSH_AUTH_SOCK|TERM|UID|UPSTART_EVENTS|UPSTART_INSTANCE|UPSTART_JOB|UPSTART_SESSION|USER|WINDOWID|XAUTHORITY|XDG_CONFIG_DIRS|XDG_CURRENT_DESKTOP|XDG_DATA_DIRS|XDG_GREETER_DATA_DIR|XDG_MENU_PREFIX|XDG_RUNTIME_DIR|XDG_SEAT|XDG_SEAT_PATH|XDG_SESSION_DESKTOP|XDG_SESSION_ID|XDG_SESSION_PATH|XDG_SESSION_TYPE|XDG_VTNR|XMODIFIERS)\\b",n={pattern:/(^(["']?)\w+\2)[ \t]+\S.*/,lookbehind:!0,alias:"punctuation",inside:null},r={bash:n,environment:{pattern:RegExp("\\$"+t),alias:"constant"},variable:[{pattern:/\$?\(\([\s\S]+?\)\)/,greedy:!0,inside:{variable:[{pattern:/(^\$\(\([\s\S]+)\)\)/,lookbehind:!0},/^\$\(\(/],number:/\b0x[\dA-Fa-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[Ee]-?\d+)?/,operator:/--|\+\+|\*\*=?|<<=?|>>=?|&&|\|\||[=!+\-*/%<>^&|]=?|[?~:]/,punctuation:/\(\(?|\)\)?|,|;/}},{pattern:/\$\((?:\([^)]+\)|[^()])+\)|`[^`]+`/,greedy:!0,inside:{variable:/^\$\(|^`|\)$|`$/}},{pattern:/\$\{[^}]+\}/,greedy:!0,inside:{operator:/:[-=?+]?|[!\/]|##?|%%?|\^\^?|,,?/,punctuation:/[\[\]]/,environment:{pattern:RegExp("(\\{)"+t),lookbehind:!0,alias:"constant"}}},/\$(?:\w+|[#?*!@$])/],entity:/\\(?:[abceEfnrtv\\"]|O?[0-7]{1,3}|U[0-9a-fA-F]{8}|u[0-9a-fA-F]{4}|x[0-9a-fA-F]{1,2})/};e.languages.bash={shebang:{pattern:/^#!\s*\/.*/,alias:"important"},comment:{pattern:/(^|[^"{\\$])#.*/,lookbehind:!0},"function-name":[{pattern:/(\bfunction\s+)[\w-]+(?=(?:\s*\(?:\s*\))?\s*\{)/,lookbehind:!0,alias:"function"},{pattern:/\b[\w-]+(?=\s*\(\s*\)\s*\{)/,alias:"function"}],"for-or-select":{pattern:/(\b(?:for|select)\s+)\w+(?=\s+in\s)/,alias:"variable",lookbehind:!0},"assign-left":{pattern:/(^|[\s;|&]|[<>]\()\w+(?=\+?=)/,inside:{environment:{pattern:RegExp("(^|[\\s;|&]|[<>]\\()"+t),lookbehind:!0,alias:"constant"}},alias:"variable",lookbehind:!0},string:[{pattern:/((?:^|[^<])<<-?\s*)(\w+)\s[\s\S]*?(?:\r?\n|\r)\2/,lookbehind:!0,greedy:!0,inside:r},{pattern:/((?:^|[^<])<<-?\s*)(["'])(\w+)\2\s[\s\S]*?(?:\r?\n|\r)\3/,lookbehind:!0,greedy:!0,inside:{bash:n}},{pattern:/(^|[^\\](?:\\\\)*)"(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|[^"\\`$])*"/,lookbehind:!0,greedy:!0,inside:r},{pattern:/(^|[^$\\])'[^']*'/,lookbehind:!0,greedy:!0},{pattern:/\$'(?:[^'\\]|\\[\s\S])*'/,greedy:!0,inside:{entity:r.entity}}],environment:{pattern:RegExp("\\$?"+t),alias:"constant"},variable:r.variable,function:{pattern:/(^|[\s;|&]|[<>]\()(?:add|apropos|apt|apt-cache|apt-get|aptitude|aspell|automysqlbackup|awk|basename|bash|bc|bconsole|bg|bzip2|cal|cat|cfdisk|chgrp|chkconfig|chmod|chown|chroot|cksum|clear|cmp|column|comm|composer|cp|cron|crontab|csplit|curl|cut|date|dc|dd|ddrescue|debootstrap|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|docker|docker-compose|du|egrep|eject|env|ethtool|expand|expect|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|git|gparted|grep|groupadd|groupdel|groupmod|groups|grub-mkconfig|gzip|halt|head|hg|history|host|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|ip|jobs|join|kill|killall|less|link|ln|locate|logname|logrotate|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|lynx|make|man|mc|mdadm|mkconfig|mkdir|mke2fs|mkfifo|mkfs|mkisofs|mknod|mkswap|mmv|more|most|mount|mtools|mtr|mutt|mv|nano|nc|netstat|nice|nl|node|nohup|notify-send|npm|nslookup|op|open|parted|passwd|paste|pathchk|ping|pkill|pnpm|podman|podman-compose|popd|pr|printcap|printenv|ps|pushd|pv|quota|quotacheck|quotactl|ram|rar|rcp|reboot|remsync|rename|renice|rev|rm|rmdir|rpm|rsync|scp|screen|sdiff|sed|sendmail|seq|service|sftp|sh|shellcheck|shuf|shutdown|sleep|slocate|sort|split|ssh|stat|strace|su|sudo|sum|suspend|swapon|sync|tac|tail|tar|tee|time|timeout|top|touch|tr|traceroute|tsort|tty|umount|uname|unexpand|uniq|units|unrar|unshar|unzip|update-grub|uptime|useradd|userdel|usermod|users|uudecode|uuencode|v|vcpkg|vdir|vi|vim|virsh|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yarn|yes|zenity|zip|zsh|zypper)(?=$|[)\s;|&])/,lookbehind:!0},keyword:{pattern:/(^|[\s;|&]|[<>]\()(?:case|do|done|elif|else|esac|fi|for|function|if|in|select|then|until|while)(?=$|[)\s;|&])/,lookbehind:!0},builtin:{pattern:/(^|[\s;|&]|[<>]\()(?:\.|:|alias|bind|break|builtin|caller|cd|command|continue|declare|echo|enable|eval|exec|exit|export|getopts|hash|help|let|local|logout|mapfile|printf|pwd|read|readarray|readonly|return|set|shift|shopt|source|test|times|trap|type|typeset|ulimit|umask|unalias|unset)(?=$|[)\s;|&])/,lookbehind:!0,alias:"class-name"},boolean:{pattern:/(^|[\s;|&]|[<>]\()(?:false|true)(?=$|[)\s;|&])/,lookbehind:!0},"file-descriptor":{pattern:/\B&\d\b/,alias:"important"},operator:{pattern:/\d?<>|>\||\+=|=[=~]?|!=?|<<[<-]?|[&\d]?>>|\d[<>]&?|[<>][&=]?|&[>&]?|\|[&|]?/,inside:{"file-descriptor":{pattern:/^\d/,alias:"important"}}},punctuation:/\$?\(\(?|\)\)?|\.\.|[{}[\];\\]/,number:{pattern:/(^|\s)(?:[1-9]\d*|0)(?:[.,]\d+)?\b/,lookbehind:!0}},n.inside=e.languages.bash;for(var a=["comment","function-name","for-or-select","assign-left","string","environment","function","keyword","builtin","boolean","file-descriptor","operator","punctuation","number"],i=r.variable[1].inside,o=0;o<a.length;o++)i[a[o]]=e.languages.bash[a[o]];e.languages.shell=e.languages.bash}(a),a.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0,greedy:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/(\b(?:class|extends|implements|instanceof|interface|new|trait)\s+|\bcatch\s+\()[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:break|catch|continue|do|else|finally|for|function|if|in|instanceof|new|null|return|throw|try|while)\b/,boolean:/\b(?:false|true)\b/,function:/\b\w+(?=\()/,number:/\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i,operator:/[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,punctuation:/[{}[\];(),.:]/},a.languages.c=a.languages.extend("clike",{comment:{pattern:/\/\/(?:[^\r\n\\]|\\(?:\r\n?|\n|(?![\r\n])))*|\/\*[\s\S]*?(?:\*\/|$)/,greedy:!0},string:{pattern:/"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"/,greedy:!0},"class-name":{pattern:/(\b(?:enum|struct)\s+(?:__attribute__\s*\(\([\s\S]*?\)\)\s*)?)\w+|\b[a-z]\w*_t\b/,lookbehind:!0},keyword:/\b(?:_Alignas|_Alignof|_Atomic|_Bool|_Complex|_Generic|_Imaginary|_Noreturn|_Static_assert|_Thread_local|__attribute__|asm|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|inline|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|typeof|union|unsigned|void|volatile|while)\b/,function:/\b[a-z_]\w*(?=\s*\()/i,number:/(?:\b0x(?:[\da-f]+(?:\.[\da-f]*)?|\.[\da-f]+)(?:p[+-]?\d+)?|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?)[ful]{0,4}/i,operator:/>>=?|<<=?|->|([-+&|:])\1|[?:~]|[-+*/%&|^!=<>]=?/}),a.languages.insertBefore("c","string",{char:{pattern:/'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n]){0,32}'/,greedy:!0}}),a.languages.insertBefore("c","string",{macro:{pattern:/(^[\t ]*)#\s*[a-z](?:[^\r\n\\/]|\/(?!\*)|\/\*(?:[^*]|\*(?!\/))*\*\/|\\(?:\r\n|[\s\S]))*/im,lookbehind:!0,greedy:!0,alias:"property",inside:{string:[{pattern:/^(#\s*include\s*)<[^>]+>/,lookbehind:!0},a.languages.c.string],char:a.languages.c.char,comment:a.languages.c.comment,"macro-name":[{pattern:/(^#\s*define\s+)\w+\b(?!\()/i,lookbehind:!0},{pattern:/(^#\s*define\s+)\w+\b(?=\()/i,lookbehind:!0,alias:"function"}],directive:{pattern:/^(#\s*)[a-z]+/,lookbehind:!0,alias:"keyword"},"directive-hash":/^#/,punctuation:/##|\\(?=[\r\n])/,expression:{pattern:/\S[\s\S]*/,inside:a.languages.c}}}}),a.languages.insertBefore("c","function",{constant:/\b(?:EOF|NULL|SEEK_CUR|SEEK_END|SEEK_SET|__DATE__|__FILE__|__LINE__|__TIMESTAMP__|__TIME__|__func__|stderr|stdin|stdout)\b/}),delete a.languages.c.boolean,function(e){var t=/\b(?:alignas|alignof|asm|auto|bool|break|case|catch|char|char16_t|char32_t|char8_t|class|co_await|co_return|co_yield|compl|concept|const|const_cast|consteval|constexpr|constinit|continue|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|final|float|for|friend|goto|if|import|inline|int|int16_t|int32_t|int64_t|int8_t|long|module|mutable|namespace|new|noexcept|nullptr|operator|override|private|protected|public|register|reinterpret_cast|requires|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|uint16_t|uint32_t|uint64_t|uint8_t|union|unsigned|using|virtual|void|volatile|wchar_t|while)\b/,n=/\b(?!<keyword>)\w+(?:\s*\.\s*\w+)*\b/.source.replace(/<keyword>/g,(function(){return t.source}));e.languages.cpp=e.languages.extend("c",{"class-name":[{pattern:RegExp(/(\b(?:class|concept|enum|struct|typename)\s+)(?!<keyword>)\w+/.source.replace(/<keyword>/g,(function(){return t.source}))),lookbehind:!0},/\b[A-Z]\w*(?=\s*::\s*\w+\s*\()/,/\b[A-Z_]\w*(?=\s*::\s*~\w+\s*\()/i,/\b\w+(?=\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>\s*::\s*\w+\s*\()/],keyword:t,number:{pattern:/(?:\b0b[01']+|\b0x(?:[\da-f']+(?:\.[\da-f']*)?|\.[\da-f']+)(?:p[+-]?[\d']+)?|(?:\b[\d']+(?:\.[\d']*)?|\B\.[\d']+)(?:e[+-]?[\d']+)?)[ful]{0,4}/i,greedy:!0},operator:/>>=?|<<=?|->|--|\+\+|&&|\|\||[?:~]|<=>|[-+*/%&|^!=<>]=?|\b(?:and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/,boolean:/\b(?:false|true)\b/}),e.languages.insertBefore("cpp","string",{module:{pattern:RegExp(/(\b(?:import|module)\s+)/.source+"(?:"+/"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|<[^<>\r\n]*>/.source+"|"+/<mod-name>(?:\s*:\s*<mod-name>)?|:\s*<mod-name>/.source.replace(/<mod-name>/g,(function(){return n}))+")"),lookbehind:!0,greedy:!0,inside:{string:/^[<"][\s\S]+/,operator:/:/,punctuation:/\./}},"raw-string":{pattern:/R"([^()\\ ]{0,16})\([\s\S]*?\)\1"/,alias:"string",greedy:!0}}),e.languages.insertBefore("cpp","keyword",{"generic-function":{pattern:/\b(?!operator\b)[a-z_]\w*\s*<(?:[^<>]|<[^<>]*>)*>(?=\s*\()/i,inside:{function:/^\w+/,generic:{pattern:/<[\s\S]+/,alias:"class-name",inside:e.languages.cpp}}}}),e.languages.insertBefore("cpp","operator",{"double-colon":{pattern:/::/,alias:"punctuation"}}),e.languages.insertBefore("cpp","class-name",{"base-clause":{pattern:/(\b(?:class|struct)\s+\w+\s*:\s*)[^;{}"'\s]+(?:\s+[^;{}"'\s]+)*(?=\s*[;{])/,lookbehind:!0,greedy:!0,inside:e.languages.extend("cpp",{})}}),e.languages.insertBefore("inside","double-colon",{"class-name":/\b[a-z_]\w*\b(?!\s*::)/i},e.languages.cpp["base-clause"])}(a),function(e){var t=/(?:"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n])*')/;e.languages.css={comment:/\/\*[\s\S]*?\*\//,atrule:{pattern:/@[\w-](?:[^;{\s]|\s+(?![\s{]))*(?:;|(?=\s*\{))/,inside:{rule:/^@[\w-]+/,"selector-function-argument":{pattern:/(\bselector\s*\(\s*(?![\s)]))(?:[^()\s]|\s+(?![\s)])|\((?:[^()]|\([^()]*\))*\))+(?=\s*\))/,lookbehind:!0,alias:"selector"},keyword:{pattern:/(^|[^\w-])(?:and|not|only|or)(?![\w-])/,lookbehind:!0}}},url:{pattern:RegExp("\\burl\\((?:"+t.source+"|"+/(?:[^\\\r\n()"']|\\[\s\S])*/.source+")\\)","i"),greedy:!0,inside:{function:/^url/i,punctuation:/^\(|\)$/,string:{pattern:RegExp("^"+t.source+"$"),alias:"url"}}},selector:{pattern:RegExp("(^|[{}\\s])[^{}\\s](?:[^{};\"'\\s]|\\s+(?![\\s{])|"+t.source+")*(?=\\s*\\{)"),lookbehind:!0},string:{pattern:t,greedy:!0},property:{pattern:/(^|[^-\w\xA0-\uFFFF])(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*(?=\s*:)/i,lookbehind:!0},important:/!important\b/i,function:{pattern:/(^|[^-a-z0-9])[-a-z0-9]+(?=\()/i,lookbehind:!0},punctuation:/[(){};:,]/},e.languages.css.atrule.inside.rest=e.languages.css;var n=e.languages.markup;n&&(n.tag.addInlined("style","css"),n.tag.addAttribute("style","css"))}(a),function(e){var t,n=/("|')(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/;e.languages.css.selector={pattern:e.languages.css.selector.pattern,lookbehind:!0,inside:t={"pseudo-element":/:(?:after|before|first-letter|first-line|selection)|::[-\w]+/,"pseudo-class":/:[-\w]+/,class:/\.[-\w]+/,id:/#[-\w]+/,attribute:{pattern:RegExp("\\[(?:[^[\\]\"']|"+n.source+")*\\]"),greedy:!0,inside:{punctuation:/^\[|\]$/,"case-sensitivity":{pattern:/(\s)[si]$/i,lookbehind:!0,alias:"keyword"},namespace:{pattern:/^(\s*)(?:(?!\s)[-*\w\xA0-\uFFFF])*\|(?!=)/,lookbehind:!0,inside:{punctuation:/\|$/}},"attr-name":{pattern:/^(\s*)(?:(?!\s)[-\w\xA0-\uFFFF])+/,lookbehind:!0},"attr-value":[n,{pattern:/(=\s*)(?:(?!\s)[-\w\xA0-\uFFFF])+(?=\s*$)/,lookbehind:!0}],operator:/[|~*^$]?=/}},"n-th":[{pattern:/(\(\s*)[+-]?\d*[\dn](?:\s*[+-]\s*\d+)?(?=\s*\))/,lookbehind:!0,inside:{number:/[\dn]+/,operator:/[+-]/}},{pattern:/(\(\s*)(?:even|odd)(?=\s*\))/i,lookbehind:!0}],combinator:/>|\+|~|\|\|/,punctuation:/[(),]/}},e.languages.css.atrule.inside["selector-function-argument"].inside=t,e.languages.insertBefore("css","property",{variable:{pattern:/(^|[^-\w\xA0-\uFFFF])--(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*/i,lookbehind:!0}});var r={pattern:/(\b\d+)(?:%|[a-z]+(?![\w-]))/,lookbehind:!0},a={pattern:/(^|[^\w.-])-?(?:\d+(?:\.\d+)?|\.\d+)/,lookbehind:!0};e.languages.insertBefore("css","function",{operator:{pattern:/(\s)[+\-*\/](?=\s)/,lookbehind:!0},hexcode:{pattern:/\B#[\da-f]{3,8}\b/i,alias:"color"},color:[{pattern:/(^|[^\w-])(?:AliceBlue|AntiqueWhite|Aqua|Aquamarine|Azure|Beige|Bisque|Black|BlanchedAlmond|Blue|BlueViolet|Brown|BurlyWood|CadetBlue|Chartreuse|Chocolate|Coral|CornflowerBlue|Cornsilk|Crimson|Cyan|DarkBlue|DarkCyan|DarkGoldenRod|DarkGr[ae]y|DarkGreen|DarkKhaki|DarkMagenta|DarkOliveGreen|DarkOrange|DarkOrchid|DarkRed|DarkSalmon|DarkSeaGreen|DarkSlateBlue|DarkSlateGr[ae]y|DarkTurquoise|DarkViolet|DeepPink|DeepSkyBlue|DimGr[ae]y|DodgerBlue|FireBrick|FloralWhite|ForestGreen|Fuchsia|Gainsboro|GhostWhite|Gold|GoldenRod|Gr[ae]y|Green|GreenYellow|HoneyDew|HotPink|IndianRed|Indigo|Ivory|Khaki|Lavender|LavenderBlush|LawnGreen|LemonChiffon|LightBlue|LightCoral|LightCyan|LightGoldenRodYellow|LightGr[ae]y|LightGreen|LightPink|LightSalmon|LightSeaGreen|LightSkyBlue|LightSlateGr[ae]y|LightSteelBlue|LightYellow|Lime|LimeGreen|Linen|Magenta|Maroon|MediumAquaMarine|MediumBlue|MediumOrchid|MediumPurple|MediumSeaGreen|MediumSlateBlue|MediumSpringGreen|MediumTurquoise|MediumVioletRed|MidnightBlue|MintCream|MistyRose|Moccasin|NavajoWhite|Navy|OldLace|Olive|OliveDrab|Orange|OrangeRed|Orchid|PaleGoldenRod|PaleGreen|PaleTurquoise|PaleVioletRed|PapayaWhip|PeachPuff|Peru|Pink|Plum|PowderBlue|Purple|Red|RosyBrown|RoyalBlue|SaddleBrown|Salmon|SandyBrown|SeaGreen|SeaShell|Sienna|Silver|SkyBlue|SlateBlue|SlateGr[ae]y|Snow|SpringGreen|SteelBlue|Tan|Teal|Thistle|Tomato|Transparent|Turquoise|Violet|Wheat|White|WhiteSmoke|Yellow|YellowGreen)(?![\w-])/i,lookbehind:!0},{pattern:/\b(?:hsl|rgb)\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*\)\B|\b(?:hsl|rgb)a\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*,\s*(?:0|0?\.\d+|1)\s*\)\B/i,inside:{unit:r,number:a,function:/[\w-]+(?=\()/,punctuation:/[(),]/}}],entity:/\\[\da-f]{1,8}/i,unit:r,number:a})}(a),a.languages.javascript=a.languages.extend("clike",{"class-name":[a.languages.clike["class-name"],{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$A-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\.(?:constructor|prototype))/,lookbehind:!0}],keyword:[{pattern:/((?:^|\})\s*)catch\b/,lookbehind:!0},{pattern:/(^|[^.]|\.\.\.\s*)\b(?:as|assert(?=\s*\{)|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally(?=\s*(?:\{|$))|for|from(?=\s*(?:['"]|$))|function|(?:get|set)(?=\s*(?:[#\[$\w\xA0-\uFFFF]|$))|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/,lookbehind:!0}],function:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,number:{pattern:RegExp(/(^|[^\w$])/.source+"(?:"+/NaN|Infinity/.source+"|"+/0[bB][01]+(?:_[01]+)*n?/.source+"|"+/0[oO][0-7]+(?:_[0-7]+)*n?/.source+"|"+/0[xX][\dA-Fa-f]+(?:_[\dA-Fa-f]+)*n?/.source+"|"+/\d+(?:_\d+)*n/.source+"|"+/(?:\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\.\d+(?:_\d+)*)(?:[Ee][+-]?\d+(?:_\d+)*)?/.source+")"+/(?![\w$])/.source),lookbehind:!0},operator:/--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/}),a.languages.javascript["class-name"][0].pattern=/(\b(?:class|extends|implements|instanceof|interface|new)\s+)[\w.\\]+/,a.languages.insertBefore("javascript","keyword",{regex:{pattern:/((?:^|[^$\w\xA0-\uFFFF."'\])\s]|\b(?:return|yield))\s*)\/(?:\[(?:[^\]\\\r\n]|\\.)*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}(?=(?:\s|\/\*(?:[^*]|\*(?!\/))*\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/,lookbehind:!0,greedy:!0,inside:{"regex-source":{pattern:/^(\/)[\s\S]+(?=\/[a-z]*$)/,lookbehind:!0,alias:"language-regex",inside:a.languages.regex},"regex-delimiter":/^\/|\/$/,"regex-flags":/^[a-z]+$/}},"function-variable":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/,alias:"function"},parameter:[{pattern:/(function(?:\s+(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)?\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\))/,lookbehind:!0,inside:a.languages.javascript},{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=>)/i,lookbehind:!0,inside:a.languages.javascript},{pattern:/(\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*=>)/,lookbehind:!0,inside:a.languages.javascript},{pattern:/((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*\{)/,lookbehind:!0,inside:a.languages.javascript}],constant:/\b[A-Z](?:[A-Z_]|\dx?)*\b/}),a.languages.insertBefore("javascript","string",{hashbang:{pattern:/^#!.*/,greedy:!0,alias:"comment"},"template-string":{pattern:/`(?:\\[\s\S]|\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}|(?!\$\{)[^\\`])*`/,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}/,lookbehind:!0,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:a.languages.javascript}},string:/[\s\S]+/}},"string-property":{pattern:/((?:^|[,{])[ \t]*)(["'])(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2(?=\s*:)/m,lookbehind:!0,greedy:!0,alias:"property"}}),a.languages.insertBefore("javascript","operator",{"literal-property":{pattern:/((?:^|[,{])[ \t]*)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*:)/m,lookbehind:!0,alias:"property"}}),a.languages.markup&&(a.languages.markup.tag.addInlined("script","javascript"),a.languages.markup.tag.addAttribute(/on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)/.source,"javascript")),a.languages.js=a.languages.javascript,function(e){var t=/#(?!\{).+/,n={pattern:/#\{[^}]+\}/,alias:"variable"};e.languages.coffeescript=e.languages.extend("javascript",{comment:t,string:[{pattern:/'(?:\\[\s\S]|[^\\'])*'/,greedy:!0},{pattern:/"(?:\\[\s\S]|[^\\"])*"/,greedy:!0,inside:{interpolation:n}}],keyword:/\b(?:and|break|by|catch|class|continue|debugger|delete|do|each|else|extend|extends|false|finally|for|if|in|instanceof|is|isnt|let|loop|namespace|new|no|not|null|of|off|on|or|own|return|super|switch|then|this|throw|true|try|typeof|undefined|unless|until|when|while|window|with|yes|yield)\b/,"class-member":{pattern:/@(?!\d)\w+/,alias:"variable"}}),e.languages.insertBefore("coffeescript","comment",{"multiline-comment":{pattern:/###[\s\S]+?###/,alias:"comment"},"block-regex":{pattern:/\/{3}[\s\S]*?\/{3}/,alias:"regex",inside:{comment:t,interpolation:n}}}),e.languages.insertBefore("coffeescript","string",{"inline-javascript":{pattern:/`(?:\\[\s\S]|[^\\`])*`/,inside:{delimiter:{pattern:/^`|`$/,alias:"punctuation"},script:{pattern:/[\s\S]+/,alias:"language-javascript",inside:e.languages.javascript}}},"multiline-string":[{pattern:/'''[\s\S]*?'''/,greedy:!0,alias:"string"},{pattern:/"""[\s\S]*?"""/,greedy:!0,alias:"string",inside:{interpolation:n}}]}),e.languages.insertBefore("coffeescript","keyword",{property:/(?!\d)\w+(?=\s*:(?!:))/}),delete e.languages.coffeescript["template-string"],e.languages.coffee=e.languages.coffeescript}(a),function(e){var t=/[*&][^\s[\]{},]+/,n=/!(?:<[\w\-%#;/?:@&=+$,.!~*'()[\]]+>|(?:[a-zA-Z\d-]*!)?[\w\-%#;/?:@&=+$.~*'()]+)?/,r="(?:"+n.source+"(?:[ \t]+"+t.source+")?|"+t.source+"(?:[ \t]+"+n.source+")?)",a=/(?:[^\s\x00-\x08\x0e-\x1f!"#%&'*,\-:>?@[\]`{|}\x7f-\x84\x86-\x9f\ud800-\udfff\ufffe\uffff]|[?:-]<PLAIN>)(?:[ \t]*(?:(?![#:])<PLAIN>|:<PLAIN>))*/.source.replace(/<PLAIN>/g,(function(){return/[^\s\x00-\x08\x0e-\x1f,[\]{}\x7f-\x84\x86-\x9f\ud800-\udfff\ufffe\uffff]/.source})),i=/"(?:[^"\\\r\n]|\\.)*"|'(?:[^'\\\r\n]|\\.)*'/.source;function o(e,t){t=(t||"").replace(/m/g,"")+"m";var n=/([:\-,[{]\s*(?:\s<<prop>>[ \t]+)?)(?:<<value>>)(?=[ \t]*(?:$|,|\]|\}|(?:[\r\n]\s*)?#))/.source.replace(/<<prop>>/g,(function(){return r})).replace(/<<value>>/g,(function(){return e}));return RegExp(n,t)}e.languages.yaml={scalar:{pattern:RegExp(/([\-:]\s*(?:\s<<prop>>[ \t]+)?[|>])[ \t]*(?:((?:\r?\n|\r)[ \t]+)\S[^\r\n]*(?:\2[^\r\n]+)*)/.source.replace(/<<prop>>/g,(function(){return r}))),lookbehind:!0,alias:"string"},comment:/#.*/,key:{pattern:RegExp(/((?:^|[:\-,[{\r\n?])[ \t]*(?:<<prop>>[ \t]+)?)<<key>>(?=\s*:\s)/.source.replace(/<<prop>>/g,(function(){return r})).replace(/<<key>>/g,(function(){return"(?:"+a+"|"+i+")"}))),lookbehind:!0,greedy:!0,alias:"atrule"},directive:{pattern:/(^[ \t]*)%.+/m,lookbehind:!0,alias:"important"},datetime:{pattern:o(/\d{4}-\d\d?-\d\d?(?:[tT]|[ \t]+)\d\d?:\d{2}:\d{2}(?:\.\d*)?(?:[ \t]*(?:Z|[-+]\d\d?(?::\d{2})?))?|\d{4}-\d{2}-\d{2}|\d\d?:\d{2}(?::\d{2}(?:\.\d*)?)?/.source),lookbehind:!0,alias:"number"},boolean:{pattern:o(/false|true/.source,"i"),lookbehind:!0,alias:"important"},null:{pattern:o(/null|~/.source,"i"),lookbehind:!0,alias:"important"},string:{pattern:o(i),lookbehind:!0,greedy:!0},number:{pattern:o(/[+-]?(?:0x[\da-f]+|0o[0-7]+|(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?|\.inf|\.nan)/.source,"i"),lookbehind:!0},tag:n,important:t,punctuation:/---|[:[\]{}\-,|>?]|\.\.\./},e.languages.yml=e.languages.yaml}(a),function(e){var t=/(?:\\.|[^\\\n\r]|(?:\n|\r\n?)(?![\r\n]))/.source;function n(e){return e=e.replace(/<inner>/g,(function(){return t})),RegExp(/((?:^|[^\\])(?:\\{2})*)/.source+"(?:"+e+")")}var r=/(?:\\.|``(?:[^`\r\n]|`(?!`))+``|`[^`\r\n]+`|[^\\|\r\n`])+/.source,a=/\|?__(?:\|__)+\|?(?:(?:\n|\r\n?)|(?![\s\S]))/.source.replace(/__/g,(function(){return r})),i=/\|?[ \t]*:?-{3,}:?[ \t]*(?:\|[ \t]*:?-{3,}:?[ \t]*)+\|?(?:\n|\r\n?)/.source;e.languages.markdown=e.languages.extend("markup",{}),e.languages.insertBefore("markdown","prolog",{"front-matter-block":{pattern:/(^(?:\s*[\r\n])?)---(?!.)[\s\S]*?[\r\n]---(?!.)/,lookbehind:!0,greedy:!0,inside:{punctuation:/^---|---$/,"front-matter":{pattern:/\S+(?:\s+\S+)*/,alias:["yaml","language-yaml"],inside:e.languages.yaml}}},blockquote:{pattern:/^>(?:[\t ]*>)*/m,alias:"punctuation"},table:{pattern:RegExp("^"+a+i+"(?:"+a+")*","m"),inside:{"table-data-rows":{pattern:RegExp("^("+a+i+")(?:"+a+")*$"),lookbehind:!0,inside:{"table-data":{pattern:RegExp(r),inside:e.languages.markdown},punctuation:/\|/}},"table-line":{pattern:RegExp("^("+a+")"+i+"$"),lookbehind:!0,inside:{punctuation:/\||:?-{3,}:?/}},"table-header-row":{pattern:RegExp("^"+a+"$"),inside:{"table-header":{pattern:RegExp(r),alias:"important",inside:e.languages.markdown},punctuation:/\|/}}}},code:[{pattern:/((?:^|\n)[ \t]*\n|(?:^|\r\n?)[ \t]*\r\n?)(?: {4}|\t).+(?:(?:\n|\r\n?)(?: {4}|\t).+)*/,lookbehind:!0,alias:"keyword"},{pattern:/^```[\s\S]*?^```$/m,greedy:!0,inside:{"code-block":{pattern:/^(```.*(?:\n|\r\n?))[\s\S]+?(?=(?:\n|\r\n?)^```$)/m,lookbehind:!0},"code-language":{pattern:/^(```).+/,lookbehind:!0},punctuation:/```/}}],title:[{pattern:/\S.*(?:\n|\r\n?)(?:==+|--+)(?=[ \t]*$)/m,alias:"important",inside:{punctuation:/==+$|--+$/}},{pattern:/(^\s*)#.+/m,lookbehind:!0,alias:"important",inside:{punctuation:/^#+|#+$/}}],hr:{pattern:/(^\s*)([*-])(?:[\t ]*\2){2,}(?=\s*$)/m,lookbehind:!0,alias:"punctuation"},list:{pattern:/(^\s*)(?:[*+-]|\d+\.)(?=[\t ].)/m,lookbehind:!0,alias:"punctuation"},"url-reference":{pattern:/!?\[[^\]]+\]:[\t ]+(?:\S+|<(?:\\.|[^>\\])+>)(?:[\t ]+(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\)))?/,inside:{variable:{pattern:/^(!?\[)[^\]]+/,lookbehind:!0},string:/(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\))$/,punctuation:/^[\[\]!:]|[<>]/},alias:"url"},bold:{pattern:n(/\b__(?:(?!_)<inner>|_(?:(?!_)<inner>)+_)+__\b|\*\*(?:(?!\*)<inner>|\*(?:(?!\*)<inner>)+\*)+\*\*/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^..)[\s\S]+(?=..$)/,lookbehind:!0,inside:{}},punctuation:/\*\*|__/}},italic:{pattern:n(/\b_(?:(?!_)<inner>|__(?:(?!_)<inner>)+__)+_\b|\*(?:(?!\*)<inner>|\*\*(?:(?!\*)<inner>)+\*\*)+\*/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^.)[\s\S]+(?=.$)/,lookbehind:!0,inside:{}},punctuation:/[*_]/}},strike:{pattern:n(/(~~?)(?:(?!~)<inner>)+\2/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^~~?)[\s\S]+(?=\1$)/,lookbehind:!0,inside:{}},punctuation:/~~?/}},"code-snippet":{pattern:/(^|[^\\`])(?:``[^`\r\n]+(?:`[^`\r\n]+)*``(?!`)|`[^`\r\n]+`(?!`))/,lookbehind:!0,greedy:!0,alias:["code","keyword"]},url:{pattern:n(/!?\[(?:(?!\])<inner>)+\](?:\([^\s)]+(?:[\t ]+"(?:\\.|[^"\\])*")?\)|[ \t]?\[(?:(?!\])<inner>)+\])/.source),lookbehind:!0,greedy:!0,inside:{operator:/^!/,content:{pattern:/(^\[)[^\]]+(?=\])/,lookbehind:!0,inside:{}},variable:{pattern:/(^\][ \t]?\[)[^\]]+(?=\]$)/,lookbehind:!0},url:{pattern:/(^\]\()[^\s)]+/,lookbehind:!0},string:{pattern:/(^[ \t]+)"(?:\\.|[^"\\])*"(?=\)$)/,lookbehind:!0}}}}),["url","bold","italic","strike"].forEach((function(t){["url","bold","italic","strike","code-snippet"].forEach((function(n){t!==n&&(e.languages.markdown[t].inside.content.inside[n]=e.languages.markdown[n])}))})),e.hooks.add("after-tokenize",(function(e){"markdown"!==e.language&&"md"!==e.language||function e(t){if(t&&"string"!=typeof t)for(var n=0,r=t.length;n<r;n++){var a=t[n];if("code"===a.type){var i=a.content[1],o=a.content[3];if(i&&o&&"code-language"===i.type&&"code-block"===o.type&&"string"==typeof i.content){var l=i.content.replace(/\b#/g,"sharp").replace(/\b\+\+/g,"pp"),s="language-"+(l=(/[a-z][\w-]*/i.exec(l)||[""])[0].toLowerCase());o.alias?"string"==typeof o.alias?o.alias=[o.alias,s]:o.alias.push(s):o.alias=[s]}}else e(a.content)}}(e.tokens)})),e.hooks.add("wrap",(function(t){if("code-block"===t.type){for(var n="",r=0,a=t.classes.length;r<a;r++){var i=t.classes[r],c=/language-(.+)/.exec(i);if(c){n=c[1];break}}var u,d=e.languages[n];if(d)t.content=e.highlight((u=t.content,u.replace(o,"").replace(/&(\w{1,8}|#x?[\da-f]{1,8});/gi,(function(e,t){var n;if("#"===(t=t.toLowerCase())[0])return n="x"===t[1]?parseInt(t.slice(2),16):Number(t.slice(1)),s(n);var r=l[t];return r||e}))),d,n);else if(n&&"none"!==n&&e.plugins.autoloader){var p="md-"+(new Date).valueOf()+"-"+Math.floor(1e16*Math.random());t.attributes.id=p,e.plugins.autoloader.loadLanguages(n,(function(){var t=document.getElementById(p);t&&(t.innerHTML=e.highlight(t.textContent,e.languages[n],n))}))}}}));var o=RegExp(e.languages.markup.tag.pattern.source,"gi"),l={amp:"&",lt:"<",gt:">",quot:'"'},s=String.fromCodePoint||String.fromCharCode;e.languages.md=e.languages.markdown}(a),a.languages.graphql={comment:/#.*/,description:{pattern:/(?:"""(?:[^"]|(?!""")")*"""|"(?:\\.|[^\\"\r\n])*")(?=\s*[a-z_])/i,greedy:!0,alias:"string",inside:{"language-markdown":{pattern:/(^"(?:"")?)(?!\1)[\s\S]+(?=\1$)/,lookbehind:!0,inside:a.languages.markdown}}},string:{pattern:/"""(?:[^"]|(?!""")")*"""|"(?:\\.|[^\\"\r\n])*"/,greedy:!0},number:/(?:\B-|\b)\d+(?:\.\d+)?(?:e[+-]?\d+)?\b/i,boolean:/\b(?:false|true)\b/,variable:/\$[a-z_]\w*/i,directive:{pattern:/@[a-z_]\w*/i,alias:"function"},"attr-name":{pattern:/\b[a-z_]\w*(?=\s*(?:\((?:[^()"]|"(?:\\.|[^\\"\r\n])*")*\))?:)/i,greedy:!0},"atom-input":{pattern:/\b[A-Z]\w*Input\b/,alias:"class-name"},scalar:/\b(?:Boolean|Float|ID|Int|String)\b/,constant:/\b[A-Z][A-Z_\d]*\b/,"class-name":{pattern:/(\b(?:enum|implements|interface|on|scalar|type|union)\s+|&\s*|:\s*|\[)[A-Z_]\w*/,lookbehind:!0},fragment:{pattern:/(\bfragment\s+|\.{3}\s*(?!on\b))[a-zA-Z_]\w*/,lookbehind:!0,alias:"function"},"definition-mutation":{pattern:/(\bmutation\s+)[a-zA-Z_]\w*/,lookbehind:!0,alias:"function"},"definition-query":{pattern:/(\bquery\s+)[a-zA-Z_]\w*/,lookbehind:!0,alias:"function"},keyword:/\b(?:directive|enum|extend|fragment|implements|input|interface|mutation|on|query|repeatable|scalar|schema|subscription|type|union)\b/,operator:/[!=|&]|\.{3}/,"property-query":/\w+(?=\s*\()/,object:/\w+(?=\s*\{)/,punctuation:/[!(){}\[\]:=,]/,property:/\w+/},a.hooks.add("after-tokenize",(function(e){if("graphql"===e.language)for(var t=e.tokens.filter((function(e){return"string"!=typeof e&&"comment"!==e.type&&"scalar"!==e.type})),n=0;n<t.length;){var r=t[n++];if("keyword"===r.type&&"mutation"===r.content){var a=[];if(d(["definition-mutation","punctuation"])&&"("===u(1).content){n+=2;var i=p(/^\($/,/^\)$/);if(-1===i)continue;for(;n<i;n++){var o=u(0);"variable"===o.type&&(f(o,"variable-input"),a.push(o.content))}n=i+1}if(d(["punctuation","property-query"])&&"{"===u(0).content&&(n++,f(u(0),"property-mutation"),a.length>0)){var l=p(/^\{$/,/^\}$/);if(-1===l)continue;for(var s=n;s<l;s++){var c=t[s];"variable"===c.type&&a.indexOf(c.content)>=0&&f(c,"variable-input")}}}}function u(e){return t[n+e]}function d(e,t){t=t||0;for(var n=0;n<e.length;n++){var r=u(n+t);if(!r||r.type!==e[n])return!1}return!0}function p(e,r){for(var a=1,i=n;i<t.length;i++){var o=t[i],l=o.content;if("punctuation"===o.type&&"string"==typeof l)if(e.test(l))a++;else if(r.test(l)&&0===--a)return i}return-1}function f(e,t){var n=e.alias;n?Array.isArray(n)||(e.alias=n=[n]):e.alias=n=[],n.push(t)}})),a.languages.sql={comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|(?:--|\/\/|#).*)/,lookbehind:!0},variable:[{pattern:/@(["'`])(?:\\[\s\S]|(?!\1)[^\\])+\1/,greedy:!0},/@[\w.$]+/],string:{pattern:/(^|[^@\\])("|')(?:\\[\s\S]|(?!\2)[^\\]|\2\2)*\2/,greedy:!0,lookbehind:!0},identifier:{pattern:/(^|[^@\\])`(?:\\[\s\S]|[^`\\]|``)*`/,greedy:!0,lookbehind:!0,inside:{punctuation:/^`|`$/}},function:/\b(?:AVG|COUNT|FIRST|FORMAT|LAST|LCASE|LEN|MAX|MID|MIN|MOD|NOW|ROUND|SUM|UCASE)(?=\s*\()/i,keyword:/\b(?:ACTION|ADD|AFTER|ALGORITHM|ALL|ALTER|ANALYZE|ANY|APPLY|AS|ASC|AUTHORIZATION|AUTO_INCREMENT|BACKUP|BDB|BEGIN|BERKELEYDB|BIGINT|BINARY|BIT|BLOB|BOOL|BOOLEAN|BREAK|BROWSE|BTREE|BULK|BY|CALL|CASCADED?|CASE|CHAIN|CHAR(?:ACTER|SET)?|CHECK(?:POINT)?|CLOSE|CLUSTERED|COALESCE|COLLATE|COLUMNS?|COMMENT|COMMIT(?:TED)?|COMPUTE|CONNECT|CONSISTENT|CONSTRAINT|CONTAINS(?:TABLE)?|CONTINUE|CONVERT|CREATE|CROSS|CURRENT(?:_DATE|_TIME|_TIMESTAMP|_USER)?|CURSOR|CYCLE|DATA(?:BASES?)?|DATE(?:TIME)?|DAY|DBCC|DEALLOCATE|DEC|DECIMAL|DECLARE|DEFAULT|DEFINER|DELAYED|DELETE|DELIMITERS?|DENY|DESC|DESCRIBE|DETERMINISTIC|DISABLE|DISCARD|DISK|DISTINCT|DISTINCTROW|DISTRIBUTED|DO|DOUBLE|DROP|DUMMY|DUMP(?:FILE)?|DUPLICATE|ELSE(?:IF)?|ENABLE|ENCLOSED|END|ENGINE|ENUM|ERRLVL|ERRORS|ESCAPED?|EXCEPT|EXEC(?:UTE)?|EXISTS|EXIT|EXPLAIN|EXTENDED|FETCH|FIELDS|FILE|FILLFACTOR|FIRST|FIXED|FLOAT|FOLLOWING|FOR(?: EACH ROW)?|FORCE|FOREIGN|FREETEXT(?:TABLE)?|FROM|FULL|FUNCTION|GEOMETRY(?:COLLECTION)?|GLOBAL|GOTO|GRANT|GROUP|HANDLER|HASH|HAVING|HOLDLOCK|HOUR|IDENTITY(?:COL|_INSERT)?|IF|IGNORE|IMPORT|INDEX|INFILE|INNER|INNODB|INOUT|INSERT|INT|INTEGER|INTERSECT|INTERVAL|INTO|INVOKER|ISOLATION|ITERATE|JOIN|KEYS?|KILL|LANGUAGE|LAST|LEAVE|LEFT|LEVEL|LIMIT|LINENO|LINES|LINESTRING|LOAD|LOCAL|LOCK|LONG(?:BLOB|TEXT)|LOOP|MATCH(?:ED)?|MEDIUM(?:BLOB|INT|TEXT)|MERGE|MIDDLEINT|MINUTE|MODE|MODIFIES|MODIFY|MONTH|MULTI(?:LINESTRING|POINT|POLYGON)|NATIONAL|NATURAL|NCHAR|NEXT|NO|NONCLUSTERED|NULLIF|NUMERIC|OFF?|OFFSETS?|ON|OPEN(?:DATASOURCE|QUERY|ROWSET)?|OPTIMIZE|OPTION(?:ALLY)?|ORDER|OUT(?:ER|FILE)?|OVER|PARTIAL|PARTITION|PERCENT|PIVOT|PLAN|POINT|POLYGON|PRECEDING|PRECISION|PREPARE|PREV|PRIMARY|PRINT|PRIVILEGES|PROC(?:EDURE)?|PUBLIC|PURGE|QUICK|RAISERROR|READS?|REAL|RECONFIGURE|REFERENCES|RELEASE|RENAME|REPEAT(?:ABLE)?|REPLACE|REPLICATION|REQUIRE|RESIGNAL|RESTORE|RESTRICT|RETURN(?:ING|S)?|REVOKE|RIGHT|ROLLBACK|ROUTINE|ROW(?:COUNT|GUIDCOL|S)?|RTREE|RULE|SAVE(?:POINT)?|SCHEMA|SECOND|SELECT|SERIAL(?:IZABLE)?|SESSION(?:_USER)?|SET(?:USER)?|SHARE|SHOW|SHUTDOWN|SIMPLE|SMALLINT|SNAPSHOT|SOME|SONAME|SQL|START(?:ING)?|STATISTICS|STATUS|STRIPED|SYSTEM_USER|TABLES?|TABLESPACE|TEMP(?:ORARY|TABLE)?|TERMINATED|TEXT(?:SIZE)?|THEN|TIME(?:STAMP)?|TINY(?:BLOB|INT|TEXT)|TOP?|TRAN(?:SACTIONS?)?|TRIGGER|TRUNCATE|TSEQUAL|TYPES?|UNBOUNDED|UNCOMMITTED|UNDEFINED|UNION|UNIQUE|UNLOCK|UNPIVOT|UNSIGNED|UPDATE(?:TEXT)?|USAGE|USE|USER|USING|VALUES?|VAR(?:BINARY|CHAR|CHARACTER|YING)|VIEW|WAITFOR|WARNINGS|WHEN|WHERE|WHILE|WITH(?: ROLLUP|IN)?|WORK|WRITE(?:TEXT)?|YEAR)\b/i,boolean:/\b(?:FALSE|NULL|TRUE)\b/i,number:/\b0x[\da-f]+\b|\b\d+(?:\.\d*)?|\B\.\d+\b/i,operator:/[-+*\/=%^~]|&&?|\|\|?|!=?|<(?:=>?|<|>)?|>[>=]?|\b(?:AND|BETWEEN|DIV|ILIKE|IN|IS|LIKE|NOT|OR|REGEXP|RLIKE|SOUNDS LIKE|XOR)\b/i,punctuation:/[;[\]()`,.]/},function(e){var t=e.languages.javascript["template-string"],n=t.pattern.source,r=t.inside.interpolation,a=r.inside["interpolation-punctuation"],i=r.pattern.source;function o(t,r){if(e.languages[t])return{pattern:RegExp("((?:"+r+")\\s*)"+n),lookbehind:!0,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},"embedded-code":{pattern:/[\s\S]+/,alias:t}}}}function l(e,t){return"___"+t.toUpperCase()+"_"+e+"___"}function s(t,n,r){var a={code:t,grammar:n,language:r};return e.hooks.run("before-tokenize",a),a.tokens=e.tokenize(a.code,a.grammar),e.hooks.run("after-tokenize",a),a.tokens}function c(t){var n={};n["interpolation-punctuation"]=a;var i=e.tokenize(t,n);if(3===i.length){var o=[1,1];o.push.apply(o,s(i[1],e.languages.javascript,"javascript")),i.splice.apply(i,o)}return new e.Token("interpolation",i,r.alias,t)}function u(t,n,r){var a=e.tokenize(t,{interpolation:{pattern:RegExp(i),lookbehind:!0}}),o=0,u={},d=s(a.map((function(e){if("string"==typeof e)return e;for(var n,a=e.content;-1!==t.indexOf(n=l(o++,r)););return u[n]=a,n})).join(""),n,r),p=Object.keys(u);return o=0,function e(t){for(var n=0;n<t.length;n++){if(o>=p.length)return;var r=t[n];if("string"==typeof r||"string"==typeof r.content){var a=p[o],i="string"==typeof r?r:r.content,l=i.indexOf(a);if(-1!==l){++o;var s=i.substring(0,l),d=c(u[a]),f=i.substring(l+a.length),m=[];if(s&&m.push(s),m.push(d),f){var g=[f];e(g),m.push.apply(m,g)}"string"==typeof r?(t.splice.apply(t,[n,1].concat(m)),n+=m.length-1):r.content=m}}else{var h=r.content;Array.isArray(h)?e(h):e([h])}}}(d),new e.Token(r,d,"language-"+r,t)}e.languages.javascript["template-string"]=[o("css",/\b(?:styled(?:\([^)]*\))?(?:\s*\.\s*\w+(?:\([^)]*\))*)*|css(?:\s*\.\s*(?:global|resolve))?|createGlobalStyle|keyframes)/.source),o("html",/\bhtml|\.\s*(?:inner|outer)HTML\s*\+?=/.source),o("svg",/\bsvg/.source),o("markdown",/\b(?:markdown|md)/.source),o("graphql",/\b(?:gql|graphql(?:\s*\.\s*experimental)?)/.source),o("sql",/\bsql/.source),t].filter(Boolean);var d={javascript:!0,js:!0,typescript:!0,ts:!0,jsx:!0,tsx:!0};function p(e){return"string"==typeof e?e:Array.isArray(e)?e.map(p).join(""):p(e.content)}e.hooks.add("after-tokenize",(function(t){t.language in d&&function t(n){for(var r=0,a=n.length;r<a;r++){var i=n[r];if("string"!=typeof i){var o=i.content;if(Array.isArray(o))if("template-string"===i.type){var l=o[1];if(3===o.length&&"string"!=typeof l&&"embedded-code"===l.type){var s=p(l),c=l.alias,d=Array.isArray(c)?c[0]:c,f=e.languages[d];if(!f)continue;o[1]=u(s,f,d)}}else t(o);else"string"!=typeof o&&t([o])}}}(t.tokens)}))}(a),function(e){e.languages.typescript=e.languages.extend("javascript",{"class-name":{pattern:/(\b(?:class|extends|implements|instanceof|interface|new|type)\s+)(?!keyof\b)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?:\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>)?/,lookbehind:!0,greedy:!0,inside:null},builtin:/\b(?:Array|Function|Promise|any|boolean|console|never|number|string|symbol|unknown)\b/}),e.languages.typescript.keyword.push(/\b(?:abstract|declare|is|keyof|readonly|require)\b/,/\b(?:asserts|infer|interface|module|namespace|type)\b(?=\s*(?:[{_$a-zA-Z\xA0-\uFFFF]|$))/,/\btype\b(?=\s*(?:[\{*]|$))/),delete e.languages.typescript.parameter,delete e.languages.typescript["literal-property"];var t=e.languages.extend("typescript",{});delete t["class-name"],e.languages.typescript["class-name"].inside=t,e.languages.insertBefore("typescript","function",{decorator:{pattern:/@[$\w\xA0-\uFFFF]+/,inside:{at:{pattern:/^@/,alias:"operator"},function:/^[\s\S]+/}},"generic-function":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>(?=\s*\()/,greedy:!0,inside:{function:/^#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*/,generic:{pattern:/<[\s\S]+/,alias:"class-name",inside:t}}}}),e.languages.ts=e.languages.typescript}(a),function(e){function t(e,t){return RegExp(e.replace(/<ID>/g,(function(){return/(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*/.source})),t)}e.languages.insertBefore("javascript","function-variable",{"method-variable":{pattern:RegExp("(\\.\\s*)"+e.languages.javascript["function-variable"].pattern.source),lookbehind:!0,alias:["function-variable","method","function","property-access"]}}),e.languages.insertBefore("javascript","function",{method:{pattern:RegExp("(\\.\\s*)"+e.languages.javascript.function.source),lookbehind:!0,alias:["function","property-access"]}}),e.languages.insertBefore("javascript","constant",{"known-class-name":[{pattern:/\b(?:(?:Float(?:32|64)|(?:Int|Uint)(?:8|16|32)|Uint8Clamped)?Array|ArrayBuffer|BigInt|Boolean|DataView|Date|Error|Function|Intl|JSON|(?:Weak)?(?:Map|Set)|Math|Number|Object|Promise|Proxy|Reflect|RegExp|String|Symbol|WebAssembly)\b/,alias:"class-name"},{pattern:/\b(?:[A-Z]\w*)Error\b/,alias:"class-name"}]}),e.languages.insertBefore("javascript","keyword",{imports:{pattern:t(/(\bimport\b\s*)(?:<ID>(?:\s*,\s*(?:\*\s*as\s+<ID>|\{[^{}]*\}))?|\*\s*as\s+<ID>|\{[^{}]*\})(?=\s*\bfrom\b)/.source),lookbehind:!0,inside:e.languages.javascript},exports:{pattern:t(/(\bexport\b\s*)(?:\*(?:\s*as\s+<ID>)?(?=\s*\bfrom\b)|\{[^{}]*\})/.source),lookbehind:!0,inside:e.languages.javascript}}),e.languages.javascript.keyword.unshift({pattern:/\b(?:as|default|export|from|import)\b/,alias:"module"},{pattern:/\b(?:await|break|catch|continue|do|else|finally|for|if|return|switch|throw|try|while|yield)\b/,alias:"control-flow"},{pattern:/\bnull\b/,alias:["null","nil"]},{pattern:/\bundefined\b/,alias:"nil"}),e.languages.insertBefore("javascript","operator",{spread:{pattern:/\.{3}/,alias:"operator"},arrow:{pattern:/=>/,alias:"operator"}}),e.languages.insertBefore("javascript","punctuation",{"property-access":{pattern:t(/(\.\s*)#?<ID>/.source),lookbehind:!0},"maybe-class-name":{pattern:/(^|[^$\w\xA0-\uFFFF])[A-Z][$\w\xA0-\uFFFF]+/,lookbehind:!0},dom:{pattern:/\b(?:document|(?:local|session)Storage|location|navigator|performance|window)\b/,alias:"variable"},console:{pattern:/\bconsole(?=\s*\.)/,alias:"class-name"}});for(var n=["function","function-variable","method","method-variable","property-access"],r=0;r<n.length;r++){var a=n[r],i=e.languages.javascript[a];"RegExp"===e.util.type(i)&&(i=e.languages.javascript[a]={pattern:i});var o=i.inside||{};i.inside=o,o["maybe-class-name"]=/^[A-Z][\s\S]*/}}(a),function(e){var t=e.util.clone(e.languages.javascript),n=/(?:\s|\/\/.*(?!.)|\/\*(?:[^*]|\*(?!\/))\*\/)/.source,r=/(?:\{(?:\{(?:\{[^{}]*\}|[^{}])*\}|[^{}])*\})/.source,a=/(?:\{<S>*\.{3}(?:[^{}]|<BRACES>)*\})/.source;function i(e,t){return e=e.replace(/<S>/g,(function(){return n})).replace(/<BRACES>/g,(function(){return r})).replace(/<SPREAD>/g,(function(){return a})),RegExp(e,t)}a=i(a).source,e.languages.jsx=e.languages.extend("markup",t),e.languages.jsx.tag.pattern=i(/<\/?(?:[\w.:-]+(?:<S>+(?:[\w.:$-]+(?:=(?:"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*'|[^\s{'"/>=]+|<BRACES>))?|<SPREAD>))*<S>*\/?)?>/.source),e.languages.jsx.tag.inside.tag.pattern=/^<\/?[^\s>\/]*/,e.languages.jsx.tag.inside["attr-value"].pattern=/=(?!\{)(?:"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*'|[^\s'">]+)/,e.languages.jsx.tag.inside.tag.inside["class-name"]=/^[A-Z]\w*(?:\.[A-Z]\w*)*$/,e.languages.jsx.tag.inside.comment=t.comment,e.languages.insertBefore("inside","attr-name",{spread:{pattern:i(/<SPREAD>/.source),inside:e.languages.jsx}},e.languages.jsx.tag),e.languages.insertBefore("inside","special-attr",{script:{pattern:i(/=<BRACES>/.source),alias:"language-javascript",inside:{"script-punctuation":{pattern:/^=(?=\{)/,alias:"punctuation"},rest:e.languages.jsx}}},e.languages.jsx.tag);var o=function(e){return e?"string"==typeof e?e:"string"==typeof e.content?e.content:e.content.map(o).join(""):""},l=function(t){for(var n=[],r=0;r<t.length;r++){var a=t[r],i=!1;if("string"!=typeof a&&("tag"===a.type&&a.content[0]&&"tag"===a.content[0].type?"</"===a.content[0].content[0].content?n.length>0&&n[n.length-1].tagName===o(a.content[0].content[1])&&n.pop():"/>"===a.content[a.content.length-1].content||n.push({tagName:o(a.content[0].content[1]),openedBraces:0}):n.length>0&&"punctuation"===a.type&&"{"===a.content?n[n.length-1].openedBraces++:n.length>0&&n[n.length-1].openedBraces>0&&"punctuation"===a.type&&"}"===a.content?n[n.length-1].openedBraces--:i=!0),(i||"string"==typeof a)&&n.length>0&&0===n[n.length-1].openedBraces){var s=o(a);r<t.length-1&&("string"==typeof t[r+1]||"plain-text"===t[r+1].type)&&(s+=o(t[r+1]),t.splice(r+1,1)),r>0&&("string"==typeof t[r-1]||"plain-text"===t[r-1].type)&&(s=o(t[r-1])+s,t.splice(r-1,1),r--),t[r]=new e.Token("plain-text",s,null,s)}a.content&&"string"!=typeof a.content&&l(a.content)}};e.hooks.add("after-tokenize",(function(e){"jsx"!==e.language&&"tsx"!==e.language||l(e.tokens)}))}(a),function(e){e.languages.diff={coord:[/^(?:\*{3}|-{3}|\+{3}).*$/m,/^@@.*@@$/m,/^\d.*$/m]};var t={"deleted-sign":"-","deleted-arrow":"<","inserted-sign":"+","inserted-arrow":">",unchanged:" ",diff:"!"};Object.keys(t).forEach((function(n){var r=t[n],a=[];/^\w+$/.test(n)||a.push(/\w+/.exec(n)[0]),"diff"===n&&a.push("bold"),e.languages.diff[n]={pattern:RegExp("^(?:["+r+"].*(?:\r\n?|\n|(?![\\s\\S])))+","m"),alias:a,inside:{line:{pattern:/(.)(?=[\s\S]).*(?:\r\n?|\n)?/,lookbehind:!0},prefix:{pattern:/[\s\S]/,alias:/\w+/.exec(n)[0]}}}})),Object.defineProperty(e.languages.diff,"PREFIXES",{value:t})}(a),a.languages.git={comment:/^#.*/m,deleted:/^[-\u2013].*/m,inserted:/^\+.*/m,string:/("|')(?:\\.|(?!\1)[^\\\r\n])*\1/,command:{pattern:/^.*\$ git .*$/m,inside:{parameter:/\s--?\w+/}},coord:/^@@.*@@$/m,"commit-sha1":/^commit \w{40}$/m},a.languages.go=a.languages.extend("clike",{string:{pattern:/(^|[^\\])"(?:\\.|[^"\\\r\n])*"|`[^`]*`/,lookbehind:!0,greedy:!0},keyword:/\b(?:break|case|chan|const|continue|default|defer|else|fallthrough|for|func|go(?:to)?|if|import|interface|map|package|range|return|select|struct|switch|type|var)\b/,boolean:/\b(?:_|false|iota|nil|true)\b/,number:[/\b0(?:b[01_]+|o[0-7_]+)i?\b/i,/\b0x(?:[a-f\d_]+(?:\.[a-f\d_]*)?|\.[a-f\d_]+)(?:p[+-]?\d+(?:_\d+)*)?i?(?!\w)/i,/(?:\b\d[\d_]*(?:\.[\d_]*)?|\B\.\d[\d_]*)(?:e[+-]?[\d_]+)?i?(?!\w)/i],operator:/[*\/%^!=]=?|\+[=+]?|-[=-]?|\|[=|]?|&(?:=|&|\^=?)?|>(?:>=?|=)?|<(?:<=?|=|-)?|:=|\.\.\./,builtin:/\b(?:append|bool|byte|cap|close|complex|complex(?:64|128)|copy|delete|error|float(?:32|64)|u?int(?:8|16|32|64)?|imag|len|make|new|panic|print(?:ln)?|real|recover|rune|string|uintptr)\b/}),a.languages.insertBefore("go","string",{char:{pattern:/'(?:\\.|[^'\\\r\n]){0,10}'/,greedy:!0}}),delete a.languages.go["class-name"],function(e){function t(e,t){return"___"+e.toUpperCase()+t+"___"}Object.defineProperties(e.languages["markup-templating"]={},{buildPlaceholders:{value:function(n,r,a,i){if(n.language===r){var o=n.tokenStack=[];n.code=n.code.replace(a,(function(e){if("function"==typeof i&&!i(e))return e;for(var a,l=o.length;-1!==n.code.indexOf(a=t(r,l));)++l;return o[l]=e,a})),n.grammar=e.languages.markup}}},tokenizePlaceholders:{value:function(n,r){if(n.language===r&&n.tokenStack){n.grammar=e.languages[r];var a=0,i=Object.keys(n.tokenStack);!function o(l){for(var s=0;s<l.length&&!(a>=i.length);s++){var c=l[s];if("string"==typeof c||c.content&&"string"==typeof c.content){var u=i[a],d=n.tokenStack[u],p="string"==typeof c?c:c.content,f=t(r,u),m=p.indexOf(f);if(m>-1){++a;var g=p.substring(0,m),h=new e.Token(r,e.tokenize(d,n.grammar),"language-"+r,d),b=p.substring(m+f.length),v=[];g&&v.push.apply(v,o([g])),v.push(h),b&&v.push.apply(v,o([b])),"string"==typeof c?l.splice.apply(l,[s,1].concat(v)):c.content=v}}else c.content&&o(c.content)}return l}(n.tokens)}}}})}(a),function(e){e.languages.handlebars={comment:/\{\{![\s\S]*?\}\}/,delimiter:{pattern:/^\{\{\{?|\}\}\}?$/,alias:"punctuation"},string:/(["'])(?:\\.|(?!\1)[^\\\r\n])*\1/,number:/\b0x[\dA-Fa-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[Ee][+-]?\d+)?/,boolean:/\b(?:false|true)\b/,block:{pattern:/^(\s*(?:~\s*)?)[#\/]\S+?(?=\s*(?:~\s*)?$|\s)/,lookbehind:!0,alias:"keyword"},brackets:{pattern:/\[[^\]]+\]/,inside:{punctuation:/\[|\]/,variable:/[\s\S]+/}},punctuation:/[!"#%&':()*+,.\/;<=>@\[\\\]^`{|}~]/,variable:/[^!"#%&'()*+,\/;<=>@\[\\\]^`{|}~\s]+/},e.hooks.add("before-tokenize",(function(t){e.languages["markup-templating"].buildPlaceholders(t,"handlebars",/\{\{\{[\s\S]+?\}\}\}|\{\{[\s\S]+?\}\}/g)})),e.hooks.add("after-tokenize",(function(t){e.languages["markup-templating"].tokenizePlaceholders(t,"handlebars")})),e.languages.hbs=e.languages.handlebars}(a),a.languages.json={property:{pattern:/(^|[^\\])"(?:\\.|[^\\"\r\n])*"(?=\s*:)/,lookbehind:!0,greedy:!0},string:{pattern:/(^|[^\\])"(?:\\.|[^\\"\r\n])*"(?!\s*:)/,lookbehind:!0,greedy:!0},comment:{pattern:/\/\/.*|\/\*[\s\S]*?(?:\*\/|$)/,greedy:!0},number:/-?\b\d+(?:\.\d+)?(?:e[+-]?\d+)?\b/i,punctuation:/[{}[\],]/,operator:/:/,boolean:/\b(?:false|true)\b/,null:{pattern:/\bnull\b/,alias:"keyword"}},a.languages.webmanifest=a.languages.json,a.languages.less=a.languages.extend("css",{comment:[/\/\*[\s\S]*?\*\//,{pattern:/(^|[^\\])\/\/.*/,lookbehind:!0}],atrule:{pattern:/@[\w-](?:\((?:[^(){}]|\([^(){}]*\))*\)|[^(){};\s]|\s+(?!\s))*?(?=\s*\{)/,inside:{punctuation:/[:()]/}},selector:{pattern:/(?:@\{[\w-]+\}|[^{};\s@])(?:@\{[\w-]+\}|\((?:[^(){}]|\([^(){}]*\))*\)|[^(){};@\s]|\s+(?!\s))*?(?=\s*\{)/,inside:{variable:/@+[\w-]+/}},property:/(?:@\{[\w-]+\}|[\w-])+(?:\+_?)?(?=\s*:)/,operator:/[+\-*\/]/}),a.languages.insertBefore("less","property",{variable:[{pattern:/@[\w-]+\s*:/,inside:{punctuation:/:/}},/@@?[\w-]+/],"mixin-usage":{pattern:/([{;]\s*)[.#](?!\d)[\w-].*?(?=[(;])/,lookbehind:!0,alias:"function"}}),a.languages.makefile={comment:{pattern:/(^|[^\\])#(?:\\(?:\r\n|[\s\S])|[^\\\r\n])*/,lookbehind:!0},string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"builtin-target":{pattern:/\.[A-Z][^:#=\s]+(?=\s*:(?!=))/,alias:"builtin"},target:{pattern:/^(?:[^:=\s]|[ \t]+(?![\s:]))+(?=\s*:(?!=))/m,alias:"symbol",inside:{variable:/\$+(?:(?!\$)[^(){}:#=\s]+|(?=[({]))/}},variable:/\$+(?:(?!\$)[^(){}:#=\s]+|\([@*%<^+?][DF]\)|(?=[({]))/,keyword:/-include\b|\b(?:define|else|endef|endif|export|ifn?def|ifn?eq|include|override|private|sinclude|undefine|unexport|vpath)\b/,function:{pattern:/(\()(?:abspath|addsuffix|and|basename|call|dir|error|eval|file|filter(?:-out)?|findstring|firstword|flavor|foreach|guile|if|info|join|lastword|load|notdir|or|origin|patsubst|realpath|shell|sort|strip|subst|suffix|value|warning|wildcard|word(?:list|s)?)(?=[ \t])/,lookbehind:!0},operator:/(?:::|[?:+!])?=|[|@]/,punctuation:/[:;(){}]/},a.languages.objectivec=a.languages.extend("c",{string:{pattern:/@?"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"/,greedy:!0},keyword:/\b(?:asm|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|in|inline|int|long|register|return|self|short|signed|sizeof|static|struct|super|switch|typedef|typeof|union|unsigned|void|volatile|while)\b|(?:@interface|@end|@implementation|@protocol|@class|@public|@protected|@private|@property|@try|@catch|@finally|@throw|@synthesize|@dynamic|@selector)\b/,operator:/-[->]?|\+\+?|!=?|<<?=?|>>?=?|==?|&&?|\|\|?|[~^%?*\/@]/}),delete a.languages.objectivec["class-name"],a.languages.objc=a.languages.objectivec,a.languages.ocaml={comment:{pattern:/\(\*[\s\S]*?\*\)/,greedy:!0},char:{pattern:/'(?:[^\\\r\n']|\\(?:.|[ox]?[0-9a-f]{1,3}))'/i,greedy:!0},string:[{pattern:/"(?:\\(?:[\s\S]|\r\n)|[^\\\r\n"])*"/,greedy:!0},{pattern:/\{([a-z_]*)\|[\s\S]*?\|\1\}/,greedy:!0}],number:[/\b(?:0b[01][01_]*|0o[0-7][0-7_]*)\b/i,/\b0x[a-f0-9][a-f0-9_]*(?:\.[a-f0-9_]*)?(?:p[+-]?\d[\d_]*)?(?!\w)/i,/\b\d[\d_]*(?:\.[\d_]*)?(?:e[+-]?\d[\d_]*)?(?!\w)/i],directive:{pattern:/\B#\w+/,alias:"property"},label:{pattern:/\B~\w+/,alias:"property"},"type-variable":{pattern:/\B'\w+/,alias:"function"},variant:{pattern:/`\w+/,alias:"symbol"},keyword:/\b(?:as|assert|begin|class|constraint|do|done|downto|else|end|exception|external|for|fun|function|functor|if|in|include|inherit|initializer|lazy|let|match|method|module|mutable|new|nonrec|object|of|open|private|rec|sig|struct|then|to|try|type|val|value|virtual|when|where|while|with)\b/,boolean:/\b(?:false|true)\b/,"operator-like-punctuation":{pattern:/\[[<>|]|[>|]\]|\{<|>\}/,alias:"punctuation"},operator:/\.[.~]|:[=>]|[=<>@^|&+\-*\/$%!?~][!$%&*+\-.\/:<=>?@^|~]*|\b(?:and|asr|land|lor|lsl|lsr|lxor|mod|or)\b/,punctuation:/;;|::|[(){}\[\].,:;#]|\b_\b/},a.languages.python={comment:{pattern:/(^|[^\\])#.*/,lookbehind:!0,greedy:!0},"string-interpolation":{pattern:/(?:f|fr|rf)(?:("""|''')[\s\S]*?\1|("|')(?:\\.|(?!\2)[^\\\r\n])*\2)/i,greedy:!0,inside:{interpolation:{pattern:/((?:^|[^{])(?:\{\{)*)\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}])+\})+\})+\}/,lookbehind:!0,inside:{"format-spec":{pattern:/(:)[^:(){}]+(?=\}$)/,lookbehind:!0},"conversion-option":{pattern:/![sra](?=[:}]$)/,alias:"punctuation"},rest:null}},string:/[\s\S]+/}},"triple-quoted-string":{pattern:/(?:[rub]|br|rb)?("""|''')[\s\S]*?\1/i,greedy:!0,alias:"string"},string:{pattern:/(?:[rub]|br|rb)?("|')(?:\\.|(?!\1)[^\\\r\n])*\1/i,greedy:!0},function:{pattern:/((?:^|\s)def[ \t]+)[a-zA-Z_]\w*(?=\s*\()/g,lookbehind:!0},"class-name":{pattern:/(\bclass\s+)\w+/i,lookbehind:!0},decorator:{pattern:/(^[\t ]*)@\w+(?:\.\w+)*/m,lookbehind:!0,alias:["annotation","punctuation"],inside:{punctuation:/\./}},keyword:/\b(?:_(?=\s*:)|and|as|assert|async|await|break|case|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|match|nonlocal|not|or|pass|print|raise|return|try|while|with|yield)\b/,builtin:/\b(?:__import__|abs|all|any|apply|ascii|basestring|bin|bool|buffer|bytearray|bytes|callable|chr|classmethod|cmp|coerce|compile|complex|delattr|dict|dir|divmod|enumerate|eval|execfile|file|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|intern|isinstance|issubclass|iter|len|list|locals|long|map|max|memoryview|min|next|object|oct|open|ord|pow|property|range|raw_input|reduce|reload|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|unichr|unicode|vars|xrange|zip)\b/,boolean:/\b(?:False|None|True)\b/,number:/\b0(?:b(?:_?[01])+|o(?:_?[0-7])+|x(?:_?[a-f0-9])+)\b|(?:\b\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\B\.\d+(?:_\d+)*)(?:e[+-]?\d+(?:_\d+)*)?j?(?!\w)/i,operator:/[-+%=]=?|!=|:=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]/,punctuation:/[{}[\];(),.:]/},a.languages.python["string-interpolation"].inside.interpolation.inside.rest=a.languages.python,a.languages.py=a.languages.python,a.languages.reason=a.languages.extend("clike",{string:{pattern:/"(?:\\(?:\r\n|[\s\S])|[^\\\r\n"])*"/,greedy:!0},"class-name":/\b[A-Z]\w*/,keyword:/\b(?:and|as|assert|begin|class|constraint|do|done|downto|else|end|exception|external|for|fun|function|functor|if|in|include|inherit|initializer|lazy|let|method|module|mutable|new|nonrec|object|of|open|or|private|rec|sig|struct|switch|then|to|try|type|val|virtual|when|while|with)\b/,operator:/\.{3}|:[:=]|\|>|->|=(?:==?|>)?|<=?|>=?|[|^?'#!~`]|[+\-*\/]\.?|\b(?:asr|land|lor|lsl|lsr|lxor|mod)\b/}),a.languages.insertBefore("reason","class-name",{char:{pattern:/'(?:\\x[\da-f]{2}|\\o[0-3][0-7][0-7]|\\\d{3}|\\.|[^'\\\r\n])'/,greedy:!0},constructor:/\b[A-Z]\w*\b(?!\s*\.)/,label:{pattern:/\b[a-z]\w*(?=::)/,alias:"symbol"}}),delete a.languages.reason.function,function(e){e.languages.sass=e.languages.extend("css",{comment:{pattern:/^([ \t]*)\/[\/*].*(?:(?:\r?\n|\r)\1[ \t].+)*/m,lookbehind:!0,greedy:!0}}),e.languages.insertBefore("sass","atrule",{"atrule-line":{pattern:/^(?:[ \t]*)[@+=].+/m,greedy:!0,inside:{atrule:/(?:@[\w-]+|[+=])/}}}),delete e.languages.sass.atrule;var t=/\$[-\w]+|#\{\$[-\w]+\}/,n=[/[+*\/%]|[=!]=|<=?|>=?|\b(?:and|not|or)\b/,{pattern:/(\s)-(?=\s)/,lookbehind:!0}];e.languages.insertBefore("sass","property",{"variable-line":{pattern:/^[ \t]*\$.+/m,greedy:!0,inside:{punctuation:/:/,variable:t,operator:n}},"property-line":{pattern:/^[ \t]*(?:[^:\s]+ *:.*|:[^:\s].*)/m,greedy:!0,inside:{property:[/[^:\s]+(?=\s*:)/,{pattern:/(:)[^:\s]+/,lookbehind:!0}],punctuation:/:/,variable:t,operator:n,important:e.languages.sass.important}}}),delete e.languages.sass.property,delete e.languages.sass.important,e.languages.insertBefore("sass","punctuation",{selector:{pattern:/^([ \t]*)\S(?:,[^,\r\n]+|[^,\r\n]*)(?:,[^,\r\n]+)*(?:,(?:\r?\n|\r)\1[ \t]+\S(?:,[^,\r\n]+|[^,\r\n]*)(?:,[^,\r\n]+)*)*/m,lookbehind:!0,greedy:!0}})}(a),a.languages.scss=a.languages.extend("css",{comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|\/\/.*)/,lookbehind:!0},atrule:{pattern:/@[\w-](?:\([^()]+\)|[^()\s]|\s+(?!\s))*?(?=\s+[{;])/,inside:{rule:/@[\w-]+/}},url:/(?:[-a-z]+-)?url(?=\()/i,selector:{pattern:/(?=\S)[^@;{}()]?(?:[^@;{}()\s]|\s+(?!\s)|#\{\$[-\w]+\})+(?=\s*\{(?:\}|\s|[^}][^:{}]*[:{][^}]))/,inside:{parent:{pattern:/&/,alias:"important"},placeholder:/%[-\w]+/,variable:/\$[-\w]+|#\{\$[-\w]+\}/}},property:{pattern:/(?:[-\w]|\$[-\w]|#\{\$[-\w]+\})+(?=\s*:)/,inside:{variable:/\$[-\w]+|#\{\$[-\w]+\}/}}}),a.languages.insertBefore("scss","atrule",{keyword:[/@(?:content|debug|each|else(?: if)?|extend|for|forward|function|if|import|include|mixin|return|use|warn|while)\b/i,{pattern:/( )(?:from|through)(?= )/,lookbehind:!0}]}),a.languages.insertBefore("scss","important",{variable:/\$[-\w]+|#\{\$[-\w]+\}/}),a.languages.insertBefore("scss","function",{"module-modifier":{pattern:/\b(?:as|hide|show|with)\b/i,alias:"keyword"},placeholder:{pattern:/%[-\w]+/,alias:"selector"},statement:{pattern:/\B!(?:default|optional)\b/i,alias:"keyword"},boolean:/\b(?:false|true)\b/,null:{pattern:/\bnull\b/,alias:"keyword"},operator:{pattern:/(\s)(?:[-+*\/%]|[=!]=|<=?|>=?|and|not|or)(?=\s)/,lookbehind:!0}}),a.languages.scss.atrule.inside.rest=a.languages.scss,function(e){var t={pattern:/(\b\d+)(?:%|[a-z]+)/,lookbehind:!0},n={pattern:/(^|[^\w.-])-?(?:\d+(?:\.\d+)?|\.\d+)/,lookbehind:!0},r={comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|\/\/.*)/,lookbehind:!0},url:{pattern:/\burl\((["']?).*?\1\)/i,greedy:!0},string:{pattern:/("|')(?:(?!\1)[^\\\r\n]|\\(?:\r\n|[\s\S]))*\1/,greedy:!0},interpolation:null,func:null,important:/\B!(?:important|optional)\b/i,keyword:{pattern:/(^|\s+)(?:(?:else|for|if|return|unless)(?=\s|$)|@[\w-]+)/,lookbehind:!0},hexcode:/#[\da-f]{3,6}/i,color:[/\b(?:AliceBlue|AntiqueWhite|Aqua|Aquamarine|Azure|Beige|Bisque|Black|BlanchedAlmond|Blue|BlueViolet|Brown|BurlyWood|CadetBlue|Chartreuse|Chocolate|Coral|CornflowerBlue|Cornsilk|Crimson|Cyan|DarkBlue|DarkCyan|DarkGoldenRod|DarkGr[ae]y|DarkGreen|DarkKhaki|DarkMagenta|DarkOliveGreen|DarkOrange|DarkOrchid|DarkRed|DarkSalmon|DarkSeaGreen|DarkSlateBlue|DarkSlateGr[ae]y|DarkTurquoise|DarkViolet|DeepPink|DeepSkyBlue|DimGr[ae]y|DodgerBlue|FireBrick|FloralWhite|ForestGreen|Fuchsia|Gainsboro|GhostWhite|Gold|GoldenRod|Gr[ae]y|Green|GreenYellow|HoneyDew|HotPink|IndianRed|Indigo|Ivory|Khaki|Lavender|LavenderBlush|LawnGreen|LemonChiffon|LightBlue|LightCoral|LightCyan|LightGoldenRodYellow|LightGr[ae]y|LightGreen|LightPink|LightSalmon|LightSeaGreen|LightSkyBlue|LightSlateGr[ae]y|LightSteelBlue|LightYellow|Lime|LimeGreen|Linen|Magenta|Maroon|MediumAquaMarine|MediumBlue|MediumOrchid|MediumPurple|MediumSeaGreen|MediumSlateBlue|MediumSpringGreen|MediumTurquoise|MediumVioletRed|MidnightBlue|MintCream|MistyRose|Moccasin|NavajoWhite|Navy|OldLace|Olive|OliveDrab|Orange|OrangeRed|Orchid|PaleGoldenRod|PaleGreen|PaleTurquoise|PaleVioletRed|PapayaWhip|PeachPuff|Peru|Pink|Plum|PowderBlue|Purple|Red|RosyBrown|RoyalBlue|SaddleBrown|Salmon|SandyBrown|SeaGreen|SeaShell|Sienna|Silver|SkyBlue|SlateBlue|SlateGr[ae]y|Snow|SpringGreen|SteelBlue|Tan|Teal|Thistle|Tomato|Transparent|Turquoise|Violet|Wheat|White|WhiteSmoke|Yellow|YellowGreen)\b/i,{pattern:/\b(?:hsl|rgb)\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*\)\B|\b(?:hsl|rgb)a\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*,\s*(?:0|0?\.\d+|1)\s*\)\B/i,inside:{unit:t,number:n,function:/[\w-]+(?=\()/,punctuation:/[(),]/}}],entity:/\\[\da-f]{1,8}/i,unit:t,boolean:/\b(?:false|true)\b/,operator:[/~|[+!\/%<>?=]=?|[-:]=|\*[*=]?|\.{2,3}|&&|\|\||\B-\B|\b(?:and|in|is(?: a| defined| not|nt)?|not|or)\b/],number:n,punctuation:/[{}()\[\];:,]/};r.interpolation={pattern:/\{[^\r\n}:]+\}/,alias:"variable",inside:{delimiter:{pattern:/^\{|\}$/,alias:"punctuation"},rest:r}},r.func={pattern:/[\w-]+\([^)]*\).*/,inside:{function:/^[^(]+/,rest:r}},e.languages.stylus={"atrule-declaration":{pattern:/(^[ \t]*)@.+/m,lookbehind:!0,inside:{atrule:/^@[\w-]+/,rest:r}},"variable-declaration":{pattern:/(^[ \t]*)[\w$-]+\s*.?=[ \t]*(?:\{[^{}]*\}|\S.*|$)/m,lookbehind:!0,inside:{variable:/^\S+/,rest:r}},statement:{pattern:/(^[ \t]*)(?:else|for|if|return|unless)[ \t].+/m,lookbehind:!0,inside:{keyword:/^\S+/,rest:r}},"property-declaration":{pattern:/((?:^|\{)([ \t]*))(?:[\w-]|\{[^}\r\n]+\})+(?:\s*:\s*|[ \t]+)(?!\s)[^{\r\n]*(?:;|[^{\r\n,]$(?!(?:\r?\n|\r)(?:\{|\2[ \t])))/m,lookbehind:!0,inside:{property:{pattern:/^[^\s:]+/,inside:{interpolation:r.interpolation}},rest:r}},selector:{pattern:/(^[ \t]*)(?:(?=\S)(?:[^{}\r\n:()]|::?[\w-]+(?:\([^)\r\n]*\)|(?![\w-]))|\{[^}\r\n]+\})+)(?:(?:\r?\n|\r)(?:\1(?:(?=\S)(?:[^{}\r\n:()]|::?[\w-]+(?:\([^)\r\n]*\)|(?![\w-]))|\{[^}\r\n]+\})+)))*(?:,$|\{|(?=(?:\r?\n|\r)(?:\{|\1[ \t])))/m,lookbehind:!0,inside:{interpolation:r.interpolation,comment:r.comment,punctuation:/[{},]/}},func:r.func,string:r.string,comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|\/\/.*)/,lookbehind:!0,greedy:!0},interpolation:r.interpolation,punctuation:/[{}()\[\];:.]/}}(a),function(e){var t=e.util.clone(e.languages.typescript);e.languages.tsx=e.languages.extend("jsx",t),delete e.languages.tsx.parameter,delete e.languages.tsx["literal-property"];var n=e.languages.tsx.tag;n.pattern=RegExp(/(^|[^\w$]|(?=<\/))/.source+"(?:"+n.pattern.source+")",n.pattern.flags),n.lookbehind=!0}(a),a.languages.wasm={comment:[/\(;[\s\S]*?;\)/,{pattern:/;;.*/,greedy:!0}],string:{pattern:/"(?:\\[\s\S]|[^"\\])*"/,greedy:!0},keyword:[{pattern:/\b(?:align|offset)=/,inside:{operator:/=/}},{pattern:/\b(?:(?:f32|f64|i32|i64)(?:\.(?:abs|add|and|ceil|clz|const|convert_[su]\/i(?:32|64)|copysign|ctz|demote\/f64|div(?:_[su])?|eqz?|extend_[su]\/i32|floor|ge(?:_[su])?|gt(?:_[su])?|le(?:_[su])?|load(?:(?:8|16|32)_[su])?|lt(?:_[su])?|max|min|mul|neg?|nearest|or|popcnt|promote\/f32|reinterpret\/[fi](?:32|64)|rem_[su]|rot[lr]|shl|shr_[su]|sqrt|store(?:8|16|32)?|sub|trunc(?:_[su]\/f(?:32|64))?|wrap\/i64|xor))?|memory\.(?:grow|size))\b/,inside:{punctuation:/\./}},/\b(?:anyfunc|block|br(?:_if|_table)?|call(?:_indirect)?|data|drop|elem|else|end|export|func|get_(?:global|local)|global|if|import|local|loop|memory|module|mut|nop|offset|param|result|return|select|set_(?:global|local)|start|table|tee_local|then|type|unreachable)\b/],variable:/\$[\w!#$%&'*+\-./:<=>?@\\^`|~]+/,number:/[+-]?\b(?:\d(?:_?\d)*(?:\.\d(?:_?\d)*)?(?:[eE][+-]?\d(?:_?\d)*)?|0x[\da-fA-F](?:_?[\da-fA-F])*(?:\.[\da-fA-F](?:_?[\da-fA-D])*)?(?:[pP][+-]?\d(?:_?\d)*)?)\b|\binf\b|\bnan(?::0x[\da-fA-F](?:_?[\da-fA-D])*)?\b/,punctuation:/[()]/};const i=a},485:()=>{!function(e){var t={pattern:/((?:^|[^\\$])(?:\\{2})*)\$(?:\w+|\{[^{}]*\})/,lookbehind:!0,inside:{"interpolation-punctuation":{pattern:/^\$\{?|\}$/,alias:"punctuation"},expression:{pattern:/[\s\S]+/,inside:null}}};e.languages.groovy=e.languages.extend("clike",{string:{pattern:/'''(?:[^\\]|\\[\s\S])*?'''|'(?:\\.|[^\\'\r\n])*'/,greedy:!0},keyword:/\b(?:abstract|as|assert|boolean|break|byte|case|catch|char|class|const|continue|def|default|do|double|else|enum|extends|final|finally|float|for|goto|if|implements|import|in|instanceof|int|interface|long|native|new|package|private|protected|public|return|short|static|strictfp|super|switch|synchronized|this|throw|throws|trait|transient|try|void|volatile|while)\b/,number:/\b(?:0b[01_]+|0x[\da-f_]+(?:\.[\da-f_p\-]+)?|[\d_]+(?:\.[\d_]+)?(?:e[+-]?\d+)?)[glidf]?\b/i,operator:{pattern:/(^|[^.])(?:~|==?~?|\?[.:]?|\*(?:[.=]|\*=?)?|\.[@&]|\.\.<|\.\.(?!\.)|-[-=>]?|\+[+=]?|!=?|<(?:<=?|=>?)?|>(?:>>?=?|=)?|&[&=]?|\|[|=]?|\/=?|\^=?|%=?)/,lookbehind:!0},punctuation:/\.+|[{}[\];(),:$]/}),e.languages.insertBefore("groovy","string",{shebang:{pattern:/#!.+/,alias:"comment",greedy:!0},"interpolation-string":{pattern:/"""(?:[^\\]|\\[\s\S])*?"""|(["/])(?:\\.|(?!\1)[^\\\r\n])*\1|\$\/(?:[^/$]|\$(?:[/$]|(?![/$]))|\/(?!\$))*\/\$/,greedy:!0,inside:{interpolation:t,string:/[\s\S]+/}}}),e.languages.insertBefore("groovy","punctuation",{"spock-block":/\b(?:and|cleanup|expect|given|setup|then|when|where):/}),e.languages.insertBefore("groovy","function",{annotation:{pattern:/(^|[^.])@\w+/,lookbehind:!0,alias:"punctuation"}}),t.inside.expression.inside=e.languages.groovy}(Prism)},2503:()=>{!function(e){var t=/\b(?:abstract|assert|boolean|break|byte|case|catch|char|class|const|continue|default|do|double|else|enum|exports|extends|final|finally|float|for|goto|if|implements|import|instanceof|int|interface|long|module|native|new|non-sealed|null|open|opens|package|permits|private|protected|provides|public|record(?!\s*[(){}[\]<>=%~.:,;?+\-*/&|^])|requires|return|sealed|short|static|strictfp|super|switch|synchronized|this|throw|throws|to|transient|transitive|try|uses|var|void|volatile|while|with|yield)\b/,n=/(?:[a-z]\w*\s*\.\s*)*(?:[A-Z]\w*\s*\.\s*)*/.source,r={pattern:RegExp(/(^|[^\w.])/.source+n+/[A-Z](?:[\d_A-Z]*[a-z]\w*)?\b/.source),lookbehind:!0,inside:{namespace:{pattern:/^[a-z]\w*(?:\s*\.\s*[a-z]\w*)*(?:\s*\.)?/,inside:{punctuation:/\./}},punctuation:/\./}};e.languages.java=e.languages.extend("clike",{string:{pattern:/(^|[^\\])"(?:\\.|[^"\\\r\n])*"/,lookbehind:!0,greedy:!0},"class-name":[r,{pattern:RegExp(/(^|[^\w.])/.source+n+/[A-Z]\w*(?=\s+\w+\s*[;,=()]|\s*(?:\[[\s,]*\]\s*)?::\s*new\b)/.source),lookbehind:!0,inside:r.inside},{pattern:RegExp(/(\b(?:class|enum|extends|implements|instanceof|interface|new|record|throws)\s+)/.source+n+/[A-Z]\w*\b/.source),lookbehind:!0,inside:r.inside}],keyword:t,function:[e.languages.clike.function,{pattern:/(::\s*)[a-z_]\w*/,lookbehind:!0}],number:/\b0b[01][01_]*L?\b|\b0x(?:\.[\da-f_p+-]+|[\da-f_]+(?:\.[\da-f_p+-]+)?)\b|(?:\b\d[\d_]*(?:\.[\d_]*)?|\B\.\d[\d_]*)(?:e[+-]?\d[\d_]*)?[dfl]?/i,operator:{pattern:/(^|[^.])(?:<<=?|>>>?=?|->|--|\+\+|&&|\|\||::|[?:~]|[-+*/%&|^!=<>]=?)/m,lookbehind:!0},constant:/\b[A-Z][A-Z_\d]+\b/}),e.languages.insertBefore("java","string",{"triple-quoted-string":{pattern:/"""[ \t]*[\r\n](?:(?:"|"")?(?:\\.|[^"\\]))*"""/,greedy:!0,alias:"string"},char:{pattern:/'(?:\\.|[^'\\\r\n]){1,6}'/,greedy:!0}}),e.languages.insertBefore("java","class-name",{annotation:{pattern:/(^|[^.])@\w+(?:\s*\.\s*\w+)*/,lookbehind:!0,alias:"punctuation"},generics:{pattern:/<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&))*>)*>)*>)*>/,inside:{"class-name":r,keyword:t,punctuation:/[<>(),.:]/,operator:/[?&|]/}},import:[{pattern:RegExp(/(\bimport\s+)/.source+n+/(?:[A-Z]\w*|\*)(?=\s*;)/.source),lookbehind:!0,inside:{namespace:r.inside.namespace,punctuation:/\./,operator:/\*/,"class-name":/\w+/}},{pattern:RegExp(/(\bimport\s+static\s+)/.source+n+/(?:\w+|\*)(?=\s*;)/.source),lookbehind:!0,alias:"static",inside:{namespace:r.inside.namespace,static:/\b\w+$/,punctuation:/\./,operator:/\*/,"class-name":/\w+/}}],namespace:{pattern:RegExp(/(\b(?:exports|import(?:\s+static)?|module|open|opens|package|provides|requires|to|transitive|uses|with)\s+)(?!<keyword>)[a-z]\w*(?:\.[a-z]\w*)*\.?/.source.replace(/<keyword>/g,(function(){return t.source}))),lookbehind:!0,inside:{punctuation:/\./}}})}(Prism)},2334:()=>{!function(e){e.languages.kotlin=e.languages.extend("clike",{keyword:{pattern:/(^|[^.])\b(?:abstract|actual|annotation|as|break|by|catch|class|companion|const|constructor|continue|crossinline|data|do|dynamic|else|enum|expect|external|final|finally|for|fun|get|if|import|in|infix|init|inline|inner|interface|internal|is|lateinit|noinline|null|object|open|operator|out|override|package|private|protected|public|reified|return|sealed|set|super|suspend|tailrec|this|throw|to|try|typealias|val|var|vararg|when|where|while)\b/,lookbehind:!0},function:[{pattern:/(?:`[^\r\n`]+`|\b\w+)(?=\s*\()/,greedy:!0},{pattern:/(\.)(?:`[^\r\n`]+`|\w+)(?=\s*\{)/,lookbehind:!0,greedy:!0}],number:/\b(?:0[xX][\da-fA-F]+(?:_[\da-fA-F]+)*|0[bB][01]+(?:_[01]+)*|\d+(?:_\d+)*(?:\.\d+(?:_\d+)*)?(?:[eE][+-]?\d+(?:_\d+)*)?[fFL]?)\b/,operator:/\+[+=]?|-[-=>]?|==?=?|!(?:!|==?)?|[\/*%<>]=?|[?:]:?|\.\.|&&|\|\||\b(?:and|inv|or|shl|shr|ushr|xor)\b/}),delete e.languages.kotlin["class-name"];var t={"interpolation-punctuation":{pattern:/^\$\{?|\}$/,alias:"punctuation"},expression:{pattern:/[\s\S]+/,inside:e.languages.kotlin}};e.languages.insertBefore("kotlin","string",{"string-literal":[{pattern:/"""(?:[^$]|\$(?:(?!\{)|\{[^{}]*\}))*?"""/,alias:"multiline",inside:{interpolation:{pattern:/\$(?:[a-z_]\w*|\{[^{}]*\})/i,inside:t},string:/[\s\S]+/}},{pattern:/"(?:[^"\\\r\n$]|\\.|\$(?:(?!\{)|\{[^{}]*\}))*"/,alias:"singleline",inside:{interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\$(?:[a-z_]\w*|\{[^{}]*\})/i,lookbehind:!0,inside:t},string:/[\s\S]+/}}],char:{pattern:/'(?:[^'\\\r\n]|\\(?:.|u[a-fA-F0-9]{0,4}))'/,greedy:!0}}),delete e.languages.kotlin.string,e.languages.insertBefore("kotlin","keyword",{annotation:{pattern:/\B@(?:\w+:)?(?:[A-Z]\w*|\[[^\]]+\])/,alias:"builtin"}}),e.languages.insertBefore("kotlin","function",{label:{pattern:/\b\w+@|@\w+\b/,alias:"symbol"}}),e.languages.kt=e.languages.kotlin,e.languages.kts=e.languages.kotlin}(Prism)},9930:()=>{!function(e){var t=/(?:[\w-]+|'[^'\n\r]*'|"(?:\\.|[^\\"\r\n])*")/.source;function n(e){return e.replace(/__/g,(function(){return t}))}e.languages.toml={comment:{pattern:/#.*/,greedy:!0},table:{pattern:RegExp(n(/(^[\t ]*\[\s*(?:\[\s*)?)__(?:\s*\.\s*__)*(?=\s*\])/.source),"m"),lookbehind:!0,greedy:!0,alias:"class-name"},key:{pattern:RegExp(n(/(^[\t ]*|[{,]\s*)__(?:\s*\.\s*__)*(?=\s*=)/.source),"m"),lookbehind:!0,greedy:!0,alias:"property"},string:{pattern:/"""(?:\\[\s\S]|[^\\])*?"""|'''[\s\S]*?'''|'[^'\n\r]*'|"(?:\\.|[^\\"\r\n])*"/,greedy:!0},date:[{pattern:/\b\d{4}-\d{2}-\d{2}(?:[T\s]\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})?)?\b/i,alias:"number"},{pattern:/\b\d{2}:\d{2}:\d{2}(?:\.\d+)?\b/,alias:"number"}],number:/(?:\b0(?:x[\da-zA-Z]+(?:_[\da-zA-Z]+)*|o[0-7]+(?:_[0-7]+)*|b[10]+(?:_[10]+)*))\b|[-+]?\b\d+(?:_\d+)*(?:\.\d+(?:_\d+)*)?(?:[eE][+-]?\d+(?:_\d+)*)?\b|[-+]?\b(?:inf|nan)\b/,boolean:/\b(?:false|true)\b/,punctuation:/[.,=[\]{}]/}}(Prism)},7665:(e,t,n)=>{var r={"./prism-groovy":485,"./prism-java":2503,"./prism-kotlin":2334,"./prism-toml":9930};function a(e){var t=i(e);return n(t)}function i(e){if(!n.o(r,e)){var t=new Error("Cannot find module '"+e+"'");throw t.code="MODULE_NOT_FOUND",t}return r[e]}a.keys=function(){return Object.keys(r)},a.resolve=i,e.exports=a,a.id=7665},2703:(e,t,n)=>{"use strict";var r=n(414);function a(){}function i(){}i.resetWarningCache=a,e.exports=function(){function e(e,t,n,a,i,o){if(o!==r){var l=new Error("Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types");throw l.name="Invariant Violation",l}}function t(){return e}e.isRequired=e;var n={array:e,bigint:e,bool:e,func:e,number:e,object:e,string:e,symbol:e,any:e,arrayOf:t,element:e,elementType:e,instanceOf:t,node:e,objectOf:t,oneOf:t,oneOfType:t,shape:t,exact:t,checkPropTypes:i,resetWarningCache:a};return n.PropTypes=n,n}},5697:(e,t,n)=>{e.exports=n(2703)()},414:e=>{"use strict";e.exports="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"},4448:(e,t,n)=>{"use strict";var r=n(7294),a=n(7418),i=n(3840);function o(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n<arguments.length;n++)t+="&args[]="+encodeURIComponent(arguments[n]);return"Minified React error #"+e+"; visit "+t+" for the full message or use the non-minified dev environment for full errors and additional helpful warnings."}if(!r)throw Error(o(227));function l(e,t,n,r,a,i,o,l,s){var c=Array.prototype.slice.call(arguments,3);try{t.apply(n,c)}catch(u){this.onError(u)}}var s=!1,c=null,u=!1,d=null,p={onError:function(e){s=!0,c=e}};function f(e,t,n,r,a,i,o,u,d){s=!1,c=null,l.apply(p,arguments)}var m=null,g=null,h=null;function b(e,t,n){var r=e.type||"unknown-event";e.currentTarget=h(n),function(e,t,n,r,a,i,l,p,m){if(f.apply(this,arguments),s){if(!s)throw Error(o(198));var g=c;s=!1,c=null,u||(u=!0,d=g)}}(r,t,void 0,e),e.currentTarget=null}var v=null,y={};function w(){if(v)for(var e in y){var t=y[e],n=v.indexOf(e);if(!(-1<n))throw Error(o(96,e));if(!k[n]){if(!t.extractEvents)throw Error(o(97,e));for(var r in k[n]=t,n=t.eventTypes){var a=void 0,i=n[r],l=t,s=r;if(E.hasOwnProperty(s))throw Error(o(99,s));E[s]=i;var c=i.phasedRegistrationNames;if(c){for(a in c)c.hasOwnProperty(a)&&x(c[a],l,s);a=!0}else i.registrationName?(x(i.registrationName,l,s),a=!0):a=!1;if(!a)throw Error(o(98,r,e))}}}}function x(e,t,n){if(S[e])throw Error(o(100,e));S[e]=t,T[e]=t.eventTypes[n].dependencies}var k=[],E={},S={},T={};function _(e){var t,n=!1;for(t in e)if(e.hasOwnProperty(t)){var r=e[t];if(!y.hasOwnProperty(t)||y[t]!==r){if(y[t])throw Error(o(102,t));y[t]=r,n=!0}}n&&w()}var C=!("undefined"==typeof window||void 0===window.document||void 0===window.document.createElement),A=null,P=null,N=null;function O(e){if(e=g(e)){if("function"!=typeof A)throw Error(o(280));var t=e.stateNode;t&&(t=m(t),A(e.stateNode,e.type,t))}}function I(e){P?N?N.push(e):N=[e]:P=e}function L(){if(P){var e=P,t=N;if(N=P=null,O(e),t)for(e=0;e<t.length;e++)O(t[e])}}function D(e,t){return e(t)}function R(e,t,n,r,a){return e(t,n,r,a)}function M(){}var F=D,B=!1,$=!1;function z(){null===P&&null===N||(M(),L())}function U(e,t,n){if($)return e(t,n);$=!0;try{return F(e,t,n)}finally{$=!1,z()}}var j=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,Z=Object.prototype.hasOwnProperty,H={},W={};function V(e,t,n,r,a,i){this.acceptsBooleans=2===t||3===t||4===t,this.attributeName=r,this.attributeNamespace=a,this.mustUseProperty=n,this.propertyName=e,this.type=t,this.sanitizeURL=i}var G={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach((function(e){G[e]=new V(e,0,!1,e,null,!1)})),[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach((function(e){var t=e[0];G[t]=new V(t,1,!1,e[1],null,!1)})),["contentEditable","draggable","spellCheck","value"].forEach((function(e){G[e]=new V(e,2,!1,e.toLowerCase(),null,!1)})),["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach((function(e){G[e]=new V(e,2,!1,e,null,!1)})),"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach((function(e){G[e]=new V(e,3,!1,e.toLowerCase(),null,!1)})),["checked","multiple","muted","selected"].forEach((function(e){G[e]=new V(e,3,!0,e,null,!1)})),["capture","download"].forEach((function(e){G[e]=new V(e,4,!1,e,null,!1)})),["cols","rows","size","span"].forEach((function(e){G[e]=new V(e,6,!1,e,null,!1)})),["rowSpan","start"].forEach((function(e){G[e]=new V(e,5,!1,e.toLowerCase(),null,!1)}));var q=/[\-:]([a-z])/g;function Y(e){return e[1].toUpperCase()}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach((function(e){var t=e.replace(q,Y);G[t]=new V(t,1,!1,e,null,!1)})),"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach((function(e){var t=e.replace(q,Y);G[t]=new V(t,1,!1,e,"http://www.w3.org/1999/xlink",!1)})),["xml:base","xml:lang","xml:space"].forEach((function(e){var t=e.replace(q,Y);G[t]=new V(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1)})),["tabIndex","crossOrigin"].forEach((function(e){G[e]=new V(e,1,!1,e.toLowerCase(),null,!1)})),G.xlinkHref=new V("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0),["src","href","action","formAction"].forEach((function(e){G[e]=new V(e,1,!1,e.toLowerCase(),null,!0)}));var K=r.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;function Q(e,t,n,r){var a=G.hasOwnProperty(t)?G[t]:null;(null!==a?0===a.type:!r&&(2<t.length&&("o"===t[0]||"O"===t[0])&&("n"===t[1]||"N"===t[1])))||(function(e,t,n,r){if(null==t||function(e,t,n,r){if(null!==n&&0===n.type)return!1;switch(typeof t){case"function":case"symbol":return!0;case"boolean":return!r&&(null!==n?!n.acceptsBooleans:"data-"!==(e=e.toLowerCase().slice(0,5))&&"aria-"!==e);default:return!1}}(e,t,n,r))return!0;if(r)return!1;if(null!==n)switch(n.type){case 3:return!t;case 4:return!1===t;case 5:return isNaN(t);case 6:return isNaN(t)||1>t}return!1}(t,n,a,r)&&(n=null),r||null===a?function(e){return!!Z.call(W,e)||!Z.call(H,e)&&(j.test(e)?W[e]=!0:(H[e]=!0,!1))}(t)&&(null===n?e.removeAttribute(t):e.setAttribute(t,""+n)):a.mustUseProperty?e[a.propertyName]=null===n?3!==a.type&&"":n:(t=a.attributeName,r=a.attributeNamespace,null===n?e.removeAttribute(t):(n=3===(a=a.type)||4===a&&!0===n?"":""+n,r?e.setAttributeNS(r,t,n):e.setAttribute(t,n))))}K.hasOwnProperty("ReactCurrentDispatcher")||(K.ReactCurrentDispatcher={current:null}),K.hasOwnProperty("ReactCurrentBatchConfig")||(K.ReactCurrentBatchConfig={suspense:null});var X=/^(.*)[\\\/]/,J="function"==typeof Symbol&&Symbol.for,ee=J?Symbol.for("react.element"):60103,te=J?Symbol.for("react.portal"):60106,ne=J?Symbol.for("react.fragment"):60107,re=J?Symbol.for("react.strict_mode"):60108,ae=J?Symbol.for("react.profiler"):60114,ie=J?Symbol.for("react.provider"):60109,oe=J?Symbol.for("react.context"):60110,le=J?Symbol.for("react.concurrent_mode"):60111,se=J?Symbol.for("react.forward_ref"):60112,ce=J?Symbol.for("react.suspense"):60113,ue=J?Symbol.for("react.suspense_list"):60120,de=J?Symbol.for("react.memo"):60115,pe=J?Symbol.for("react.lazy"):60116,fe=J?Symbol.for("react.block"):60121,me="function"==typeof Symbol&&Symbol.iterator;function ge(e){return null===e||"object"!=typeof e?null:"function"==typeof(e=me&&e[me]||e["@@iterator"])?e:null}function he(e){if(null==e)return null;if("function"==typeof e)return e.displayName||e.name||null;if("string"==typeof e)return e;switch(e){case ne:return"Fragment";case te:return"Portal";case ae:return"Profiler";case re:return"StrictMode";case ce:return"Suspense";case ue:return"SuspenseList"}if("object"==typeof e)switch(e.$$typeof){case oe:return"Context.Consumer";case ie:return"Context.Provider";case se:var t=e.render;return t=t.displayName||t.name||"",e.displayName||(""!==t?"ForwardRef("+t+")":"ForwardRef");case de:return he(e.type);case fe:return he(e.render);case pe:if(e=1===e._status?e._result:null)return he(e)}return null}function be(e){var t="";do{e:switch(e.tag){case 3:case 4:case 6:case 7:case 10:case 9:var n="";break e;default:var r=e._debugOwner,a=e._debugSource,i=he(e.type);n=null,r&&(n=he(r.type)),r=i,i="",a?i=" (at "+a.fileName.replace(X,"")+":"+a.lineNumber+")":n&&(i=" (created by "+n+")"),n="\n in "+(r||"Unknown")+i}t+=n,e=e.return}while(e);return t}function ve(e){switch(typeof e){case"boolean":case"number":case"object":case"string":case"undefined":return e;default:return""}}function ye(e){var t=e.type;return(e=e.nodeName)&&"input"===e.toLowerCase()&&("checkbox"===t||"radio"===t)}function we(e){e._valueTracker||(e._valueTracker=function(e){var t=ye(e)?"checked":"value",n=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),r=""+e[t];if(!e.hasOwnProperty(t)&&void 0!==n&&"function"==typeof n.get&&"function"==typeof n.set){var a=n.get,i=n.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return a.call(this)},set:function(e){r=""+e,i.call(this,e)}}),Object.defineProperty(e,t,{enumerable:n.enumerable}),{getValue:function(){return r},setValue:function(e){r=""+e},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}(e))}function xe(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var n=t.getValue(),r="";return e&&(r=ye(e)?e.checked?"true":"false":e.value),(e=r)!==n&&(t.setValue(e),!0)}function ke(e,t){var n=t.checked;return a({},t,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:null!=n?n:e._wrapperState.initialChecked})}function Ee(e,t){var n=null==t.defaultValue?"":t.defaultValue,r=null!=t.checked?t.checked:t.defaultChecked;n=ve(null!=t.value?t.value:n),e._wrapperState={initialChecked:r,initialValue:n,controlled:"checkbox"===t.type||"radio"===t.type?null!=t.checked:null!=t.value}}function Se(e,t){null!=(t=t.checked)&&Q(e,"checked",t,!1)}function Te(e,t){Se(e,t);var n=ve(t.value),r=t.type;if(null!=n)"number"===r?(0===n&&""===e.value||e.value!=n)&&(e.value=""+n):e.value!==""+n&&(e.value=""+n);else if("submit"===r||"reset"===r)return void e.removeAttribute("value");t.hasOwnProperty("value")?Ce(e,t.type,n):t.hasOwnProperty("defaultValue")&&Ce(e,t.type,ve(t.defaultValue)),null==t.checked&&null!=t.defaultChecked&&(e.defaultChecked=!!t.defaultChecked)}function _e(e,t,n){if(t.hasOwnProperty("value")||t.hasOwnProperty("defaultValue")){var r=t.type;if(!("submit"!==r&&"reset"!==r||void 0!==t.value&&null!==t.value))return;t=""+e._wrapperState.initialValue,n||t===e.value||(e.value=t),e.defaultValue=t}""!==(n=e.name)&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,""!==n&&(e.name=n)}function Ce(e,t,n){"number"===t&&e.ownerDocument.activeElement===e||(null==n?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+n&&(e.defaultValue=""+n))}function Ae(e,t){return e=a({children:void 0},t),(t=function(e){var t="";return r.Children.forEach(e,(function(e){null!=e&&(t+=e)})),t}(t.children))&&(e.children=t),e}function Pe(e,t,n,r){if(e=e.options,t){t={};for(var a=0;a<n.length;a++)t["$"+n[a]]=!0;for(n=0;n<e.length;n++)a=t.hasOwnProperty("$"+e[n].value),e[n].selected!==a&&(e[n].selected=a),a&&r&&(e[n].defaultSelected=!0)}else{for(n=""+ve(n),t=null,a=0;a<e.length;a++){if(e[a].value===n)return e[a].selected=!0,void(r&&(e[a].defaultSelected=!0));null!==t||e[a].disabled||(t=e[a])}null!==t&&(t.selected=!0)}}function Ne(e,t){if(null!=t.dangerouslySetInnerHTML)throw Error(o(91));return a({},t,{value:void 0,defaultValue:void 0,children:""+e._wrapperState.initialValue})}function Oe(e,t){var n=t.value;if(null==n){if(n=t.children,t=t.defaultValue,null!=n){if(null!=t)throw Error(o(92));if(Array.isArray(n)){if(!(1>=n.length))throw Error(o(93));n=n[0]}t=n}null==t&&(t=""),n=t}e._wrapperState={initialValue:ve(n)}}function Ie(e,t){var n=ve(t.value),r=ve(t.defaultValue);null!=n&&((n=""+n)!==e.value&&(e.value=n),null==t.defaultValue&&e.defaultValue!==n&&(e.defaultValue=n)),null!=r&&(e.defaultValue=""+r)}function Le(e){var t=e.textContent;t===e._wrapperState.initialValue&&""!==t&&null!==t&&(e.value=t)}var De="http://www.w3.org/1999/xhtml",Re="http://www.w3.org/2000/svg";function Me(e){switch(e){case"svg":return"http://www.w3.org/2000/svg";case"math":return"http://www.w3.org/1998/Math/MathML";default:return"http://www.w3.org/1999/xhtml"}}function Fe(e,t){return null==e||"http://www.w3.org/1999/xhtml"===e?Me(t):"http://www.w3.org/2000/svg"===e&&"foreignObject"===t?"http://www.w3.org/1999/xhtml":e}var Be,$e,ze=($e=function(e,t){if(e.namespaceURI!==Re||"innerHTML"in e)e.innerHTML=t;else{for((Be=Be||document.createElement("div")).innerHTML="<svg>"+t.valueOf().toString()+"</svg>",t=Be.firstChild;e.firstChild;)e.removeChild(e.firstChild);for(;t.firstChild;)e.appendChild(t.firstChild)}},"undefined"!=typeof MSApp&&MSApp.execUnsafeLocalFunction?function(e,t,n,r){MSApp.execUnsafeLocalFunction((function(){return $e(e,t)}))}:$e);function Ue(e,t){if(t){var n=e.firstChild;if(n&&n===e.lastChild&&3===n.nodeType)return void(n.nodeValue=t)}e.textContent=t}function je(e,t){var n={};return n[e.toLowerCase()]=t.toLowerCase(),n["Webkit"+e]="webkit"+t,n["Moz"+e]="moz"+t,n}var Ze={animationend:je("Animation","AnimationEnd"),animationiteration:je("Animation","AnimationIteration"),animationstart:je("Animation","AnimationStart"),transitionend:je("Transition","TransitionEnd")},He={},We={};function Ve(e){if(He[e])return He[e];if(!Ze[e])return e;var t,n=Ze[e];for(t in n)if(n.hasOwnProperty(t)&&t in We)return He[e]=n[t];return e}C&&(We=document.createElement("div").style,"AnimationEvent"in window||(delete Ze.animationend.animation,delete Ze.animationiteration.animation,delete Ze.animationstart.animation),"TransitionEvent"in window||delete Ze.transitionend.transition);var Ge=Ve("animationend"),qe=Ve("animationiteration"),Ye=Ve("animationstart"),Ke=Ve("transitionend"),Qe="abort canplay canplaythrough durationchange emptied encrypted ended error loadeddata loadedmetadata loadstart pause play playing progress ratechange seeked seeking stalled suspend timeupdate volumechange waiting".split(" "),Xe=new("function"==typeof WeakMap?WeakMap:Map);function Je(e){var t=Xe.get(e);return void 0===t&&(t=new Map,Xe.set(e,t)),t}function et(e){var t=e,n=e;if(e.alternate)for(;t.return;)t=t.return;else{e=t;do{0!=(1026&(t=e).effectTag)&&(n=t.return),e=t.return}while(e)}return 3===t.tag?n:null}function tt(e){if(13===e.tag){var t=e.memoizedState;if(null===t&&(null!==(e=e.alternate)&&(t=e.memoizedState)),null!==t)return t.dehydrated}return null}function nt(e){if(et(e)!==e)throw Error(o(188))}function rt(e){if(e=function(e){var t=e.alternate;if(!t){if(null===(t=et(e)))throw Error(o(188));return t!==e?null:e}for(var n=e,r=t;;){var a=n.return;if(null===a)break;var i=a.alternate;if(null===i){if(null!==(r=a.return)){n=r;continue}break}if(a.child===i.child){for(i=a.child;i;){if(i===n)return nt(a),e;if(i===r)return nt(a),t;i=i.sibling}throw Error(o(188))}if(n.return!==r.return)n=a,r=i;else{for(var l=!1,s=a.child;s;){if(s===n){l=!0,n=a,r=i;break}if(s===r){l=!0,r=a,n=i;break}s=s.sibling}if(!l){for(s=i.child;s;){if(s===n){l=!0,n=i,r=a;break}if(s===r){l=!0,r=i,n=a;break}s=s.sibling}if(!l)throw Error(o(189))}}if(n.alternate!==r)throw Error(o(190))}if(3!==n.tag)throw Error(o(188));return n.stateNode.current===n?e:t}(e),!e)return null;for(var t=e;;){if(5===t.tag||6===t.tag)return t;if(t.child)t.child.return=t,t=t.child;else{if(t===e)break;for(;!t.sibling;){if(!t.return||t.return===e)return null;t=t.return}t.sibling.return=t.return,t=t.sibling}}return null}function at(e,t){if(null==t)throw Error(o(30));return null==e?t:Array.isArray(e)?Array.isArray(t)?(e.push.apply(e,t),e):(e.push(t),e):Array.isArray(t)?[e].concat(t):[e,t]}function it(e,t,n){Array.isArray(e)?e.forEach(t,n):e&&t.call(n,e)}var ot=null;function lt(e){if(e){var t=e._dispatchListeners,n=e._dispatchInstances;if(Array.isArray(t))for(var r=0;r<t.length&&!e.isPropagationStopped();r++)b(e,t[r],n[r]);else t&&b(e,t,n);e._dispatchListeners=null,e._dispatchInstances=null,e.isPersistent()||e.constructor.release(e)}}function st(e){if(null!==e&&(ot=at(ot,e)),e=ot,ot=null,e){if(it(e,lt),ot)throw Error(o(95));if(u)throw e=d,u=!1,d=null,e}}function ct(e){return(e=e.target||e.srcElement||window).correspondingUseElement&&(e=e.correspondingUseElement),3===e.nodeType?e.parentNode:e}function ut(e){if(!C)return!1;var t=(e="on"+e)in document;return t||((t=document.createElement("div")).setAttribute(e,"return;"),t="function"==typeof t[e]),t}var dt=[];function pt(e){e.topLevelType=null,e.nativeEvent=null,e.targetInst=null,e.ancestors.length=0,10>dt.length&&dt.push(e)}function ft(e,t,n,r){if(dt.length){var a=dt.pop();return a.topLevelType=e,a.eventSystemFlags=r,a.nativeEvent=t,a.targetInst=n,a}return{topLevelType:e,eventSystemFlags:r,nativeEvent:t,targetInst:n,ancestors:[]}}function mt(e){var t=e.targetInst,n=t;do{if(!n){e.ancestors.push(n);break}var r=n;if(3===r.tag)r=r.stateNode.containerInfo;else{for(;r.return;)r=r.return;r=3!==r.tag?null:r.stateNode.containerInfo}if(!r)break;5!==(t=n.tag)&&6!==t||e.ancestors.push(n),n=Ln(r)}while(n);for(n=0;n<e.ancestors.length;n++){t=e.ancestors[n];var a=ct(e.nativeEvent);r=e.topLevelType;var i=e.nativeEvent,o=e.eventSystemFlags;0===n&&(o|=64);for(var l=null,s=0;s<k.length;s++){var c=k[s];c&&(c=c.extractEvents(r,t,i,a,o))&&(l=at(l,c))}st(l)}}function gt(e,t,n){if(!n.has(e)){switch(e){case"scroll":Yt(t,"scroll",!0);break;case"focus":case"blur":Yt(t,"focus",!0),Yt(t,"blur",!0),n.set("blur",null),n.set("focus",null);break;case"cancel":case"close":ut(e)&&Yt(t,e,!0);break;case"invalid":case"submit":case"reset":break;default:-1===Qe.indexOf(e)&&qt(e,t)}n.set(e,null)}}var ht,bt,vt,yt=!1,wt=[],xt=null,kt=null,Et=null,St=new Map,Tt=new Map,_t=[],Ct="mousedown mouseup touchcancel touchend touchstart auxclick dblclick pointercancel pointerdown pointerup dragend dragstart drop compositionend compositionstart keydown keypress keyup input textInput close cancel copy cut paste click change contextmenu reset submit".split(" "),At="focus blur dragenter dragleave mouseover mouseout pointerover pointerout gotpointercapture lostpointercapture".split(" ");function Pt(e,t,n,r,a){return{blockedOn:e,topLevelType:t,eventSystemFlags:32|n,nativeEvent:a,container:r}}function Nt(e,t){switch(e){case"focus":case"blur":xt=null;break;case"dragenter":case"dragleave":kt=null;break;case"mouseover":case"mouseout":Et=null;break;case"pointerover":case"pointerout":St.delete(t.pointerId);break;case"gotpointercapture":case"lostpointercapture":Tt.delete(t.pointerId)}}function Ot(e,t,n,r,a,i){return null===e||e.nativeEvent!==i?(e=Pt(t,n,r,a,i),null!==t&&(null!==(t=Dn(t))&&bt(t)),e):(e.eventSystemFlags|=r,e)}function It(e){var t=Ln(e.target);if(null!==t){var n=et(t);if(null!==n)if(13===(t=n.tag)){if(null!==(t=tt(n)))return e.blockedOn=t,void i.unstable_runWithPriority(e.priority,(function(){vt(n)}))}else if(3===t&&n.stateNode.hydrate)return void(e.blockedOn=3===n.tag?n.stateNode.containerInfo:null)}e.blockedOn=null}function Lt(e){if(null!==e.blockedOn)return!1;var t=Jt(e.topLevelType,e.eventSystemFlags,e.container,e.nativeEvent);if(null!==t){var n=Dn(t);return null!==n&&bt(n),e.blockedOn=t,!1}return!0}function Dt(e,t,n){Lt(e)&&n.delete(t)}function Rt(){for(yt=!1;0<wt.length;){var e=wt[0];if(null!==e.blockedOn){null!==(e=Dn(e.blockedOn))&&ht(e);break}var t=Jt(e.topLevelType,e.eventSystemFlags,e.container,e.nativeEvent);null!==t?e.blockedOn=t:wt.shift()}null!==xt&&Lt(xt)&&(xt=null),null!==kt&&Lt(kt)&&(kt=null),null!==Et&&Lt(Et)&&(Et=null),St.forEach(Dt),Tt.forEach(Dt)}function Mt(e,t){e.blockedOn===t&&(e.blockedOn=null,yt||(yt=!0,i.unstable_scheduleCallback(i.unstable_NormalPriority,Rt)))}function Ft(e){function t(t){return Mt(t,e)}if(0<wt.length){Mt(wt[0],e);for(var n=1;n<wt.length;n++){var r=wt[n];r.blockedOn===e&&(r.blockedOn=null)}}for(null!==xt&&Mt(xt,e),null!==kt&&Mt(kt,e),null!==Et&&Mt(Et,e),St.forEach(t),Tt.forEach(t),n=0;n<_t.length;n++)(r=_t[n]).blockedOn===e&&(r.blockedOn=null);for(;0<_t.length&&null===(n=_t[0]).blockedOn;)It(n),null===n.blockedOn&&_t.shift()}var Bt={},$t=new Map,zt=new Map,Ut=["abort","abort",Ge,"animationEnd",qe,"animationIteration",Ye,"animationStart","canplay","canPlay","canplaythrough","canPlayThrough","durationchange","durationChange","emptied","emptied","encrypted","encrypted","ended","ended","error","error","gotpointercapture","gotPointerCapture","load","load","loadeddata","loadedData","loadedmetadata","loadedMetadata","loadstart","loadStart","lostpointercapture","lostPointerCapture","playing","playing","progress","progress","seeking","seeking","stalled","stalled","suspend","suspend","timeupdate","timeUpdate",Ke,"transitionEnd","waiting","waiting"];function jt(e,t){for(var n=0;n<e.length;n+=2){var r=e[n],a=e[n+1],i="on"+(a[0].toUpperCase()+a.slice(1));i={phasedRegistrationNames:{bubbled:i,captured:i+"Capture"},dependencies:[r],eventPriority:t},zt.set(r,t),$t.set(r,i),Bt[a]=i}}jt("blur blur cancel cancel click click close close contextmenu contextMenu copy copy cut cut auxclick auxClick dblclick doubleClick dragend dragEnd dragstart dragStart drop drop focus focus input input invalid invalid keydown keyDown keypress keyPress keyup keyUp mousedown mouseDown mouseup mouseUp paste paste pause pause play play pointercancel pointerCancel pointerdown pointerDown pointerup pointerUp ratechange rateChange reset reset seeked seeked submit submit touchcancel touchCancel touchend touchEnd touchstart touchStart volumechange volumeChange".split(" "),0),jt("drag drag dragenter dragEnter dragexit dragExit dragleave dragLeave dragover dragOver mousemove mouseMove mouseout mouseOut mouseover mouseOver pointermove pointerMove pointerout pointerOut pointerover pointerOver scroll scroll toggle toggle touchmove touchMove wheel wheel".split(" "),1),jt(Ut,2);for(var Zt="change selectionchange textInput compositionstart compositionend compositionupdate".split(" "),Ht=0;Ht<Zt.length;Ht++)zt.set(Zt[Ht],0);var Wt=i.unstable_UserBlockingPriority,Vt=i.unstable_runWithPriority,Gt=!0;function qt(e,t){Yt(t,e,!1)}function Yt(e,t,n){var r=zt.get(t);switch(void 0===r?2:r){case 0:r=Kt.bind(null,t,1,e);break;case 1:r=Qt.bind(null,t,1,e);break;default:r=Xt.bind(null,t,1,e)}n?e.addEventListener(t,r,!0):e.addEventListener(t,r,!1)}function Kt(e,t,n,r){B||M();var a=Xt,i=B;B=!0;try{R(a,e,t,n,r)}finally{(B=i)||z()}}function Qt(e,t,n,r){Vt(Wt,Xt.bind(null,e,t,n,r))}function Xt(e,t,n,r){if(Gt)if(0<wt.length&&-1<Ct.indexOf(e))e=Pt(null,e,t,n,r),wt.push(e);else{var a=Jt(e,t,n,r);if(null===a)Nt(e,r);else if(-1<Ct.indexOf(e))e=Pt(a,e,t,n,r),wt.push(e);else if(!function(e,t,n,r,a){switch(t){case"focus":return xt=Ot(xt,e,t,n,r,a),!0;case"dragenter":return kt=Ot(kt,e,t,n,r,a),!0;case"mouseover":return Et=Ot(Et,e,t,n,r,a),!0;case"pointerover":var i=a.pointerId;return St.set(i,Ot(St.get(i)||null,e,t,n,r,a)),!0;case"gotpointercapture":return i=a.pointerId,Tt.set(i,Ot(Tt.get(i)||null,e,t,n,r,a)),!0}return!1}(a,e,t,n,r)){Nt(e,r),e=ft(e,r,null,t);try{U(mt,e)}finally{pt(e)}}}}function Jt(e,t,n,r){if(null!==(n=Ln(n=ct(r)))){var a=et(n);if(null===a)n=null;else{var i=a.tag;if(13===i){if(null!==(n=tt(a)))return n;n=null}else if(3===i){if(a.stateNode.hydrate)return 3===a.tag?a.stateNode.containerInfo:null;n=null}else a!==n&&(n=null)}}e=ft(e,r,n,t);try{U(mt,e)}finally{pt(e)}return null}var en={animationIterationCount:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},tn=["Webkit","ms","Moz","O"];function nn(e,t,n){return null==t||"boolean"==typeof t||""===t?"":n||"number"!=typeof t||0===t||en.hasOwnProperty(e)&&en[e]?(""+t).trim():t+"px"}function rn(e,t){for(var n in e=e.style,t)if(t.hasOwnProperty(n)){var r=0===n.indexOf("--"),a=nn(n,t[n],r);"float"===n&&(n="cssFloat"),r?e.setProperty(n,a):e[n]=a}}Object.keys(en).forEach((function(e){tn.forEach((function(t){t=t+e.charAt(0).toUpperCase()+e.substring(1),en[t]=en[e]}))}));var an=a({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function on(e,t){if(t){if(an[e]&&(null!=t.children||null!=t.dangerouslySetInnerHTML))throw Error(o(137,e,""));if(null!=t.dangerouslySetInnerHTML){if(null!=t.children)throw Error(o(60));if("object"!=typeof t.dangerouslySetInnerHTML||!("__html"in t.dangerouslySetInnerHTML))throw Error(o(61))}if(null!=t.style&&"object"!=typeof t.style)throw Error(o(62,""))}}function ln(e,t){if(-1===e.indexOf("-"))return"string"==typeof t.is;switch(e){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}var sn=De;function cn(e,t){var n=Je(e=9===e.nodeType||11===e.nodeType?e:e.ownerDocument);t=T[t];for(var r=0;r<t.length;r++)gt(t[r],e,n)}function un(){}function dn(e){if(void 0===(e=e||("undefined"!=typeof document?document:void 0)))return null;try{return e.activeElement||e.body}catch(t){return e.body}}function pn(e){for(;e&&e.firstChild;)e=e.firstChild;return e}function fn(e,t){var n,r=pn(e);for(e=0;r;){if(3===r.nodeType){if(n=e+r.textContent.length,e<=t&&n>=t)return{node:r,offset:t-e};e=n}e:{for(;r;){if(r.nextSibling){r=r.nextSibling;break e}r=r.parentNode}r=void 0}r=pn(r)}}function mn(e,t){return!(!e||!t)&&(e===t||(!e||3!==e.nodeType)&&(t&&3===t.nodeType?mn(e,t.parentNode):"contains"in e?e.contains(t):!!e.compareDocumentPosition&&!!(16&e.compareDocumentPosition(t))))}function gn(){for(var e=window,t=dn();t instanceof e.HTMLIFrameElement;){try{var n="string"==typeof t.contentWindow.location.href}catch(r){n=!1}if(!n)break;t=dn((e=t.contentWindow).document)}return t}function hn(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&("input"===t&&("text"===e.type||"search"===e.type||"tel"===e.type||"url"===e.type||"password"===e.type)||"textarea"===t||"true"===e.contentEditable)}var bn="$",vn="/$",yn="$?",wn="$!",xn=null,kn=null;function En(e,t){switch(e){case"button":case"input":case"select":case"textarea":return!!t.autoFocus}return!1}function Sn(e,t){return"textarea"===e||"option"===e||"noscript"===e||"string"==typeof t.children||"number"==typeof t.children||"object"==typeof t.dangerouslySetInnerHTML&&null!==t.dangerouslySetInnerHTML&&null!=t.dangerouslySetInnerHTML.__html}var Tn="function"==typeof setTimeout?setTimeout:void 0,_n="function"==typeof clearTimeout?clearTimeout:void 0;function Cn(e){for(;null!=e;e=e.nextSibling){var t=e.nodeType;if(1===t||3===t)break}return e}function An(e){e=e.previousSibling;for(var t=0;e;){if(8===e.nodeType){var n=e.data;if(n===bn||n===wn||n===yn){if(0===t)return e;t--}else n===vn&&t++}e=e.previousSibling}return null}var Pn=Math.random().toString(36).slice(2),Nn="__reactInternalInstance$"+Pn,On="__reactEventHandlers$"+Pn,In="__reactContainere$"+Pn;function Ln(e){var t=e[Nn];if(t)return t;for(var n=e.parentNode;n;){if(t=n[In]||n[Nn]){if(n=t.alternate,null!==t.child||null!==n&&null!==n.child)for(e=An(e);null!==e;){if(n=e[Nn])return n;e=An(e)}return t}n=(e=n).parentNode}return null}function Dn(e){return!(e=e[Nn]||e[In])||5!==e.tag&&6!==e.tag&&13!==e.tag&&3!==e.tag?null:e}function Rn(e){if(5===e.tag||6===e.tag)return e.stateNode;throw Error(o(33))}function Mn(e){return e[On]||null}function Fn(e){do{e=e.return}while(e&&5!==e.tag);return e||null}function Bn(e,t){var n=e.stateNode;if(!n)return null;var r=m(n);if(!r)return null;n=r[t];e:switch(t){case"onClick":case"onClickCapture":case"onDoubleClick":case"onDoubleClickCapture":case"onMouseDown":case"onMouseDownCapture":case"onMouseMove":case"onMouseMoveCapture":case"onMouseUp":case"onMouseUpCapture":case"onMouseEnter":(r=!r.disabled)||(r=!("button"===(e=e.type)||"input"===e||"select"===e||"textarea"===e)),e=!r;break e;default:e=!1}if(e)return null;if(n&&"function"!=typeof n)throw Error(o(231,t,typeof n));return n}function $n(e,t,n){(t=Bn(e,n.dispatchConfig.phasedRegistrationNames[t]))&&(n._dispatchListeners=at(n._dispatchListeners,t),n._dispatchInstances=at(n._dispatchInstances,e))}function zn(e){if(e&&e.dispatchConfig.phasedRegistrationNames){for(var t=e._targetInst,n=[];t;)n.push(t),t=Fn(t);for(t=n.length;0<t--;)$n(n[t],"captured",e);for(t=0;t<n.length;t++)$n(n[t],"bubbled",e)}}function Un(e,t,n){e&&n&&n.dispatchConfig.registrationName&&(t=Bn(e,n.dispatchConfig.registrationName))&&(n._dispatchListeners=at(n._dispatchListeners,t),n._dispatchInstances=at(n._dispatchInstances,e))}function jn(e){e&&e.dispatchConfig.registrationName&&Un(e._targetInst,null,e)}function Zn(e){it(e,zn)}var Hn=null,Wn=null,Vn=null;function Gn(){if(Vn)return Vn;var e,t,n=Wn,r=n.length,a="value"in Hn?Hn.value:Hn.textContent,i=a.length;for(e=0;e<r&&n[e]===a[e];e++);var o=r-e;for(t=1;t<=o&&n[r-t]===a[i-t];t++);return Vn=a.slice(e,1<t?1-t:void 0)}function qn(){return!0}function Yn(){return!1}function Kn(e,t,n,r){for(var a in this.dispatchConfig=e,this._targetInst=t,this.nativeEvent=n,e=this.constructor.Interface)e.hasOwnProperty(a)&&((t=e[a])?this[a]=t(n):"target"===a?this.target=r:this[a]=n[a]);return this.isDefaultPrevented=(null!=n.defaultPrevented?n.defaultPrevented:!1===n.returnValue)?qn:Yn,this.isPropagationStopped=Yn,this}function Qn(e,t,n,r){if(this.eventPool.length){var a=this.eventPool.pop();return this.call(a,e,t,n,r),a}return new this(e,t,n,r)}function Xn(e){if(!(e instanceof this))throw Error(o(279));e.destructor(),10>this.eventPool.length&&this.eventPool.push(e)}function Jn(e){e.eventPool=[],e.getPooled=Qn,e.release=Xn}a(Kn.prototype,{preventDefault:function(){this.defaultPrevented=!0;var e=this.nativeEvent;e&&(e.preventDefault?e.preventDefault():"unknown"!=typeof e.returnValue&&(e.returnValue=!1),this.isDefaultPrevented=qn)},stopPropagation:function(){var e=this.nativeEvent;e&&(e.stopPropagation?e.stopPropagation():"unknown"!=typeof e.cancelBubble&&(e.cancelBubble=!0),this.isPropagationStopped=qn)},persist:function(){this.isPersistent=qn},isPersistent:Yn,destructor:function(){var e,t=this.constructor.Interface;for(e in t)this[e]=null;this.nativeEvent=this._targetInst=this.dispatchConfig=null,this.isPropagationStopped=this.isDefaultPrevented=Yn,this._dispatchInstances=this._dispatchListeners=null}}),Kn.Interface={type:null,target:null,currentTarget:function(){return null},eventPhase:null,bubbles:null,cancelable:null,timeStamp:function(e){return e.timeStamp||Date.now()},defaultPrevented:null,isTrusted:null},Kn.extend=function(e){function t(){}function n(){return r.apply(this,arguments)}var r=this;t.prototype=r.prototype;var i=new t;return a(i,n.prototype),n.prototype=i,n.prototype.constructor=n,n.Interface=a({},r.Interface,e),n.extend=r.extend,Jn(n),n},Jn(Kn);var er=Kn.extend({data:null}),tr=Kn.extend({data:null}),nr=[9,13,27,32],rr=C&&"CompositionEvent"in window,ar=null;C&&"documentMode"in document&&(ar=document.documentMode);var ir=C&&"TextEvent"in window&&!ar,or=C&&(!rr||ar&&8<ar&&11>=ar),lr=String.fromCharCode(32),sr={beforeInput:{phasedRegistrationNames:{bubbled:"onBeforeInput",captured:"onBeforeInputCapture"},dependencies:["compositionend","keypress","textInput","paste"]},compositionEnd:{phasedRegistrationNames:{bubbled:"onCompositionEnd",captured:"onCompositionEndCapture"},dependencies:"blur compositionend keydown keypress keyup mousedown".split(" ")},compositionStart:{phasedRegistrationNames:{bubbled:"onCompositionStart",captured:"onCompositionStartCapture"},dependencies:"blur compositionstart keydown keypress keyup mousedown".split(" ")},compositionUpdate:{phasedRegistrationNames:{bubbled:"onCompositionUpdate",captured:"onCompositionUpdateCapture"},dependencies:"blur compositionupdate keydown keypress keyup mousedown".split(" ")}},cr=!1;function ur(e,t){switch(e){case"keyup":return-1!==nr.indexOf(t.keyCode);case"keydown":return 229!==t.keyCode;case"keypress":case"mousedown":case"blur":return!0;default:return!1}}function dr(e){return"object"==typeof(e=e.detail)&&"data"in e?e.data:null}var pr=!1;var fr={eventTypes:sr,extractEvents:function(e,t,n,r){var a;if(rr)e:{switch(e){case"compositionstart":var i=sr.compositionStart;break e;case"compositionend":i=sr.compositionEnd;break e;case"compositionupdate":i=sr.compositionUpdate;break e}i=void 0}else pr?ur(e,n)&&(i=sr.compositionEnd):"keydown"===e&&229===n.keyCode&&(i=sr.compositionStart);return i?(or&&"ko"!==n.locale&&(pr||i!==sr.compositionStart?i===sr.compositionEnd&&pr&&(a=Gn()):(Wn="value"in(Hn=r)?Hn.value:Hn.textContent,pr=!0)),i=er.getPooled(i,t,n,r),a?i.data=a:null!==(a=dr(n))&&(i.data=a),Zn(i),a=i):a=null,(e=ir?function(e,t){switch(e){case"compositionend":return dr(t);case"keypress":return 32!==t.which?null:(cr=!0,lr);case"textInput":return(e=t.data)===lr&&cr?null:e;default:return null}}(e,n):function(e,t){if(pr)return"compositionend"===e||!rr&&ur(e,t)?(e=Gn(),Vn=Wn=Hn=null,pr=!1,e):null;switch(e){case"paste":default:return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1<t.char.length)return t.char;if(t.which)return String.fromCharCode(t.which)}return null;case"compositionend":return or&&"ko"!==t.locale?null:t.data}}(e,n))?((t=tr.getPooled(sr.beforeInput,t,n,r)).data=e,Zn(t)):t=null,null===a?t:null===t?a:[a,t]}},mr={color:!0,date:!0,datetime:!0,"datetime-local":!0,email:!0,month:!0,number:!0,password:!0,range:!0,search:!0,tel:!0,text:!0,time:!0,url:!0,week:!0};function gr(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return"input"===t?!!mr[e.type]:"textarea"===t}var hr={change:{phasedRegistrationNames:{bubbled:"onChange",captured:"onChangeCapture"},dependencies:"blur change click focus input keydown keyup selectionchange".split(" ")}};function br(e,t,n){return(e=Kn.getPooled(hr.change,e,t,n)).type="change",I(n),Zn(e),e}var vr=null,yr=null;function wr(e){st(e)}function xr(e){if(xe(Rn(e)))return e}function kr(e,t){if("change"===e)return t}var Er=!1;function Sr(){vr&&(vr.detachEvent("onpropertychange",Tr),yr=vr=null)}function Tr(e){if("value"===e.propertyName&&xr(yr))if(e=br(yr,e,ct(e)),B)st(e);else{B=!0;try{D(wr,e)}finally{B=!1,z()}}}function _r(e,t,n){"focus"===e?(Sr(),yr=n,(vr=t).attachEvent("onpropertychange",Tr)):"blur"===e&&Sr()}function Cr(e){if("selectionchange"===e||"keyup"===e||"keydown"===e)return xr(yr)}function Ar(e,t){if("click"===e)return xr(t)}function Pr(e,t){if("input"===e||"change"===e)return xr(t)}C&&(Er=ut("input")&&(!document.documentMode||9<document.documentMode));var Nr={eventTypes:hr,_isInputEventSupported:Er,extractEvents:function(e,t,n,r){var a=t?Rn(t):window,i=a.nodeName&&a.nodeName.toLowerCase();if("select"===i||"input"===i&&"file"===a.type)var o=kr;else if(gr(a))if(Er)o=Pr;else{o=Cr;var l=_r}else(i=a.nodeName)&&"input"===i.toLowerCase()&&("checkbox"===a.type||"radio"===a.type)&&(o=Ar);if(o&&(o=o(e,t)))return br(o,n,r);l&&l(e,a,t),"blur"===e&&(e=a._wrapperState)&&e.controlled&&"number"===a.type&&Ce(a,"number",a.value)}},Or=Kn.extend({view:null,detail:null}),Ir={Alt:"altKey",Control:"ctrlKey",Meta:"metaKey",Shift:"shiftKey"};function Lr(e){var t=this.nativeEvent;return t.getModifierState?t.getModifierState(e):!!(e=Ir[e])&&!!t[e]}function Dr(){return Lr}var Rr=0,Mr=0,Fr=!1,Br=!1,$r=Or.extend({screenX:null,screenY:null,clientX:null,clientY:null,pageX:null,pageY:null,ctrlKey:null,shiftKey:null,altKey:null,metaKey:null,getModifierState:Dr,button:null,buttons:null,relatedTarget:function(e){return e.relatedTarget||(e.fromElement===e.srcElement?e.toElement:e.fromElement)},movementX:function(e){if("movementX"in e)return e.movementX;var t=Rr;return Rr=e.screenX,Fr?"mousemove"===e.type?e.screenX-t:0:(Fr=!0,0)},movementY:function(e){if("movementY"in e)return e.movementY;var t=Mr;return Mr=e.screenY,Br?"mousemove"===e.type?e.screenY-t:0:(Br=!0,0)}}),zr=$r.extend({pointerId:null,width:null,height:null,pressure:null,tangentialPressure:null,tiltX:null,tiltY:null,twist:null,pointerType:null,isPrimary:null}),Ur={mouseEnter:{registrationName:"onMouseEnter",dependencies:["mouseout","mouseover"]},mouseLeave:{registrationName:"onMouseLeave",dependencies:["mouseout","mouseover"]},pointerEnter:{registrationName:"onPointerEnter",dependencies:["pointerout","pointerover"]},pointerLeave:{registrationName:"onPointerLeave",dependencies:["pointerout","pointerover"]}},jr={eventTypes:Ur,extractEvents:function(e,t,n,r,a){var i="mouseover"===e||"pointerover"===e,o="mouseout"===e||"pointerout"===e;if(i&&0==(32&a)&&(n.relatedTarget||n.fromElement)||!o&&!i)return null;(i=r.window===r?r:(i=r.ownerDocument)?i.defaultView||i.parentWindow:window,o)?(o=t,null!==(t=(t=n.relatedTarget||n.toElement)?Ln(t):null)&&(t!==et(t)||5!==t.tag&&6!==t.tag)&&(t=null)):o=null;if(o===t)return null;if("mouseout"===e||"mouseover"===e)var l=$r,s=Ur.mouseLeave,c=Ur.mouseEnter,u="mouse";else"pointerout"!==e&&"pointerover"!==e||(l=zr,s=Ur.pointerLeave,c=Ur.pointerEnter,u="pointer");if(e=null==o?i:Rn(o),i=null==t?i:Rn(t),(s=l.getPooled(s,o,n,r)).type=u+"leave",s.target=e,s.relatedTarget=i,(n=l.getPooled(c,t,n,r)).type=u+"enter",n.target=i,n.relatedTarget=e,u=t,(r=o)&&u)e:{for(c=u,o=0,e=l=r;e;e=Fn(e))o++;for(e=0,t=c;t;t=Fn(t))e++;for(;0<o-e;)l=Fn(l),o--;for(;0<e-o;)c=Fn(c),e--;for(;o--;){if(l===c||l===c.alternate)break e;l=Fn(l),c=Fn(c)}l=null}else l=null;for(c=l,l=[];r&&r!==c&&(null===(o=r.alternate)||o!==c);)l.push(r),r=Fn(r);for(r=[];u&&u!==c&&(null===(o=u.alternate)||o!==c);)r.push(u),u=Fn(u);for(u=0;u<l.length;u++)Un(l[u],"bubbled",s);for(u=r.length;0<u--;)Un(r[u],"captured",n);return 0==(64&a)?[s]:[s,n]}};var Zr="function"==typeof Object.is?Object.is:function(e,t){return e===t&&(0!==e||1/e==1/t)||e!=e&&t!=t},Hr=Object.prototype.hasOwnProperty;function Wr(e,t){if(Zr(e,t))return!0;if("object"!=typeof e||null===e||"object"!=typeof t||null===t)return!1;var n=Object.keys(e),r=Object.keys(t);if(n.length!==r.length)return!1;for(r=0;r<n.length;r++)if(!Hr.call(t,n[r])||!Zr(e[n[r]],t[n[r]]))return!1;return!0}var Vr=C&&"documentMode"in document&&11>=document.documentMode,Gr={select:{phasedRegistrationNames:{bubbled:"onSelect",captured:"onSelectCapture"},dependencies:"blur contextmenu dragend focus keydown keyup mousedown mouseup selectionchange".split(" ")}},qr=null,Yr=null,Kr=null,Qr=!1;function Xr(e,t){var n=t.window===t?t.document:9===t.nodeType?t:t.ownerDocument;return Qr||null==qr||qr!==dn(n)?null:("selectionStart"in(n=qr)&&hn(n)?n={start:n.selectionStart,end:n.selectionEnd}:n={anchorNode:(n=(n.ownerDocument&&n.ownerDocument.defaultView||window).getSelection()).anchorNode,anchorOffset:n.anchorOffset,focusNode:n.focusNode,focusOffset:n.focusOffset},Kr&&Wr(Kr,n)?null:(Kr=n,(e=Kn.getPooled(Gr.select,Yr,e,t)).type="select",e.target=qr,Zn(e),e))}var Jr={eventTypes:Gr,extractEvents:function(e,t,n,r,a,i){if(!(i=!(a=i||(r.window===r?r.document:9===r.nodeType?r:r.ownerDocument)))){e:{a=Je(a),i=T.onSelect;for(var o=0;o<i.length;o++)if(!a.has(i[o])){a=!1;break e}a=!0}i=!a}if(i)return null;switch(a=t?Rn(t):window,e){case"focus":(gr(a)||"true"===a.contentEditable)&&(qr=a,Yr=t,Kr=null);break;case"blur":Kr=Yr=qr=null;break;case"mousedown":Qr=!0;break;case"contextmenu":case"mouseup":case"dragend":return Qr=!1,Xr(n,r);case"selectionchange":if(Vr)break;case"keydown":case"keyup":return Xr(n,r)}return null}},ea=Kn.extend({animationName:null,elapsedTime:null,pseudoElement:null}),ta=Kn.extend({clipboardData:function(e){return"clipboardData"in e?e.clipboardData:window.clipboardData}}),na=Or.extend({relatedTarget:null});function ra(e){var t=e.keyCode;return"charCode"in e?0===(e=e.charCode)&&13===t&&(e=13):e=t,10===e&&(e=13),32<=e||13===e?e:0}var aa={Esc:"Escape",Spacebar:" ",Left:"ArrowLeft",Up:"ArrowUp",Right:"ArrowRight",Down:"ArrowDown",Del:"Delete",Win:"OS",Menu:"ContextMenu",Apps:"ContextMenu",Scroll:"ScrollLock",MozPrintableKey:"Unidentified"},ia={8:"Backspace",9:"Tab",12:"Clear",13:"Enter",16:"Shift",17:"Control",18:"Alt",19:"Pause",20:"CapsLock",27:"Escape",32:" ",33:"PageUp",34:"PageDown",35:"End",36:"Home",37:"ArrowLeft",38:"ArrowUp",39:"ArrowRight",40:"ArrowDown",45:"Insert",46:"Delete",112:"F1",113:"F2",114:"F3",115:"F4",116:"F5",117:"F6",118:"F7",119:"F8",120:"F9",121:"F10",122:"F11",123:"F12",144:"NumLock",145:"ScrollLock",224:"Meta"},oa=Or.extend({key:function(e){if(e.key){var t=aa[e.key]||e.key;if("Unidentified"!==t)return t}return"keypress"===e.type?13===(e=ra(e))?"Enter":String.fromCharCode(e):"keydown"===e.type||"keyup"===e.type?ia[e.keyCode]||"Unidentified":""},location:null,ctrlKey:null,shiftKey:null,altKey:null,metaKey:null,repeat:null,locale:null,getModifierState:Dr,charCode:function(e){return"keypress"===e.type?ra(e):0},keyCode:function(e){return"keydown"===e.type||"keyup"===e.type?e.keyCode:0},which:function(e){return"keypress"===e.type?ra(e):"keydown"===e.type||"keyup"===e.type?e.keyCode:0}}),la=$r.extend({dataTransfer:null}),sa=Or.extend({touches:null,targetTouches:null,changedTouches:null,altKey:null,metaKey:null,ctrlKey:null,shiftKey:null,getModifierState:Dr}),ca=Kn.extend({propertyName:null,elapsedTime:null,pseudoElement:null}),ua=$r.extend({deltaX:function(e){return"deltaX"in e?e.deltaX:"wheelDeltaX"in e?-e.wheelDeltaX:0},deltaY:function(e){return"deltaY"in e?e.deltaY:"wheelDeltaY"in e?-e.wheelDeltaY:"wheelDelta"in e?-e.wheelDelta:0},deltaZ:null,deltaMode:null}),da={eventTypes:Bt,extractEvents:function(e,t,n,r){var a=$t.get(e);if(!a)return null;switch(e){case"keypress":if(0===ra(n))return null;case"keydown":case"keyup":e=oa;break;case"blur":case"focus":e=na;break;case"click":if(2===n.button)return null;case"auxclick":case"dblclick":case"mousedown":case"mousemove":case"mouseup":case"mouseout":case"mouseover":case"contextmenu":e=$r;break;case"drag":case"dragend":case"dragenter":case"dragexit":case"dragleave":case"dragover":case"dragstart":case"drop":e=la;break;case"touchcancel":case"touchend":case"touchmove":case"touchstart":e=sa;break;case Ge:case qe:case Ye:e=ea;break;case Ke:e=ca;break;case"scroll":e=Or;break;case"wheel":e=ua;break;case"copy":case"cut":case"paste":e=ta;break;case"gotpointercapture":case"lostpointercapture":case"pointercancel":case"pointerdown":case"pointermove":case"pointerout":case"pointerover":case"pointerup":e=zr;break;default:e=Kn}return Zn(t=e.getPooled(a,t,n,r)),t}};if(v)throw Error(o(101));v=Array.prototype.slice.call("ResponderEventPlugin SimpleEventPlugin EnterLeaveEventPlugin ChangeEventPlugin SelectEventPlugin BeforeInputEventPlugin".split(" ")),w(),m=Mn,g=Dn,h=Rn,_({SimpleEventPlugin:da,EnterLeaveEventPlugin:jr,ChangeEventPlugin:Nr,SelectEventPlugin:Jr,BeforeInputEventPlugin:fr});var pa=[],fa=-1;function ma(e){0>fa||(e.current=pa[fa],pa[fa]=null,fa--)}function ga(e,t){fa++,pa[fa]=e.current,e.current=t}var ha={},ba={current:ha},va={current:!1},ya=ha;function wa(e,t){var n=e.type.contextTypes;if(!n)return ha;var r=e.stateNode;if(r&&r.__reactInternalMemoizedUnmaskedChildContext===t)return r.__reactInternalMemoizedMaskedChildContext;var a,i={};for(a in n)i[a]=t[a];return r&&((e=e.stateNode).__reactInternalMemoizedUnmaskedChildContext=t,e.__reactInternalMemoizedMaskedChildContext=i),i}function xa(e){return null!=(e=e.childContextTypes)}function ka(){ma(va),ma(ba)}function Ea(e,t,n){if(ba.current!==ha)throw Error(o(168));ga(ba,t),ga(va,n)}function Sa(e,t,n){var r=e.stateNode;if(e=t.childContextTypes,"function"!=typeof r.getChildContext)return n;for(var i in r=r.getChildContext())if(!(i in e))throw Error(o(108,he(t)||"Unknown",i));return a({},n,{},r)}function Ta(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||ha,ya=ba.current,ga(ba,e),ga(va,va.current),!0}function _a(e,t,n){var r=e.stateNode;if(!r)throw Error(o(169));n?(e=Sa(e,t,ya),r.__reactInternalMemoizedMergedChildContext=e,ma(va),ma(ba),ga(ba,e)):ma(va),ga(va,n)}var Ca=i.unstable_runWithPriority,Aa=i.unstable_scheduleCallback,Pa=i.unstable_cancelCallback,Na=i.unstable_requestPaint,Oa=i.unstable_now,Ia=i.unstable_getCurrentPriorityLevel,La=i.unstable_ImmediatePriority,Da=i.unstable_UserBlockingPriority,Ra=i.unstable_NormalPriority,Ma=i.unstable_LowPriority,Fa=i.unstable_IdlePriority,Ba={},$a=i.unstable_shouldYield,za=void 0!==Na?Na:function(){},Ua=null,ja=null,Za=!1,Ha=Oa(),Wa=1e4>Ha?Oa:function(){return Oa()-Ha};function Va(){switch(Ia()){case La:return 99;case Da:return 98;case Ra:return 97;case Ma:return 96;case Fa:return 95;default:throw Error(o(332))}}function Ga(e){switch(e){case 99:return La;case 98:return Da;case 97:return Ra;case 96:return Ma;case 95:return Fa;default:throw Error(o(332))}}function qa(e,t){return e=Ga(e),Ca(e,t)}function Ya(e,t,n){return e=Ga(e),Aa(e,t,n)}function Ka(e){return null===Ua?(Ua=[e],ja=Aa(La,Xa)):Ua.push(e),Ba}function Qa(){if(null!==ja){var e=ja;ja=null,Pa(e)}Xa()}function Xa(){if(!Za&&null!==Ua){Za=!0;var e=0;try{var t=Ua;qa(99,(function(){for(;e<t.length;e++){var n=t[e];do{n=n(!0)}while(null!==n)}})),Ua=null}catch(n){throw null!==Ua&&(Ua=Ua.slice(e+1)),Aa(La,Qa),n}finally{Za=!1}}}function Ja(e,t,n){return 1073741821-(1+((1073741821-e+t/10)/(n/=10)|0))*n}function ei(e,t){if(e&&e.defaultProps)for(var n in t=a({},t),e=e.defaultProps)void 0===t[n]&&(t[n]=e[n]);return t}var ti={current:null},ni=null,ri=null,ai=null;function ii(){ai=ri=ni=null}function oi(e){var t=ti.current;ma(ti),e.type._context._currentValue=t}function li(e,t){for(;null!==e;){var n=e.alternate;if(e.childExpirationTime<t)e.childExpirationTime=t,null!==n&&n.childExpirationTime<t&&(n.childExpirationTime=t);else{if(!(null!==n&&n.childExpirationTime<t))break;n.childExpirationTime=t}e=e.return}}function si(e,t){ni=e,ai=ri=null,null!==(e=e.dependencies)&&null!==e.firstContext&&(e.expirationTime>=t&&(Mo=!0),e.firstContext=null)}function ci(e,t){if(ai!==e&&!1!==t&&0!==t)if("number"==typeof t&&1073741823!==t||(ai=e,t=1073741823),t={context:e,observedBits:t,next:null},null===ri){if(null===ni)throw Error(o(308));ri=t,ni.dependencies={expirationTime:0,firstContext:t,responders:null}}else ri=ri.next=t;return e._currentValue}var ui=!1;function di(e){e.updateQueue={baseState:e.memoizedState,baseQueue:null,shared:{pending:null},effects:null}}function pi(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,baseQueue:e.baseQueue,shared:e.shared,effects:e.effects})}function fi(e,t){return(e={expirationTime:e,suspenseConfig:t,tag:0,payload:null,callback:null,next:null}).next=e}function mi(e,t){if(null!==(e=e.updateQueue)){var n=(e=e.shared).pending;null===n?t.next=t:(t.next=n.next,n.next=t),e.pending=t}}function gi(e,t){var n=e.alternate;null!==n&&pi(n,e),null===(n=(e=e.updateQueue).baseQueue)?(e.baseQueue=t.next=t,t.next=t):(t.next=n.next,n.next=t)}function hi(e,t,n,r){var i=e.updateQueue;ui=!1;var o=i.baseQueue,l=i.shared.pending;if(null!==l){if(null!==o){var s=o.next;o.next=l.next,l.next=s}o=l,i.shared.pending=null,null!==(s=e.alternate)&&(null!==(s=s.updateQueue)&&(s.baseQueue=l))}if(null!==o){s=o.next;var c=i.baseState,u=0,d=null,p=null,f=null;if(null!==s)for(var m=s;;){if((l=m.expirationTime)<r){var g={expirationTime:m.expirationTime,suspenseConfig:m.suspenseConfig,tag:m.tag,payload:m.payload,callback:m.callback,next:null};null===f?(p=f=g,d=c):f=f.next=g,l>u&&(u=l)}else{null!==f&&(f=f.next={expirationTime:1073741823,suspenseConfig:m.suspenseConfig,tag:m.tag,payload:m.payload,callback:m.callback,next:null}),ks(l,m.suspenseConfig);e:{var h=e,b=m;switch(l=t,g=n,b.tag){case 1:if("function"==typeof(h=b.payload)){c=h.call(g,c,l);break e}c=h;break e;case 3:h.effectTag=-4097&h.effectTag|64;case 0:if(null==(l="function"==typeof(h=b.payload)?h.call(g,c,l):h))break e;c=a({},c,l);break e;case 2:ui=!0}}null!==m.callback&&(e.effectTag|=32,null===(l=i.effects)?i.effects=[m]:l.push(m))}if(null===(m=m.next)||m===s){if(null===(l=i.shared.pending))break;m=o.next=l.next,l.next=s,i.baseQueue=o=l,i.shared.pending=null}}null===f?d=c:f.next=p,i.baseState=d,i.baseQueue=f,Es(u),e.expirationTime=u,e.memoizedState=c}}function bi(e,t,n){if(e=t.effects,t.effects=null,null!==e)for(t=0;t<e.length;t++){var r=e[t],a=r.callback;if(null!==a){if(r.callback=null,r=a,a=n,"function"!=typeof r)throw Error(o(191,r));r.call(a)}}}var vi=K.ReactCurrentBatchConfig,yi=(new r.Component).refs;function wi(e,t,n,r){n=null==(n=n(r,t=e.memoizedState))?t:a({},t,n),e.memoizedState=n,0===e.expirationTime&&(e.updateQueue.baseState=n)}var xi={isMounted:function(e){return!!(e=e._reactInternalFiber)&&et(e)===e},enqueueSetState:function(e,t,n){e=e._reactInternalFiber;var r=cs(),a=vi.suspense;(a=fi(r=us(r,e,a),a)).payload=t,null!=n&&(a.callback=n),mi(e,a),ds(e,r)},enqueueReplaceState:function(e,t,n){e=e._reactInternalFiber;var r=cs(),a=vi.suspense;(a=fi(r=us(r,e,a),a)).tag=1,a.payload=t,null!=n&&(a.callback=n),mi(e,a),ds(e,r)},enqueueForceUpdate:function(e,t){e=e._reactInternalFiber;var n=cs(),r=vi.suspense;(r=fi(n=us(n,e,r),r)).tag=2,null!=t&&(r.callback=t),mi(e,r),ds(e,n)}};function ki(e,t,n,r,a,i,o){return"function"==typeof(e=e.stateNode).shouldComponentUpdate?e.shouldComponentUpdate(r,i,o):!t.prototype||!t.prototype.isPureReactComponent||(!Wr(n,r)||!Wr(a,i))}function Ei(e,t,n){var r=!1,a=ha,i=t.contextType;return"object"==typeof i&&null!==i?i=ci(i):(a=xa(t)?ya:ba.current,i=(r=null!=(r=t.contextTypes))?wa(e,a):ha),t=new t(n,i),e.memoizedState=null!==t.state&&void 0!==t.state?t.state:null,t.updater=xi,e.stateNode=t,t._reactInternalFiber=e,r&&((e=e.stateNode).__reactInternalMemoizedUnmaskedChildContext=a,e.__reactInternalMemoizedMaskedChildContext=i),t}function Si(e,t,n,r){e=t.state,"function"==typeof t.componentWillReceiveProps&&t.componentWillReceiveProps(n,r),"function"==typeof t.UNSAFE_componentWillReceiveProps&&t.UNSAFE_componentWillReceiveProps(n,r),t.state!==e&&xi.enqueueReplaceState(t,t.state,null)}function Ti(e,t,n,r){var a=e.stateNode;a.props=n,a.state=e.memoizedState,a.refs=yi,di(e);var i=t.contextType;"object"==typeof i&&null!==i?a.context=ci(i):(i=xa(t)?ya:ba.current,a.context=wa(e,i)),hi(e,n,a,r),a.state=e.memoizedState,"function"==typeof(i=t.getDerivedStateFromProps)&&(wi(e,t,i,n),a.state=e.memoizedState),"function"==typeof t.getDerivedStateFromProps||"function"==typeof a.getSnapshotBeforeUpdate||"function"!=typeof a.UNSAFE_componentWillMount&&"function"!=typeof a.componentWillMount||(t=a.state,"function"==typeof a.componentWillMount&&a.componentWillMount(),"function"==typeof a.UNSAFE_componentWillMount&&a.UNSAFE_componentWillMount(),t!==a.state&&xi.enqueueReplaceState(a,a.state,null),hi(e,n,a,r),a.state=e.memoizedState),"function"==typeof a.componentDidMount&&(e.effectTag|=4)}var _i=Array.isArray;function Ci(e,t,n){if(null!==(e=n.ref)&&"function"!=typeof e&&"object"!=typeof e){if(n._owner){if(n=n._owner){if(1!==n.tag)throw Error(o(309));var r=n.stateNode}if(!r)throw Error(o(147,e));var a=""+e;return null!==t&&null!==t.ref&&"function"==typeof t.ref&&t.ref._stringRef===a?t.ref:(t=function(e){var t=r.refs;t===yi&&(t=r.refs={}),null===e?delete t[a]:t[a]=e},t._stringRef=a,t)}if("string"!=typeof e)throw Error(o(284));if(!n._owner)throw Error(o(290,e))}return e}function Ai(e,t){if("textarea"!==e.type)throw Error(o(31,"[object Object]"===Object.prototype.toString.call(t)?"object with keys {"+Object.keys(t).join(", ")+"}":t,""))}function Pi(e){function t(t,n){if(e){var r=t.lastEffect;null!==r?(r.nextEffect=n,t.lastEffect=n):t.firstEffect=t.lastEffect=n,n.nextEffect=null,n.effectTag=8}}function n(n,r){if(!e)return null;for(;null!==r;)t(n,r),r=r.sibling;return null}function r(e,t){for(e=new Map;null!==t;)null!==t.key?e.set(t.key,t):e.set(t.index,t),t=t.sibling;return e}function a(e,t){return(e=Zs(e,t)).index=0,e.sibling=null,e}function i(t,n,r){return t.index=r,e?null!==(r=t.alternate)?(r=r.index)<n?(t.effectTag=2,n):r:(t.effectTag=2,n):n}function l(t){return e&&null===t.alternate&&(t.effectTag=2),t}function s(e,t,n,r){return null===t||6!==t.tag?((t=Vs(n,e.mode,r)).return=e,t):((t=a(t,n)).return=e,t)}function c(e,t,n,r){return null!==t&&t.elementType===n.type?((r=a(t,n.props)).ref=Ci(e,t,n),r.return=e,r):((r=Hs(n.type,n.key,n.props,null,e.mode,r)).ref=Ci(e,t,n),r.return=e,r)}function u(e,t,n,r){return null===t||4!==t.tag||t.stateNode.containerInfo!==n.containerInfo||t.stateNode.implementation!==n.implementation?((t=Gs(n,e.mode,r)).return=e,t):((t=a(t,n.children||[])).return=e,t)}function d(e,t,n,r,i){return null===t||7!==t.tag?((t=Ws(n,e.mode,r,i)).return=e,t):((t=a(t,n)).return=e,t)}function p(e,t,n){if("string"==typeof t||"number"==typeof t)return(t=Vs(""+t,e.mode,n)).return=e,t;if("object"==typeof t&&null!==t){switch(t.$$typeof){case ee:return(n=Hs(t.type,t.key,t.props,null,e.mode,n)).ref=Ci(e,null,t),n.return=e,n;case te:return(t=Gs(t,e.mode,n)).return=e,t}if(_i(t)||ge(t))return(t=Ws(t,e.mode,n,null)).return=e,t;Ai(e,t)}return null}function f(e,t,n,r){var a=null!==t?t.key:null;if("string"==typeof n||"number"==typeof n)return null!==a?null:s(e,t,""+n,r);if("object"==typeof n&&null!==n){switch(n.$$typeof){case ee:return n.key===a?n.type===ne?d(e,t,n.props.children,r,a):c(e,t,n,r):null;case te:return n.key===a?u(e,t,n,r):null}if(_i(n)||ge(n))return null!==a?null:d(e,t,n,r,null);Ai(e,n)}return null}function m(e,t,n,r,a){if("string"==typeof r||"number"==typeof r)return s(t,e=e.get(n)||null,""+r,a);if("object"==typeof r&&null!==r){switch(r.$$typeof){case ee:return e=e.get(null===r.key?n:r.key)||null,r.type===ne?d(t,e,r.props.children,a,r.key):c(t,e,r,a);case te:return u(t,e=e.get(null===r.key?n:r.key)||null,r,a)}if(_i(r)||ge(r))return d(t,e=e.get(n)||null,r,a,null);Ai(t,r)}return null}function g(a,o,l,s){for(var c=null,u=null,d=o,g=o=0,h=null;null!==d&&g<l.length;g++){d.index>g?(h=d,d=null):h=d.sibling;var b=f(a,d,l[g],s);if(null===b){null===d&&(d=h);break}e&&d&&null===b.alternate&&t(a,d),o=i(b,o,g),null===u?c=b:u.sibling=b,u=b,d=h}if(g===l.length)return n(a,d),c;if(null===d){for(;g<l.length;g++)null!==(d=p(a,l[g],s))&&(o=i(d,o,g),null===u?c=d:u.sibling=d,u=d);return c}for(d=r(a,d);g<l.length;g++)null!==(h=m(d,a,g,l[g],s))&&(e&&null!==h.alternate&&d.delete(null===h.key?g:h.key),o=i(h,o,g),null===u?c=h:u.sibling=h,u=h);return e&&d.forEach((function(e){return t(a,e)})),c}function h(a,l,s,c){var u=ge(s);if("function"!=typeof u)throw Error(o(150));if(null==(s=u.call(s)))throw Error(o(151));for(var d=u=null,g=l,h=l=0,b=null,v=s.next();null!==g&&!v.done;h++,v=s.next()){g.index>h?(b=g,g=null):b=g.sibling;var y=f(a,g,v.value,c);if(null===y){null===g&&(g=b);break}e&&g&&null===y.alternate&&t(a,g),l=i(y,l,h),null===d?u=y:d.sibling=y,d=y,g=b}if(v.done)return n(a,g),u;if(null===g){for(;!v.done;h++,v=s.next())null!==(v=p(a,v.value,c))&&(l=i(v,l,h),null===d?u=v:d.sibling=v,d=v);return u}for(g=r(a,g);!v.done;h++,v=s.next())null!==(v=m(g,a,h,v.value,c))&&(e&&null!==v.alternate&&g.delete(null===v.key?h:v.key),l=i(v,l,h),null===d?u=v:d.sibling=v,d=v);return e&&g.forEach((function(e){return t(a,e)})),u}return function(e,r,i,s){var c="object"==typeof i&&null!==i&&i.type===ne&&null===i.key;c&&(i=i.props.children);var u="object"==typeof i&&null!==i;if(u)switch(i.$$typeof){case ee:e:{for(u=i.key,c=r;null!==c;){if(c.key===u){if(7===c.tag){if(i.type===ne){n(e,c.sibling),(r=a(c,i.props.children)).return=e,e=r;break e}}else if(c.elementType===i.type){n(e,c.sibling),(r=a(c,i.props)).ref=Ci(e,c,i),r.return=e,e=r;break e}n(e,c);break}t(e,c),c=c.sibling}i.type===ne?((r=Ws(i.props.children,e.mode,s,i.key)).return=e,e=r):((s=Hs(i.type,i.key,i.props,null,e.mode,s)).ref=Ci(e,r,i),s.return=e,e=s)}return l(e);case te:e:{for(c=i.key;null!==r;){if(r.key===c){if(4===r.tag&&r.stateNode.containerInfo===i.containerInfo&&r.stateNode.implementation===i.implementation){n(e,r.sibling),(r=a(r,i.children||[])).return=e,e=r;break e}n(e,r);break}t(e,r),r=r.sibling}(r=Gs(i,e.mode,s)).return=e,e=r}return l(e)}if("string"==typeof i||"number"==typeof i)return i=""+i,null!==r&&6===r.tag?(n(e,r.sibling),(r=a(r,i)).return=e,e=r):(n(e,r),(r=Vs(i,e.mode,s)).return=e,e=r),l(e);if(_i(i))return g(e,r,i,s);if(ge(i))return h(e,r,i,s);if(u&&Ai(e,i),void 0===i&&!c)switch(e.tag){case 1:case 0:throw e=e.type,Error(o(152,e.displayName||e.name||"Component"))}return n(e,r)}}var Ni=Pi(!0),Oi=Pi(!1),Ii={},Li={current:Ii},Di={current:Ii},Ri={current:Ii};function Mi(e){if(e===Ii)throw Error(o(174));return e}function Fi(e,t){switch(ga(Ri,t),ga(Di,e),ga(Li,Ii),e=t.nodeType){case 9:case 11:t=(t=t.documentElement)?t.namespaceURI:Fe(null,"");break;default:t=Fe(t=(e=8===e?t.parentNode:t).namespaceURI||null,e=e.tagName)}ma(Li),ga(Li,t)}function Bi(){ma(Li),ma(Di),ma(Ri)}function $i(e){Mi(Ri.current);var t=Mi(Li.current),n=Fe(t,e.type);t!==n&&(ga(Di,e),ga(Li,n))}function zi(e){Di.current===e&&(ma(Li),ma(Di))}var Ui={current:0};function ji(e){for(var t=e;null!==t;){if(13===t.tag){var n=t.memoizedState;if(null!==n&&(null===(n=n.dehydrated)||n.data===yn||n.data===wn))return t}else if(19===t.tag&&void 0!==t.memoizedProps.revealOrder){if(0!=(64&t.effectTag))return t}else if(null!==t.child){t.child.return=t,t=t.child;continue}if(t===e)break;for(;null===t.sibling;){if(null===t.return||t.return===e)return null;t=t.return}t.sibling.return=t.return,t=t.sibling}return null}function Zi(e,t){return{responder:e,props:t}}var Hi=K.ReactCurrentDispatcher,Wi=K.ReactCurrentBatchConfig,Vi=0,Gi=null,qi=null,Yi=null,Ki=!1;function Qi(){throw Error(o(321))}function Xi(e,t){if(null===t)return!1;for(var n=0;n<t.length&&n<e.length;n++)if(!Zr(e[n],t[n]))return!1;return!0}function Ji(e,t,n,r,a,i){if(Vi=i,Gi=t,t.memoizedState=null,t.updateQueue=null,t.expirationTime=0,Hi.current=null===e||null===e.memoizedState?Eo:So,e=n(r,a),t.expirationTime===Vi){i=0;do{if(t.expirationTime=0,!(25>i))throw Error(o(301));i+=1,Yi=qi=null,t.updateQueue=null,Hi.current=To,e=n(r,a)}while(t.expirationTime===Vi)}if(Hi.current=ko,t=null!==qi&&null!==qi.next,Vi=0,Yi=qi=Gi=null,Ki=!1,t)throw Error(o(300));return e}function eo(){var e={memoizedState:null,baseState:null,baseQueue:null,queue:null,next:null};return null===Yi?Gi.memoizedState=Yi=e:Yi=Yi.next=e,Yi}function to(){if(null===qi){var e=Gi.alternate;e=null!==e?e.memoizedState:null}else e=qi.next;var t=null===Yi?Gi.memoizedState:Yi.next;if(null!==t)Yi=t,qi=e;else{if(null===e)throw Error(o(310));e={memoizedState:(qi=e).memoizedState,baseState:qi.baseState,baseQueue:qi.baseQueue,queue:qi.queue,next:null},null===Yi?Gi.memoizedState=Yi=e:Yi=Yi.next=e}return Yi}function no(e,t){return"function"==typeof t?t(e):t}function ro(e){var t=to(),n=t.queue;if(null===n)throw Error(o(311));n.lastRenderedReducer=e;var r=qi,a=r.baseQueue,i=n.pending;if(null!==i){if(null!==a){var l=a.next;a.next=i.next,i.next=l}r.baseQueue=a=i,n.pending=null}if(null!==a){a=a.next,r=r.baseState;var s=l=i=null,c=a;do{var u=c.expirationTime;if(u<Vi){var d={expirationTime:c.expirationTime,suspenseConfig:c.suspenseConfig,action:c.action,eagerReducer:c.eagerReducer,eagerState:c.eagerState,next:null};null===s?(l=s=d,i=r):s=s.next=d,u>Gi.expirationTime&&(Gi.expirationTime=u,Es(u))}else null!==s&&(s=s.next={expirationTime:1073741823,suspenseConfig:c.suspenseConfig,action:c.action,eagerReducer:c.eagerReducer,eagerState:c.eagerState,next:null}),ks(u,c.suspenseConfig),r=c.eagerReducer===e?c.eagerState:e(r,c.action);c=c.next}while(null!==c&&c!==a);null===s?i=r:s.next=l,Zr(r,t.memoizedState)||(Mo=!0),t.memoizedState=r,t.baseState=i,t.baseQueue=s,n.lastRenderedState=r}return[t.memoizedState,n.dispatch]}function ao(e){var t=to(),n=t.queue;if(null===n)throw Error(o(311));n.lastRenderedReducer=e;var r=n.dispatch,a=n.pending,i=t.memoizedState;if(null!==a){n.pending=null;var l=a=a.next;do{i=e(i,l.action),l=l.next}while(l!==a);Zr(i,t.memoizedState)||(Mo=!0),t.memoizedState=i,null===t.baseQueue&&(t.baseState=i),n.lastRenderedState=i}return[i,r]}function io(e){var t=eo();return"function"==typeof e&&(e=e()),t.memoizedState=t.baseState=e,e=(e=t.queue={pending:null,dispatch:null,lastRenderedReducer:no,lastRenderedState:e}).dispatch=xo.bind(null,Gi,e),[t.memoizedState,e]}function oo(e,t,n,r){return e={tag:e,create:t,destroy:n,deps:r,next:null},null===(t=Gi.updateQueue)?(t={lastEffect:null},Gi.updateQueue=t,t.lastEffect=e.next=e):null===(n=t.lastEffect)?t.lastEffect=e.next=e:(r=n.next,n.next=e,e.next=r,t.lastEffect=e),e}function lo(){return to().memoizedState}function so(e,t,n,r){var a=eo();Gi.effectTag|=e,a.memoizedState=oo(1|t,n,void 0,void 0===r?null:r)}function co(e,t,n,r){var a=to();r=void 0===r?null:r;var i=void 0;if(null!==qi){var o=qi.memoizedState;if(i=o.destroy,null!==r&&Xi(r,o.deps))return void oo(t,n,i,r)}Gi.effectTag|=e,a.memoizedState=oo(1|t,n,i,r)}function uo(e,t){return so(516,4,e,t)}function po(e,t){return co(516,4,e,t)}function fo(e,t){return co(4,2,e,t)}function mo(e,t){return"function"==typeof t?(e=e(),t(e),function(){t(null)}):null!=t?(e=e(),t.current=e,function(){t.current=null}):void 0}function go(e,t,n){return n=null!=n?n.concat([e]):null,co(4,2,mo.bind(null,t,e),n)}function ho(){}function bo(e,t){return eo().memoizedState=[e,void 0===t?null:t],e}function vo(e,t){var n=to();t=void 0===t?null:t;var r=n.memoizedState;return null!==r&&null!==t&&Xi(t,r[1])?r[0]:(n.memoizedState=[e,t],e)}function yo(e,t){var n=to();t=void 0===t?null:t;var r=n.memoizedState;return null!==r&&null!==t&&Xi(t,r[1])?r[0]:(e=e(),n.memoizedState=[e,t],e)}function wo(e,t,n){var r=Va();qa(98>r?98:r,(function(){e(!0)})),qa(97<r?97:r,(function(){var r=Wi.suspense;Wi.suspense=void 0===t?null:t;try{e(!1),n()}finally{Wi.suspense=r}}))}function xo(e,t,n){var r=cs(),a=vi.suspense;a={expirationTime:r=us(r,e,a),suspenseConfig:a,action:n,eagerReducer:null,eagerState:null,next:null};var i=t.pending;if(null===i?a.next=a:(a.next=i.next,i.next=a),t.pending=a,i=e.alternate,e===Gi||null!==i&&i===Gi)Ki=!0,a.expirationTime=Vi,Gi.expirationTime=Vi;else{if(0===e.expirationTime&&(null===i||0===i.expirationTime)&&null!==(i=t.lastRenderedReducer))try{var o=t.lastRenderedState,l=i(o,n);if(a.eagerReducer=i,a.eagerState=l,Zr(l,o))return}catch(s){}ds(e,r)}}var ko={readContext:ci,useCallback:Qi,useContext:Qi,useEffect:Qi,useImperativeHandle:Qi,useLayoutEffect:Qi,useMemo:Qi,useReducer:Qi,useRef:Qi,useState:Qi,useDebugValue:Qi,useResponder:Qi,useDeferredValue:Qi,useTransition:Qi},Eo={readContext:ci,useCallback:bo,useContext:ci,useEffect:uo,useImperativeHandle:function(e,t,n){return n=null!=n?n.concat([e]):null,so(4,2,mo.bind(null,t,e),n)},useLayoutEffect:function(e,t){return so(4,2,e,t)},useMemo:function(e,t){var n=eo();return t=void 0===t?null:t,e=e(),n.memoizedState=[e,t],e},useReducer:function(e,t,n){var r=eo();return t=void 0!==n?n(t):t,r.memoizedState=r.baseState=t,e=(e=r.queue={pending:null,dispatch:null,lastRenderedReducer:e,lastRenderedState:t}).dispatch=xo.bind(null,Gi,e),[r.memoizedState,e]},useRef:function(e){return e={current:e},eo().memoizedState=e},useState:io,useDebugValue:ho,useResponder:Zi,useDeferredValue:function(e,t){var n=io(e),r=n[0],a=n[1];return uo((function(){var n=Wi.suspense;Wi.suspense=void 0===t?null:t;try{a(e)}finally{Wi.suspense=n}}),[e,t]),r},useTransition:function(e){var t=io(!1),n=t[0];return t=t[1],[bo(wo.bind(null,t,e),[t,e]),n]}},So={readContext:ci,useCallback:vo,useContext:ci,useEffect:po,useImperativeHandle:go,useLayoutEffect:fo,useMemo:yo,useReducer:ro,useRef:lo,useState:function(){return ro(no)},useDebugValue:ho,useResponder:Zi,useDeferredValue:function(e,t){var n=ro(no),r=n[0],a=n[1];return po((function(){var n=Wi.suspense;Wi.suspense=void 0===t?null:t;try{a(e)}finally{Wi.suspense=n}}),[e,t]),r},useTransition:function(e){var t=ro(no),n=t[0];return t=t[1],[vo(wo.bind(null,t,e),[t,e]),n]}},To={readContext:ci,useCallback:vo,useContext:ci,useEffect:po,useImperativeHandle:go,useLayoutEffect:fo,useMemo:yo,useReducer:ao,useRef:lo,useState:function(){return ao(no)},useDebugValue:ho,useResponder:Zi,useDeferredValue:function(e,t){var n=ao(no),r=n[0],a=n[1];return po((function(){var n=Wi.suspense;Wi.suspense=void 0===t?null:t;try{a(e)}finally{Wi.suspense=n}}),[e,t]),r},useTransition:function(e){var t=ao(no),n=t[0];return t=t[1],[vo(wo.bind(null,t,e),[t,e]),n]}},_o=null,Co=null,Ao=!1;function Po(e,t){var n=Us(5,null,null,0);n.elementType="DELETED",n.type="DELETED",n.stateNode=t,n.return=e,n.effectTag=8,null!==e.lastEffect?(e.lastEffect.nextEffect=n,e.lastEffect=n):e.firstEffect=e.lastEffect=n}function No(e,t){switch(e.tag){case 5:var n=e.type;return null!==(t=1!==t.nodeType||n.toLowerCase()!==t.nodeName.toLowerCase()?null:t)&&(e.stateNode=t,!0);case 6:return null!==(t=""===e.pendingProps||3!==t.nodeType?null:t)&&(e.stateNode=t,!0);default:return!1}}function Oo(e){if(Ao){var t=Co;if(t){var n=t;if(!No(e,t)){if(!(t=Cn(n.nextSibling))||!No(e,t))return e.effectTag=-1025&e.effectTag|2,Ao=!1,void(_o=e);Po(_o,n)}_o=e,Co=Cn(t.firstChild)}else e.effectTag=-1025&e.effectTag|2,Ao=!1,_o=e}}function Io(e){for(e=e.return;null!==e&&5!==e.tag&&3!==e.tag&&13!==e.tag;)e=e.return;_o=e}function Lo(e){if(e!==_o)return!1;if(!Ao)return Io(e),Ao=!0,!1;var t=e.type;if(5!==e.tag||"head"!==t&&"body"!==t&&!Sn(t,e.memoizedProps))for(t=Co;t;)Po(e,t),t=Cn(t.nextSibling);if(Io(e),13===e.tag){if(!(e=null!==(e=e.memoizedState)?e.dehydrated:null))throw Error(o(317));e:{for(e=e.nextSibling,t=0;e;){if(8===e.nodeType){var n=e.data;if(n===vn){if(0===t){Co=Cn(e.nextSibling);break e}t--}else n!==bn&&n!==wn&&n!==yn||t++}e=e.nextSibling}Co=null}}else Co=_o?Cn(e.stateNode.nextSibling):null;return!0}function Do(){Co=_o=null,Ao=!1}var Ro=K.ReactCurrentOwner,Mo=!1;function Fo(e,t,n,r){t.child=null===e?Oi(t,null,n,r):Ni(t,e.child,n,r)}function Bo(e,t,n,r,a){n=n.render;var i=t.ref;return si(t,a),r=Ji(e,t,n,r,i,a),null===e||Mo?(t.effectTag|=1,Fo(e,t,r,a),t.child):(t.updateQueue=e.updateQueue,t.effectTag&=-517,e.expirationTime<=a&&(e.expirationTime=0),tl(e,t,a))}function $o(e,t,n,r,a,i){if(null===e){var o=n.type;return"function"!=typeof o||js(o)||void 0!==o.defaultProps||null!==n.compare||void 0!==n.defaultProps?((e=Hs(n.type,null,r,null,t.mode,i)).ref=t.ref,e.return=t,t.child=e):(t.tag=15,t.type=o,zo(e,t,o,r,a,i))}return o=e.child,a<i&&(a=o.memoizedProps,(n=null!==(n=n.compare)?n:Wr)(a,r)&&e.ref===t.ref)?tl(e,t,i):(t.effectTag|=1,(e=Zs(o,r)).ref=t.ref,e.return=t,t.child=e)}function zo(e,t,n,r,a,i){return null!==e&&Wr(e.memoizedProps,r)&&e.ref===t.ref&&(Mo=!1,a<i)?(t.expirationTime=e.expirationTime,tl(e,t,i)):jo(e,t,n,r,i)}function Uo(e,t){var n=t.ref;(null===e&&null!==n||null!==e&&e.ref!==n)&&(t.effectTag|=128)}function jo(e,t,n,r,a){var i=xa(n)?ya:ba.current;return i=wa(t,i),si(t,a),n=Ji(e,t,n,r,i,a),null===e||Mo?(t.effectTag|=1,Fo(e,t,n,a),t.child):(t.updateQueue=e.updateQueue,t.effectTag&=-517,e.expirationTime<=a&&(e.expirationTime=0),tl(e,t,a))}function Zo(e,t,n,r,a){if(xa(n)){var i=!0;Ta(t)}else i=!1;if(si(t,a),null===t.stateNode)null!==e&&(e.alternate=null,t.alternate=null,t.effectTag|=2),Ei(t,n,r),Ti(t,n,r,a),r=!0;else if(null===e){var o=t.stateNode,l=t.memoizedProps;o.props=l;var s=o.context,c=n.contextType;"object"==typeof c&&null!==c?c=ci(c):c=wa(t,c=xa(n)?ya:ba.current);var u=n.getDerivedStateFromProps,d="function"==typeof u||"function"==typeof o.getSnapshotBeforeUpdate;d||"function"!=typeof o.UNSAFE_componentWillReceiveProps&&"function"!=typeof o.componentWillReceiveProps||(l!==r||s!==c)&&Si(t,o,r,c),ui=!1;var p=t.memoizedState;o.state=p,hi(t,r,o,a),s=t.memoizedState,l!==r||p!==s||va.current||ui?("function"==typeof u&&(wi(t,n,u,r),s=t.memoizedState),(l=ui||ki(t,n,l,r,p,s,c))?(d||"function"!=typeof o.UNSAFE_componentWillMount&&"function"!=typeof o.componentWillMount||("function"==typeof o.componentWillMount&&o.componentWillMount(),"function"==typeof o.UNSAFE_componentWillMount&&o.UNSAFE_componentWillMount()),"function"==typeof o.componentDidMount&&(t.effectTag|=4)):("function"==typeof o.componentDidMount&&(t.effectTag|=4),t.memoizedProps=r,t.memoizedState=s),o.props=r,o.state=s,o.context=c,r=l):("function"==typeof o.componentDidMount&&(t.effectTag|=4),r=!1)}else o=t.stateNode,pi(e,t),l=t.memoizedProps,o.props=t.type===t.elementType?l:ei(t.type,l),s=o.context,"object"==typeof(c=n.contextType)&&null!==c?c=ci(c):c=wa(t,c=xa(n)?ya:ba.current),(d="function"==typeof(u=n.getDerivedStateFromProps)||"function"==typeof o.getSnapshotBeforeUpdate)||"function"!=typeof o.UNSAFE_componentWillReceiveProps&&"function"!=typeof o.componentWillReceiveProps||(l!==r||s!==c)&&Si(t,o,r,c),ui=!1,s=t.memoizedState,o.state=s,hi(t,r,o,a),p=t.memoizedState,l!==r||s!==p||va.current||ui?("function"==typeof u&&(wi(t,n,u,r),p=t.memoizedState),(u=ui||ki(t,n,l,r,s,p,c))?(d||"function"!=typeof o.UNSAFE_componentWillUpdate&&"function"!=typeof o.componentWillUpdate||("function"==typeof o.componentWillUpdate&&o.componentWillUpdate(r,p,c),"function"==typeof o.UNSAFE_componentWillUpdate&&o.UNSAFE_componentWillUpdate(r,p,c)),"function"==typeof o.componentDidUpdate&&(t.effectTag|=4),"function"==typeof o.getSnapshotBeforeUpdate&&(t.effectTag|=256)):("function"!=typeof o.componentDidUpdate||l===e.memoizedProps&&s===e.memoizedState||(t.effectTag|=4),"function"!=typeof o.getSnapshotBeforeUpdate||l===e.memoizedProps&&s===e.memoizedState||(t.effectTag|=256),t.memoizedProps=r,t.memoizedState=p),o.props=r,o.state=p,o.context=c,r=u):("function"!=typeof o.componentDidUpdate||l===e.memoizedProps&&s===e.memoizedState||(t.effectTag|=4),"function"!=typeof o.getSnapshotBeforeUpdate||l===e.memoizedProps&&s===e.memoizedState||(t.effectTag|=256),r=!1);return Ho(e,t,n,r,i,a)}function Ho(e,t,n,r,a,i){Uo(e,t);var o=0!=(64&t.effectTag);if(!r&&!o)return a&&_a(t,n,!1),tl(e,t,i);r=t.stateNode,Ro.current=t;var l=o&&"function"!=typeof n.getDerivedStateFromError?null:r.render();return t.effectTag|=1,null!==e&&o?(t.child=Ni(t,e.child,null,i),t.child=Ni(t,null,l,i)):Fo(e,t,l,i),t.memoizedState=r.state,a&&_a(t,n,!0),t.child}function Wo(e){var t=e.stateNode;t.pendingContext?Ea(0,t.pendingContext,t.pendingContext!==t.context):t.context&&Ea(0,t.context,!1),Fi(e,t.containerInfo)}var Vo,Go,qo,Yo,Ko={dehydrated:null,retryTime:0};function Qo(e,t,n){var r,a=t.mode,i=t.pendingProps,o=Ui.current,l=!1;if((r=0!=(64&t.effectTag))||(r=0!=(2&o)&&(null===e||null!==e.memoizedState)),r?(l=!0,t.effectTag&=-65):null!==e&&null===e.memoizedState||void 0===i.fallback||!0===i.unstable_avoidThisFallback||(o|=1),ga(Ui,1&o),null===e){if(void 0!==i.fallback&&Oo(t),l){if(l=i.fallback,(i=Ws(null,a,0,null)).return=t,0==(2&t.mode))for(e=null!==t.memoizedState?t.child.child:t.child,i.child=e;null!==e;)e.return=i,e=e.sibling;return(n=Ws(l,a,n,null)).return=t,i.sibling=n,t.memoizedState=Ko,t.child=i,n}return a=i.children,t.memoizedState=null,t.child=Oi(t,null,a,n)}if(null!==e.memoizedState){if(a=(e=e.child).sibling,l){if(i=i.fallback,(n=Zs(e,e.pendingProps)).return=t,0==(2&t.mode)&&(l=null!==t.memoizedState?t.child.child:t.child)!==e.child)for(n.child=l;null!==l;)l.return=n,l=l.sibling;return(a=Zs(a,i)).return=t,n.sibling=a,n.childExpirationTime=0,t.memoizedState=Ko,t.child=n,a}return n=Ni(t,e.child,i.children,n),t.memoizedState=null,t.child=n}if(e=e.child,l){if(l=i.fallback,(i=Ws(null,a,0,null)).return=t,i.child=e,null!==e&&(e.return=i),0==(2&t.mode))for(e=null!==t.memoizedState?t.child.child:t.child,i.child=e;null!==e;)e.return=i,e=e.sibling;return(n=Ws(l,a,n,null)).return=t,i.sibling=n,n.effectTag|=2,i.childExpirationTime=0,t.memoizedState=Ko,t.child=i,n}return t.memoizedState=null,t.child=Ni(t,e,i.children,n)}function Xo(e,t){e.expirationTime<t&&(e.expirationTime=t);var n=e.alternate;null!==n&&n.expirationTime<t&&(n.expirationTime=t),li(e.return,t)}function Jo(e,t,n,r,a,i){var o=e.memoizedState;null===o?e.memoizedState={isBackwards:t,rendering:null,renderingStartTime:0,last:r,tail:n,tailExpiration:0,tailMode:a,lastEffect:i}:(o.isBackwards=t,o.rendering=null,o.renderingStartTime=0,o.last=r,o.tail=n,o.tailExpiration=0,o.tailMode=a,o.lastEffect=i)}function el(e,t,n){var r=t.pendingProps,a=r.revealOrder,i=r.tail;if(Fo(e,t,r.children,n),0!=(2&(r=Ui.current)))r=1&r|2,t.effectTag|=64;else{if(null!==e&&0!=(64&e.effectTag))e:for(e=t.child;null!==e;){if(13===e.tag)null!==e.memoizedState&&Xo(e,n);else if(19===e.tag)Xo(e,n);else if(null!==e.child){e.child.return=e,e=e.child;continue}if(e===t)break e;for(;null===e.sibling;){if(null===e.return||e.return===t)break e;e=e.return}e.sibling.return=e.return,e=e.sibling}r&=1}if(ga(Ui,r),0==(2&t.mode))t.memoizedState=null;else switch(a){case"forwards":for(n=t.child,a=null;null!==n;)null!==(e=n.alternate)&&null===ji(e)&&(a=n),n=n.sibling;null===(n=a)?(a=t.child,t.child=null):(a=n.sibling,n.sibling=null),Jo(t,!1,a,n,i,t.lastEffect);break;case"backwards":for(n=null,a=t.child,t.child=null;null!==a;){if(null!==(e=a.alternate)&&null===ji(e)){t.child=a;break}e=a.sibling,a.sibling=n,n=a,a=e}Jo(t,!0,n,null,i,t.lastEffect);break;case"together":Jo(t,!1,null,null,void 0,t.lastEffect);break;default:t.memoizedState=null}return t.child}function tl(e,t,n){null!==e&&(t.dependencies=e.dependencies);var r=t.expirationTime;if(0!==r&&Es(r),t.childExpirationTime<n)return null;if(null!==e&&t.child!==e.child)throw Error(o(153));if(null!==t.child){for(n=Zs(e=t.child,e.pendingProps),t.child=n,n.return=t;null!==e.sibling;)e=e.sibling,(n=n.sibling=Zs(e,e.pendingProps)).return=t;n.sibling=null}return t.child}function nl(e,t){switch(e.tailMode){case"hidden":t=e.tail;for(var n=null;null!==t;)null!==t.alternate&&(n=t),t=t.sibling;null===n?e.tail=null:n.sibling=null;break;case"collapsed":n=e.tail;for(var r=null;null!==n;)null!==n.alternate&&(r=n),n=n.sibling;null===r?t||null===e.tail?e.tail=null:e.tail.sibling=null:r.sibling=null}}function rl(e,t,n){var r=t.pendingProps;switch(t.tag){case 2:case 16:case 15:case 0:case 11:case 7:case 8:case 12:case 9:case 14:return null;case 1:case 17:return xa(t.type)&&ka(),null;case 3:return Bi(),ma(va),ma(ba),(n=t.stateNode).pendingContext&&(n.context=n.pendingContext,n.pendingContext=null),null!==e&&null!==e.child||!Lo(t)||(t.effectTag|=4),Go(t),null;case 5:zi(t),n=Mi(Ri.current);var i=t.type;if(null!==e&&null!=t.stateNode)qo(e,t,i,r,n),e.ref!==t.ref&&(t.effectTag|=128);else{if(!r){if(null===t.stateNode)throw Error(o(166));return null}if(e=Mi(Li.current),Lo(t)){r=t.stateNode,i=t.type;var l=t.memoizedProps;switch(r[Nn]=t,r[On]=l,i){case"iframe":case"object":case"embed":qt("load",r);break;case"video":case"audio":for(e=0;e<Qe.length;e++)qt(Qe[e],r);break;case"source":qt("error",r);break;case"img":case"image":case"link":qt("error",r),qt("load",r);break;case"form":qt("reset",r),qt("submit",r);break;case"details":qt("toggle",r);break;case"input":Ee(r,l),qt("invalid",r),cn(n,"onChange");break;case"select":r._wrapperState={wasMultiple:!!l.multiple},qt("invalid",r),cn(n,"onChange");break;case"textarea":Oe(r,l),qt("invalid",r),cn(n,"onChange")}for(var s in on(i,l),e=null,l)if(l.hasOwnProperty(s)){var c=l[s];"children"===s?"string"==typeof c?r.textContent!==c&&(e=["children",c]):"number"==typeof c&&r.textContent!==""+c&&(e=["children",""+c]):S.hasOwnProperty(s)&&null!=c&&cn(n,s)}switch(i){case"input":we(r),_e(r,l,!0);break;case"textarea":we(r),Le(r);break;case"select":case"option":break;default:"function"==typeof l.onClick&&(r.onclick=un)}n=e,t.updateQueue=n,null!==n&&(t.effectTag|=4)}else{switch(s=9===n.nodeType?n:n.ownerDocument,e===sn&&(e=Me(i)),e===sn?"script"===i?((e=s.createElement("div")).innerHTML="<script><\/script>",e=e.removeChild(e.firstChild)):"string"==typeof r.is?e=s.createElement(i,{is:r.is}):(e=s.createElement(i),"select"===i&&(s=e,r.multiple?s.multiple=!0:r.size&&(s.size=r.size))):e=s.createElementNS(e,i),e[Nn]=t,e[On]=r,Vo(e,t,!1,!1),t.stateNode=e,s=ln(i,r),i){case"iframe":case"object":case"embed":qt("load",e),c=r;break;case"video":case"audio":for(c=0;c<Qe.length;c++)qt(Qe[c],e);c=r;break;case"source":qt("error",e),c=r;break;case"img":case"image":case"link":qt("error",e),qt("load",e),c=r;break;case"form":qt("reset",e),qt("submit",e),c=r;break;case"details":qt("toggle",e),c=r;break;case"input":Ee(e,r),c=ke(e,r),qt("invalid",e),cn(n,"onChange");break;case"option":c=Ae(e,r);break;case"select":e._wrapperState={wasMultiple:!!r.multiple},c=a({},r,{value:void 0}),qt("invalid",e),cn(n,"onChange");break;case"textarea":Oe(e,r),c=Ne(e,r),qt("invalid",e),cn(n,"onChange");break;default:c=r}on(i,c);var u=c;for(l in u)if(u.hasOwnProperty(l)){var d=u[l];"style"===l?rn(e,d):"dangerouslySetInnerHTML"===l?null!=(d=d?d.__html:void 0)&&ze(e,d):"children"===l?"string"==typeof d?("textarea"!==i||""!==d)&&Ue(e,d):"number"==typeof d&&Ue(e,""+d):"suppressContentEditableWarning"!==l&&"suppressHydrationWarning"!==l&&"autoFocus"!==l&&(S.hasOwnProperty(l)?null!=d&&cn(n,l):null!=d&&Q(e,l,d,s))}switch(i){case"input":we(e),_e(e,r,!1);break;case"textarea":we(e),Le(e);break;case"option":null!=r.value&&e.setAttribute("value",""+ve(r.value));break;case"select":e.multiple=!!r.multiple,null!=(n=r.value)?Pe(e,!!r.multiple,n,!1):null!=r.defaultValue&&Pe(e,!!r.multiple,r.defaultValue,!0);break;default:"function"==typeof c.onClick&&(e.onclick=un)}En(i,r)&&(t.effectTag|=4)}null!==t.ref&&(t.effectTag|=128)}return null;case 6:if(e&&null!=t.stateNode)Yo(e,t,e.memoizedProps,r);else{if("string"!=typeof r&&null===t.stateNode)throw Error(o(166));n=Mi(Ri.current),Mi(Li.current),Lo(t)?(n=t.stateNode,r=t.memoizedProps,n[Nn]=t,n.nodeValue!==r&&(t.effectTag|=4)):((n=(9===n.nodeType?n:n.ownerDocument).createTextNode(r))[Nn]=t,t.stateNode=n)}return null;case 13:return ma(Ui),r=t.memoizedState,0!=(64&t.effectTag)?(t.expirationTime=n,t):(n=null!==r,r=!1,null===e?void 0!==t.memoizedProps.fallback&&Lo(t):(r=null!==(i=e.memoizedState),n||null===i||null!==(i=e.child.sibling)&&(null!==(l=t.firstEffect)?(t.firstEffect=i,i.nextEffect=l):(t.firstEffect=t.lastEffect=i,i.nextEffect=null),i.effectTag=8)),n&&!r&&0!=(2&t.mode)&&(null===e&&!0!==t.memoizedProps.unstable_avoidThisFallback||0!=(1&Ui.current)?Zl===Ll&&(Zl=Ml):(Zl!==Ll&&Zl!==Ml||(Zl=Fl),0!==ql&&null!==zl&&(Ks(zl,jl),Qs(zl,ql)))),(n||r)&&(t.effectTag|=4),null);case 4:return Bi(),Go(t),null;case 10:return oi(t),null;case 19:if(ma(Ui),null===(r=t.memoizedState))return null;if(i=0!=(64&t.effectTag),null===(l=r.rendering)){if(i)nl(r,!1);else if(Zl!==Ll||null!==e&&0!=(64&e.effectTag))for(l=t.child;null!==l;){if(null!==(e=ji(l))){for(t.effectTag|=64,nl(r,!1),null!==(i=e.updateQueue)&&(t.updateQueue=i,t.effectTag|=4),null===r.lastEffect&&(t.firstEffect=null),t.lastEffect=r.lastEffect,r=t.child;null!==r;)l=n,(i=r).effectTag&=2,i.nextEffect=null,i.firstEffect=null,i.lastEffect=null,null===(e=i.alternate)?(i.childExpirationTime=0,i.expirationTime=l,i.child=null,i.memoizedProps=null,i.memoizedState=null,i.updateQueue=null,i.dependencies=null):(i.childExpirationTime=e.childExpirationTime,i.expirationTime=e.expirationTime,i.child=e.child,i.memoizedProps=e.memoizedProps,i.memoizedState=e.memoizedState,i.updateQueue=e.updateQueue,l=e.dependencies,i.dependencies=null===l?null:{expirationTime:l.expirationTime,firstContext:l.firstContext,responders:l.responders}),r=r.sibling;return ga(Ui,1&Ui.current|2),t.child}l=l.sibling}}else{if(!i)if(null!==(e=ji(l))){if(t.effectTag|=64,i=!0,null!==(n=e.updateQueue)&&(t.updateQueue=n,t.effectTag|=4),nl(r,!0),null===r.tail&&"hidden"===r.tailMode&&!l.alternate)return null!==(t=t.lastEffect=r.lastEffect)&&(t.nextEffect=null),null}else 2*Wa()-r.renderingStartTime>r.tailExpiration&&1<n&&(t.effectTag|=64,i=!0,nl(r,!1),t.expirationTime=t.childExpirationTime=n-1);r.isBackwards?(l.sibling=t.child,t.child=l):(null!==(n=r.last)?n.sibling=l:t.child=l,r.last=l)}return null!==r.tail?(0===r.tailExpiration&&(r.tailExpiration=Wa()+500),n=r.tail,r.rendering=n,r.tail=n.sibling,r.lastEffect=t.lastEffect,r.renderingStartTime=Wa(),n.sibling=null,t=Ui.current,ga(Ui,i?1&t|2:1&t),n):null}throw Error(o(156,t.tag))}function al(e){switch(e.tag){case 1:xa(e.type)&&ka();var t=e.effectTag;return 4096&t?(e.effectTag=-4097&t|64,e):null;case 3:if(Bi(),ma(va),ma(ba),0!=(64&(t=e.effectTag)))throw Error(o(285));return e.effectTag=-4097&t|64,e;case 5:return zi(e),null;case 13:return ma(Ui),4096&(t=e.effectTag)?(e.effectTag=-4097&t|64,e):null;case 19:return ma(Ui),null;case 4:return Bi(),null;case 10:return oi(e),null;default:return null}}function il(e,t){return{value:e,source:t,stack:be(t)}}Vo=function(e,t){for(var n=t.child;null!==n;){if(5===n.tag||6===n.tag)e.appendChild(n.stateNode);else if(4!==n.tag&&null!==n.child){n.child.return=n,n=n.child;continue}if(n===t)break;for(;null===n.sibling;){if(null===n.return||n.return===t)return;n=n.return}n.sibling.return=n.return,n=n.sibling}},Go=function(){},qo=function(e,t,n,r,i){var o=e.memoizedProps;if(o!==r){var l,s,c=t.stateNode;switch(Mi(Li.current),e=null,n){case"input":o=ke(c,o),r=ke(c,r),e=[];break;case"option":o=Ae(c,o),r=Ae(c,r),e=[];break;case"select":o=a({},o,{value:void 0}),r=a({},r,{value:void 0}),e=[];break;case"textarea":o=Ne(c,o),r=Ne(c,r),e=[];break;default:"function"!=typeof o.onClick&&"function"==typeof r.onClick&&(c.onclick=un)}for(l in on(n,r),n=null,o)if(!r.hasOwnProperty(l)&&o.hasOwnProperty(l)&&null!=o[l])if("style"===l)for(s in c=o[l])c.hasOwnProperty(s)&&(n||(n={}),n[s]="");else"dangerouslySetInnerHTML"!==l&&"children"!==l&&"suppressContentEditableWarning"!==l&&"suppressHydrationWarning"!==l&&"autoFocus"!==l&&(S.hasOwnProperty(l)?e||(e=[]):(e=e||[]).push(l,null));for(l in r){var u=r[l];if(c=null!=o?o[l]:void 0,r.hasOwnProperty(l)&&u!==c&&(null!=u||null!=c))if("style"===l)if(c){for(s in c)!c.hasOwnProperty(s)||u&&u.hasOwnProperty(s)||(n||(n={}),n[s]="");for(s in u)u.hasOwnProperty(s)&&c[s]!==u[s]&&(n||(n={}),n[s]=u[s])}else n||(e||(e=[]),e.push(l,n)),n=u;else"dangerouslySetInnerHTML"===l?(u=u?u.__html:void 0,c=c?c.__html:void 0,null!=u&&c!==u&&(e=e||[]).push(l,u)):"children"===l?c===u||"string"!=typeof u&&"number"!=typeof u||(e=e||[]).push(l,""+u):"suppressContentEditableWarning"!==l&&"suppressHydrationWarning"!==l&&(S.hasOwnProperty(l)?(null!=u&&cn(i,l),e||c===u||(e=[])):(e=e||[]).push(l,u))}n&&(e=e||[]).push("style",n),i=e,(t.updateQueue=i)&&(t.effectTag|=4)}},Yo=function(e,t,n,r){n!==r&&(t.effectTag|=4)};var ol="function"==typeof WeakSet?WeakSet:Set;function ll(e,t){var n=t.source,r=t.stack;null===r&&null!==n&&(r=be(n)),null!==n&&he(n.type),t=t.value,null!==e&&1===e.tag&&he(e.type);try{console.error(t)}catch(a){setTimeout((function(){throw a}))}}function sl(e){var t=e.ref;if(null!==t)if("function"==typeof t)try{t(null)}catch(n){Rs(e,n)}else t.current=null}function cl(e,t){switch(t.tag){case 0:case 11:case 15:case 22:case 3:case 5:case 6:case 4:case 17:return;case 1:if(256&t.effectTag&&null!==e){var n=e.memoizedProps,r=e.memoizedState;t=(e=t.stateNode).getSnapshotBeforeUpdate(t.elementType===t.type?n:ei(t.type,n),r),e.__reactInternalSnapshotBeforeUpdate=t}return}throw Error(o(163))}function ul(e,t){if(null!==(t=null!==(t=t.updateQueue)?t.lastEffect:null)){var n=t=t.next;do{if((n.tag&e)===e){var r=n.destroy;n.destroy=void 0,void 0!==r&&r()}n=n.next}while(n!==t)}}function dl(e,t){if(null!==(t=null!==(t=t.updateQueue)?t.lastEffect:null)){var n=t=t.next;do{if((n.tag&e)===e){var r=n.create;n.destroy=r()}n=n.next}while(n!==t)}}function pl(e,t,n){switch(n.tag){case 0:case 11:case 15:case 22:return void dl(3,n);case 1:if(e=n.stateNode,4&n.effectTag)if(null===t)e.componentDidMount();else{var r=n.elementType===n.type?t.memoizedProps:ei(n.type,t.memoizedProps);e.componentDidUpdate(r,t.memoizedState,e.__reactInternalSnapshotBeforeUpdate)}return void(null!==(t=n.updateQueue)&&bi(n,t,e));case 3:if(null!==(t=n.updateQueue)){if(e=null,null!==n.child)switch(n.child.tag){case 5:case 1:e=n.child.stateNode}bi(n,t,e)}return;case 5:return e=n.stateNode,void(null===t&&4&n.effectTag&&En(n.type,n.memoizedProps)&&e.focus());case 6:case 4:case 12:case 19:case 17:case 20:case 21:return;case 13:return void(null===n.memoizedState&&(n=n.alternate,null!==n&&(n=n.memoizedState,null!==n&&(n=n.dehydrated,null!==n&&Ft(n)))))}throw Error(o(163))}function fl(e,t,n){switch("function"==typeof $s&&$s(t),t.tag){case 0:case 11:case 14:case 15:case 22:if(null!==(e=t.updateQueue)&&null!==(e=e.lastEffect)){var r=e.next;qa(97<n?97:n,(function(){var e=r;do{var n=e.destroy;if(void 0!==n){var a=t;try{n()}catch(i){Rs(a,i)}}e=e.next}while(e!==r)}))}break;case 1:sl(t),"function"==typeof(n=t.stateNode).componentWillUnmount&&function(e,t){try{t.props=e.memoizedProps,t.state=e.memoizedState,t.componentWillUnmount()}catch(n){Rs(e,n)}}(t,n);break;case 5:sl(t);break;case 4:yl(e,t,n)}}function ml(e){var t=e.alternate;e.return=null,e.child=null,e.memoizedState=null,e.updateQueue=null,e.dependencies=null,e.alternate=null,e.firstEffect=null,e.lastEffect=null,e.pendingProps=null,e.memoizedProps=null,e.stateNode=null,null!==t&&ml(t)}function gl(e){return 5===e.tag||3===e.tag||4===e.tag}function hl(e){e:{for(var t=e.return;null!==t;){if(gl(t)){var n=t;break e}t=t.return}throw Error(o(160))}switch(t=n.stateNode,n.tag){case 5:var r=!1;break;case 3:case 4:t=t.containerInfo,r=!0;break;default:throw Error(o(161))}16&n.effectTag&&(Ue(t,""),n.effectTag&=-17);e:t:for(n=e;;){for(;null===n.sibling;){if(null===n.return||gl(n.return)){n=null;break e}n=n.return}for(n.sibling.return=n.return,n=n.sibling;5!==n.tag&&6!==n.tag&&18!==n.tag;){if(2&n.effectTag)continue t;if(null===n.child||4===n.tag)continue t;n.child.return=n,n=n.child}if(!(2&n.effectTag)){n=n.stateNode;break e}}r?bl(e,n,t):vl(e,n,t)}function bl(e,t,n){var r=e.tag,a=5===r||6===r;if(a)e=a?e.stateNode:e.stateNode.instance,t?8===n.nodeType?n.parentNode.insertBefore(e,t):n.insertBefore(e,t):(8===n.nodeType?(t=n.parentNode).insertBefore(e,n):(t=n).appendChild(e),null!=(n=n._reactRootContainer)||null!==t.onclick||(t.onclick=un));else if(4!==r&&null!==(e=e.child))for(bl(e,t,n),e=e.sibling;null!==e;)bl(e,t,n),e=e.sibling}function vl(e,t,n){var r=e.tag,a=5===r||6===r;if(a)e=a?e.stateNode:e.stateNode.instance,t?n.insertBefore(e,t):n.appendChild(e);else if(4!==r&&null!==(e=e.child))for(vl(e,t,n),e=e.sibling;null!==e;)vl(e,t,n),e=e.sibling}function yl(e,t,n){for(var r,a,i=t,l=!1;;){if(!l){l=i.return;e:for(;;){if(null===l)throw Error(o(160));switch(r=l.stateNode,l.tag){case 5:a=!1;break e;case 3:case 4:r=r.containerInfo,a=!0;break e}l=l.return}l=!0}if(5===i.tag||6===i.tag){e:for(var s=e,c=i,u=n,d=c;;)if(fl(s,d,u),null!==d.child&&4!==d.tag)d.child.return=d,d=d.child;else{if(d===c)break e;for(;null===d.sibling;){if(null===d.return||d.return===c)break e;d=d.return}d.sibling.return=d.return,d=d.sibling}a?(s=r,c=i.stateNode,8===s.nodeType?s.parentNode.removeChild(c):s.removeChild(c)):r.removeChild(i.stateNode)}else if(4===i.tag){if(null!==i.child){r=i.stateNode.containerInfo,a=!0,i.child.return=i,i=i.child;continue}}else if(fl(e,i,n),null!==i.child){i.child.return=i,i=i.child;continue}if(i===t)break;for(;null===i.sibling;){if(null===i.return||i.return===t)return;4===(i=i.return).tag&&(l=!1)}i.sibling.return=i.return,i=i.sibling}}function wl(e,t){switch(t.tag){case 0:case 11:case 14:case 15:case 22:return void ul(3,t);case 1:case 12:case 17:return;case 5:var n=t.stateNode;if(null!=n){var r=t.memoizedProps,a=null!==e?e.memoizedProps:r;e=t.type;var i=t.updateQueue;if(t.updateQueue=null,null!==i){for(n[On]=r,"input"===e&&"radio"===r.type&&null!=r.name&&Se(n,r),ln(e,a),t=ln(e,r),a=0;a<i.length;a+=2){var l=i[a],s=i[a+1];"style"===l?rn(n,s):"dangerouslySetInnerHTML"===l?ze(n,s):"children"===l?Ue(n,s):Q(n,l,s,t)}switch(e){case"input":Te(n,r);break;case"textarea":Ie(n,r);break;case"select":t=n._wrapperState.wasMultiple,n._wrapperState.wasMultiple=!!r.multiple,null!=(e=r.value)?Pe(n,!!r.multiple,e,!1):t!==!!r.multiple&&(null!=r.defaultValue?Pe(n,!!r.multiple,r.defaultValue,!0):Pe(n,!!r.multiple,r.multiple?[]:"",!1))}}}return;case 6:if(null===t.stateNode)throw Error(o(162));return void(t.stateNode.nodeValue=t.memoizedProps);case 3:return void((t=t.stateNode).hydrate&&(t.hydrate=!1,Ft(t.containerInfo)));case 13:if(n=t,null===t.memoizedState?r=!1:(r=!0,n=t.child,Kl=Wa()),null!==n)e:for(e=n;;){if(5===e.tag)i=e.stateNode,r?"function"==typeof(i=i.style).setProperty?i.setProperty("display","none","important"):i.display="none":(i=e.stateNode,a=null!=(a=e.memoizedProps.style)&&a.hasOwnProperty("display")?a.display:null,i.style.display=nn("display",a));else if(6===e.tag)e.stateNode.nodeValue=r?"":e.memoizedProps;else{if(13===e.tag&&null!==e.memoizedState&&null===e.memoizedState.dehydrated){(i=e.child.sibling).return=e,e=i;continue}if(null!==e.child){e.child.return=e,e=e.child;continue}}if(e===n)break;for(;null===e.sibling;){if(null===e.return||e.return===n)break e;e=e.return}e.sibling.return=e.return,e=e.sibling}return void xl(t);case 19:return void xl(t)}throw Error(o(163))}function xl(e){var t=e.updateQueue;if(null!==t){e.updateQueue=null;var n=e.stateNode;null===n&&(n=e.stateNode=new ol),t.forEach((function(t){var r=Fs.bind(null,e,t);n.has(t)||(n.add(t),t.then(r,r))}))}}var kl="function"==typeof WeakMap?WeakMap:Map;function El(e,t,n){(n=fi(n,null)).tag=3,n.payload={element:null};var r=t.value;return n.callback=function(){Jl||(Jl=!0,es=r),ll(e,t)},n}function Sl(e,t,n){(n=fi(n,null)).tag=3;var r=e.type.getDerivedStateFromError;if("function"==typeof r){var a=t.value;n.payload=function(){return ll(e,t),r(a)}}var i=e.stateNode;return null!==i&&"function"==typeof i.componentDidCatch&&(n.callback=function(){"function"!=typeof r&&(null===ts?ts=new Set([this]):ts.add(this),ll(e,t));var n=t.stack;this.componentDidCatch(t.value,{componentStack:null!==n?n:""})}),n}var Tl,_l=Math.ceil,Cl=K.ReactCurrentDispatcher,Al=K.ReactCurrentOwner,Pl=0,Nl=8,Ol=16,Il=32,Ll=0,Dl=1,Rl=2,Ml=3,Fl=4,Bl=5,$l=Pl,zl=null,Ul=null,jl=0,Zl=Ll,Hl=null,Wl=1073741823,Vl=1073741823,Gl=null,ql=0,Yl=!1,Kl=0,Ql=500,Xl=null,Jl=!1,es=null,ts=null,ns=!1,rs=null,as=90,is=null,os=0,ls=null,ss=0;function cs(){return($l&(Ol|Il))!==Pl?1073741821-(Wa()/10|0):0!==ss?ss:ss=1073741821-(Wa()/10|0)}function us(e,t,n){if(0==(2&(t=t.mode)))return 1073741823;var r=Va();if(0==(4&t))return 99===r?1073741823:1073741822;if(($l&Ol)!==Pl)return jl;if(null!==n)e=Ja(e,0|n.timeoutMs||5e3,250);else switch(r){case 99:e=1073741823;break;case 98:e=Ja(e,150,100);break;case 97:case 96:e=Ja(e,5e3,250);break;case 95:e=2;break;default:throw Error(o(326))}return null!==zl&&e===jl&&--e,e}function ds(e,t){if(50<os)throw os=0,ls=null,Error(o(185));if(null!==(e=ps(e,t))){var n=Va();1073741823===t?($l&Nl)!==Pl&&($l&(Ol|Il))===Pl?hs(e):(ms(e),$l===Pl&&Qa()):ms(e),(4&$l)===Pl||98!==n&&99!==n||(null===is?is=new Map([[e,t]]):(void 0===(n=is.get(e))||n>t)&&is.set(e,t))}}function ps(e,t){e.expirationTime<t&&(e.expirationTime=t);var n=e.alternate;null!==n&&n.expirationTime<t&&(n.expirationTime=t);var r=e.return,a=null;if(null===r&&3===e.tag)a=e.stateNode;else for(;null!==r;){if(n=r.alternate,r.childExpirationTime<t&&(r.childExpirationTime=t),null!==n&&n.childExpirationTime<t&&(n.childExpirationTime=t),null===r.return&&3===r.tag){a=r.stateNode;break}r=r.return}return null!==a&&(zl===a&&(Es(t),Zl===Fl&&Ks(a,jl)),Qs(a,t)),a}function fs(e){var t=e.lastExpiredTime;if(0!==t)return t;if(!Ys(e,t=e.firstPendingTime))return t;var n=e.lastPingedTime;return 2>=(e=n>(e=e.nextKnownPendingLevel)?n:e)&&t!==e?0:e}function ms(e){if(0!==e.lastExpiredTime)e.callbackExpirationTime=1073741823,e.callbackPriority=99,e.callbackNode=Ka(hs.bind(null,e));else{var t=fs(e),n=e.callbackNode;if(0===t)null!==n&&(e.callbackNode=null,e.callbackExpirationTime=0,e.callbackPriority=90);else{var r=cs();if(1073741823===t?r=99:1===t||2===t?r=95:r=0>=(r=10*(1073741821-t)-10*(1073741821-r))?99:250>=r?98:5250>=r?97:95,null!==n){var a=e.callbackPriority;if(e.callbackExpirationTime===t&&a>=r)return;n!==Ba&&Pa(n)}e.callbackExpirationTime=t,e.callbackPriority=r,t=1073741823===t?Ka(hs.bind(null,e)):Ya(r,gs.bind(null,e),{timeout:10*(1073741821-t)-Wa()}),e.callbackNode=t}}}function gs(e,t){if(ss=0,t)return Xs(e,t=cs()),ms(e),null;var n=fs(e);if(0!==n){if(t=e.callbackNode,($l&(Ol|Il))!==Pl)throw Error(o(327));if(Is(),e===zl&&n===jl||ys(e,n),null!==Ul){var r=$l;$l|=Ol;for(var a=xs();;)try{Ts();break}catch(s){ws(e,s)}if(ii(),$l=r,Cl.current=a,Zl===Dl)throw t=Hl,ys(e,n),Ks(e,n),ms(e),t;if(null===Ul)switch(a=e.finishedWork=e.current.alternate,e.finishedExpirationTime=n,r=Zl,zl=null,r){case Ll:case Dl:throw Error(o(345));case Rl:Xs(e,2<n?2:n);break;case Ml:if(Ks(e,n),n===(r=e.lastSuspendedTime)&&(e.nextKnownPendingLevel=As(a)),1073741823===Wl&&10<(a=Kl+Ql-Wa())){if(Yl){var i=e.lastPingedTime;if(0===i||i>=n){e.lastPingedTime=n,ys(e,n);break}}if(0!==(i=fs(e))&&i!==n)break;if(0!==r&&r!==n){e.lastPingedTime=r;break}e.timeoutHandle=Tn(Ps.bind(null,e),a);break}Ps(e);break;case Fl:if(Ks(e,n),n===(r=e.lastSuspendedTime)&&(e.nextKnownPendingLevel=As(a)),Yl&&(0===(a=e.lastPingedTime)||a>=n)){e.lastPingedTime=n,ys(e,n);break}if(0!==(a=fs(e))&&a!==n)break;if(0!==r&&r!==n){e.lastPingedTime=r;break}if(1073741823!==Vl?r=10*(1073741821-Vl)-Wa():1073741823===Wl?r=0:(r=10*(1073741821-Wl)-5e3,0>(r=(a=Wa())-r)&&(r=0),(n=10*(1073741821-n)-a)<(r=(120>r?120:480>r?480:1080>r?1080:1920>r?1920:3e3>r?3e3:4320>r?4320:1960*_l(r/1960))-r)&&(r=n)),10<r){e.timeoutHandle=Tn(Ps.bind(null,e),r);break}Ps(e);break;case Bl:if(1073741823!==Wl&&null!==Gl){i=Wl;var l=Gl;if(0>=(r=0|l.busyMinDurationMs)?r=0:(a=0|l.busyDelayMs,r=(i=Wa()-(10*(1073741821-i)-(0|l.timeoutMs||5e3)))<=a?0:a+r-i),10<r){Ks(e,n),e.timeoutHandle=Tn(Ps.bind(null,e),r);break}}Ps(e);break;default:throw Error(o(329))}if(ms(e),e.callbackNode===t)return gs.bind(null,e)}}return null}function hs(e){var t=e.lastExpiredTime;if(t=0!==t?t:1073741823,($l&(Ol|Il))!==Pl)throw Error(o(327));if(Is(),e===zl&&t===jl||ys(e,t),null!==Ul){var n=$l;$l|=Ol;for(var r=xs();;)try{Ss();break}catch(a){ws(e,a)}if(ii(),$l=n,Cl.current=r,Zl===Dl)throw n=Hl,ys(e,t),Ks(e,t),ms(e),n;if(null!==Ul)throw Error(o(261));e.finishedWork=e.current.alternate,e.finishedExpirationTime=t,zl=null,Ps(e),ms(e)}return null}function bs(e,t){var n=$l;$l|=1;try{return e(t)}finally{($l=n)===Pl&&Qa()}}function vs(e,t){var n=$l;$l&=-2,$l|=Nl;try{return e(t)}finally{($l=n)===Pl&&Qa()}}function ys(e,t){e.finishedWork=null,e.finishedExpirationTime=0;var n=e.timeoutHandle;if(-1!==n&&(e.timeoutHandle=-1,_n(n)),null!==Ul)for(n=Ul.return;null!==n;){var r=n;switch(r.tag){case 1:null!=(r=r.type.childContextTypes)&&ka();break;case 3:Bi(),ma(va),ma(ba);break;case 5:zi(r);break;case 4:Bi();break;case 13:case 19:ma(Ui);break;case 10:oi(r)}n=n.return}zl=e,Ul=Zs(e.current,null),jl=t,Zl=Ll,Hl=null,Vl=Wl=1073741823,Gl=null,ql=0,Yl=!1}function ws(e,t){for(;;){try{if(ii(),Hi.current=ko,Ki)for(var n=Gi.memoizedState;null!==n;){var r=n.queue;null!==r&&(r.pending=null),n=n.next}if(Vi=0,Yi=qi=Gi=null,Ki=!1,null===Ul||null===Ul.return)return Zl=Dl,Hl=t,Ul=null;e:{var a=e,i=Ul.return,o=Ul,l=t;if(t=jl,o.effectTag|=2048,o.firstEffect=o.lastEffect=null,null!==l&&"object"==typeof l&&"function"==typeof l.then){var s=l;if(0==(2&o.mode)){var c=o.alternate;c?(o.updateQueue=c.updateQueue,o.memoizedState=c.memoizedState,o.expirationTime=c.expirationTime):(o.updateQueue=null,o.memoizedState=null)}var u=0!=(1&Ui.current),d=i;do{var p;if(p=13===d.tag){var f=d.memoizedState;if(null!==f)p=null!==f.dehydrated;else{var m=d.memoizedProps;p=void 0!==m.fallback&&(!0!==m.unstable_avoidThisFallback||!u)}}if(p){var g=d.updateQueue;if(null===g){var h=new Set;h.add(s),d.updateQueue=h}else g.add(s);if(0==(2&d.mode)){if(d.effectTag|=64,o.effectTag&=-2981,1===o.tag)if(null===o.alternate)o.tag=17;else{var b=fi(1073741823,null);b.tag=2,mi(o,b)}o.expirationTime=1073741823;break e}l=void 0,o=t;var v=a.pingCache;if(null===v?(v=a.pingCache=new kl,l=new Set,v.set(s,l)):void 0===(l=v.get(s))&&(l=new Set,v.set(s,l)),!l.has(o)){l.add(o);var y=Ms.bind(null,a,s,o);s.then(y,y)}d.effectTag|=4096,d.expirationTime=t;break e}d=d.return}while(null!==d);l=Error((he(o.type)||"A React component")+" suspended while rendering, but no fallback UI was specified.\n\nAdd a <Suspense fallback=...> component higher in the tree to provide a loading indicator or placeholder to display."+be(o))}Zl!==Bl&&(Zl=Rl),l=il(l,o),d=i;do{switch(d.tag){case 3:s=l,d.effectTag|=4096,d.expirationTime=t,gi(d,El(d,s,t));break e;case 1:s=l;var w=d.type,x=d.stateNode;if(0==(64&d.effectTag)&&("function"==typeof w.getDerivedStateFromError||null!==x&&"function"==typeof x.componentDidCatch&&(null===ts||!ts.has(x)))){d.effectTag|=4096,d.expirationTime=t,gi(d,Sl(d,s,t));break e}}d=d.return}while(null!==d)}Ul=Cs(Ul)}catch(k){t=k;continue}break}}function xs(){var e=Cl.current;return Cl.current=ko,null===e?ko:e}function ks(e,t){e<Wl&&2<e&&(Wl=e),null!==t&&e<Vl&&2<e&&(Vl=e,Gl=t)}function Es(e){e>ql&&(ql=e)}function Ss(){for(;null!==Ul;)Ul=_s(Ul)}function Ts(){for(;null!==Ul&&!$a();)Ul=_s(Ul)}function _s(e){var t=Tl(e.alternate,e,jl);return e.memoizedProps=e.pendingProps,null===t&&(t=Cs(e)),Al.current=null,t}function Cs(e){Ul=e;do{var t=Ul.alternate;if(e=Ul.return,0==(2048&Ul.effectTag)){if(t=rl(t,Ul,jl),1===jl||1!==Ul.childExpirationTime){for(var n=0,r=Ul.child;null!==r;){var a=r.expirationTime,i=r.childExpirationTime;a>n&&(n=a),i>n&&(n=i),r=r.sibling}Ul.childExpirationTime=n}if(null!==t)return t;null!==e&&0==(2048&e.effectTag)&&(null===e.firstEffect&&(e.firstEffect=Ul.firstEffect),null!==Ul.lastEffect&&(null!==e.lastEffect&&(e.lastEffect.nextEffect=Ul.firstEffect),e.lastEffect=Ul.lastEffect),1<Ul.effectTag&&(null!==e.lastEffect?e.lastEffect.nextEffect=Ul:e.firstEffect=Ul,e.lastEffect=Ul))}else{if(null!==(t=al(Ul)))return t.effectTag&=2047,t;null!==e&&(e.firstEffect=e.lastEffect=null,e.effectTag|=2048)}if(null!==(t=Ul.sibling))return t;Ul=e}while(null!==Ul);return Zl===Ll&&(Zl=Bl),null}function As(e){var t=e.expirationTime;return t>(e=e.childExpirationTime)?t:e}function Ps(e){var t=Va();return qa(99,Ns.bind(null,e,t)),null}function Ns(e,t){do{Is()}while(null!==rs);if(($l&(Ol|Il))!==Pl)throw Error(o(327));var n=e.finishedWork,r=e.finishedExpirationTime;if(null===n)return null;if(e.finishedWork=null,e.finishedExpirationTime=0,n===e.current)throw Error(o(177));e.callbackNode=null,e.callbackExpirationTime=0,e.callbackPriority=90,e.nextKnownPendingLevel=0;var a=As(n);if(e.firstPendingTime=a,r<=e.lastSuspendedTime?e.firstSuspendedTime=e.lastSuspendedTime=e.nextKnownPendingLevel=0:r<=e.firstSuspendedTime&&(e.firstSuspendedTime=r-1),r<=e.lastPingedTime&&(e.lastPingedTime=0),r<=e.lastExpiredTime&&(e.lastExpiredTime=0),e===zl&&(Ul=zl=null,jl=0),1<n.effectTag?null!==n.lastEffect?(n.lastEffect.nextEffect=n,a=n.firstEffect):a=n:a=n.firstEffect,null!==a){var i=$l;$l|=Il,Al.current=null,xn=Gt;var l=gn();if(hn(l)){if("selectionStart"in l)var s={start:l.selectionStart,end:l.selectionEnd};else e:{var c=(s=(s=l.ownerDocument)&&s.defaultView||window).getSelection&&s.getSelection();if(c&&0!==c.rangeCount){s=c.anchorNode;var u=c.anchorOffset,d=c.focusNode;c=c.focusOffset;try{s.nodeType,d.nodeType}catch(_){s=null;break e}var p=0,f=-1,m=-1,g=0,h=0,b=l,v=null;t:for(;;){for(var y;b!==s||0!==u&&3!==b.nodeType||(f=p+u),b!==d||0!==c&&3!==b.nodeType||(m=p+c),3===b.nodeType&&(p+=b.nodeValue.length),null!==(y=b.firstChild);)v=b,b=y;for(;;){if(b===l)break t;if(v===s&&++g===u&&(f=p),v===d&&++h===c&&(m=p),null!==(y=b.nextSibling))break;v=(b=v).parentNode}b=y}s=-1===f||-1===m?null:{start:f,end:m}}else s=null}s=s||{start:0,end:0}}else s=null;kn={activeElementDetached:null,focusedElem:l,selectionRange:s},Gt=!1,Xl=a;do{try{Os()}catch(_){if(null===Xl)throw Error(o(330));Rs(Xl,_),Xl=Xl.nextEffect}}while(null!==Xl);Xl=a;do{try{for(l=e,s=t;null!==Xl;){var w=Xl.effectTag;if(16&w&&Ue(Xl.stateNode,""),128&w){var x=Xl.alternate;if(null!==x){var k=x.ref;null!==k&&("function"==typeof k?k(null):k.current=null)}}switch(1038&w){case 2:hl(Xl),Xl.effectTag&=-3;break;case 6:hl(Xl),Xl.effectTag&=-3,wl(Xl.alternate,Xl);break;case 1024:Xl.effectTag&=-1025;break;case 1028:Xl.effectTag&=-1025,wl(Xl.alternate,Xl);break;case 4:wl(Xl.alternate,Xl);break;case 8:yl(l,u=Xl,s),ml(u)}Xl=Xl.nextEffect}}catch(_){if(null===Xl)throw Error(o(330));Rs(Xl,_),Xl=Xl.nextEffect}}while(null!==Xl);if(k=kn,x=gn(),w=k.focusedElem,s=k.selectionRange,x!==w&&w&&w.ownerDocument&&mn(w.ownerDocument.documentElement,w)){null!==s&&hn(w)&&(x=s.start,void 0===(k=s.end)&&(k=x),"selectionStart"in w?(w.selectionStart=x,w.selectionEnd=Math.min(k,w.value.length)):(k=(x=w.ownerDocument||document)&&x.defaultView||window).getSelection&&(k=k.getSelection(),u=w.textContent.length,l=Math.min(s.start,u),s=void 0===s.end?l:Math.min(s.end,u),!k.extend&&l>s&&(u=s,s=l,l=u),u=fn(w,l),d=fn(w,s),u&&d&&(1!==k.rangeCount||k.anchorNode!==u.node||k.anchorOffset!==u.offset||k.focusNode!==d.node||k.focusOffset!==d.offset)&&((x=x.createRange()).setStart(u.node,u.offset),k.removeAllRanges(),l>s?(k.addRange(x),k.extend(d.node,d.offset)):(x.setEnd(d.node,d.offset),k.addRange(x))))),x=[];for(k=w;k=k.parentNode;)1===k.nodeType&&x.push({element:k,left:k.scrollLeft,top:k.scrollTop});for("function"==typeof w.focus&&w.focus(),w=0;w<x.length;w++)(k=x[w]).element.scrollLeft=k.left,k.element.scrollTop=k.top}Gt=!!xn,kn=xn=null,e.current=n,Xl=a;do{try{for(w=e;null!==Xl;){var E=Xl.effectTag;if(36&E&&pl(w,Xl.alternate,Xl),128&E){x=void 0;var S=Xl.ref;if(null!==S){var T=Xl.stateNode;Xl.tag,x=T,"function"==typeof S?S(x):S.current=x}}Xl=Xl.nextEffect}}catch(_){if(null===Xl)throw Error(o(330));Rs(Xl,_),Xl=Xl.nextEffect}}while(null!==Xl);Xl=null,za(),$l=i}else e.current=n;if(ns)ns=!1,rs=e,as=t;else for(Xl=a;null!==Xl;)t=Xl.nextEffect,Xl.nextEffect=null,Xl=t;if(0===(t=e.firstPendingTime)&&(ts=null),1073741823===t?e===ls?os++:(os=0,ls=e):os=0,"function"==typeof Bs&&Bs(n.stateNode,r),ms(e),Jl)throw Jl=!1,e=es,es=null,e;return($l&Nl)!==Pl||Qa(),null}function Os(){for(;null!==Xl;){var e=Xl.effectTag;0!=(256&e)&&cl(Xl.alternate,Xl),0==(512&e)||ns||(ns=!0,Ya(97,(function(){return Is(),null}))),Xl=Xl.nextEffect}}function Is(){if(90!==as){var e=97<as?97:as;return as=90,qa(e,Ls)}}function Ls(){if(null===rs)return!1;var e=rs;if(rs=null,($l&(Ol|Il))!==Pl)throw Error(o(331));var t=$l;for($l|=Il,e=e.current.firstEffect;null!==e;){try{var n=e;if(0!=(512&n.effectTag))switch(n.tag){case 0:case 11:case 15:case 22:ul(5,n),dl(5,n)}}catch(r){if(null===e)throw Error(o(330));Rs(e,r)}n=e.nextEffect,e.nextEffect=null,e=n}return $l=t,Qa(),!0}function Ds(e,t,n){mi(e,t=El(e,t=il(n,t),1073741823)),null!==(e=ps(e,1073741823))&&ms(e)}function Rs(e,t){if(3===e.tag)Ds(e,e,t);else for(var n=e.return;null!==n;){if(3===n.tag){Ds(n,e,t);break}if(1===n.tag){var r=n.stateNode;if("function"==typeof n.type.getDerivedStateFromError||"function"==typeof r.componentDidCatch&&(null===ts||!ts.has(r))){mi(n,e=Sl(n,e=il(t,e),1073741823)),null!==(n=ps(n,1073741823))&&ms(n);break}}n=n.return}}function Ms(e,t,n){var r=e.pingCache;null!==r&&r.delete(t),zl===e&&jl===n?Zl===Fl||Zl===Ml&&1073741823===Wl&&Wa()-Kl<Ql?ys(e,jl):Yl=!0:Ys(e,n)&&(0!==(t=e.lastPingedTime)&&t<n||(e.lastPingedTime=n,ms(e)))}function Fs(e,t){var n=e.stateNode;null!==n&&n.delete(t),0===(t=0)&&(t=us(t=cs(),e,null)),null!==(e=ps(e,t))&&ms(e)}Tl=function(e,t,n){var r=t.expirationTime;if(null!==e){var a=t.pendingProps;if(e.memoizedProps!==a||va.current)Mo=!0;else{if(r<n){switch(Mo=!1,t.tag){case 3:Wo(t),Do();break;case 5:if($i(t),4&t.mode&&1!==n&&a.hidden)return t.expirationTime=t.childExpirationTime=1,null;break;case 1:xa(t.type)&&Ta(t);break;case 4:Fi(t,t.stateNode.containerInfo);break;case 10:r=t.memoizedProps.value,a=t.type._context,ga(ti,a._currentValue),a._currentValue=r;break;case 13:if(null!==t.memoizedState)return 0!==(r=t.child.childExpirationTime)&&r>=n?Qo(e,t,n):(ga(Ui,1&Ui.current),null!==(t=tl(e,t,n))?t.sibling:null);ga(Ui,1&Ui.current);break;case 19:if(r=t.childExpirationTime>=n,0!=(64&e.effectTag)){if(r)return el(e,t,n);t.effectTag|=64}if(null!==(a=t.memoizedState)&&(a.rendering=null,a.tail=null),ga(Ui,Ui.current),!r)return null}return tl(e,t,n)}Mo=!1}}else Mo=!1;switch(t.expirationTime=0,t.tag){case 2:if(r=t.type,null!==e&&(e.alternate=null,t.alternate=null,t.effectTag|=2),e=t.pendingProps,a=wa(t,ba.current),si(t,n),a=Ji(null,t,r,e,a,n),t.effectTag|=1,"object"==typeof a&&null!==a&&"function"==typeof a.render&&void 0===a.$$typeof){if(t.tag=1,t.memoizedState=null,t.updateQueue=null,xa(r)){var i=!0;Ta(t)}else i=!1;t.memoizedState=null!==a.state&&void 0!==a.state?a.state:null,di(t);var l=r.getDerivedStateFromProps;"function"==typeof l&&wi(t,r,l,e),a.updater=xi,t.stateNode=a,a._reactInternalFiber=t,Ti(t,r,e,n),t=Ho(null,t,r,!0,i,n)}else t.tag=0,Fo(null,t,a,n),t=t.child;return t;case 16:e:{if(a=t.elementType,null!==e&&(e.alternate=null,t.alternate=null,t.effectTag|=2),e=t.pendingProps,function(e){if(-1===e._status){e._status=0;var t=e._ctor;t=t(),e._result=t,t.then((function(t){0===e._status&&(t=t.default,e._status=1,e._result=t)}),(function(t){0===e._status&&(e._status=2,e._result=t)}))}}(a),1!==a._status)throw a._result;switch(a=a._result,t.type=a,i=t.tag=function(e){if("function"==typeof e)return js(e)?1:0;if(null!=e){if((e=e.$$typeof)===se)return 11;if(e===de)return 14}return 2}(a),e=ei(a,e),i){case 0:t=jo(null,t,a,e,n);break e;case 1:t=Zo(null,t,a,e,n);break e;case 11:t=Bo(null,t,a,e,n);break e;case 14:t=$o(null,t,a,ei(a.type,e),r,n);break e}throw Error(o(306,a,""))}return t;case 0:return r=t.type,a=t.pendingProps,jo(e,t,r,a=t.elementType===r?a:ei(r,a),n);case 1:return r=t.type,a=t.pendingProps,Zo(e,t,r,a=t.elementType===r?a:ei(r,a),n);case 3:if(Wo(t),r=t.updateQueue,null===e||null===r)throw Error(o(282));if(r=t.pendingProps,a=null!==(a=t.memoizedState)?a.element:null,pi(e,t),hi(t,r,null,n),(r=t.memoizedState.element)===a)Do(),t=tl(e,t,n);else{if((a=t.stateNode.hydrate)&&(Co=Cn(t.stateNode.containerInfo.firstChild),_o=t,a=Ao=!0),a)for(n=Oi(t,null,r,n),t.child=n;n;)n.effectTag=-3&n.effectTag|1024,n=n.sibling;else Fo(e,t,r,n),Do();t=t.child}return t;case 5:return $i(t),null===e&&Oo(t),r=t.type,a=t.pendingProps,i=null!==e?e.memoizedProps:null,l=a.children,Sn(r,a)?l=null:null!==i&&Sn(r,i)&&(t.effectTag|=16),Uo(e,t),4&t.mode&&1!==n&&a.hidden?(t.expirationTime=t.childExpirationTime=1,t=null):(Fo(e,t,l,n),t=t.child),t;case 6:return null===e&&Oo(t),null;case 13:return Qo(e,t,n);case 4:return Fi(t,t.stateNode.containerInfo),r=t.pendingProps,null===e?t.child=Ni(t,null,r,n):Fo(e,t,r,n),t.child;case 11:return r=t.type,a=t.pendingProps,Bo(e,t,r,a=t.elementType===r?a:ei(r,a),n);case 7:return Fo(e,t,t.pendingProps,n),t.child;case 8:case 12:return Fo(e,t,t.pendingProps.children,n),t.child;case 10:e:{r=t.type._context,a=t.pendingProps,l=t.memoizedProps,i=a.value;var s=t.type._context;if(ga(ti,s._currentValue),s._currentValue=i,null!==l)if(s=l.value,0===(i=Zr(s,i)?0:0|("function"==typeof r._calculateChangedBits?r._calculateChangedBits(s,i):1073741823))){if(l.children===a.children&&!va.current){t=tl(e,t,n);break e}}else for(null!==(s=t.child)&&(s.return=t);null!==s;){var c=s.dependencies;if(null!==c){l=s.child;for(var u=c.firstContext;null!==u;){if(u.context===r&&0!=(u.observedBits&i)){1===s.tag&&((u=fi(n,null)).tag=2,mi(s,u)),s.expirationTime<n&&(s.expirationTime=n),null!==(u=s.alternate)&&u.expirationTime<n&&(u.expirationTime=n),li(s.return,n),c.expirationTime<n&&(c.expirationTime=n);break}u=u.next}}else l=10===s.tag&&s.type===t.type?null:s.child;if(null!==l)l.return=s;else for(l=s;null!==l;){if(l===t){l=null;break}if(null!==(s=l.sibling)){s.return=l.return,l=s;break}l=l.return}s=l}Fo(e,t,a.children,n),t=t.child}return t;case 9:return a=t.type,r=(i=t.pendingProps).children,si(t,n),r=r(a=ci(a,i.unstable_observedBits)),t.effectTag|=1,Fo(e,t,r,n),t.child;case 14:return i=ei(a=t.type,t.pendingProps),$o(e,t,a,i=ei(a.type,i),r,n);case 15:return zo(e,t,t.type,t.pendingProps,r,n);case 17:return r=t.type,a=t.pendingProps,a=t.elementType===r?a:ei(r,a),null!==e&&(e.alternate=null,t.alternate=null,t.effectTag|=2),t.tag=1,xa(r)?(e=!0,Ta(t)):e=!1,si(t,n),Ei(t,r,a),Ti(t,r,a,n),Ho(null,t,r,!0,e,n);case 19:return el(e,t,n)}throw Error(o(156,t.tag))};var Bs=null,$s=null;function zs(e,t,n,r){this.tag=e,this.key=n,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=t,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=r,this.effectTag=0,this.lastEffect=this.firstEffect=this.nextEffect=null,this.childExpirationTime=this.expirationTime=0,this.alternate=null}function Us(e,t,n,r){return new zs(e,t,n,r)}function js(e){return!(!(e=e.prototype)||!e.isReactComponent)}function Zs(e,t){var n=e.alternate;return null===n?((n=Us(e.tag,t,e.key,e.mode)).elementType=e.elementType,n.type=e.type,n.stateNode=e.stateNode,n.alternate=e,e.alternate=n):(n.pendingProps=t,n.effectTag=0,n.nextEffect=null,n.firstEffect=null,n.lastEffect=null),n.childExpirationTime=e.childExpirationTime,n.expirationTime=e.expirationTime,n.child=e.child,n.memoizedProps=e.memoizedProps,n.memoizedState=e.memoizedState,n.updateQueue=e.updateQueue,t=e.dependencies,n.dependencies=null===t?null:{expirationTime:t.expirationTime,firstContext:t.firstContext,responders:t.responders},n.sibling=e.sibling,n.index=e.index,n.ref=e.ref,n}function Hs(e,t,n,r,a,i){var l=2;if(r=e,"function"==typeof e)js(e)&&(l=1);else if("string"==typeof e)l=5;else e:switch(e){case ne:return Ws(n.children,a,i,t);case le:l=8,a|=7;break;case re:l=8,a|=1;break;case ae:return(e=Us(12,n,t,8|a)).elementType=ae,e.type=ae,e.expirationTime=i,e;case ce:return(e=Us(13,n,t,a)).type=ce,e.elementType=ce,e.expirationTime=i,e;case ue:return(e=Us(19,n,t,a)).elementType=ue,e.expirationTime=i,e;default:if("object"==typeof e&&null!==e)switch(e.$$typeof){case ie:l=10;break e;case oe:l=9;break e;case se:l=11;break e;case de:l=14;break e;case pe:l=16,r=null;break e;case fe:l=22;break e}throw Error(o(130,null==e?e:typeof e,""))}return(t=Us(l,n,t,a)).elementType=e,t.type=r,t.expirationTime=i,t}function Ws(e,t,n,r){return(e=Us(7,e,r,t)).expirationTime=n,e}function Vs(e,t,n){return(e=Us(6,e,null,t)).expirationTime=n,e}function Gs(e,t,n){return(t=Us(4,null!==e.children?e.children:[],e.key,t)).expirationTime=n,t.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},t}function qs(e,t,n){this.tag=t,this.current=null,this.containerInfo=e,this.pingCache=this.pendingChildren=null,this.finishedExpirationTime=0,this.finishedWork=null,this.timeoutHandle=-1,this.pendingContext=this.context=null,this.hydrate=n,this.callbackNode=null,this.callbackPriority=90,this.lastExpiredTime=this.lastPingedTime=this.nextKnownPendingLevel=this.lastSuspendedTime=this.firstSuspendedTime=this.firstPendingTime=0}function Ys(e,t){var n=e.firstSuspendedTime;return e=e.lastSuspendedTime,0!==n&&n>=t&&e<=t}function Ks(e,t){var n=e.firstSuspendedTime,r=e.lastSuspendedTime;n<t&&(e.firstSuspendedTime=t),(r>t||0===n)&&(e.lastSuspendedTime=t),t<=e.lastPingedTime&&(e.lastPingedTime=0),t<=e.lastExpiredTime&&(e.lastExpiredTime=0)}function Qs(e,t){t>e.firstPendingTime&&(e.firstPendingTime=t);var n=e.firstSuspendedTime;0!==n&&(t>=n?e.firstSuspendedTime=e.lastSuspendedTime=e.nextKnownPendingLevel=0:t>=e.lastSuspendedTime&&(e.lastSuspendedTime=t+1),t>e.nextKnownPendingLevel&&(e.nextKnownPendingLevel=t))}function Xs(e,t){var n=e.lastExpiredTime;(0===n||n>t)&&(e.lastExpiredTime=t)}function Js(e,t,n,r){var a=t.current,i=cs(),l=vi.suspense;i=us(i,a,l);e:if(n){t:{if(et(n=n._reactInternalFiber)!==n||1!==n.tag)throw Error(o(170));var s=n;do{switch(s.tag){case 3:s=s.stateNode.context;break t;case 1:if(xa(s.type)){s=s.stateNode.__reactInternalMemoizedMergedChildContext;break t}}s=s.return}while(null!==s);throw Error(o(171))}if(1===n.tag){var c=n.type;if(xa(c)){n=Sa(n,c,s);break e}}n=s}else n=ha;return null===t.context?t.context=n:t.pendingContext=n,(t=fi(i,l)).payload={element:e},null!==(r=void 0===r?null:r)&&(t.callback=r),mi(a,t),ds(a,i),i}function ec(e){return(e=e.current).child?(e.child.tag,e.child.stateNode):null}function tc(e,t){null!==(e=e.memoizedState)&&null!==e.dehydrated&&e.retryTime<t&&(e.retryTime=t)}function nc(e,t){tc(e,t),(e=e.alternate)&&tc(e,t)}function rc(e,t,n){var r=new qs(e,t,n=null!=n&&!0===n.hydrate),a=Us(3,null,null,2===t?7:1===t?3:0);r.current=a,a.stateNode=r,di(a),e[In]=r.current,n&&0!==t&&function(e,t){var n=Je(t);Ct.forEach((function(e){gt(e,t,n)})),At.forEach((function(e){gt(e,t,n)}))}(0,9===e.nodeType?e:e.ownerDocument),this._internalRoot=r}function ac(e){return!(!e||1!==e.nodeType&&9!==e.nodeType&&11!==e.nodeType&&(8!==e.nodeType||" react-mount-point-unstable "!==e.nodeValue))}function ic(e,t,n,r,a){var i=n._reactRootContainer;if(i){var o=i._internalRoot;if("function"==typeof a){var l=a;a=function(){var e=ec(o);l.call(e)}}Js(t,o,e,a)}else{if(i=n._reactRootContainer=function(e,t){if(t||(t=!(!(t=e?9===e.nodeType?e.documentElement:e.firstChild:null)||1!==t.nodeType||!t.hasAttribute("data-reactroot"))),!t)for(var n;n=e.lastChild;)e.removeChild(n);return new rc(e,0,t?{hydrate:!0}:void 0)}(n,r),o=i._internalRoot,"function"==typeof a){var s=a;a=function(){var e=ec(o);s.call(e)}}vs((function(){Js(t,o,e,a)}))}return ec(o)}function oc(e,t){var n=2<arguments.length&&void 0!==arguments[2]?arguments[2]:null;if(!ac(t))throw Error(o(200));return function(e,t,n){var r=3<arguments.length&&void 0!==arguments[3]?arguments[3]:null;return{$$typeof:te,key:null==r?null:""+r,children:e,containerInfo:t,implementation:n}}(e,t,null,n)}rc.prototype.render=function(e){Js(e,this._internalRoot,null,null)},rc.prototype.unmount=function(){var e=this._internalRoot,t=e.containerInfo;Js(null,e,null,(function(){t[In]=null}))},ht=function(e){if(13===e.tag){var t=Ja(cs(),150,100);ds(e,t),nc(e,t)}},bt=function(e){13===e.tag&&(ds(e,3),nc(e,3))},vt=function(e){if(13===e.tag){var t=cs();ds(e,t=us(t,e,null)),nc(e,t)}},A=function(e,t,n){switch(t){case"input":if(Te(e,n),t=n.name,"radio"===n.type&&null!=t){for(n=e;n.parentNode;)n=n.parentNode;for(n=n.querySelectorAll("input[name="+JSON.stringify(""+t)+'][type="radio"]'),t=0;t<n.length;t++){var r=n[t];if(r!==e&&r.form===e.form){var a=Mn(r);if(!a)throw Error(o(90));xe(r),Te(r,a)}}}break;case"textarea":Ie(e,n);break;case"select":null!=(t=n.value)&&Pe(e,!!n.multiple,t,!1)}},D=bs,R=function(e,t,n,r,a){var i=$l;$l|=4;try{return qa(98,e.bind(null,t,n,r,a))}finally{($l=i)===Pl&&Qa()}},M=function(){($l&(1|Ol|Il))===Pl&&(function(){if(null!==is){var e=is;is=null,e.forEach((function(e,t){Xs(t,e),ms(t)})),Qa()}}(),Is())},F=function(e,t){var n=$l;$l|=2;try{return e(t)}finally{($l=n)===Pl&&Qa()}};var lc={Events:[Dn,Rn,Mn,_,E,Zn,function(e){it(e,jn)},I,L,Xt,st,Is,{current:!1}]};!function(e){var t=e.findFiberByHostInstance;(function(e){if("undefined"==typeof __REACT_DEVTOOLS_GLOBAL_HOOK__)return!1;var t=__REACT_DEVTOOLS_GLOBAL_HOOK__;if(t.isDisabled||!t.supportsFiber)return!0;try{var n=t.inject(e);Bs=function(e){try{t.onCommitFiberRoot(n,e,void 0,64==(64&e.current.effectTag))}catch(r){}},$s=function(e){try{t.onCommitFiberUnmount(n,e)}catch(r){}}}catch(r){}})(a({},e,{overrideHookState:null,overrideProps:null,setSuspenseHandler:null,scheduleUpdate:null,currentDispatcherRef:K.ReactCurrentDispatcher,findHostInstanceByFiber:function(e){return null===(e=rt(e))?null:e.stateNode},findFiberByHostInstance:function(e){return t?t(e):null},findHostInstancesForRefresh:null,scheduleRefresh:null,scheduleRoot:null,setRefreshHandler:null,getCurrentFiber:null}))}({findFiberByHostInstance:Ln,bundleType:0,version:"16.14.0",rendererPackageName:"react-dom"}),t.hydrate=function(e,t,n){if(!ac(t))throw Error(o(200));return ic(null,e,t,!0,n)}},3935:(e,t,n)=>{"use strict";!function e(){if("undefined"!=typeof __REACT_DEVTOOLS_GLOBAL_HOOK__&&"function"==typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE)try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(e)}catch(t){console.error(t)}}(),e.exports=n(4448)},9590:e=>{var t="undefined"!=typeof Element,n="function"==typeof Map,r="function"==typeof Set,a="function"==typeof ArrayBuffer&&!!ArrayBuffer.isView;function i(e,o){if(e===o)return!0;if(e&&o&&"object"==typeof e&&"object"==typeof o){if(e.constructor!==o.constructor)return!1;var l,s,c,u;if(Array.isArray(e)){if((l=e.length)!=o.length)return!1;for(s=l;0!=s--;)if(!i(e[s],o[s]))return!1;return!0}if(n&&e instanceof Map&&o instanceof Map){if(e.size!==o.size)return!1;for(u=e.entries();!(s=u.next()).done;)if(!o.has(s.value[0]))return!1;for(u=e.entries();!(s=u.next()).done;)if(!i(s.value[1],o.get(s.value[0])))return!1;return!0}if(r&&e instanceof Set&&o instanceof Set){if(e.size!==o.size)return!1;for(u=e.entries();!(s=u.next()).done;)if(!o.has(s.value[0]))return!1;return!0}if(a&&ArrayBuffer.isView(e)&&ArrayBuffer.isView(o)){if((l=e.length)!=o.length)return!1;for(s=l;0!=s--;)if(e[s]!==o[s])return!1;return!0}if(e.constructor===RegExp)return e.source===o.source&&e.flags===o.flags;if(e.valueOf!==Object.prototype.valueOf&&"function"==typeof e.valueOf&&"function"==typeof o.valueOf)return e.valueOf()===o.valueOf();if(e.toString!==Object.prototype.toString&&"function"==typeof e.toString&&"function"==typeof o.toString)return e.toString()===o.toString();if((l=(c=Object.keys(e)).length)!==Object.keys(o).length)return!1;for(s=l;0!=s--;)if(!Object.prototype.hasOwnProperty.call(o,c[s]))return!1;if(t&&e instanceof Element)return!1;for(s=l;0!=s--;)if(("_owner"!==c[s]&&"__v"!==c[s]&&"__o"!==c[s]||!e.$$typeof)&&!i(e[c[s]],o[c[s]]))return!1;return!0}return e!=e&&o!=o}e.exports=function(e,t){try{return i(e,t)}catch(n){if((n.message||"").match(/stack|recursion/i))return console.warn("react-fast-compare cannot handle circular refs"),!1;throw n}}},405:(e,t,n)=>{"use strict";n.d(t,{B6:()=>W,ql:()=>J});var r=n(7294),a=n(5697),i=n.n(a),o=n(9590),l=n.n(o),s=n(1143),c=n.n(s),u=n(6774),d=n.n(u);function p(){return p=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},p.apply(this,arguments)}function f(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,m(e,t)}function m(e,t){return m=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e},m(e,t)}function g(e,t){if(null==e)return{};var n,r,a={},i=Object.keys(e);for(r=0;r<i.length;r++)t.indexOf(n=i[r])>=0||(a[n]=e[n]);return a}var h={BASE:"base",BODY:"body",HEAD:"head",HTML:"html",LINK:"link",META:"meta",NOSCRIPT:"noscript",SCRIPT:"script",STYLE:"style",TITLE:"title",FRAGMENT:"Symbol(react.fragment)"},b={rel:["amphtml","canonical","alternate"]},v={type:["application/ld+json"]},y={charset:"",name:["robots","description"],property:["og:type","og:title","og:url","og:image","og:image:alt","og:description","twitter:url","twitter:title","twitter:description","twitter:image","twitter:image:alt","twitter:card","twitter:site"]},w=Object.keys(h).map((function(e){return h[e]})),x={accesskey:"accessKey",charset:"charSet",class:"className",contenteditable:"contentEditable",contextmenu:"contextMenu","http-equiv":"httpEquiv",itemprop:"itemProp",tabindex:"tabIndex"},k=Object.keys(x).reduce((function(e,t){return e[x[t]]=t,e}),{}),E=function(e,t){for(var n=e.length-1;n>=0;n-=1){var r=e[n];if(Object.prototype.hasOwnProperty.call(r,t))return r[t]}return null},S=function(e){var t=E(e,h.TITLE),n=E(e,"titleTemplate");if(Array.isArray(t)&&(t=t.join("")),n&&t)return n.replace(/%s/g,(function(){return t}));var r=E(e,"defaultTitle");return t||r||void 0},T=function(e){return E(e,"onChangeClientState")||function(){}},_=function(e,t){return t.filter((function(t){return void 0!==t[e]})).map((function(t){return t[e]})).reduce((function(e,t){return p({},e,t)}),{})},C=function(e,t){return t.filter((function(e){return void 0!==e[h.BASE]})).map((function(e){return e[h.BASE]})).reverse().reduce((function(t,n){if(!t.length)for(var r=Object.keys(n),a=0;a<r.length;a+=1){var i=r[a].toLowerCase();if(-1!==e.indexOf(i)&&n[i])return t.concat(n)}return t}),[])},A=function(e,t,n){var r={};return n.filter((function(t){return!!Array.isArray(t[e])||(void 0!==t[e]&&console&&"function"==typeof console.warn&&console.warn("Helmet: "+e+' should be of type "Array". Instead found type "'+typeof t[e]+'"'),!1)})).map((function(t){return t[e]})).reverse().reduce((function(e,n){var a={};n.filter((function(e){for(var n,i=Object.keys(e),o=0;o<i.length;o+=1){var l=i[o],s=l.toLowerCase();-1===t.indexOf(s)||"rel"===n&&"canonical"===e[n].toLowerCase()||"rel"===s&&"stylesheet"===e[s].toLowerCase()||(n=s),-1===t.indexOf(l)||"innerHTML"!==l&&"cssText"!==l&&"itemprop"!==l||(n=l)}if(!n||!e[n])return!1;var c=e[n].toLowerCase();return r[n]||(r[n]={}),a[n]||(a[n]={}),!r[n][c]&&(a[n][c]=!0,!0)})).reverse().forEach((function(t){return e.push(t)}));for(var i=Object.keys(a),o=0;o<i.length;o+=1){var l=i[o],s=p({},r[l],a[l]);r[l]=s}return e}),[]).reverse()},P=function(e,t){if(Array.isArray(e)&&e.length)for(var n=0;n<e.length;n+=1)if(e[n][t])return!0;return!1},N=function(e){return Array.isArray(e)?e.join(""):e},O=function(e,t){return Array.isArray(e)?e.reduce((function(e,n){return function(e,t){for(var n=Object.keys(e),r=0;r<n.length;r+=1)if(t[n[r]]&&t[n[r]].includes(e[n[r]]))return!0;return!1}(n,t)?e.priority.push(n):e.default.push(n),e}),{priority:[],default:[]}):{default:e}},I=function(e,t){var n;return p({},e,((n={})[t]=void 0,n))},L=[h.NOSCRIPT,h.SCRIPT,h.STYLE],D=function(e,t){return void 0===t&&(t=!0),!1===t?String(e):String(e).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")},R=function(e){return Object.keys(e).reduce((function(t,n){var r=void 0!==e[n]?n+'="'+e[n]+'"':""+n;return t?t+" "+r:r}),"")},M=function(e,t){return void 0===t&&(t={}),Object.keys(e).reduce((function(t,n){return t[x[n]||n]=e[n],t}),t)},F=function(e,t){return t.map((function(t,n){var a,i=((a={key:n})["data-rh"]=!0,a);return Object.keys(t).forEach((function(e){var n=x[e]||e;"innerHTML"===n||"cssText"===n?i.dangerouslySetInnerHTML={__html:t.innerHTML||t.cssText}:i[n]=t[e]})),r.createElement(e,i)}))},B=function(e,t,n){switch(e){case h.TITLE:return{toComponent:function(){return n=t.titleAttributes,(a={key:e=t.title})["data-rh"]=!0,i=M(n,a),[r.createElement(h.TITLE,i,e)];var e,n,a,i},toString:function(){return function(e,t,n,r){var a=R(n),i=N(t);return a?"<"+e+' data-rh="true" '+a+">"+D(i,r)+"</"+e+">":"<"+e+' data-rh="true">'+D(i,r)+"</"+e+">"}(e,t.title,t.titleAttributes,n)}};case"bodyAttributes":case"htmlAttributes":return{toComponent:function(){return M(t)},toString:function(){return R(t)}};default:return{toComponent:function(){return F(e,t)},toString:function(){return function(e,t,n){return t.reduce((function(t,r){var a=Object.keys(r).filter((function(e){return!("innerHTML"===e||"cssText"===e)})).reduce((function(e,t){var a=void 0===r[t]?t:t+'="'+D(r[t],n)+'"';return e?e+" "+a:a}),""),i=r.innerHTML||r.cssText||"",o=-1===L.indexOf(e);return t+"<"+e+' data-rh="true" '+a+(o?"/>":">"+i+"</"+e+">")}),"")}(e,t,n)}}}},$=function(e){var t=e.baseTag,n=e.bodyAttributes,r=e.encode,a=e.htmlAttributes,i=e.noscriptTags,o=e.styleTags,l=e.title,s=void 0===l?"":l,c=e.titleAttributes,u=e.linkTags,d=e.metaTags,p=e.scriptTags,f={toComponent:function(){},toString:function(){return""}};if(e.prioritizeSeoTags){var m=function(e){var t=e.linkTags,n=e.scriptTags,r=e.encode,a=O(e.metaTags,y),i=O(t,b),o=O(n,v);return{priorityMethods:{toComponent:function(){return[].concat(F(h.META,a.priority),F(h.LINK,i.priority),F(h.SCRIPT,o.priority))},toString:function(){return B(h.META,a.priority,r)+" "+B(h.LINK,i.priority,r)+" "+B(h.SCRIPT,o.priority,r)}},metaTags:a.default,linkTags:i.default,scriptTags:o.default}}(e);f=m.priorityMethods,u=m.linkTags,d=m.metaTags,p=m.scriptTags}return{priority:f,base:B(h.BASE,t,r),bodyAttributes:B("bodyAttributes",n,r),htmlAttributes:B("htmlAttributes",a,r),link:B(h.LINK,u,r),meta:B(h.META,d,r),noscript:B(h.NOSCRIPT,i,r),script:B(h.SCRIPT,p,r),style:B(h.STYLE,o,r),title:B(h.TITLE,{title:s,titleAttributes:c},r)}},z=[],U=function(e,t){var n=this;void 0===t&&(t="undefined"!=typeof document),this.instances=[],this.value={setHelmet:function(e){n.context.helmet=e},helmetInstances:{get:function(){return n.canUseDOM?z:n.instances},add:function(e){(n.canUseDOM?z:n.instances).push(e)},remove:function(e){var t=(n.canUseDOM?z:n.instances).indexOf(e);(n.canUseDOM?z:n.instances).splice(t,1)}}},this.context=e,this.canUseDOM=t,t||(e.helmet=$({baseTag:[],bodyAttributes:{},encodeSpecialCharacters:!0,htmlAttributes:{},linkTags:[],metaTags:[],noscriptTags:[],scriptTags:[],styleTags:[],title:"",titleAttributes:{}}))},j=r.createContext({}),Z=i().shape({setHelmet:i().func,helmetInstances:i().shape({get:i().func,add:i().func,remove:i().func})}),H="undefined"!=typeof document,W=function(e){function t(n){var r;return(r=e.call(this,n)||this).helmetData=new U(r.props.context,t.canUseDOM),r}return f(t,e),t.prototype.render=function(){return r.createElement(j.Provider,{value:this.helmetData.value},this.props.children)},t}(r.Component);W.canUseDOM=H,W.propTypes={context:i().shape({helmet:i().shape()}),children:i().node.isRequired},W.defaultProps={context:{}},W.displayName="HelmetProvider";var V=function(e,t){var n,r=document.head||document.querySelector(h.HEAD),a=r.querySelectorAll(e+"[data-rh]"),i=[].slice.call(a),o=[];return t&&t.length&&t.forEach((function(t){var r=document.createElement(e);for(var a in t)Object.prototype.hasOwnProperty.call(t,a)&&("innerHTML"===a?r.innerHTML=t.innerHTML:"cssText"===a?r.styleSheet?r.styleSheet.cssText=t.cssText:r.appendChild(document.createTextNode(t.cssText)):r.setAttribute(a,void 0===t[a]?"":t[a]));r.setAttribute("data-rh","true"),i.some((function(e,t){return n=t,r.isEqualNode(e)}))?i.splice(n,1):o.push(r)})),i.forEach((function(e){return e.parentNode.removeChild(e)})),o.forEach((function(e){return r.appendChild(e)})),{oldTags:i,newTags:o}},G=function(e,t){var n=document.getElementsByTagName(e)[0];if(n){for(var r=n.getAttribute("data-rh"),a=r?r.split(","):[],i=[].concat(a),o=Object.keys(t),l=0;l<o.length;l+=1){var s=o[l],c=t[s]||"";n.getAttribute(s)!==c&&n.setAttribute(s,c),-1===a.indexOf(s)&&a.push(s);var u=i.indexOf(s);-1!==u&&i.splice(u,1)}for(var d=i.length-1;d>=0;d-=1)n.removeAttribute(i[d]);a.length===i.length?n.removeAttribute("data-rh"):n.getAttribute("data-rh")!==o.join(",")&&n.setAttribute("data-rh",o.join(","))}},q=function(e,t){var n=e.baseTag,r=e.htmlAttributes,a=e.linkTags,i=e.metaTags,o=e.noscriptTags,l=e.onChangeClientState,s=e.scriptTags,c=e.styleTags,u=e.title,d=e.titleAttributes;G(h.BODY,e.bodyAttributes),G(h.HTML,r),function(e,t){void 0!==e&&document.title!==e&&(document.title=N(e)),G(h.TITLE,t)}(u,d);var p={baseTag:V(h.BASE,n),linkTags:V(h.LINK,a),metaTags:V(h.META,i),noscriptTags:V(h.NOSCRIPT,o),scriptTags:V(h.SCRIPT,s),styleTags:V(h.STYLE,c)},f={},m={};Object.keys(p).forEach((function(e){var t=p[e],n=t.newTags,r=t.oldTags;n.length&&(f[e]=n),r.length&&(m[e]=p[e].oldTags)})),t&&t(),l(e,f,m)},Y=null,K=function(e){function t(){for(var t,n=arguments.length,r=new Array(n),a=0;a<n;a++)r[a]=arguments[a];return(t=e.call.apply(e,[this].concat(r))||this).rendered=!1,t}f(t,e);var n=t.prototype;return n.shouldComponentUpdate=function(e){return!d()(e,this.props)},n.componentDidUpdate=function(){this.emitChange()},n.componentWillUnmount=function(){this.props.context.helmetInstances.remove(this),this.emitChange()},n.emitChange=function(){var e,t,n=this.props.context,r=n.setHelmet,a=null,i=(e=n.helmetInstances.get().map((function(e){var t=p({},e.props);return delete t.context,t})),{baseTag:C(["href"],e),bodyAttributes:_("bodyAttributes",e),defer:E(e,"defer"),encode:E(e,"encodeSpecialCharacters"),htmlAttributes:_("htmlAttributes",e),linkTags:A(h.LINK,["rel","href"],e),metaTags:A(h.META,["name","charset","http-equiv","property","itemprop"],e),noscriptTags:A(h.NOSCRIPT,["innerHTML"],e),onChangeClientState:T(e),scriptTags:A(h.SCRIPT,["src","innerHTML"],e),styleTags:A(h.STYLE,["cssText"],e),title:S(e),titleAttributes:_("titleAttributes",e),prioritizeSeoTags:P(e,"prioritizeSeoTags")});W.canUseDOM?(t=i,Y&&cancelAnimationFrame(Y),t.defer?Y=requestAnimationFrame((function(){q(t,(function(){Y=null}))})):(q(t),Y=null)):$&&(a=$(i)),r(a)},n.init=function(){this.rendered||(this.rendered=!0,this.props.context.helmetInstances.add(this),this.emitChange())},n.render=function(){return this.init(),null},t}(r.Component);K.propTypes={context:Z.isRequired},K.displayName="HelmetDispatcher";var Q=["children"],X=["children"],J=function(e){function t(){return e.apply(this,arguments)||this}f(t,e);var n=t.prototype;return n.shouldComponentUpdate=function(e){return!l()(I(this.props,"helmetData"),I(e,"helmetData"))},n.mapNestedChildrenToProps=function(e,t){if(!t)return null;switch(e.type){case h.SCRIPT:case h.NOSCRIPT:return{innerHTML:t};case h.STYLE:return{cssText:t};default:throw new Error("<"+e.type+" /> elements are self-closing and can not contain children. Refer to our API for more information.")}},n.flattenArrayTypeChildren=function(e){var t,n=e.child,r=e.arrayTypeChildren;return p({},r,((t={})[n.type]=[].concat(r[n.type]||[],[p({},e.newChildProps,this.mapNestedChildrenToProps(n,e.nestedChildren))]),t))},n.mapObjectTypeChildren=function(e){var t,n,r=e.child,a=e.newProps,i=e.newChildProps,o=e.nestedChildren;switch(r.type){case h.TITLE:return p({},a,((t={})[r.type]=o,t.titleAttributes=p({},i),t));case h.BODY:return p({},a,{bodyAttributes:p({},i)});case h.HTML:return p({},a,{htmlAttributes:p({},i)});default:return p({},a,((n={})[r.type]=p({},i),n))}},n.mapArrayTypeChildrenToProps=function(e,t){var n=p({},t);return Object.keys(e).forEach((function(t){var r;n=p({},n,((r={})[t]=e[t],r))})),n},n.warnOnInvalidChildren=function(e,t){return c()(w.some((function(t){return e.type===t})),"function"==typeof e.type?"You may be attempting to nest <Helmet> components within each other, which is not allowed. Refer to our API for more information.":"Only elements types "+w.join(", ")+" are allowed. Helmet does not support rendering <"+e.type+"> elements. Refer to our API for more information."),c()(!t||"string"==typeof t||Array.isArray(t)&&!t.some((function(e){return"string"!=typeof e})),"Helmet expects a string as a child of <"+e.type+">. Did you forget to wrap your children in braces? ( <"+e.type+">{``}</"+e.type+"> ) Refer to our API for more information."),!0},n.mapChildrenToProps=function(e,t){var n=this,a={};return r.Children.forEach(e,(function(e){if(e&&e.props){var r=e.props,i=r.children,o=g(r,Q),l=Object.keys(o).reduce((function(e,t){return e[k[t]||t]=o[t],e}),{}),s=e.type;switch("symbol"==typeof s?s=s.toString():n.warnOnInvalidChildren(e,i),s){case h.FRAGMENT:t=n.mapChildrenToProps(i,t);break;case h.LINK:case h.META:case h.NOSCRIPT:case h.SCRIPT:case h.STYLE:a=n.flattenArrayTypeChildren({child:e,arrayTypeChildren:a,newChildProps:l,nestedChildren:i});break;default:t=n.mapObjectTypeChildren({child:e,newProps:t,newChildProps:l,nestedChildren:i})}}})),this.mapArrayTypeChildrenToProps(a,t)},n.render=function(){var e=this.props,t=e.children,n=g(e,X),a=p({},n),i=n.helmetData;return t&&(a=this.mapChildrenToProps(t,a)),!i||i instanceof U||(i=new U(i.context,i.instances)),i?r.createElement(K,p({},a,{context:i.value,helmetData:void 0})):r.createElement(j.Consumer,null,(function(e){return r.createElement(K,p({},a,{context:e}))}))},t}(r.Component);J.propTypes={base:i().object,bodyAttributes:i().object,children:i().oneOfType([i().arrayOf(i().node),i().node]),defaultTitle:i().string,defer:i().bool,encodeSpecialCharacters:i().bool,htmlAttributes:i().object,link:i().arrayOf(i().object),meta:i().arrayOf(i().object),noscript:i().arrayOf(i().object),onChangeClientState:i().func,script:i().arrayOf(i().object),style:i().arrayOf(i().object),title:i().string,titleAttributes:i().object,titleTemplate:i().string,prioritizeSeoTags:i().bool,helmetData:i().object},J.defaultProps={defer:!0,encodeSpecialCharacters:!0,prioritizeSeoTags:!1},J.displayName="Helmet"},9921:(e,t)=>{"use strict";var n="function"==typeof Symbol&&Symbol.for,r=n?Symbol.for("react.element"):60103,a=n?Symbol.for("react.portal"):60106,i=n?Symbol.for("react.fragment"):60107,o=n?Symbol.for("react.strict_mode"):60108,l=n?Symbol.for("react.profiler"):60114,s=n?Symbol.for("react.provider"):60109,c=n?Symbol.for("react.context"):60110,u=n?Symbol.for("react.async_mode"):60111,d=n?Symbol.for("react.concurrent_mode"):60111,p=n?Symbol.for("react.forward_ref"):60112,f=n?Symbol.for("react.suspense"):60113,m=n?Symbol.for("react.suspense_list"):60120,g=n?Symbol.for("react.memo"):60115,h=n?Symbol.for("react.lazy"):60116,b=n?Symbol.for("react.block"):60121,v=n?Symbol.for("react.fundamental"):60117,y=n?Symbol.for("react.responder"):60118,w=n?Symbol.for("react.scope"):60119;function x(e){if("object"==typeof e&&null!==e){var t=e.$$typeof;switch(t){case r:switch(e=e.type){case u:case d:case i:case l:case o:case f:return e;default:switch(e=e&&e.$$typeof){case c:case p:case h:case g:case s:return e;default:return t}}case a:return t}}}function k(e){return x(e)===d}t.AsyncMode=u,t.ConcurrentMode=d,t.ContextConsumer=c,t.ContextProvider=s,t.Element=r,t.ForwardRef=p,t.Fragment=i,t.Lazy=h,t.Memo=g,t.Portal=a,t.Profiler=l,t.StrictMode=o,t.Suspense=f,t.isAsyncMode=function(e){return k(e)||x(e)===u},t.isConcurrentMode=k,t.isContextConsumer=function(e){return x(e)===c},t.isContextProvider=function(e){return x(e)===s},t.isElement=function(e){return"object"==typeof e&&null!==e&&e.$$typeof===r},t.isForwardRef=function(e){return x(e)===p},t.isFragment=function(e){return x(e)===i},t.isLazy=function(e){return x(e)===h},t.isMemo=function(e){return x(e)===g},t.isPortal=function(e){return x(e)===a},t.isProfiler=function(e){return x(e)===l},t.isStrictMode=function(e){return x(e)===o},t.isSuspense=function(e){return x(e)===f},t.isValidElementType=function(e){return"string"==typeof e||"function"==typeof e||e===i||e===d||e===l||e===o||e===f||e===m||"object"==typeof e&&null!==e&&(e.$$typeof===h||e.$$typeof===g||e.$$typeof===s||e.$$typeof===c||e.$$typeof===p||e.$$typeof===v||e.$$typeof===y||e.$$typeof===w||e.$$typeof===b)},t.typeOf=x},9864:(e,t,n)=>{"use strict";e.exports=n(9921)},8356:(e,t,n)=>{"use strict";function r(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,e.__proto__=t}function a(e){if(void 0===e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return e}function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(){return o=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},o.apply(this,arguments)}var l=n(7294),s=n(5697),c=[],u=[];function d(e){var t=e(),n={loading:!0,loaded:null,error:null};return n.promise=t.then((function(e){return n.loading=!1,n.loaded=e,e})).catch((function(e){throw n.loading=!1,n.error=e,e})),n}function p(e){var t={loading:!1,loaded:{},error:null},n=[];try{Object.keys(e).forEach((function(r){var a=d(e[r]);a.loading?t.loading=!0:(t.loaded[r]=a.loaded,t.error=a.error),n.push(a.promise),a.promise.then((function(e){t.loaded[r]=e})).catch((function(e){t.error=e}))}))}catch(r){t.error=r}return t.promise=Promise.all(n).then((function(e){return t.loading=!1,e})).catch((function(e){throw t.loading=!1,e})),t}function f(e,t){return l.createElement((n=e)&&n.__esModule?n.default:n,t);var n}function m(e,t){var d,p;if(!t.loading)throw new Error("react-loadable requires a `loading` component");var m=o({loader:null,loading:null,delay:200,timeout:null,render:f,webpack:null,modules:null},t),g=null;function h(){return g||(g=e(m.loader)),g.promise}return c.push(h),"function"==typeof m.webpack&&u.push((function(){if((0,m.webpack)().every((function(e){return void 0!==e&&void 0!==n.m[e]})))return h()})),p=d=function(t){function n(n){var r;return i(a(a(r=t.call(this,n)||this)),"retry",(function(){r.setState({error:null,loading:!0,timedOut:!1}),g=e(m.loader),r._loadModule()})),h(),r.state={error:g.error,pastDelay:!1,timedOut:!1,loading:g.loading,loaded:g.loaded},r}r(n,t),n.preload=function(){return h()};var o=n.prototype;return o.UNSAFE_componentWillMount=function(){this._loadModule()},o.componentDidMount=function(){this._mounted=!0},o._loadModule=function(){var e=this;if(this.context.loadable&&Array.isArray(m.modules)&&m.modules.forEach((function(t){e.context.loadable.report(t)})),g.loading){var t=function(t){e._mounted&&e.setState(t)};"number"==typeof m.delay&&(0===m.delay?this.setState({pastDelay:!0}):this._delay=setTimeout((function(){t({pastDelay:!0})}),m.delay)),"number"==typeof m.timeout&&(this._timeout=setTimeout((function(){t({timedOut:!0})}),m.timeout));var n=function(){t({error:g.error,loaded:g.loaded,loading:g.loading}),e._clearTimeouts()};g.promise.then((function(){return n(),null})).catch((function(e){return n(),null}))}},o.componentWillUnmount=function(){this._mounted=!1,this._clearTimeouts()},o._clearTimeouts=function(){clearTimeout(this._delay),clearTimeout(this._timeout)},o.render=function(){return this.state.loading||this.state.error?l.createElement(m.loading,{isLoading:this.state.loading,pastDelay:this.state.pastDelay,timedOut:this.state.timedOut,error:this.state.error,retry:this.retry}):this.state.loaded?m.render(this.state.loaded,this.props):null},n}(l.Component),i(d,"contextTypes",{loadable:s.shape({report:s.func.isRequired})}),p}function g(e){return m(d,e)}g.Map=function(e){if("function"!=typeof e.render)throw new Error("LoadableMap requires a `render(loaded, props)` function");return m(p,e)};var h=function(e){function t(){return e.apply(this,arguments)||this}r(t,e);var n=t.prototype;return n.getChildContext=function(){return{loadable:{report:this.props.report}}},n.render=function(){return l.Children.only(this.props.children)},t}(l.Component);function b(e){for(var t=[];e.length;){var n=e.pop();t.push(n())}return Promise.all(t).then((function(){if(e.length)return b(e)}))}i(h,"propTypes",{report:s.func.isRequired}),i(h,"childContextTypes",{loadable:s.shape({report:s.func.isRequired}).isRequired}),g.Capture=h,g.preloadAll=function(){return new Promise((function(e,t){b(c).then(e,t)}))},g.preloadReady=function(){return new Promise((function(e,t){b(u).then(e,e)}))},e.exports=g},8790:(e,t,n)=>{"use strict";n.d(t,{H:()=>l,f:()=>o});var r=n(6550),a=n(7462),i=n(7294);function o(e,t,n){return void 0===n&&(n=[]),e.some((function(e){var a=e.path?(0,r.LX)(t,e):n.length?n[n.length-1].match:r.F0.computeRootMatch(t);return a&&(n.push({route:e,match:a}),e.routes&&o(e.routes,t,n)),a})),n}function l(e,t,n){return void 0===t&&(t={}),void 0===n&&(n={}),e?i.createElement(r.rs,n,e.map((function(e,n){return i.createElement(r.AW,{key:e.key||n,path:e.path,exact:e.exact,strict:e.strict,render:function(n){return e.render?e.render((0,a.Z)({},n,{},t,{route:e})):i.createElement(e.component,(0,a.Z)({},n,t,{route:e}))}})}))):null}},3727:(e,t,n)=>{"use strict";n.d(t,{OL:()=>y,VK:()=>u,rU:()=>h});var r=n(6550),a=n(5068),i=n(7294),o=n(9318),l=n(7462),s=n(3366),c=n(8776),u=function(e){function t(){for(var t,n=arguments.length,r=new Array(n),a=0;a<n;a++)r[a]=arguments[a];return(t=e.call.apply(e,[this].concat(r))||this).history=(0,o.lX)(t.props),t}return(0,a.Z)(t,e),t.prototype.render=function(){return i.createElement(r.F0,{history:this.history,children:this.props.children})},t}(i.Component);i.Component;var d=function(e,t){return"function"==typeof e?e(t):e},p=function(e,t){return"string"==typeof e?(0,o.ob)(e,null,null,t):e},f=function(e){return e},m=i.forwardRef;void 0===m&&(m=f);var g=m((function(e,t){var n=e.innerRef,r=e.navigate,a=e.onClick,o=(0,s.Z)(e,["innerRef","navigate","onClick"]),c=o.target,u=(0,l.Z)({},o,{onClick:function(e){try{a&&a(e)}catch(t){throw e.preventDefault(),t}e.defaultPrevented||0!==e.button||c&&"_self"!==c||function(e){return!!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)}(e)||(e.preventDefault(),r())}});return u.ref=f!==m&&t||n,i.createElement("a",u)}));var h=m((function(e,t){var n=e.component,a=void 0===n?g:n,u=e.replace,h=e.to,b=e.innerRef,v=(0,s.Z)(e,["component","replace","to","innerRef"]);return i.createElement(r.s6.Consumer,null,(function(e){e||(0,c.Z)(!1);var n=e.history,r=p(d(h,e.location),e.location),s=r?n.createHref(r):"",g=(0,l.Z)({},v,{href:s,navigate:function(){var t=d(h,e.location),r=(0,o.Ep)(e.location)===(0,o.Ep)(p(t));(u||r?n.replace:n.push)(t)}});return f!==m?g.ref=t||b:g.innerRef=b,i.createElement(a,g)}))})),b=function(e){return e},v=i.forwardRef;void 0===v&&(v=b);var y=v((function(e,t){var n=e["aria-current"],a=void 0===n?"page":n,o=e.activeClassName,u=void 0===o?"active":o,f=e.activeStyle,m=e.className,g=e.exact,y=e.isActive,w=e.location,x=e.sensitive,k=e.strict,E=e.style,S=e.to,T=e.innerRef,_=(0,s.Z)(e,["aria-current","activeClassName","activeStyle","className","exact","isActive","location","sensitive","strict","style","to","innerRef"]);return i.createElement(r.s6.Consumer,null,(function(e){e||(0,c.Z)(!1);var n=w||e.location,o=p(d(S,n),n),s=o.pathname,C=s&&s.replace(/([.+*?=^!:${}()[\]|/\\])/g,"\\$1"),A=C?(0,r.LX)(n.pathname,{path:C,exact:g,sensitive:x,strict:k}):null,P=!!(y?y(A,n):A),N="function"==typeof m?m(P):m,O="function"==typeof E?E(P):E;P&&(N=function(){for(var e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];return t.filter((function(e){return e})).join(" ")}(N,u),O=(0,l.Z)({},O,f));var I=(0,l.Z)({"aria-current":P&&a||null,className:N,style:O,to:o},_);return b!==v?I.ref=t||T:I.innerRef=T,i.createElement(h,I)}))}))},6550:(e,t,n)=>{"use strict";n.d(t,{AW:()=>S,F0:()=>y,LX:()=>E,TH:()=>L,k6:()=>I,rs:()=>N,s6:()=>v});var r=n(5068),a=n(7294),i=n(5697),o=n.n(i),l=n(9318),s=n(8776),c=n(7462),u=n(4779),d=n.n(u),p=(n(9864),n(3366)),f=(n(8679),1073741823),m="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:void 0!==n.g?n.g:{};var g=a.createContext||function(e,t){var n,i,l="__create-react-context-"+function(){var e="__global_unique_id__";return m[e]=(m[e]||0)+1}()+"__",s=function(e){function n(){for(var t,n,r,a=arguments.length,i=new Array(a),o=0;o<a;o++)i[o]=arguments[o];return(t=e.call.apply(e,[this].concat(i))||this).emitter=(n=t.props.value,r=[],{on:function(e){r.push(e)},off:function(e){r=r.filter((function(t){return t!==e}))},get:function(){return n},set:function(e,t){n=e,r.forEach((function(e){return e(n,t)}))}}),t}(0,r.Z)(n,e);var a=n.prototype;return a.getChildContext=function(){var e;return(e={})[l]=this.emitter,e},a.componentWillReceiveProps=function(e){if(this.props.value!==e.value){var n,r=this.props.value,a=e.value;((i=r)===(o=a)?0!==i||1/i==1/o:i!=i&&o!=o)?n=0:(n="function"==typeof t?t(r,a):f,0!==(n|=0)&&this.emitter.set(e.value,n))}var i,o},a.render=function(){return this.props.children},n}(a.Component);s.childContextTypes=((n={})[l]=o().object.isRequired,n);var c=function(t){function n(){for(var e,n=arguments.length,r=new Array(n),a=0;a<n;a++)r[a]=arguments[a];return(e=t.call.apply(t,[this].concat(r))||this).observedBits=void 0,e.state={value:e.getValue()},e.onUpdate=function(t,n){0!=((0|e.observedBits)&n)&&e.setState({value:e.getValue()})},e}(0,r.Z)(n,t);var a=n.prototype;return a.componentWillReceiveProps=function(e){var t=e.observedBits;this.observedBits=null==t?f:t},a.componentDidMount=function(){this.context[l]&&this.context[l].on(this.onUpdate);var e=this.props.observedBits;this.observedBits=null==e?f:e},a.componentWillUnmount=function(){this.context[l]&&this.context[l].off(this.onUpdate)},a.getValue=function(){return this.context[l]?this.context[l].get():e},a.render=function(){return(e=this.props.children,Array.isArray(e)?e[0]:e)(this.state.value);var e},n}(a.Component);return c.contextTypes=((i={})[l]=o().object,i),{Provider:s,Consumer:c}},h=function(e){var t=g();return t.displayName=e,t},b=h("Router-History"),v=h("Router"),y=function(e){function t(t){var n;return(n=e.call(this,t)||this).state={location:t.history.location},n._isMounted=!1,n._pendingLocation=null,t.staticContext||(n.unlisten=t.history.listen((function(e){n._pendingLocation=e}))),n}(0,r.Z)(t,e),t.computeRootMatch=function(e){return{path:"/",url:"/",params:{},isExact:"/"===e}};var n=t.prototype;return n.componentDidMount=function(){var e=this;this._isMounted=!0,this.unlisten&&this.unlisten(),this.props.staticContext||(this.unlisten=this.props.history.listen((function(t){e._isMounted&&e.setState({location:t})}))),this._pendingLocation&&this.setState({location:this._pendingLocation})},n.componentWillUnmount=function(){this.unlisten&&(this.unlisten(),this._isMounted=!1,this._pendingLocation=null)},n.render=function(){return a.createElement(v.Provider,{value:{history:this.props.history,location:this.state.location,match:t.computeRootMatch(this.state.location.pathname),staticContext:this.props.staticContext}},a.createElement(b.Provider,{children:this.props.children||null,value:this.props.history}))},t}(a.Component);a.Component;a.Component;var w={},x=1e4,k=0;function E(e,t){void 0===t&&(t={}),("string"==typeof t||Array.isArray(t))&&(t={path:t});var n=t,r=n.path,a=n.exact,i=void 0!==a&&a,o=n.strict,l=void 0!==o&&o,s=n.sensitive,c=void 0!==s&&s;return[].concat(r).reduce((function(t,n){if(!n&&""!==n)return null;if(t)return t;var r=function(e,t){var n=""+t.end+t.strict+t.sensitive,r=w[n]||(w[n]={});if(r[e])return r[e];var a=[],i={regexp:d()(e,a,t),keys:a};return k<x&&(r[e]=i,k++),i}(n,{end:i,strict:l,sensitive:c}),a=r.regexp,o=r.keys,s=a.exec(e);if(!s)return null;var u=s[0],p=s.slice(1),f=e===u;return i&&!f?null:{path:n,url:"/"===n&&""===u?"/":u,isExact:f,params:o.reduce((function(e,t,n){return e[t.name]=p[n],e}),{})}}),null)}var S=function(e){function t(){return e.apply(this,arguments)||this}return(0,r.Z)(t,e),t.prototype.render=function(){var e=this;return a.createElement(v.Consumer,null,(function(t){t||(0,s.Z)(!1);var n=e.props.location||t.location,r=e.props.computedMatch?e.props.computedMatch:e.props.path?E(n.pathname,e.props):t.match,i=(0,c.Z)({},t,{location:n,match:r}),o=e.props,l=o.children,u=o.component,d=o.render;return Array.isArray(l)&&function(e){return 0===a.Children.count(e)}(l)&&(l=null),a.createElement(v.Provider,{value:i},i.match?l?"function"==typeof l?l(i):l:u?a.createElement(u,i):d?d(i):null:"function"==typeof l?l(i):null)}))},t}(a.Component);function T(e){return"/"===e.charAt(0)?e:"/"+e}function _(e,t){if(!e)return t;var n=T(e);return 0!==t.pathname.indexOf(n)?t:(0,c.Z)({},t,{pathname:t.pathname.substr(n.length)})}function C(e){return"string"==typeof e?e:(0,l.Ep)(e)}function A(e){return function(){(0,s.Z)(!1)}}function P(){}a.Component;var N=function(e){function t(){return e.apply(this,arguments)||this}return(0,r.Z)(t,e),t.prototype.render=function(){var e=this;return a.createElement(v.Consumer,null,(function(t){t||(0,s.Z)(!1);var n,r,i=e.props.location||t.location;return a.Children.forEach(e.props.children,(function(e){if(null==r&&a.isValidElement(e)){n=e;var o=e.props.path||e.props.from;r=o?E(i.pathname,(0,c.Z)({},e.props,{path:o})):t.match}})),r?a.cloneElement(n,{location:i,computedMatch:r}):null}))},t}(a.Component);var O=a.useContext;function I(){return O(b)}function L(){return O(v).location}},2408:(e,t,n)=>{"use strict";var r=n(7418),a="function"==typeof Symbol&&Symbol.for,i=a?Symbol.for("react.element"):60103,o=a?Symbol.for("react.portal"):60106,l=a?Symbol.for("react.fragment"):60107,s=a?Symbol.for("react.strict_mode"):60108,c=a?Symbol.for("react.profiler"):60114,u=a?Symbol.for("react.provider"):60109,d=a?Symbol.for("react.context"):60110,p=a?Symbol.for("react.forward_ref"):60112,f=a?Symbol.for("react.suspense"):60113,m=a?Symbol.for("react.memo"):60115,g=a?Symbol.for("react.lazy"):60116,h="function"==typeof Symbol&&Symbol.iterator;function b(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n<arguments.length;n++)t+="&args[]="+encodeURIComponent(arguments[n]);return"Minified React error #"+e+"; visit "+t+" for the full message or use the non-minified dev environment for full errors and additional helpful warnings."}var v={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},y={};function w(e,t,n){this.props=e,this.context=t,this.refs=y,this.updater=n||v}function x(){}function k(e,t,n){this.props=e,this.context=t,this.refs=y,this.updater=n||v}w.prototype.isReactComponent={},w.prototype.setState=function(e,t){if("object"!=typeof e&&"function"!=typeof e&&null!=e)throw Error(b(85));this.updater.enqueueSetState(this,e,t,"setState")},w.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")},x.prototype=w.prototype;var E=k.prototype=new x;E.constructor=k,r(E,w.prototype),E.isPureReactComponent=!0;var S={current:null},T=Object.prototype.hasOwnProperty,_={key:!0,ref:!0,__self:!0,__source:!0};function C(e,t,n){var r,a={},o=null,l=null;if(null!=t)for(r in void 0!==t.ref&&(l=t.ref),void 0!==t.key&&(o=""+t.key),t)T.call(t,r)&&!_.hasOwnProperty(r)&&(a[r]=t[r]);var s=arguments.length-2;if(1===s)a.children=n;else if(1<s){for(var c=Array(s),u=0;u<s;u++)c[u]=arguments[u+2];a.children=c}if(e&&e.defaultProps)for(r in s=e.defaultProps)void 0===a[r]&&(a[r]=s[r]);return{$$typeof:i,type:e,key:o,ref:l,props:a,_owner:S.current}}function A(e){return"object"==typeof e&&null!==e&&e.$$typeof===i}var P=/\/+/g,N=[];function O(e,t,n,r){if(N.length){var a=N.pop();return a.result=e,a.keyPrefix=t,a.func=n,a.context=r,a.count=0,a}return{result:e,keyPrefix:t,func:n,context:r,count:0}}function I(e){e.result=null,e.keyPrefix=null,e.func=null,e.context=null,e.count=0,10>N.length&&N.push(e)}function L(e,t,n,r){var a=typeof e;"undefined"!==a&&"boolean"!==a||(e=null);var l=!1;if(null===e)l=!0;else switch(a){case"string":case"number":l=!0;break;case"object":switch(e.$$typeof){case i:case o:l=!0}}if(l)return n(r,e,""===t?"."+R(e,0):t),1;if(l=0,t=""===t?".":t+":",Array.isArray(e))for(var s=0;s<e.length;s++){var c=t+R(a=e[s],s);l+=L(a,c,n,r)}else if(null===e||"object"!=typeof e?c=null:c="function"==typeof(c=h&&e[h]||e["@@iterator"])?c:null,"function"==typeof c)for(e=c.call(e),s=0;!(a=e.next()).done;)l+=L(a=a.value,c=t+R(a,s++),n,r);else if("object"===a)throw n=""+e,Error(b(31,"[object Object]"===n?"object with keys {"+Object.keys(e).join(", ")+"}":n,""));return l}function D(e,t,n){return null==e?0:L(e,"",t,n)}function R(e,t){return"object"==typeof e&&null!==e&&null!=e.key?function(e){var t={"=":"=0",":":"=2"};return"$"+(""+e).replace(/[=:]/g,(function(e){return t[e]}))}(e.key):t.toString(36)}function M(e,t){e.func.call(e.context,t,e.count++)}function F(e,t,n){var r=e.result,a=e.keyPrefix;e=e.func.call(e.context,t,e.count++),Array.isArray(e)?B(e,r,n,(function(e){return e})):null!=e&&(A(e)&&(e=function(e,t){return{$$typeof:i,type:e.type,key:t,ref:e.ref,props:e.props,_owner:e._owner}}(e,a+(!e.key||t&&t.key===e.key?"":(""+e.key).replace(P,"$&/")+"/")+n)),r.push(e))}function B(e,t,n,r,a){var i="";null!=n&&(i=(""+n).replace(P,"$&/")+"/"),D(e,F,t=O(t,i,r,a)),I(t)}var $={current:null};function z(){var e=$.current;if(null===e)throw Error(b(321));return e}var U={ReactCurrentDispatcher:$,ReactCurrentBatchConfig:{suspense:null},ReactCurrentOwner:S,IsSomeRendererActing:{current:!1},assign:r};t.Children={map:function(e,t,n){if(null==e)return e;var r=[];return B(e,r,null,t,n),r},forEach:function(e,t,n){if(null==e)return e;D(e,M,t=O(null,null,t,n)),I(t)},count:function(e){return D(e,(function(){return null}),null)},toArray:function(e){var t=[];return B(e,t,null,(function(e){return e})),t},only:function(e){if(!A(e))throw Error(b(143));return e}},t.Component=w,t.Fragment=l,t.Profiler=c,t.PureComponent=k,t.StrictMode=s,t.Suspense=f,t.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=U,t.cloneElement=function(e,t,n){if(null==e)throw Error(b(267,e));var a=r({},e.props),o=e.key,l=e.ref,s=e._owner;if(null!=t){if(void 0!==t.ref&&(l=t.ref,s=S.current),void 0!==t.key&&(o=""+t.key),e.type&&e.type.defaultProps)var c=e.type.defaultProps;for(u in t)T.call(t,u)&&!_.hasOwnProperty(u)&&(a[u]=void 0===t[u]&&void 0!==c?c[u]:t[u])}var u=arguments.length-2;if(1===u)a.children=n;else if(1<u){c=Array(u);for(var d=0;d<u;d++)c[d]=arguments[d+2];a.children=c}return{$$typeof:i,type:e.type,key:o,ref:l,props:a,_owner:s}},t.createContext=function(e,t){return void 0===t&&(t=null),(e={$$typeof:d,_calculateChangedBits:t,_currentValue:e,_currentValue2:e,_threadCount:0,Provider:null,Consumer:null}).Provider={$$typeof:u,_context:e},e.Consumer=e},t.createElement=C,t.createFactory=function(e){var t=C.bind(null,e);return t.type=e,t},t.createRef=function(){return{current:null}},t.forwardRef=function(e){return{$$typeof:p,render:e}},t.isValidElement=A,t.lazy=function(e){return{$$typeof:g,_ctor:e,_status:-1,_result:null}},t.memo=function(e,t){return{$$typeof:m,type:e,compare:void 0===t?null:t}},t.useCallback=function(e,t){return z().useCallback(e,t)},t.useContext=function(e,t){return z().useContext(e,t)},t.useDebugValue=function(){},t.useEffect=function(e,t){return z().useEffect(e,t)},t.useImperativeHandle=function(e,t,n){return z().useImperativeHandle(e,t,n)},t.useLayoutEffect=function(e,t){return z().useLayoutEffect(e,t)},t.useMemo=function(e,t){return z().useMemo(e,t)},t.useReducer=function(e,t,n){return z().useReducer(e,t,n)},t.useRef=function(e){return z().useRef(e)},t.useState=function(e){return z().useState(e)},t.version="16.14.0"},7294:(e,t,n)=>{"use strict";e.exports=n(2408)},53:(e,t)=>{"use strict";var n,r,a,i,o;if("undefined"==typeof window||"function"!=typeof MessageChannel){var l=null,s=null,c=function(){if(null!==l)try{var e=t.unstable_now();l(!0,e),l=null}catch(n){throw setTimeout(c,0),n}},u=Date.now();t.unstable_now=function(){return Date.now()-u},n=function(e){null!==l?setTimeout(n,0,e):(l=e,setTimeout(c,0))},r=function(e,t){s=setTimeout(e,t)},a=function(){clearTimeout(s)},i=function(){return!1},o=t.unstable_forceFrameRate=function(){}}else{var d=window.performance,p=window.Date,f=window.setTimeout,m=window.clearTimeout;if("undefined"!=typeof console){var g=window.cancelAnimationFrame;"function"!=typeof window.requestAnimationFrame&&console.error("This browser doesn't support requestAnimationFrame. Make sure that you load a polyfill in older browsers. https://fb.me/react-polyfills"),"function"!=typeof g&&console.error("This browser doesn't support cancelAnimationFrame. Make sure that you load a polyfill in older browsers. https://fb.me/react-polyfills")}if("object"==typeof d&&"function"==typeof d.now)t.unstable_now=function(){return d.now()};else{var h=p.now();t.unstable_now=function(){return p.now()-h}}var b=!1,v=null,y=-1,w=5,x=0;i=function(){return t.unstable_now()>=x},o=function(){},t.unstable_forceFrameRate=function(e){0>e||125<e?console.error("forceFrameRate takes a positive int between 0 and 125, forcing framerates higher than 125 fps is not unsupported"):w=0<e?Math.floor(1e3/e):5};var k=new MessageChannel,E=k.port2;k.port1.onmessage=function(){if(null!==v){var e=t.unstable_now();x=e+w;try{v(!0,e)?E.postMessage(null):(b=!1,v=null)}catch(n){throw E.postMessage(null),n}}else b=!1},n=function(e){v=e,b||(b=!0,E.postMessage(null))},r=function(e,n){y=f((function(){e(t.unstable_now())}),n)},a=function(){m(y),y=-1}}function S(e,t){var n=e.length;e.push(t);e:for(;;){var r=n-1>>>1,a=e[r];if(!(void 0!==a&&0<C(a,t)))break e;e[r]=t,e[n]=a,n=r}}function T(e){return void 0===(e=e[0])?null:e}function _(e){var t=e[0];if(void 0!==t){var n=e.pop();if(n!==t){e[0]=n;e:for(var r=0,a=e.length;r<a;){var i=2*(r+1)-1,o=e[i],l=i+1,s=e[l];if(void 0!==o&&0>C(o,n))void 0!==s&&0>C(s,o)?(e[r]=s,e[l]=n,r=l):(e[r]=o,e[i]=n,r=i);else{if(!(void 0!==s&&0>C(s,n)))break e;e[r]=s,e[l]=n,r=l}}}return t}return null}function C(e,t){var n=e.sortIndex-t.sortIndex;return 0!==n?n:e.id-t.id}var A=[],P=[],N=1,O=null,I=3,L=!1,D=!1,R=!1;function M(e){for(var t=T(P);null!==t;){if(null===t.callback)_(P);else{if(!(t.startTime<=e))break;_(P),t.sortIndex=t.expirationTime,S(A,t)}t=T(P)}}function F(e){if(R=!1,M(e),!D)if(null!==T(A))D=!0,n(B);else{var t=T(P);null!==t&&r(F,t.startTime-e)}}function B(e,n){D=!1,R&&(R=!1,a()),L=!0;var o=I;try{for(M(n),O=T(A);null!==O&&(!(O.expirationTime>n)||e&&!i());){var l=O.callback;if(null!==l){O.callback=null,I=O.priorityLevel;var s=l(O.expirationTime<=n);n=t.unstable_now(),"function"==typeof s?O.callback=s:O===T(A)&&_(A),M(n)}else _(A);O=T(A)}if(null!==O)var c=!0;else{var u=T(P);null!==u&&r(F,u.startTime-n),c=!1}return c}finally{O=null,I=o,L=!1}}function $(e){switch(e){case 1:return-1;case 2:return 250;case 5:return 1073741823;case 4:return 1e4;default:return 5e3}}var z=o;t.unstable_IdlePriority=5,t.unstable_ImmediatePriority=1,t.unstable_LowPriority=4,t.unstable_NormalPriority=3,t.unstable_Profiling=null,t.unstable_UserBlockingPriority=2,t.unstable_cancelCallback=function(e){e.callback=null},t.unstable_continueExecution=function(){D||L||(D=!0,n(B))},t.unstable_getCurrentPriorityLevel=function(){return I},t.unstable_getFirstCallbackNode=function(){return T(A)},t.unstable_next=function(e){switch(I){case 1:case 2:case 3:var t=3;break;default:t=I}var n=I;I=t;try{return e()}finally{I=n}},t.unstable_pauseExecution=function(){},t.unstable_requestPaint=z,t.unstable_runWithPriority=function(e,t){switch(e){case 1:case 2:case 3:case 4:case 5:break;default:e=3}var n=I;I=e;try{return t()}finally{I=n}},t.unstable_scheduleCallback=function(e,i,o){var l=t.unstable_now();if("object"==typeof o&&null!==o){var s=o.delay;s="number"==typeof s&&0<s?l+s:l,o="number"==typeof o.timeout?o.timeout:$(e)}else o=$(e),s=l;return e={id:N++,callback:i,priorityLevel:e,startTime:s,expirationTime:o=s+o,sortIndex:-1},s>l?(e.sortIndex=s,S(P,e),null===T(A)&&e===T(P)&&(R?a():R=!0,r(F,s-l))):(e.sortIndex=o,S(A,e),D||L||(D=!0,n(B))),e},t.unstable_shouldYield=function(){var e=t.unstable_now();M(e);var n=T(A);return n!==O&&null!==O&&null!==n&&null!==n.callback&&n.startTime<=e&&n.expirationTime<O.expirationTime||i()},t.unstable_wrapCallback=function(e){var t=I;return function(){var n=I;I=t;try{return e.apply(this,arguments)}finally{I=n}}}},3840:(e,t,n)=>{"use strict";e.exports=n(53)},6774:e=>{e.exports=function(e,t,n,r){var a=n?n.call(r,e,t):void 0;if(void 0!==a)return!!a;if(e===t)return!0;if("object"!=typeof e||!e||"object"!=typeof t||!t)return!1;var i=Object.keys(e),o=Object.keys(t);if(i.length!==o.length)return!1;for(var l=Object.prototype.hasOwnProperty.bind(t),s=0;s<i.length;s++){var c=i[s];if(!l(c))return!1;var u=e[c],d=t[c];if(!1===(a=n?n.call(r,u,d,c):void 0)||void 0===a&&u!==d)return!1}return!0}},6809:(e,t,n)=>{"use strict";n.r(t),n.d(t,{default:()=>r});const r={title:"Weaver: DLT Interoperability Framework",tagline:"Documentation",url:"https://hyperledger-labs.github.io",baseUrl:"/weaver-dlt-interoperability/",onBrokenLinks:"throw",onBrokenMarkdownLinks:"warn",favicon:"shared/favicon.ico",organizationName:"hyperledger-labs",projectName:"hyperledger-labs.github.io",themeConfig:{prism:{additionalLanguages:["java","kotlin","groovy","toml"],theme:{plain:{color:"#bfc7d5",backgroundColor:"#292d3e"},styles:[{types:["comment"],style:{color:"rgb(105, 112, 152)",fontStyle:"italic"}},{types:["string","inserted"],style:{color:"rgb(195, 232, 141)"}},{types:["number"],style:{color:"rgb(247, 140, 108)"}},{types:["builtin","char","constant","function"],style:{color:"rgb(130, 170, 255)"}},{types:["punctuation","selector"],style:{color:"rgb(199, 146, 234)"}},{types:["variable"],style:{color:"rgb(191, 199, 213)"}},{types:["class-name","attr-name"],style:{color:"rgb(255, 203, 107)"}},{types:["tag","deleted"],style:{color:"rgb(255, 85, 114)"}},{types:["operator"],style:{color:"rgb(137, 221, 255)"}},{types:["boolean"],style:{color:"rgb(255, 88, 116)"}},{types:["keyword"],style:{fontStyle:"italic"}},{types:["doctype"],style:{color:"rgb(199, 146, 234)",fontStyle:"italic"}},{types:["namespace"],style:{color:"rgb(178, 204, 214)"}},{types:["url"],style:{color:"rgb(221, 221, 221)"}}]},magicComments:[{className:"theme-code-block-highlighted-line",line:"highlight-next-line",block:{start:"highlight-start",end:"highlight-end"}}]},navbar:{title:"Weaver",logo:{alt:"Weaver",src:"shared/logo.svg"},items:[{to:"docs/external/introduction",activeBasePath:"docs",label:"Docs",position:"left"},{to:"blog",label:"Blog",position:"left"},{href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability",label:"GitHub",position:"right"}],hideOnScroll:!1},footer:{style:"light",links:[],copyright:"Copyright \xa9 2023 Weaver Framework."},colorMode:{defaultMode:"light",disableSwitch:!1,respectPrefersColorScheme:!1},docs:{versionPersistence:"localStorage",sidebar:{hideable:!1,autoCollapseCategories:!1}},metadata:[],tableOfContents:{minHeadingLevel:2,maxHeadingLevel:3}},presets:[["@docusaurus/preset-classic",{docs:{sidebarPath:"/home/runner/work/weaver-dlt-interoperability/weaver-dlt-interoperability/docs/sidebars.js",editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/"},theme:{customCss:"/home/runner/work/weaver-dlt-interoperability/weaver-dlt-interoperability/docs/src/css/custom.css"}}]],baseUrlIssueBanner:!0,i18n:{defaultLocale:"en",path:"i18n",locales:["en"],localeConfigs:{}},onDuplicateRoutes:"warn",staticDirectories:["static"],customFields:{},plugins:[],themes:[],scripts:[],headTags:[],stylesheets:[],clientModules:[],titleDelimiter:"|",noIndex:!1,markdown:{mermaid:!1}}},7462:(e,t,n)=>{"use strict";function r(){return r=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},r.apply(this,arguments)}n.d(t,{Z:()=>r})},5068:(e,t,n)=>{"use strict";function r(e,t){return r=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(e,t){return e.__proto__=t,e},r(e,t)}function a(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,r(e,t)}n.d(t,{Z:()=>a})},3366:(e,t,n)=>{"use strict";function r(e,t){if(null==e)return{};var n,r,a={},i=Object.keys(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}n.d(t,{Z:()=>r})},8776:(e,t,n)=>{"use strict";n.d(t,{Z:()=>i});var r=!0,a="Invariant failed";function i(e,t){if(!e){if(r)throw new Error(a);var n="function"==typeof t?t():t,i=n?"".concat(a,": ").concat(n):a;throw new Error(i)}}},7529:e=>{"use strict";e.exports={}},6887:e=>{"use strict";e.exports=JSON.parse('{"/weaver-dlt-interoperability/blog-fba":{"__comp":"a6aa9e1f","__context":{"plugin":"ee4141e0"},"sidebar":"814f3328","items":[{"content":"bdfaba9c"},{"content":"3d5da5a5"}],"metadata":"591644de"},"/weaver-dlt-interoperability/blog/2021/01/21/cross-chain-asset-014":{"__comp":"ccc49370","__context":{"plugin":"ee4141e0"},"sidebar":"814f3328","content":"378badfe"},"/weaver-dlt-interoperability/blog/2021/01/21/emergence-enterprise-interoperability-e8d":{"__comp":"ccc49370","__context":{"plugin":"ee4141e0"},"sidebar":"814f3328","content":"56182e71"},"/weaver-dlt-interoperability/blog/archive-502":{"__comp":"9e4087bc","__context":{"plugin":"ee4141e0"},"archive":"64b157a3"},"/weaver-dlt-interoperability/docs-25b":{"__comp":"1be78505","__context":{"plugin":"99b332c9"},"versionMetadata":"935f2afb"},"/weaver-dlt-interoperability/docs/external/architecture-and-design/decentralized-identity-999":{"__comp":"17896441","content":"8758c959"},"/weaver-dlt-interoperability/docs/external/architecture-and-design/drivers-79c":{"__comp":"17896441","content":"7291aaef"},"/weaver-dlt-interoperability/docs/external/architecture-and-design/overview-390":{"__comp":"17896441","content":"b379f194"},"/weaver-dlt-interoperability/docs/external/architecture-and-design/relay-db6":{"__comp":"17896441","content":"e67be6b3"},"/weaver-dlt-interoperability/docs/external/architecture-and-design/weaver-dapps-52c":{"__comp":"17896441","content":"ec8cb05d"},"/weaver-dlt-interoperability/docs/external/deployment-considerations/deployment-patterns-22b":{"__comp":"17896441","content":"9f52c9db"},"/weaver-dlt-interoperability/docs/external/deployment-considerations/governance-and-policies-d9a":{"__comp":"17896441","content":"3ec01bef"},"/weaver-dlt-interoperability/docs/external/deployment-considerations/legal-and-regulation-956":{"__comp":"17896441","content":"ce7e6f90"},"/weaver-dlt-interoperability/docs/external/design-principles-9ec":{"__comp":"17896441","content":"e0bf5ccd"},"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/besu-6b8":{"__comp":"17896441","content":"b545330d"},"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/corda-a90":{"__comp":"17896441","content":"f0c74005"},"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/fabric-8fd":{"__comp":"17896441","content":"98ecfc99"},"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/overview-90e":{"__comp":"17896441","content":"8379e623"},"/weaver-dlt-interoperability/docs/external/getting-started/guide-465":{"__comp":"17896441","content":"20a6a7d9"},"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange-8e9":{"__comp":"17896441","content":"a6da3080"},"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/besu-besu-c57":{"__comp":"17896441","content":"f1311735"},"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/corda-besu-eea":{"__comp":"17896441","content":"15db90ce"},"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/corda-corda-929":{"__comp":"17896441","content":"935bcf2a"},"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-besu-51a":{"__comp":"17896441","content":"25e7257c"},"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-corda-752":{"__comp":"17896441","content":"5c41994f"},"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-fabric-7fb":{"__comp":"17896441","content":"bf5dfefe"},"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview-332":{"__comp":"17896441","content":"59395140"},"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-transfer-1df":{"__comp":"17896441","content":"2e5dd55e"},"/weaver-dlt-interoperability/docs/external/getting-started/interop/data-sharing-c36":{"__comp":"17896441","content":"da157423"},"/weaver-dlt-interoperability/docs/external/getting-started/interop/overview-91f":{"__comp":"17896441","content":"239a9e81"},"/weaver-dlt-interoperability/docs/external/getting-started/test-network/advanced-configuration-93b":{"__comp":"17896441","content":"2ec21c4a"},"/weaver-dlt-interoperability/docs/external/getting-started/test-network/ledger-initialization-704":{"__comp":"17896441","content":"b0f8195e"},"/weaver-dlt-interoperability/docs/external/getting-started/test-network/overview-067":{"__comp":"17896441","content":"ec2d6a08"},"/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-local-b48":{"__comp":"17896441","content":"36367655"},"/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-local-docker-a86":{"__comp":"17896441","content":"53c981a7"},"/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-packages-452":{"__comp":"17896441","content":"8b2840ea"},"/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-packages-docker-687":{"__comp":"17896441","content":"c9723ef0"},"/weaver-dlt-interoperability/docs/external/interoperability-modes-3ac":{"__comp":"17896441","content":"85de58a0"},"/weaver-dlt-interoperability/docs/external/introduction-02e":{"__comp":"17896441","content":"ba46e1b8"},"/weaver-dlt-interoperability/docs/external/publications-1c5":{"__comp":"17896441","content":"13886346"},"/weaver-dlt-interoperability/docs/external/roadmap-877":{"__comp":"17896441","content":"ac36c4b6"},"/weaver-dlt-interoperability/docs/external/security-model/access-control-4cc":{"__comp":"17896441","content":"ee88fe61"},"/weaver-dlt-interoperability/docs/external/security-model/authentication-5ea":{"__comp":"17896441","content":"a92192c3"},"/weaver-dlt-interoperability/docs/external/security-model/end-to-end-security-0a1":{"__comp":"17896441","content":"a50a7707"},"/weaver-dlt-interoperability/docs/external/security-model/proofs-and-verification-095":{"__comp":"17896441","content":"46d80676"},"/weaver-dlt-interoperability/docs/external/specifications-bd8":{"__comp":"17896441","content":"6835b8cd"},"/weaver-dlt-interoperability/docs/external/user-stories/financial-markets-168":{"__comp":"17896441","content":"071be86b"},"/weaver-dlt-interoperability/docs/external/user-stories/global-trade-01e":{"__comp":"17896441","content":"a3e47e5c"},"/weaver-dlt-interoperability/docs/external/user-stories/legacy-integration-711":{"__comp":"17896441","content":"3d094f56"},"/weaver-dlt-interoperability/docs/external/user-stories/overview-1b3":{"__comp":"17896441","content":"2b962623"},"/weaver-dlt-interoperability/docs/external/what-is-interoperability/integration-patterns-6e2":{"__comp":"17896441","content":"27ea52af"},"/weaver-dlt-interoperability/docs/external/what-is-interoperability/levels-of-interoperability-541":{"__comp":"17896441","content":"f5ed51a1"},"/weaver-dlt-interoperability/docs/external/what-is-interoperability/understanding-interoperability-4c3":{"__comp":"17896441","content":"eeaeeec1"},"/weaver-dlt-interoperability/docs/internal/activity-plan-790":{"__comp":"17896441","content":"2e5ddf1e"},"/weaver-dlt-interoperability/docs/internal/development/cordapp-interop/-edc":{"__comp":"17896441","content":"cd2e0b0a"},"/weaver-dlt-interoperability/docs/internal/development/cordapp-interop/cordapp-interop-api-assets-055":{"__comp":"17896441","content":"9a814649"},"/weaver-dlt-interoperability/docs/internal/development/cordapp-interop/cordapp-interop-assets-02a":{"__comp":"17896441","content":"abd77f53"},"/weaver-dlt-interoperability/docs/internal/development/cordapp-interop/cordapp-interop-flows-810":{"__comp":"17896441","content":"d85aeaf8"},"/weaver-dlt-interoperability/docs/internal/development/cordapp-interop/cordapp-interop-rest-api-46e":{"__comp":"17896441","content":"15bfa0c2"},"/weaver-dlt-interoperability/docs/internal/documentation-guidelines-cae":{"__comp":"17896441","content":"c9886a33"},"/weaver-dlt-interoperability/docs/internal/team-331":{"__comp":"17896441","content":"eed74c9c"},"/weaver-dlt-interoperability/-6e4":{"__comp":"c4f5d8e4","__context":{"plugin":"61becdbc"},"config":"5e9f5e1a"}}')}},e=>{e.O(0,[532],(()=>{return t=9383,e(e.s=t);var t}));e.O()}]); \ No newline at end of file diff --git a/assets/js/main.b9723597.js b/assets/js/main.b9723597.js new file mode 100644 index 000000000..9dbbbabf2 --- /dev/null +++ b/assets/js/main.b9723597.js @@ -0,0 +1,2 @@ +/*! For license information please see main.b9723597.js.LICENSE.txt */ +(self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[]).push([[8792],{8328:(e,t,n)=>{"use strict";n.d(t,{A:()=>f});var r=n(6540),a=n(8168),i=n(3259),o=n.n(i),l=n(4054);const s={"071be86b":[()=>n.e(5730).then(n.bind(n,6857)),"@site/docs/external/user-stories/financial-markets.md",6857],13886346:[()=>n.e(4568).then(n.bind(n,6985)),"@site/docs/external/publications.md",6985],"15db90ce":[()=>n.e(7088).then(n.bind(n,6329)),"@site/docs/external/getting-started/interop/asset-exchange/corda-besu.md",6329],17896441:[()=>Promise.all([n.e(1869),n.e(2565),n.e(8401)]).then(n.bind(n,3597)),"@theme/DocItem",3597],"1be78505":[()=>Promise.all([n.e(1869),n.e(8714)]).then(n.bind(n,10)),"@theme/DocPage",10],"20a6a7d9":[()=>n.e(757).then(n.bind(n,6927)),"@site/docs/external/getting-started/guide.md",6927],"239a9e81":[()=>n.e(3919).then(n.bind(n,9746)),"@site/docs/external/getting-started/interop/overview.md",9746],"25e7257c":[()=>n.e(3433).then(n.bind(n,7717)),"@site/docs/external/getting-started/interop/asset-exchange/fabric-besu.md",7717],"27ea52af":[()=>n.e(3292).then(n.bind(n,9871)),"@site/docs/external/what-is-interoperability/integration-patterns.md",9871],"2b962623":[()=>n.e(8159).then(n.bind(n,4435)),"@site/docs/external/user-stories/overview.md",4435],"2e5dd55e":[()=>n.e(3108).then(n.bind(n,2453)),"@site/docs/external/getting-started/interop/asset-transfer.md",2453],"2ec21c4a":[()=>n.e(5302).then(n.bind(n,4002)),"@site/docs/external/getting-started/test-network/advanced-configuration.md",4002],36367655:[()=>n.e(3966).then(n.bind(n,3196)),"@site/docs/external/getting-started/test-network/setup-local.md",3196],"378badfe":[()=>n.e(8567).then(n.bind(n,7814)),"@site/blog/2021-01-21-cross-chain-asset.md",7814],"3d094f56":[()=>n.e(5120).then(n.bind(n,2912)),"@site/docs/external/user-stories/legacy-integration.md",2912],"3d5da5a5":[()=>n.e(6405).then(n.bind(n,6823)),"@site/blog/2021-01-21-emergence-enterprise-interoperability.md?truncated=true",6823],"3ec01bef":[()=>n.e(1590).then(n.bind(n,6825)),"@site/docs/external/deployment-considerations/governance-and-policies.md",6825],"46d80676":[()=>n.e(2016).then(n.bind(n,8222)),"@site/docs/external/security-model/proofs-and-verification.md",8222],"53c981a7":[()=>n.e(2990).then(n.bind(n,3633)),"@site/docs/external/getting-started/test-network/setup-local-docker.md",3633],"56182e71":[()=>n.e(5902).then(n.bind(n,373)),"@site/blog/2021-01-21-emergence-enterprise-interoperability.md",373],"591644de":[()=>n.e(5937).then(n.t.bind(n,6428,19)),"~blog/default/weaver-dlt-interoperability-blog-742.json",6428],59395140:[()=>n.e(3599).then(n.bind(n,645)),"@site/docs/external/getting-started/interop/asset-exchange/overview.md",645],"5c41994f":[()=>n.e(5058).then(n.bind(n,6457)),"@site/docs/external/getting-started/interop/asset-exchange/fabric-corda.md",6457],"5e9f5e1a":[()=>Promise.resolve().then(n.bind(n,4784)),"@generated/docusaurus.config",4784],"61becdbc":[()=>n.e(5863).then(n.t.bind(n,4061,19)),"/home/runner/work/weaver-dlt-interoperability/weaver-dlt-interoperability/docs/.docusaurus/docusaurus-plugin-content-pages/default/plugin-route-context-module-100.json",4061],"64b157a3":[()=>n.e(8110).then(n.t.bind(n,8027,19)),"~blog/default/weaver-dlt-interoperability-blog-archive-7bd.json",8027],"6835b8cd":[()=>n.e(9102).then(n.bind(n,2879)),"@site/docs/external/specifications.md",2879],"7291aaef":[()=>n.e(7489).then(n.bind(n,6824)),"@site/docs/external/architecture-and-design/drivers.md",6824],"814f3328":[()=>n.e(7472).then(n.t.bind(n,5513,19)),"~blog/default/blog-post-list-prop-default.json",5513],"8379e623":[()=>n.e(3872).then(n.bind(n,4757)),"@site/docs/external/getting-started/enabling-weaver-network/overview.md",4757],"85de58a0":[()=>n.e(1031).then(n.bind(n,5291)),"@site/docs/external/interoperability-modes.md",5291],"8758c959":[()=>n.e(8317).then(n.bind(n,6076)),"@site/docs/external/architecture-and-design/decentralized-identity.md",6076],"8b2840ea":[()=>n.e(6325).then(n.bind(n,3698)),"@site/docs/external/getting-started/test-network/setup-packages.md",3698],"935bcf2a":[()=>n.e(5914).then(n.bind(n,6997)),"@site/docs/external/getting-started/interop/asset-exchange/corda-corda.md",6997],"935f2afb":[()=>n.e(8581).then(n.t.bind(n,5610,19)),"~docs/default/version-current-metadata-prop-751.json",5610],"98ecfc99":[()=>n.e(31).then(n.bind(n,2111)),"@site/docs/external/getting-started/enabling-weaver-network/fabric.md",2111],"99b332c9":[()=>n.e(8003).then(n.t.bind(n,1966,19)),"/home/runner/work/weaver-dlt-interoperability/weaver-dlt-interoperability/docs/.docusaurus/docusaurus-plugin-content-docs/default/plugin-route-context-module-100.json",1966],"9e4087bc":[()=>n.e(2711).then(n.bind(n,9331)),"@theme/BlogArchivePage",9331],"9f52c9db":[()=>n.e(4625).then(n.bind(n,4585)),"@site/docs/external/deployment-considerations/deployment-patterns.md",4585],a3e47e5c:[()=>n.e(576).then(n.bind(n,6460)),"@site/docs/external/user-stories/global-trade.md",6460],a50a7707:[()=>n.e(429).then(n.bind(n,1001)),"@site/docs/external/security-model/end-to-end-security.md",1001],a6aa9e1f:[()=>Promise.all([n.e(1869),n.e(2565),n.e(2435),n.e(7643)]).then(n.bind(n,2667)),"@theme/BlogListPage",2667],a92192c3:[()=>n.e(4085).then(n.bind(n,139)),"@site/docs/external/security-model/authentication.md",139],ac36c4b6:[()=>n.e(3885).then(n.bind(n,3940)),"@site/docs/external/roadmap.md",3940],b0f8195e:[()=>n.e(7695).then(n.bind(n,2039)),"@site/docs/external/getting-started/test-network/ledger-initialization.md",2039],b379f194:[()=>n.e(6062).then(n.bind(n,1716)),"@site/docs/external/architecture-and-design/overview.md",1716],b545330d:[()=>n.e(9727).then(n.bind(n,5263)),"@site/docs/external/getting-started/enabling-weaver-network/besu.md",5263],ba46e1b8:[()=>n.e(5674).then(n.bind(n,8602)),"@site/docs/external/introduction.md",8602],bdfaba9c:[()=>n.e(1885).then(n.bind(n,8634)),"@site/blog/2021-01-21-cross-chain-asset.md?truncated=true",8634],bf5dfefe:[()=>n.e(3836).then(n.bind(n,4733)),"@site/docs/external/getting-started/interop/asset-exchange/fabric-fabric.md",4733],c4f5d8e4:[()=>Promise.all([n.e(1869),n.e(2634)]).then(n.bind(n,2468)),"@site/src/pages/index.js",2468],c9723ef0:[()=>n.e(7910).then(n.bind(n,3939)),"@site/docs/external/getting-started/test-network/setup-packages-docker.md",3939],ccc49370:[()=>Promise.all([n.e(1869),n.e(2565),n.e(2435),n.e(3249)]).then(n.bind(n,4029)),"@theme/BlogPostPage",4029],ce7e6f90:[()=>n.e(3304).then(n.bind(n,7738)),"@site/docs/external/deployment-considerations/legal-and-regulation.md",7738],da157423:[()=>n.e(320).then(n.bind(n,3948)),"@site/docs/external/getting-started/interop/data-sharing.md",3948],e0bf5ccd:[()=>n.e(2729).then(n.bind(n,2024)),"@site/docs/external/design-principles.md",2024],e67be6b3:[()=>n.e(5117).then(n.bind(n,810)),"@site/docs/external/architecture-and-design/relay.md",810],ec2d6a08:[()=>n.e(5826).then(n.bind(n,1240)),"@site/docs/external/getting-started/test-network/overview.md",1240],ec8cb05d:[()=>n.e(3129).then(n.bind(n,5534)),"@site/docs/external/architecture-and-design/weaver-dapps.md",5534],ee4141e0:[()=>n.e(3062).then(n.t.bind(n,2945,19)),"/home/runner/work/weaver-dlt-interoperability/weaver-dlt-interoperability/docs/.docusaurus/docusaurus-plugin-content-blog/default/plugin-route-context-module-100.json",2945],ee88fe61:[()=>n.e(7477).then(n.bind(n,1173)),"@site/docs/external/security-model/access-control.md",1173],eeaeeec1:[()=>n.e(7957).then(n.bind(n,6576)),"@site/docs/external/what-is-interoperability/understanding-interoperability.md",6576],f0c74005:[()=>n.e(8454).then(n.bind(n,2051)),"@site/docs/external/getting-started/enabling-weaver-network/corda.md",2051],f1311735:[()=>n.e(8136).then(n.bind(n,3621)),"@site/docs/external/getting-started/interop/asset-exchange/besu-besu.md",3621],f5ed51a1:[()=>n.e(6559).then(n.bind(n,367)),"@site/docs/external/what-is-interoperability/levels-of-interoperability.md",367]};function c(e){let{error:t,retry:n,pastDelay:a}=e;return t?r.createElement("div",{style:{textAlign:"center",color:"#fff",backgroundColor:"#fa383e",borderColor:"#fa383e",borderStyle:"solid",borderRadius:"0.25rem",borderWidth:"1px",boxSizing:"border-box",display:"block",padding:"1rem",flex:"0 0 50%",marginLeft:"25%",marginRight:"25%",marginTop:"5rem",maxWidth:"50%",width:"100%"}},r.createElement("p",null,String(t)),r.createElement("div",null,r.createElement("button",{type:"button",onClick:n},"Retry"))):a?r.createElement("div",{style:{display:"flex",justifyContent:"center",alignItems:"center",height:"100vh"}},r.createElement("svg",{id:"loader",style:{width:128,height:110,position:"absolute",top:"calc(100vh - 64%)"},viewBox:"0 0 45 45",xmlns:"http://www.w3.org/2000/svg",stroke:"#61dafb"},r.createElement("g",{fill:"none",fillRule:"evenodd",transform:"translate(1 1)",strokeWidth:"2"},r.createElement("circle",{cx:"22",cy:"22",r:"6",strokeOpacity:"0"},r.createElement("animate",{attributeName:"r",begin:"1.5s",dur:"3s",values:"6;22",calcMode:"linear",repeatCount:"indefinite"}),r.createElement("animate",{attributeName:"stroke-opacity",begin:"1.5s",dur:"3s",values:"1;0",calcMode:"linear",repeatCount:"indefinite"}),r.createElement("animate",{attributeName:"stroke-width",begin:"1.5s",dur:"3s",values:"2;0",calcMode:"linear",repeatCount:"indefinite"})),r.createElement("circle",{cx:"22",cy:"22",r:"6",strokeOpacity:"0"},r.createElement("animate",{attributeName:"r",begin:"3s",dur:"3s",values:"6;22",calcMode:"linear",repeatCount:"indefinite"}),r.createElement("animate",{attributeName:"stroke-opacity",begin:"3s",dur:"3s",values:"1;0",calcMode:"linear",repeatCount:"indefinite"}),r.createElement("animate",{attributeName:"stroke-width",begin:"3s",dur:"3s",values:"2;0",calcMode:"linear",repeatCount:"indefinite"})),r.createElement("circle",{cx:"22",cy:"22",r:"8"},r.createElement("animate",{attributeName:"r",begin:"0s",dur:"1.5s",values:"6;1;2;3;4;5;6",calcMode:"linear",repeatCount:"indefinite"}))))):null}var u=n(6921),d=n(3102);function p(e,t){if("*"===e)return o()({loading:c,loader:()=>n.e(1774).then(n.bind(n,1774)),modules:["@theme/NotFound"],webpack:()=>[1774],render(e,t){const n=e.default;return r.createElement(d.W,{value:{plugin:{name:"native",id:"default"}}},r.createElement(n,t))}});const i=l[`${e}-${t}`],p={},f=[],m=[],g=(0,u.A)(i);return Object.entries(g).forEach((e=>{let[t,n]=e;const r=s[n];r&&(p[t]=r[0],f.push(r[1]),m.push(r[2]))})),o().Map({loading:c,loader:p,modules:f,webpack:()=>m,render(t,n){const o=JSON.parse(JSON.stringify(i));Object.entries(t).forEach((t=>{let[n,r]=t;const a=r.default;if(!a)throw new Error(`The page component at ${e} doesn't have a default export. This makes it impossible to render anything. Consider default-exporting a React component.`);"object"!=typeof a&&"function"!=typeof a||Object.keys(r).filter((e=>"default"!==e)).forEach((e=>{a[e]=r[e]}));let i=o;const l=n.split(".");l.slice(0,-1).forEach((e=>{i=i[e]})),i[l[l.length-1]]=a}));const l=o.__comp;delete o.__comp;const s=o.__context;return delete o.__context,r.createElement(d.W,{value:s},r.createElement(l,(0,a.A)({},o,n)))}})}const f=[{path:"/weaver-dlt-interoperability/blog",component:p("/weaver-dlt-interoperability/blog","fba"),exact:!0},{path:"/weaver-dlt-interoperability/blog/2021/01/21/cross-chain-asset",component:p("/weaver-dlt-interoperability/blog/2021/01/21/cross-chain-asset","014"),exact:!0},{path:"/weaver-dlt-interoperability/blog/2021/01/21/emergence-enterprise-interoperability",component:p("/weaver-dlt-interoperability/blog/2021/01/21/emergence-enterprise-interoperability","e8d"),exact:!0},{path:"/weaver-dlt-interoperability/blog/archive",component:p("/weaver-dlt-interoperability/blog/archive","502"),exact:!0},{path:"/weaver-dlt-interoperability/docs",component:p("/weaver-dlt-interoperability/docs","ff4"),routes:[{path:"/weaver-dlt-interoperability/docs/external/architecture-and-design/decentralized-identity",component:p("/weaver-dlt-interoperability/docs/external/architecture-and-design/decentralized-identity","999"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/architecture-and-design/drivers",component:p("/weaver-dlt-interoperability/docs/external/architecture-and-design/drivers","79c"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/architecture-and-design/overview",component:p("/weaver-dlt-interoperability/docs/external/architecture-and-design/overview","390"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/architecture-and-design/relay",component:p("/weaver-dlt-interoperability/docs/external/architecture-and-design/relay","db6"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/architecture-and-design/weaver-dapps",component:p("/weaver-dlt-interoperability/docs/external/architecture-and-design/weaver-dapps","52c"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/deployment-considerations/deployment-patterns",component:p("/weaver-dlt-interoperability/docs/external/deployment-considerations/deployment-patterns","22b"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/deployment-considerations/governance-and-policies",component:p("/weaver-dlt-interoperability/docs/external/deployment-considerations/governance-and-policies","d9a"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/deployment-considerations/legal-and-regulation",component:p("/weaver-dlt-interoperability/docs/external/deployment-considerations/legal-and-regulation","956"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/design-principles",component:p("/weaver-dlt-interoperability/docs/external/design-principles","9ec"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/besu",component:p("/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/besu","6b8"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/corda",component:p("/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/corda","a90"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/fabric",component:p("/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/fabric","8fd"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/overview",component:p("/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/overview","90e"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/getting-started/guide",component:p("/weaver-dlt-interoperability/docs/external/getting-started/guide","465"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/besu-besu",component:p("/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/besu-besu","c57"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/corda-besu",component:p("/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/corda-besu","eea"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/corda-corda",component:p("/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/corda-corda","929"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-besu",component:p("/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-besu","51a"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-corda",component:p("/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-corda","752"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-fabric",component:p("/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-fabric","7fb"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview",component:p("/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview","332"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-transfer",component:p("/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-transfer","1df"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/getting-started/interop/data-sharing",component:p("/weaver-dlt-interoperability/docs/external/getting-started/interop/data-sharing","c36"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/getting-started/interop/overview",component:p("/weaver-dlt-interoperability/docs/external/getting-started/interop/overview","91f"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/advanced-configuration",component:p("/weaver-dlt-interoperability/docs/external/getting-started/test-network/advanced-configuration","93b"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/ledger-initialization",component:p("/weaver-dlt-interoperability/docs/external/getting-started/test-network/ledger-initialization","704"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/overview",component:p("/weaver-dlt-interoperability/docs/external/getting-started/test-network/overview","067"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-local",component:p("/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-local","b48"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-local-docker",component:p("/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-local-docker","a86"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-packages",component:p("/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-packages","452"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-packages-docker",component:p("/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-packages-docker","687"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/interoperability-modes",component:p("/weaver-dlt-interoperability/docs/external/interoperability-modes","3ac"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/introduction",component:p("/weaver-dlt-interoperability/docs/external/introduction","02e"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/publications",component:p("/weaver-dlt-interoperability/docs/external/publications","1c5"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/roadmap",component:p("/weaver-dlt-interoperability/docs/external/roadmap","877"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/security-model/access-control",component:p("/weaver-dlt-interoperability/docs/external/security-model/access-control","4cc"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/security-model/authentication",component:p("/weaver-dlt-interoperability/docs/external/security-model/authentication","5ea"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/security-model/end-to-end-security",component:p("/weaver-dlt-interoperability/docs/external/security-model/end-to-end-security","0a1"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/security-model/proofs-and-verification",component:p("/weaver-dlt-interoperability/docs/external/security-model/proofs-and-verification","095"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/specifications",component:p("/weaver-dlt-interoperability/docs/external/specifications","bd8"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/user-stories/financial-markets",component:p("/weaver-dlt-interoperability/docs/external/user-stories/financial-markets","168"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/user-stories/global-trade",component:p("/weaver-dlt-interoperability/docs/external/user-stories/global-trade","01e"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/user-stories/legacy-integration",component:p("/weaver-dlt-interoperability/docs/external/user-stories/legacy-integration","711"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/user-stories/overview",component:p("/weaver-dlt-interoperability/docs/external/user-stories/overview","1b3"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/what-is-interoperability/integration-patterns",component:p("/weaver-dlt-interoperability/docs/external/what-is-interoperability/integration-patterns","6e2"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/what-is-interoperability/levels-of-interoperability",component:p("/weaver-dlt-interoperability/docs/external/what-is-interoperability/levels-of-interoperability","541"),exact:!0,sidebar:"Documentation"},{path:"/weaver-dlt-interoperability/docs/external/what-is-interoperability/understanding-interoperability",component:p("/weaver-dlt-interoperability/docs/external/what-is-interoperability/understanding-interoperability","4c3"),exact:!0,sidebar:"Documentation"}]},{path:"/weaver-dlt-interoperability/",component:p("/weaver-dlt-interoperability/","6e4"),exact:!0},{path:"*",component:p("*")}]},6125:(e,t,n)=>{"use strict";n.d(t,{o:()=>a,x:()=>i});var r=n(6540);const a=r.createContext(!1);function i(e){let{children:t}=e;const[n,i]=(0,r.useState)(!1);return(0,r.useEffect)((()=>{i(!0)}),[]),r.createElement(a.Provider,{value:n},t)}},5660:(e,t,n)=>{"use strict";var r=n(6540),a=n(961),i=n(4625),o=n(545),l=n(8193);const s=[n(119),n(6134),n(6294),n(1043)];var c=n(8328),u=n(6347),d=n(2831);function p(e){let{children:t}=e;return r.createElement(r.Fragment,null,t)}var f=n(8168),m=n(5260),g=n(4586),h=n(6025),b=n(6342),v=n(1003),y=n(2131),w=n(4090),x=n(2967),k=n(1463);function E(){const{i18n:{defaultLocale:e,localeConfigs:t}}=(0,g.A)(),n=(0,y.o)();return r.createElement(m.A,null,Object.entries(t).map((e=>{let[t,{htmlLang:a}]=e;return r.createElement("link",{key:t,rel:"alternate",href:n.createUrl({locale:t,fullyQualified:!0}),hrefLang:a})})),r.createElement("link",{rel:"alternate",href:n.createUrl({locale:e,fullyQualified:!0}),hrefLang:"x-default"}))}function S(e){let{permalink:t}=e;const{siteConfig:{url:n}}=(0,g.A)(),a=function(){const{siteConfig:{url:e}}=(0,g.A)(),{pathname:t}=(0,u.zy)();return e+(0,h.A)(t)}(),i=t?`${n}${t}`:a;return r.createElement(m.A,null,r.createElement("meta",{property:"og:url",content:i}),r.createElement("link",{rel:"canonical",href:i}))}function T(){const{i18n:{currentLocale:e}}=(0,g.A)(),{metadata:t,image:n}=(0,b.p)();return r.createElement(r.Fragment,null,r.createElement(m.A,null,r.createElement("meta",{name:"twitter:card",content:"summary_large_image"}),r.createElement("body",{className:w.w})),n&&r.createElement(v.be,{image:n}),r.createElement(S,null),r.createElement(E,null),r.createElement(k.A,{tag:x.Cy,locale:e}),r.createElement(m.A,null,t.map(((e,t)=>r.createElement("meta",(0,f.A)({key:t},e))))))}const _=new Map;function A(e){if(_.has(e.pathname))return{...e,pathname:_.get(e.pathname)};if((0,d.u)(c.A,e.pathname).some((e=>{let{route:t}=e;return!0===t.exact})))return _.set(e.pathname,e.pathname),e;const t=e.pathname.trim().replace(/(?:\/index)?\.html$/,"")||"/";return _.set(e.pathname,t),{...e,pathname:t}}var C=n(6125),P=n(6988);function N(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),r=1;r<t;r++)n[r-1]=arguments[r];const a=s.map((t=>{const r=t.default?.[e]??t[e];return r?.(...n)}));return()=>a.forEach((e=>e?.()))}const O=function(e){let{children:t,location:n,previousLocation:a}=e;return(0,r.useLayoutEffect)((()=>{a!==n&&(a&&function(e){const{hash:t}=e;if(t){const e=decodeURIComponent(t.substring(1)),n=document.getElementById(e);n?.scrollIntoView()}else window.scrollTo(0,0)}(n),N("onRouteDidUpdate",{previousLocation:a,location:n}))}),[a,n]),t};function I(e){const t=Array.from(new Set([e,decodeURI(e)])).map((e=>(0,d.u)(c.A,e))).flat();return Promise.all(t.map((e=>e.route.component.preload?.())))}class R extends r.Component{previousLocation;routeUpdateCleanupCb;constructor(e){super(e),this.previousLocation=null,this.routeUpdateCleanupCb=l.A.canUseDOM?N("onRouteUpdate",{previousLocation:null,location:this.props.location}):()=>{},this.state={nextRouteHasLoaded:!0}}shouldComponentUpdate(e,t){if(e.location===this.props.location)return t.nextRouteHasLoaded;const n=e.location;return this.previousLocation=this.props.location,this.setState({nextRouteHasLoaded:!1}),this.routeUpdateCleanupCb=N("onRouteUpdate",{previousLocation:this.previousLocation,location:n}),I(n.pathname).then((()=>{this.routeUpdateCleanupCb(),this.setState({nextRouteHasLoaded:!0})})).catch((e=>{console.warn(e),window.location.reload()})),!1}render(){const{children:e,location:t}=this.props;return r.createElement(O,{previousLocation:this.previousLocation,location:t},r.createElement(u.qh,{location:t,render:()=>e}))}}const D=R,L="docusaurus-base-url-issue-banner-container",M="docusaurus-base-url-issue-banner",F="docusaurus-base-url-issue-banner-suggestion-container",B="__DOCUSAURUS_INSERT_BASEURL_BANNER";function $(e){return`\nwindow['${B}'] = true;\n\ndocument.addEventListener('DOMContentLoaded', maybeInsertBanner);\n\nfunction maybeInsertBanner() {\n var shouldInsert = window['${B}'];\n shouldInsert && insertBanner();\n}\n\nfunction insertBanner() {\n var bannerContainer = document.getElementById('${L}');\n if (!bannerContainer) {\n return;\n }\n var bannerHtml = ${JSON.stringify(function(e){return`\n<div id="${M}" style="border: thick solid red; background-color: rgb(255, 230, 179); margin: 20px; padding: 20px; font-size: 20px;">\n <p style="font-weight: bold; font-size: 30px;">Your Docusaurus site did not load properly.</p>\n <p>A very common reason is a wrong site <a href="https://docusaurus.io/docs/docusaurus.config.js/#baseurl" style="font-weight: bold;">baseUrl configuration</a>.</p>\n <p>Current configured baseUrl = <span style="font-weight: bold; color: red;">${e}</span> ${"/"===e?" (default value)":""}</p>\n <p>We suggest trying baseUrl = <span id="${F}" style="font-weight: bold; color: green;"></span></p>\n</div>\n`}(e)).replace(/</g,"\\<")};\n bannerContainer.innerHTML = bannerHtml;\n var suggestionContainer = document.getElementById('${F}');\n var actualHomePagePath = window.location.pathname;\n var suggestedBaseUrl = actualHomePagePath.substr(-1) === '/'\n ? actualHomePagePath\n : actualHomePagePath + '/';\n suggestionContainer.innerHTML = suggestedBaseUrl;\n}\n`}function z(){const{siteConfig:{baseUrl:e}}=(0,g.A)();return(0,r.useLayoutEffect)((()=>{window[B]=!1}),[]),r.createElement(r.Fragment,null,!l.A.canUseDOM&&r.createElement(m.A,null,r.createElement("script",null,$(e))),r.createElement("div",{id:L}))}function U(){const{siteConfig:{baseUrl:e,baseUrlIssueBanner:t}}=(0,g.A)(),{pathname:n}=(0,u.zy)();return t&&n===e?r.createElement(z,null):null}function j(){const{siteConfig:{favicon:e,title:t,noIndex:n},i18n:{currentLocale:a,localeConfigs:i}}=(0,g.A)(),o=(0,h.A)(e),{htmlLang:l,direction:s}=i[a];return r.createElement(m.A,null,r.createElement("html",{lang:l,dir:s}),r.createElement("title",null,t),r.createElement("meta",{property:"og:title",content:t}),r.createElement("meta",{name:"viewport",content:"width=device-width, initial-scale=1.0"}),n&&r.createElement("meta",{name:"robots",content:"noindex, nofollow"}),e&&r.createElement("link",{rel:"icon",href:o}))}var H=n(7489);function W(){const e=(0,d.v)(c.A),t=(0,u.zy)();return r.createElement(H.A,null,r.createElement(P.l,null,r.createElement(C.x,null,r.createElement(p,null,r.createElement(j,null),r.createElement(T,null),r.createElement(U,null),r.createElement(D,{location:A(t)},e)))))}var V=n(4054);const G=function(e){try{return document.createElement("link").relList.supports(e)}catch{return!1}}("prefetch")?function(e){return new Promise(((t,n)=>{if("undefined"==typeof document)return void n();const r=document.createElement("link");r.setAttribute("rel","prefetch"),r.setAttribute("href",e),r.onload=()=>t(),r.onerror=()=>n();const a=document.getElementsByTagName("head")[0]??document.getElementsByName("script")[0]?.parentNode;a?.appendChild(r)}))}:function(e){return new Promise(((t,n)=>{const r=new XMLHttpRequest;r.open("GET",e,!0),r.withCredentials=!0,r.onload=()=>{200===r.status?t():n()},r.send(null)}))};var q=n(6921);const K=new Set,Y=new Set,Q=()=>navigator.connection?.effectiveType.includes("2g")||navigator.connection?.saveData,Z={prefetch(e){if(!(e=>!Q()&&!Y.has(e)&&!K.has(e))(e))return!1;K.add(e);const t=(0,d.u)(c.A,e).flatMap((e=>{return t=e.route.path,Object.entries(V).filter((e=>{let[n]=e;return n.replace(/-[^-]+$/,"")===t})).flatMap((e=>{let[,t]=e;return Object.values((0,q.A)(t))}));var t}));return Promise.all(t.map((e=>{const t=n.gca(e);return t&&!t.includes("undefined")?G(t).catch((()=>{})):Promise.resolve()})))},preload:e=>!!(e=>!Q()&&!Y.has(e))(e)&&(Y.add(e),I(e))},X=Object.freeze(Z);if(l.A.canUseDOM){window.docusaurus=X;const e=a.hydrate;I(window.location.pathname).then((()=>{e(r.createElement(o.vd,null,r.createElement(i.Kd,null,r.createElement(W,null))),document.getElementById("__docusaurus"))}))}},6988:(e,t,n)=>{"use strict";n.d(t,{o:()=>u,l:()=>d});var r=n(6540),a=n(4784);const i=JSON.parse('{"docusaurus-plugin-content-docs":{"default":{"path":"/weaver-dlt-interoperability/docs","versions":[{"name":"current","label":"Next","isLast":true,"path":"/weaver-dlt-interoperability/docs","mainDocId":"external/introduction","docs":[{"id":"external/architecture-and-design/decentralized-identity","path":"/weaver-dlt-interoperability/docs/external/architecture-and-design/decentralized-identity","sidebar":"Documentation"},{"id":"external/architecture-and-design/drivers","path":"/weaver-dlt-interoperability/docs/external/architecture-and-design/drivers","sidebar":"Documentation"},{"id":"external/architecture-and-design/overview","path":"/weaver-dlt-interoperability/docs/external/architecture-and-design/overview","sidebar":"Documentation"},{"id":"external/architecture-and-design/relay","path":"/weaver-dlt-interoperability/docs/external/architecture-and-design/relay","sidebar":"Documentation"},{"id":"external/architecture-and-design/weaver-dapps","path":"/weaver-dlt-interoperability/docs/external/architecture-and-design/weaver-dapps","sidebar":"Documentation"},{"id":"external/deployment-considerations/deployment-patterns","path":"/weaver-dlt-interoperability/docs/external/deployment-considerations/deployment-patterns","sidebar":"Documentation"},{"id":"external/deployment-considerations/governance-and-policies","path":"/weaver-dlt-interoperability/docs/external/deployment-considerations/governance-and-policies","sidebar":"Documentation"},{"id":"external/deployment-considerations/legal-and-regulation","path":"/weaver-dlt-interoperability/docs/external/deployment-considerations/legal-and-regulation","sidebar":"Documentation"},{"id":"external/design-principles","path":"/weaver-dlt-interoperability/docs/external/design-principles","sidebar":"Documentation"},{"id":"external/getting-started/enabling-weaver-network/besu","path":"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/besu","sidebar":"Documentation"},{"id":"external/getting-started/enabling-weaver-network/corda","path":"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/corda","sidebar":"Documentation"},{"id":"external/getting-started/enabling-weaver-network/fabric","path":"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/fabric","sidebar":"Documentation"},{"id":"external/getting-started/enabling-weaver-network/overview","path":"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/overview","sidebar":"Documentation"},{"id":"external/getting-started/guide","path":"/weaver-dlt-interoperability/docs/external/getting-started/guide","sidebar":"Documentation"},{"id":"external/getting-started/interop/asset-exchange/besu-besu","path":"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/besu-besu","sidebar":"Documentation"},{"id":"external/getting-started/interop/asset-exchange/corda-besu","path":"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/corda-besu","sidebar":"Documentation"},{"id":"external/getting-started/interop/asset-exchange/corda-corda","path":"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/corda-corda","sidebar":"Documentation"},{"id":"external/getting-started/interop/asset-exchange/fabric-besu","path":"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-besu","sidebar":"Documentation"},{"id":"external/getting-started/interop/asset-exchange/fabric-corda","path":"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-corda","sidebar":"Documentation"},{"id":"external/getting-started/interop/asset-exchange/fabric-fabric","path":"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-fabric","sidebar":"Documentation"},{"id":"external/getting-started/interop/asset-exchange/overview","path":"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview","sidebar":"Documentation"},{"id":"external/getting-started/interop/asset-transfer","path":"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-transfer","sidebar":"Documentation"},{"id":"external/getting-started/interop/data-sharing","path":"/weaver-dlt-interoperability/docs/external/getting-started/interop/data-sharing","sidebar":"Documentation"},{"id":"external/getting-started/interop/overview","path":"/weaver-dlt-interoperability/docs/external/getting-started/interop/overview","sidebar":"Documentation"},{"id":"external/getting-started/test-network/advanced-configuration","path":"/weaver-dlt-interoperability/docs/external/getting-started/test-network/advanced-configuration","sidebar":"Documentation"},{"id":"external/getting-started/test-network/ledger-initialization","path":"/weaver-dlt-interoperability/docs/external/getting-started/test-network/ledger-initialization","sidebar":"Documentation"},{"id":"external/getting-started/test-network/overview","path":"/weaver-dlt-interoperability/docs/external/getting-started/test-network/overview","sidebar":"Documentation"},{"id":"external/getting-started/test-network/setup-local","path":"/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-local","sidebar":"Documentation"},{"id":"external/getting-started/test-network/setup-local-docker","path":"/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-local-docker","sidebar":"Documentation"},{"id":"external/getting-started/test-network/setup-packages","path":"/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-packages","sidebar":"Documentation"},{"id":"external/getting-started/test-network/setup-packages-docker","path":"/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-packages-docker","sidebar":"Documentation"},{"id":"external/interoperability-modes","path":"/weaver-dlt-interoperability/docs/external/interoperability-modes","sidebar":"Documentation"},{"id":"external/introduction","path":"/weaver-dlt-interoperability/docs/external/introduction","sidebar":"Documentation"},{"id":"external/publications","path":"/weaver-dlt-interoperability/docs/external/publications","sidebar":"Documentation"},{"id":"external/roadmap","path":"/weaver-dlt-interoperability/docs/external/roadmap","sidebar":"Documentation"},{"id":"external/security-model/access-control","path":"/weaver-dlt-interoperability/docs/external/security-model/access-control","sidebar":"Documentation"},{"id":"external/security-model/authentication","path":"/weaver-dlt-interoperability/docs/external/security-model/authentication","sidebar":"Documentation"},{"id":"external/security-model/end-to-end-security","path":"/weaver-dlt-interoperability/docs/external/security-model/end-to-end-security","sidebar":"Documentation"},{"id":"external/security-model/proofs-and-verification","path":"/weaver-dlt-interoperability/docs/external/security-model/proofs-and-verification","sidebar":"Documentation"},{"id":"external/specifications","path":"/weaver-dlt-interoperability/docs/external/specifications","sidebar":"Documentation"},{"id":"external/user-stories/financial-markets","path":"/weaver-dlt-interoperability/docs/external/user-stories/financial-markets","sidebar":"Documentation"},{"id":"external/user-stories/global-trade","path":"/weaver-dlt-interoperability/docs/external/user-stories/global-trade","sidebar":"Documentation"},{"id":"external/user-stories/legacy-integration","path":"/weaver-dlt-interoperability/docs/external/user-stories/legacy-integration","sidebar":"Documentation"},{"id":"external/user-stories/overview","path":"/weaver-dlt-interoperability/docs/external/user-stories/overview","sidebar":"Documentation"},{"id":"external/what-is-interoperability/integration-patterns","path":"/weaver-dlt-interoperability/docs/external/what-is-interoperability/integration-patterns","sidebar":"Documentation"},{"id":"external/what-is-interoperability/levels-of-interoperability","path":"/weaver-dlt-interoperability/docs/external/what-is-interoperability/levels-of-interoperability","sidebar":"Documentation"},{"id":"external/what-is-interoperability/understanding-interoperability","path":"/weaver-dlt-interoperability/docs/external/what-is-interoperability/understanding-interoperability","sidebar":"Documentation"}],"draftIds":[],"sidebars":{"Documentation":{"link":{"path":"/weaver-dlt-interoperability/docs/external/introduction","label":"external/introduction"}}}}],"breadcrumbs":true}}}'),o=JSON.parse('{"defaultLocale":"en","locales":["en"],"path":"i18n","currentLocale":"en","localeConfigs":{"en":{"label":"English","direction":"ltr","htmlLang":"en","calendar":"gregory","path":"en"}}}');var l=n(2654);const s=JSON.parse('{"docusaurusVersion":"2.2.0","siteVersion":"0.0.0","pluginVersions":{"docusaurus-plugin-content-docs":{"type":"package","name":"@docusaurus/plugin-content-docs","version":"2.2.0"},"docusaurus-plugin-content-blog":{"type":"package","name":"@docusaurus/plugin-content-blog","version":"2.2.0"},"docusaurus-plugin-content-pages":{"type":"package","name":"@docusaurus/plugin-content-pages","version":"2.2.0"},"docusaurus-plugin-sitemap":{"type":"package","name":"@docusaurus/plugin-sitemap","version":"2.2.0"},"docusaurus-theme-classic":{"type":"package","name":"@docusaurus/theme-classic","version":"2.2.0"}}}'),c={siteConfig:a.default,siteMetadata:s,globalData:i,i18n:o,codeTranslations:l},u=r.createContext(c);function d(e){let{children:t}=e;return r.createElement(u.Provider,{value:c},t)}},7489:(e,t,n)=>{"use strict";n.d(t,{A:()=>u});var r=n(6540),a=n(8193),i=n(5260),o=n(5713);function l(e){let{error:t,tryAgain:n}=e;return r.createElement("div",{style:{display:"flex",flexDirection:"column",justifyContent:"center",alignItems:"center",height:"50vh",width:"100%",fontSize:"20px"}},r.createElement("h1",null,"This page crashed."),r.createElement("p",null,t.message),r.createElement("button",{type:"button",onClick:n},"Try again"))}function s(e){let{error:t,tryAgain:n}=e;return r.createElement(u,{fallback:()=>r.createElement(l,{error:t,tryAgain:n})},r.createElement(i.A,null,r.createElement("title",null,"Page Error")),r.createElement(o.A,null,r.createElement(l,{error:t,tryAgain:n})))}const c=e=>r.createElement(s,e);class u extends r.Component{constructor(e){super(e),this.state={error:null}}componentDidCatch(e){a.A.canUseDOM&&this.setState({error:e})}render(){const{children:e}=this.props,{error:t}=this.state;if(t){const e={error:t,tryAgain:()=>this.setState({error:null})};return(this.props.fallback??c)(e)}return e??null}}},8193:(e,t,n)=>{"use strict";n.d(t,{A:()=>a});const r="undefined"!=typeof window&&"document"in window&&"createElement"in window.document,a={canUseDOM:r,canUseEventListeners:r&&("addEventListener"in window||"attachEvent"in window),canUseIntersectionObserver:r&&"IntersectionObserver"in window,canUseViewport:r&&"screen"in window}},5260:(e,t,n)=>{"use strict";n.d(t,{A:()=>i});var r=n(6540),a=n(545);function i(e){return r.createElement(a.mg,e)}},5489:(e,t,n)=>{"use strict";n.d(t,{A:()=>f});var r=n(8168),a=n(6540),i=n(4625),o=n(440),l=n(4586),s=n(6654),c=n(8193);const u=a.createContext({collectLink:()=>{}});var d=n(6025);function p(e,t){let{isNavLink:n,to:p,href:f,activeClassName:m,isActive:g,"data-noBrokenLinkCheck":h,autoAddBaseUrl:b=!0,...v}=e;const{siteConfig:{trailingSlash:y,baseUrl:w}}=(0,l.A)(),{withBaseUrl:x}=(0,d.h)(),k=(0,a.useContext)(u),E=(0,a.useRef)(null);(0,a.useImperativeHandle)(t,(()=>E.current));const S=p||f;const T=(0,s.A)(S),_=S?.replace("pathname://","");let A=void 0!==_?(C=_,b&&(e=>e.startsWith("/"))(C)?x(C):C):void 0;var C;A&&T&&(A=(0,o.applyTrailingSlash)(A,{trailingSlash:y,baseUrl:w}));const P=(0,a.useRef)(!1),N=n?i.k2:i.N_,O=c.A.canUseIntersectionObserver,I=(0,a.useRef)(),R=()=>{P.current||null==A||(window.docusaurus.preload(A),P.current=!0)};(0,a.useEffect)((()=>(!O&&T&&null!=A&&window.docusaurus.prefetch(A),()=>{O&&I.current&&I.current.disconnect()})),[I,A,O,T]);const D=A?.startsWith("#")??!1,L=!A||!T||D;return L||h||k.collectLink(A),L?a.createElement("a",(0,r.A)({ref:E,href:A},S&&!T&&{target:"_blank",rel:"noopener noreferrer"},v)):a.createElement(N,(0,r.A)({},v,{onMouseEnter:R,onTouchStart:R,innerRef:e=>{E.current=e,O&&e&&T&&(I.current=new window.IntersectionObserver((t=>{t.forEach((t=>{e===t.target&&(t.isIntersecting||t.intersectionRatio>0)&&(I.current.unobserve(e),I.current.disconnect(),null!=A&&window.docusaurus.prefetch(A))}))})),I.current.observe(e))},to:A},n&&{isActive:g,activeClassName:m}))}const f=a.forwardRef(p)},418:(e,t,n)=>{"use strict";n.d(t,{A:()=>r});const r=()=>null},1312:(e,t,n)=>{"use strict";n.d(t,{A:()=>s,T:()=>l});var r=n(6540);function a(e,t){const n=e.split(/(\{\w+\})/).map(((e,n)=>{if(n%2==1){const n=t?.[e.slice(1,-1)];if(void 0!==n)return n}return e}));return n.some((e=>(0,r.isValidElement)(e)))?n.map(((e,t)=>(0,r.isValidElement)(e)?r.cloneElement(e,{key:t}):e)).filter((e=>""!==e)):n.join("")}var i=n(2654);function o(e){let{id:t,message:n}=e;if(void 0===t&&void 0===n)throw new Error("Docusaurus translation declarations must have at least a translation id or a default translation message");return i[t??n]??n??t}function l(e,t){let{message:n,id:r}=e;return a(o({message:n,id:r}),t)}function s(e){let{children:t,id:n,values:i}=e;if(t&&"string"!=typeof t)throw console.warn("Illegal <Translate> children",t),new Error("The Docusaurus <Translate> component only accept simple string values");const l=o({message:t,id:n});return r.createElement(r.Fragment,null,a(l,i))}},7065:(e,t,n)=>{"use strict";n.d(t,{W:()=>r});const r="default"},6654:(e,t,n)=>{"use strict";function r(e){return/^(?:\w*:|\/\/)/.test(e)}function a(e){return void 0!==e&&!r(e)}n.d(t,{A:()=>a,z:()=>r})},6025:(e,t,n)=>{"use strict";n.d(t,{A:()=>o,h:()=>i});var r=n(4586),a=n(6654);function i(){const{siteConfig:{baseUrl:e,url:t}}=(0,r.A)();return{withBaseUrl:(n,r)=>function(e,t,n,r){let{forcePrependBaseUrl:i=!1,absolute:o=!1}=void 0===r?{}:r;if(!n||n.startsWith("#")||(0,a.z)(n))return n;if(i)return t+n.replace(/^\//,"");if(n===t.replace(/\/$/,""))return t;const l=n.startsWith(t)?n:t+n.replace(/^\//,"");return o?e+l:l}(t,e,n,r)}}function o(e,t){void 0===t&&(t={});const{withBaseUrl:n}=i();return n(e,t)}},4586:(e,t,n)=>{"use strict";n.d(t,{A:()=>i});var r=n(6540),a=n(6988);function i(){return(0,r.useContext)(a.o)}},2303:(e,t,n)=>{"use strict";n.d(t,{A:()=>i});var r=n(6540),a=n(6125);function i(){return(0,r.useContext)(a.o)}},6921:(e,t,n)=>{"use strict";n.d(t,{A:()=>a});const r=e=>"object"==typeof e&&!!e&&Object.keys(e).length>0;function a(e){const t={};return function e(n,a){Object.entries(n).forEach((n=>{let[i,o]=n;const l=a?`${a}.${i}`:i;r(o)?e(o,l):t[l]=o}))}(e),t}},3102:(e,t,n)=>{"use strict";n.d(t,{W:()=>i,o:()=>a});var r=n(6540);const a=r.createContext(null);function i(e){let{children:t,value:n}=e;const i=r.useContext(a),o=(0,r.useMemo)((()=>function(e){let{parent:t,value:n}=e;if(!t){if(!n)throw new Error("Unexpected: no Docusaurus route context found");if(!("plugin"in n))throw new Error("Unexpected: Docusaurus topmost route context has no `plugin` attribute");return n}const r={...t.data,...n?.data};return{plugin:t.plugin,data:r}}({parent:i,value:n})),[i,n]);return r.createElement(a.Provider,{value:o},t)}},4070:(e,t,n)=>{"use strict";n.d(t,{zK:()=>g,vT:()=>p,Gy:()=>u,HW:()=>h,ht:()=>d,r7:()=>m,jh:()=>f});var r=n(6347),a=n(4586),i=n(7065);function o(e,t){void 0===t&&(t={});const n=function(){const{globalData:e}=(0,a.A)();return e}()[e];if(!n&&t.failfast)throw new Error(`Docusaurus plugin global data not found for "${e}" plugin.`);return n}const l=e=>e.versions.find((e=>e.isLast));function s(e,t){const n=function(e,t){const n=l(e);return[...e.versions.filter((e=>e!==n)),n].find((e=>!!(0,r.B6)(t,{path:e.path,exact:!1,strict:!1})))}(e,t),a=n?.docs.find((e=>!!(0,r.B6)(t,{path:e.path,exact:!0,strict:!1})));return{activeVersion:n,activeDoc:a,alternateDocVersions:a?function(t){const n={};return e.versions.forEach((e=>{e.docs.forEach((r=>{r.id===t&&(n[e.name]=r)}))})),n}(a.id):{}}}const c={},u=()=>o("docusaurus-plugin-content-docs")??c,d=e=>function(e,t,n){void 0===t&&(t=i.W),void 0===n&&(n={});const r=o(e),a=r?.[t];if(!a&&n.failfast)throw new Error(`Docusaurus plugin global data not found for "${e}" plugin with id "${t}".`);return a}("docusaurus-plugin-content-docs",e,{failfast:!0});function p(e){void 0===e&&(e={});const t=u(),{pathname:n}=(0,r.zy)();return function(e,t,n){void 0===n&&(n={});const a=Object.entries(e).sort(((e,t)=>t[1].path.localeCompare(e[1].path))).find((e=>{let[,n]=e;return!!(0,r.B6)(t,{path:n.path,exact:!1,strict:!1})})),i=a?{pluginId:a[0],pluginData:a[1]}:void 0;if(!i&&n.failfast)throw new Error(`Can't find active docs plugin for "${t}" pathname, while it was expected to be found. Maybe you tried to use a docs feature that can only be used on a docs-related page? Existing docs plugin paths are: ${Object.values(e).map((e=>e.path)).join(", ")}`);return i}(t,n,e)}function f(e){return d(e).versions}function m(e){const t=d(e);return l(t)}function g(e){const t=d(e),{pathname:n}=(0,r.zy)();return s(t,n)}function h(e){const t=d(e),{pathname:n}=(0,r.zy)();return function(e,t){const n=l(e);return{latestDocSuggestion:s(e,t).alternateDocVersions[n.name],latestVersionSuggestion:n}}(t,n)}},6294:(e,t,n)=>{"use strict";n.r(t),n.d(t,{default:()=>i});var r=n(5947),a=n.n(r);a().configure({showSpinner:!1});const i={onRouteUpdate(e){let{location:t,previousLocation:n}=e;if(n&&t.pathname!==n.pathname){const e=window.setTimeout((()=>{a().start()}),200);return()=>window.clearTimeout(e)}},onRouteDidUpdate(){a().done()}}},6134:(e,t,n)=>{"use strict";n.r(t);var r=n(1258),a=n(4784);!function(e){const{themeConfig:{prism:t}}=a.default,{additionalLanguages:r}=t;globalThis.Prism=e,r.forEach((e=>{n(4176)(`./prism-${e}`)})),delete globalThis.Prism}(r.A)},3186:(e,t,n)=>{"use strict";n.d(t,{A:()=>i});var r=n(6540);const a={iconExternalLink:"iconExternalLink_nPIU"};function i(e){let{width:t=13.5,height:n=13.5}=e;return r.createElement("svg",{width:t,height:n,"aria-hidden":"true",viewBox:"0 0 24 24",className:a.iconExternalLink},r.createElement("path",{fill:"currentColor",d:"M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"}))}},5713:(e,t,n)=>{"use strict";n.d(t,{A:()=>st});var r=n(6540),a=n(53),i=n(7489),o=n(1003),l=n(8168),s=n(6347),c=n(1312),u=n(5062);const d="docusaurus_skipToContent_fallback";function p(e){e.setAttribute("tabindex","-1"),e.focus(),e.removeAttribute("tabindex")}function f(){const e=(0,r.useRef)(null),{action:t}=(0,s.W6)(),n=(0,r.useCallback)((e=>{e.preventDefault();const t=document.querySelector("main:first-of-type")??document.getElementById(d);t&&p(t)}),[]);return(0,u.$)((n=>{let{location:r}=n;e.current&&!r.hash&&"PUSH"===t&&p(e.current)})),{containerRef:e,onClick:n}}const m=(0,c.T)({id:"theme.common.skipToMainContent",description:"The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation",message:"Skip to main content"});function g(e){const t=e.children??m,{containerRef:n,onClick:a}=f();return r.createElement("div",{ref:n,role:"region","aria-label":m},r.createElement("a",(0,l.A)({},e,{href:`#${d}`,onClick:a}),t))}var h=n(7559),b=n(4090);const v={skipToContent:"skipToContent_fXgn"};function y(){return r.createElement(g,{className:v.skipToContent})}var w=n(6342),x=n(5041);function k(e){let{width:t=21,height:n=21,color:a="currentColor",strokeWidth:i=1.2,className:o,...s}=e;return r.createElement("svg",(0,l.A)({viewBox:"0 0 15 15",width:t,height:n},s),r.createElement("g",{stroke:a,strokeWidth:i},r.createElement("path",{d:"M.75.75l13.5 13.5M14.25.75L.75 14.25"})))}const E={closeButton:"closeButton_CVFx"};function S(e){return r.createElement("button",(0,l.A)({type:"button","aria-label":(0,c.T)({id:"theme.AnnouncementBar.closeButtonAriaLabel",message:"Close",description:"The ARIA label for close button of announcement bar"})},e,{className:(0,a.A)("clean-btn close",E.closeButton,e.className)}),r.createElement(k,{width:14,height:14,strokeWidth:3.1}))}const T={content:"content_knG7"};function _(e){const{announcementBar:t}=(0,w.p)(),{content:n}=t;return r.createElement("div",(0,l.A)({},e,{className:(0,a.A)(T.content,e.className),dangerouslySetInnerHTML:{__html:n}}))}const A={announcementBar:"announcementBar_mb4j",announcementBarPlaceholder:"announcementBarPlaceholder_vyr4",announcementBarClose:"announcementBarClose_gvF7",announcementBarContent:"announcementBarContent_xLdY"};function C(){const{announcementBar:e}=(0,w.p)(),{isActive:t,close:n}=(0,x.Mj)();if(!t)return null;const{backgroundColor:a,textColor:i,isCloseable:o}=e;return r.createElement("div",{className:A.announcementBar,style:{backgroundColor:a,color:i},role:"banner"},o&&r.createElement("div",{className:A.announcementBarPlaceholder}),r.createElement(_,{className:A.announcementBarContent}),o&&r.createElement(S,{onClick:n,className:A.announcementBarClose}))}var P=n(9876),N=n(3104);var O=n(9532),I=n(5600);const R=r.createContext(null);function D(e){let{children:t}=e;const n=function(){const e=(0,P.M)(),t=(0,I.YL)(),[n,a]=(0,r.useState)(!1),i=null!==t.component,o=(0,O.ZC)(i);return(0,r.useEffect)((()=>{i&&!o&&a(!0)}),[i,o]),(0,r.useEffect)((()=>{i?e.shown||a(!0):a(!1)}),[e.shown,i]),(0,r.useMemo)((()=>[n,a]),[n])}();return r.createElement(R.Provider,{value:n},t)}function L(e){if(e.component){const t=e.component;return r.createElement(t,e.props)}}function M(){const e=(0,r.useContext)(R);if(!e)throw new O.dV("NavbarSecondaryMenuDisplayProvider");const[t,n]=e,a=(0,r.useCallback)((()=>n(!1)),[n]),i=(0,I.YL)();return(0,r.useMemo)((()=>({shown:t,hide:a,content:L(i)})),[a,i,t])}function F(e){let{header:t,primaryMenu:n,secondaryMenu:i}=e;const{shown:o}=M();return r.createElement("div",{className:"navbar-sidebar"},t,r.createElement("div",{className:(0,a.A)("navbar-sidebar__items",{"navbar-sidebar__items--show-secondary":o})},r.createElement("div",{className:"navbar-sidebar__item menu"},n),r.createElement("div",{className:"navbar-sidebar__item menu"},i)))}var B=n(5293),$=n(2303);function z(e){return r.createElement("svg",(0,l.A)({viewBox:"0 0 24 24",width:24,height:24},e),r.createElement("path",{fill:"currentColor",d:"M12,9c1.65,0,3,1.35,3,3s-1.35,3-3,3s-3-1.35-3-3S10.35,9,12,9 M12,7c-2.76,0-5,2.24-5,5s2.24,5,5,5s5-2.24,5-5 S14.76,7,12,7L12,7z M2,13l2,0c0.55,0,1-0.45,1-1s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S1.45,13,2,13z M20,13l2,0c0.55,0,1-0.45,1-1 s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S19.45,13,20,13z M11,2v2c0,0.55,0.45,1,1,1s1-0.45,1-1V2c0-0.55-0.45-1-1-1S11,1.45,11,2z M11,20v2c0,0.55,0.45,1,1,1s1-0.45,1-1v-2c0-0.55-0.45-1-1-1C11.45,19,11,19.45,11,20z M5.99,4.58c-0.39-0.39-1.03-0.39-1.41,0 c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0s0.39-1.03,0-1.41L5.99,4.58z M18.36,16.95 c-0.39-0.39-1.03-0.39-1.41,0c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0c0.39-0.39,0.39-1.03,0-1.41 L18.36,16.95z M19.42,5.99c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06c-0.39,0.39-0.39,1.03,0,1.41 s1.03,0.39,1.41,0L19.42,5.99z M7.05,18.36c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06 c-0.39,0.39-0.39,1.03,0,1.41s1.03,0.39,1.41,0L7.05,18.36z"}))}function U(e){return r.createElement("svg",(0,l.A)({viewBox:"0 0 24 24",width:24,height:24},e),r.createElement("path",{fill:"currentColor",d:"M9.37,5.51C9.19,6.15,9.1,6.82,9.1,7.5c0,4.08,3.32,7.4,7.4,7.4c0.68,0,1.35-0.09,1.99-0.27C17.45,17.19,14.93,19,12,19 c-3.86,0-7-3.14-7-7C5,9.07,6.81,6.55,9.37,5.51z M12,3c-4.97,0-9,4.03-9,9s4.03,9,9,9s9-4.03,9-9c0-0.46-0.04-0.92-0.1-1.36 c-0.98,1.37-2.58,2.26-4.4,2.26c-2.98,0-5.4-2.42-5.4-5.4c0-1.81,0.89-3.42,2.26-4.4C12.92,3.04,12.46,3,12,3L12,3z"}))}const j={toggle:"toggle_vylO",toggleButton:"toggleButton_gllP",darkToggleIcon:"darkToggleIcon_wfgR",lightToggleIcon:"lightToggleIcon_pyhR",toggleButtonDisabled:"toggleButtonDisabled_aARS"};function H(e){let{className:t,value:n,onChange:i}=e;const o=(0,$.A)(),l=(0,c.T)({message:"Switch between dark and light mode (currently {mode})",id:"theme.colorToggle.ariaLabel",description:"The ARIA label for the navbar color mode toggle"},{mode:"dark"===n?(0,c.T)({message:"dark mode",id:"theme.colorToggle.ariaLabel.mode.dark",description:"The name for the dark color mode"}):(0,c.T)({message:"light mode",id:"theme.colorToggle.ariaLabel.mode.light",description:"The name for the light color mode"})});return r.createElement("div",{className:(0,a.A)(j.toggle,t)},r.createElement("button",{className:(0,a.A)("clean-btn",j.toggleButton,!o&&j.toggleButtonDisabled),type:"button",onClick:()=>i("dark"===n?"light":"dark"),disabled:!o,title:l,"aria-label":l,"aria-live":"polite"},r.createElement(z,{className:(0,a.A)(j.toggleIcon,j.lightToggleIcon)}),r.createElement(U,{className:(0,a.A)(j.toggleIcon,j.darkToggleIcon)})))}const W=r.memo(H);function V(e){let{className:t}=e;const n=(0,w.p)().colorMode.disableSwitch,{colorMode:a,setColorMode:i}=(0,B.G)();return n?null:r.createElement(W,{className:t,value:a,onChange:i})}var G=n(3465);function q(){return r.createElement(G.A,{className:"navbar__brand",imageClassName:"navbar__logo",titleClassName:"navbar__title text--truncate"})}function K(){const e=(0,P.M)();return r.createElement("button",{type:"button","aria-label":(0,c.T)({id:"theme.docs.sidebar.closeSidebarButtonAriaLabel",message:"Close navigation bar",description:"The ARIA label for close button of mobile sidebar"}),className:"clean-btn navbar-sidebar__close",onClick:()=>e.toggle()},r.createElement(k,{color:"var(--ifm-color-emphasis-600)"}))}function Y(){return r.createElement("div",{className:"navbar-sidebar__brand"},r.createElement(q,null),r.createElement(V,{className:"margin-right--md"}),r.createElement(K,null))}var Q=n(5489),Z=n(6025),X=n(6654);function J(e,t){return void 0!==e&&void 0!==t&&new RegExp(e,"gi").test(t)}var ee=n(3186);function te(e){let{activeBasePath:t,activeBaseRegex:n,to:a,href:i,label:o,html:s,isDropdownLink:c,prependBaseUrlToHref:u,...d}=e;const p=(0,Z.A)(a),f=(0,Z.A)(t),m=(0,Z.A)(i,{forcePrependBaseUrl:!0}),g=o&&i&&!(0,X.A)(i),h=s?{dangerouslySetInnerHTML:{__html:s}}:{children:r.createElement(r.Fragment,null,o,g&&r.createElement(ee.A,c&&{width:12,height:12}))};return i?r.createElement(Q.A,(0,l.A)({href:u?m:i},d,h)):r.createElement(Q.A,(0,l.A)({to:p,isNavLink:!0},(t||n)&&{isActive:(e,t)=>n?J(n,t.pathname):t.pathname.startsWith(f)},d,h))}function ne(e){let{className:t,isDropdownItem:n=!1,...i}=e;const o=r.createElement(te,(0,l.A)({className:(0,a.A)(n?"dropdown__link":"navbar__item navbar__link",t),isDropdownLink:n},i));return n?r.createElement("li",null,o):o}function re(e){let{className:t,isDropdownItem:n,...i}=e;return r.createElement("li",{className:"menu__list-item"},r.createElement(te,(0,l.A)({className:(0,a.A)("menu__link",t)},i)))}function ae(e){let{mobile:t=!1,position:n,...a}=e;const i=t?re:ne;return r.createElement(i,(0,l.A)({},a,{activeClassName:a.activeClassName??(t?"menu__link--active":"navbar__link--active")}))}var ie=n(1422),oe=n(9169),le=n(4586);function se(e,t){return e.some((e=>function(e,t){return!!(0,oe.ys)(e.to,t)||!!J(e.activeBaseRegex,t)||!(!e.activeBasePath||!t.startsWith(e.activeBasePath))}(e,t)))}function ce(e){let{items:t,position:n,className:i,onClick:o,...s}=e;const c=(0,r.useRef)(null),[u,d]=(0,r.useState)(!1);return(0,r.useEffect)((()=>{const e=e=>{c.current&&!c.current.contains(e.target)&&d(!1)};return document.addEventListener("mousedown",e),document.addEventListener("touchstart",e),()=>{document.removeEventListener("mousedown",e),document.removeEventListener("touchstart",e)}}),[c]),r.createElement("div",{ref:c,className:(0,a.A)("navbar__item","dropdown","dropdown--hoverable",{"dropdown--right":"right"===n,"dropdown--show":u})},r.createElement(te,(0,l.A)({"aria-haspopup":"true","aria-expanded":u,role:"button",href:s.to?void 0:"#",className:(0,a.A)("navbar__link",i)},s,{onClick:s.to?void 0:e=>e.preventDefault(),onKeyDown:e=>{"Enter"===e.key&&(e.preventDefault(),d(!u))}}),s.children??s.label),r.createElement("ul",{className:"dropdown__menu"},t.map(((e,n)=>r.createElement(Ee,(0,l.A)({isDropdownItem:!0,onKeyDown:e=>{if(n===t.length-1&&"Tab"===e.key){e.preventDefault(),d(!1);const t=c.current.nextElementSibling;if(t){(t instanceof HTMLAnchorElement?t:t.querySelector("a")).focus()}}},activeClassName:"dropdown__link--active"},e,{key:n}))))))}function ue(e){let{items:t,className:n,position:i,onClick:o,...c}=e;const u=function(){const{siteConfig:{baseUrl:e}}=(0,le.A)(),{pathname:t}=(0,s.zy)();return t.replace(e,"/")}(),d=se(t,u),{collapsed:p,toggleCollapsed:f,setCollapsed:m}=(0,ie.u)({initialState:()=>!d});return(0,r.useEffect)((()=>{d&&m(!d)}),[u,d,m]),r.createElement("li",{className:(0,a.A)("menu__list-item",{"menu__list-item--collapsed":p})},r.createElement(te,(0,l.A)({role:"button",className:(0,a.A)("menu__link menu__link--sublist menu__link--sublist-caret",n)},c,{onClick:e=>{e.preventDefault(),f()}}),c.children??c.label),r.createElement(ie.N,{lazy:!0,as:"ul",className:"menu__list",collapsed:p},t.map(((e,t)=>r.createElement(Ee,(0,l.A)({mobile:!0,isDropdownItem:!0,onClick:o,activeClassName:"menu__link--active"},e,{key:t}))))))}function de(e){let{mobile:t=!1,...n}=e;const a=t?ue:ce;return r.createElement(a,n)}var pe=n(2131);function fe(e){let{width:t=20,height:n=20,...a}=e;return r.createElement("svg",(0,l.A)({viewBox:"0 0 24 24",width:t,height:n,"aria-hidden":!0},a),r.createElement("path",{fill:"currentColor",d:"M12.87 15.07l-2.54-2.51.03-.03c1.74-1.94 2.98-4.17 3.71-6.53H17V4h-7V2H8v2H1v1.99h11.17C11.5 7.92 10.44 9.75 9 11.35 8.07 10.32 7.3 9.19 6.69 8h-2c.73 1.63 1.73 3.17 2.98 4.56l-5.09 5.02L4 19l5-5 3.11 3.11.76-2.04zM18.5 10h-2L12 22h2l1.12-3h4.75L21 22h2l-4.5-12zm-2.62 7l1.62-4.33L19.12 17h-3.24z"}))}const me="iconLanguage_nlXk";var ge=n(418);const he={searchBox:"searchBox_ZlJk"};function be(e){let{children:t,className:n}=e;return r.createElement("div",{className:(0,a.A)(n,he.searchBox)},t)}var ve=n(4070),ye=n(1754);var we=n(5597);const xe=e=>e.docs.find((t=>t.id===e.mainDocId));const ke={default:ae,localeDropdown:function(e){let{mobile:t,dropdownItemsBefore:n,dropdownItemsAfter:a,...i}=e;const{i18n:{currentLocale:o,locales:u,localeConfigs:d}}=(0,le.A)(),p=(0,pe.o)(),{search:f,hash:m}=(0,s.zy)(),g=[...n,...u.map((e=>{const n=`${`pathname://${p.createUrl({locale:e,fullyQualified:!1})}`}${f}${m}`;return{label:d[e].label,lang:d[e].htmlLang,to:n,target:"_self",autoAddBaseUrl:!1,className:e===o?t?"menu__link--active":"dropdown__link--active":""}})),...a],h=t?(0,c.T)({message:"Languages",id:"theme.navbar.mobileLanguageDropdown.label",description:"The label for the mobile language switcher dropdown"}):d[o].label;return r.createElement(de,(0,l.A)({},i,{mobile:t,label:r.createElement(r.Fragment,null,r.createElement(fe,{className:me}),h),items:g}))},search:function(e){let{mobile:t,className:n}=e;return t?null:r.createElement(be,{className:n},r.createElement(ge.A,null))},dropdown:de,html:function(e){let{value:t,className:n,mobile:i=!1,isDropdownItem:o=!1}=e;const l=o?"li":"div";return r.createElement(l,{className:(0,a.A)({navbar__item:!i&&!o,"menu__list-item":i},n),dangerouslySetInnerHTML:{__html:t}})},doc:function(e){let{docId:t,label:n,docsPluginId:a,...i}=e;const{activeDoc:o}=(0,ve.zK)(a),s=(0,ye.QB)(t,a);return null===s?null:r.createElement(ae,(0,l.A)({exact:!0},i,{isActive:()=>o?.path===s.path||!!o?.sidebar&&o.sidebar===s.sidebar,label:n??s.id,to:s.path}))},docSidebar:function(e){let{sidebarId:t,label:n,docsPluginId:a,...i}=e;const{activeDoc:o}=(0,ve.zK)(a),s=(0,ye.fW)(t,a).link;if(!s)throw new Error(`DocSidebarNavbarItem: Sidebar with ID "${t}" doesn't have anything to be linked to.`);return r.createElement(ae,(0,l.A)({exact:!0},i,{isActive:()=>o?.sidebar===t,label:n??s.label,to:s.path}))},docsVersion:function(e){let{label:t,to:n,docsPluginId:a,...i}=e;const o=(0,ye.Vd)(a)[0],s=t??o.label,c=n??(e=>e.docs.find((t=>t.id===e.mainDocId)))(o).path;return r.createElement(ae,(0,l.A)({},i,{label:s,to:c}))},docsVersionDropdown:function(e){let{mobile:t,docsPluginId:n,dropdownActiveClassDisabled:a,dropdownItemsBefore:i,dropdownItemsAfter:o,...u}=e;const{search:d,hash:p}=(0,s.zy)(),f=(0,ve.zK)(n),m=(0,ve.jh)(n),{savePreferredVersionName:g}=(0,we.g1)(n),h=[...i,...m.map((e=>{const t=f.alternateDocVersions[e.name]??xe(e);return{label:e.label,to:`${t.path}${d}${p}`,isActive:()=>e===f.activeVersion,onClick:()=>g(e.name)}})),...o],b=(0,ye.Vd)(n)[0],v=t&&h.length>1?(0,c.T)({id:"theme.navbar.mobileVersionsDropdown.label",message:"Versions",description:"The label for the navbar versions dropdown on mobile view"}):b.label,y=t&&h.length>1?void 0:xe(b).path;return h.length<=1?r.createElement(ae,(0,l.A)({},u,{mobile:t,label:v,to:y,isActive:a?()=>!1:void 0})):r.createElement(de,(0,l.A)({},u,{mobile:t,label:v,to:y,items:h,isActive:a?()=>!1:void 0}))}};function Ee(e){let{type:t,...n}=e;const a=function(e,t){return e&&"default"!==e?e:"items"in t?"dropdown":"default"}(t,n),i=ke[a];if(!i)throw new Error(`No NavbarItem component found for type "${t}".`);return r.createElement(i,n)}function Se(){const e=(0,P.M)(),t=(0,w.p)().navbar.items;return r.createElement("ul",{className:"menu__list"},t.map(((t,n)=>r.createElement(Ee,(0,l.A)({mobile:!0},t,{onClick:()=>e.toggle(),key:n})))))}function Te(e){return r.createElement("button",(0,l.A)({},e,{type:"button",className:"clean-btn navbar-sidebar__back"}),r.createElement(c.A,{id:"theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel",description:"The label of the back button to return to main menu, inside the mobile navbar sidebar secondary menu (notably used to display the docs sidebar)"},"\u2190 Back to main menu"))}function _e(){const e=0===(0,w.p)().navbar.items.length,t=M();return r.createElement(r.Fragment,null,!e&&r.createElement(Te,{onClick:()=>t.hide()}),t.content)}function Ae(){const e=(0,P.M)();var t;return void 0===(t=e.shown)&&(t=!0),(0,r.useEffect)((()=>(document.body.style.overflow=t?"hidden":"visible",()=>{document.body.style.overflow="visible"})),[t]),e.shouldRender?r.createElement(F,{header:r.createElement(Y,null),primaryMenu:r.createElement(Se,null),secondaryMenu:r.createElement(_e,null)}):null}const Ce={navbarHideable:"navbarHideable_m1mJ",navbarHidden:"navbarHidden_jGov"};function Pe(e){return r.createElement("div",(0,l.A)({role:"presentation"},e,{className:(0,a.A)("navbar-sidebar__backdrop",e.className)}))}function Ne(e){let{children:t}=e;const{navbar:{hideOnScroll:n,style:i}}=(0,w.p)(),o=(0,P.M)(),{navbarRef:l,isNavbarVisible:s}=function(e){const[t,n]=(0,r.useState)(e),a=(0,r.useRef)(!1),i=(0,r.useRef)(0),o=(0,r.useCallback)((e=>{null!==e&&(i.current=e.getBoundingClientRect().height)}),[]);return(0,N.Mq)(((t,r)=>{let{scrollY:o}=t;if(!e)return;if(o<i.current)return void n(!0);if(a.current)return void(a.current=!1);const l=r?.scrollY,s=document.documentElement.scrollHeight-i.current,c=window.innerHeight;l&&o>=l?n(!1):o+c<s&&n(!0)})),(0,u.$)((t=>{if(!e)return;const r=t.location.hash;if(r?document.getElementById(r.substring(1)):void 0)return a.current=!0,void n(!1);n(!0)})),{navbarRef:o,isNavbarVisible:t}}(n);return r.createElement("nav",{ref:l,className:(0,a.A)("navbar","navbar--fixed-top",n&&[Ce.navbarHideable,!s&&Ce.navbarHidden],{"navbar--dark":"dark"===i,"navbar--primary":"primary"===i,"navbar-sidebar--show":o.shown})},t,r.createElement(Pe,{onClick:o.toggle}),r.createElement(Ae,null))}const Oe="right";function Ie(e){let{width:t=30,height:n=30,className:a,...i}=e;return r.createElement("svg",(0,l.A)({className:a,width:t,height:n,viewBox:"0 0 30 30","aria-hidden":"true"},i),r.createElement("path",{stroke:"currentColor",strokeLinecap:"round",strokeMiterlimit:"10",strokeWidth:"2",d:"M4 7h22M4 15h22M4 23h22"}))}function Re(){const{toggle:e,shown:t}=(0,P.M)();return r.createElement("button",{onClick:e,"aria-label":(0,c.T)({id:"theme.docs.sidebar.toggleSidebarButtonAriaLabel",message:"Toggle navigation bar",description:"The ARIA label for hamburger menu button of mobile navigation"}),"aria-expanded":t,className:"navbar__toggle clean-btn",type:"button"},r.createElement(Ie,null))}const De={colorModeToggle:"colorModeToggle_DEke"};function Le(e){let{items:t}=e;return r.createElement(r.Fragment,null,t.map(((e,t)=>r.createElement(Ee,(0,l.A)({},e,{key:t})))))}function Me(e){let{left:t,right:n}=e;return r.createElement("div",{className:"navbar__inner"},r.createElement("div",{className:"navbar__items"},t),r.createElement("div",{className:"navbar__items navbar__items--right"},n))}function Fe(){const e=(0,P.M)(),t=(0,w.p)().navbar.items,[n,a]=function(e){function t(e){return"left"===(e.position??Oe)}return[e.filter(t),e.filter((e=>!t(e)))]}(t),i=t.find((e=>"search"===e.type));return r.createElement(Me,{left:r.createElement(r.Fragment,null,!e.disabled&&r.createElement(Re,null),r.createElement(q,null),r.createElement(Le,{items:n})),right:r.createElement(r.Fragment,null,r.createElement(Le,{items:a}),r.createElement(V,{className:De.colorModeToggle}),!i&&r.createElement(be,null,r.createElement(ge.A,null)))})}function Be(){return r.createElement(Ne,null,r.createElement(Fe,null))}function $e(e){let{item:t}=e;const{to:n,href:a,label:i,prependBaseUrlToHref:o,...s}=t,c=(0,Z.A)(n),u=(0,Z.A)(a,{forcePrependBaseUrl:!0});return r.createElement(Q.A,(0,l.A)({className:"footer__link-item"},a?{href:o?u:a}:{to:c},s),i,a&&!(0,X.A)(a)&&r.createElement(ee.A,null))}function ze(e){let{item:t}=e;return t.html?r.createElement("li",{className:"footer__item",dangerouslySetInnerHTML:{__html:t.html}}):r.createElement("li",{key:t.href??t.to,className:"footer__item"},r.createElement($e,{item:t}))}function Ue(e){let{column:t}=e;return r.createElement("div",{className:"col footer__col"},r.createElement("div",{className:"footer__title"},t.title),r.createElement("ul",{className:"footer__items clean-list"},t.items.map(((e,t)=>r.createElement(ze,{key:t,item:e})))))}function je(e){let{columns:t}=e;return r.createElement("div",{className:"row footer__links"},t.map(((e,t)=>r.createElement(Ue,{key:t,column:e}))))}function He(){return r.createElement("span",{className:"footer__link-separator"},"\xb7")}function We(e){let{item:t}=e;return t.html?r.createElement("span",{className:"footer__link-item",dangerouslySetInnerHTML:{__html:t.html}}):r.createElement($e,{item:t})}function Ve(e){let{links:t}=e;return r.createElement("div",{className:"footer__links text--center"},r.createElement("div",{className:"footer__links"},t.map(((e,n)=>r.createElement(r.Fragment,{key:n},r.createElement(We,{item:e}),t.length!==n+1&&r.createElement(He,null))))))}function Ge(e){let{links:t}=e;return function(e){return"title"in e[0]}(t)?r.createElement(je,{columns:t}):r.createElement(Ve,{links:t})}var qe=n(1653);const Ke={footerLogoLink:"footerLogoLink_BH7S"};function Ye(e){let{logo:t}=e;const{withBaseUrl:n}=(0,Z.h)(),i={light:n(t.src),dark:n(t.srcDark??t.src)};return r.createElement(qe.A,{className:(0,a.A)("footer__logo",t.className),alt:t.alt,sources:i,width:t.width,height:t.height,style:t.style})}function Qe(e){let{logo:t}=e;return t.href?r.createElement(Q.A,{href:t.href,className:Ke.footerLogoLink,target:t.target},r.createElement(Ye,{logo:t})):r.createElement(Ye,{logo:t})}function Ze(e){let{copyright:t}=e;return r.createElement("div",{className:"footer__copyright",dangerouslySetInnerHTML:{__html:t}})}function Xe(e){let{style:t,links:n,logo:i,copyright:o}=e;return r.createElement("footer",{className:(0,a.A)("footer",{"footer--dark":"dark"===t})},r.createElement("div",{className:"container container-fluid"},n,(i||o)&&r.createElement("div",{className:"footer__bottom text--center"},i&&r.createElement("div",{className:"margin-bottom--sm"},i),o)))}function Je(){const{footer:e}=(0,w.p)();if(!e)return null;const{copyright:t,links:n,logo:a,style:i}=e;return r.createElement(Xe,{style:i,links:n&&n.length>0&&r.createElement(Ge,{links:n}),logo:a&&r.createElement(Qe,{logo:a}),copyright:t&&r.createElement(Ze,{copyright:t})})}const et=r.memo(Je);var tt=n(9466);const nt="docusaurus.tab.",rt=r.createContext(void 0);const at=(0,O.fM)([B.a,x.oq,function(e){let{children:t}=e;const n=function(){const[e,t]=(0,r.useState)({}),n=(0,r.useCallback)(((e,t)=>{(0,tt.W)(`${nt}${e}`).set(t)}),[]);(0,r.useEffect)((()=>{try{const e={};(0,tt.E)().forEach((t=>{if(t.startsWith(nt)){const n=t.substring(nt.length);e[n]=(0,tt.W)(t).get()}})),t(e)}catch(e){console.error(e)}}),[]);const a=(0,r.useCallback)(((e,r)=>{t((t=>({...t,[e]:r}))),n(e,r)}),[n]);return(0,r.useMemo)((()=>({tabGroupChoices:e,setTabGroupChoices:a})),[e,a])}();return r.createElement(rt.Provider,{value:n},t)},N.Tv,we.VQ,o.Jx,function(e){let{children:t}=e;return r.createElement(I.y_,null,r.createElement(P.e,null,r.createElement(D,null,t)))}]);function it(e){let{children:t}=e;return r.createElement(at,null,t)}function ot(e){let{error:t,tryAgain:n}=e;return r.createElement("main",{className:"container margin-vert--xl"},r.createElement("div",{className:"row"},r.createElement("div",{className:"col col--6 col--offset-3"},r.createElement("h1",{className:"hero__title"},r.createElement(c.A,{id:"theme.ErrorPageContent.title",description:"The title of the fallback page when the page crashed"},"This page crashed.")),r.createElement("p",null,t.message),r.createElement("div",null,r.createElement("button",{type:"button",onClick:n},r.createElement(c.A,{id:"theme.ErrorPageContent.tryAgain",description:"The label of the button to try again when the page crashed"},"Try again"))))))}const lt={mainWrapper:"mainWrapper_z2l0"};function st(e){const{children:t,noFooter:n,wrapperClassName:l,title:s,description:c}=e;return(0,b.J)(),r.createElement(it,null,r.createElement(o.be,{title:s,description:c}),r.createElement(y,null),r.createElement(C,null),r.createElement(Be,null),r.createElement("div",{id:d,className:(0,a.A)(h.G.wrapper.main,lt.mainWrapper,l)},r.createElement(i.A,{fallback:e=>r.createElement(ot,e)},t)),!n&&r.createElement(et,null))}},3465:(e,t,n)=>{"use strict";n.d(t,{A:()=>d});var r=n(8168),a=n(6540),i=n(5489),o=n(6025),l=n(4586),s=n(6342),c=n(1653);function u(e){let{logo:t,alt:n,imageClassName:r}=e;const i={light:(0,o.A)(t.src),dark:(0,o.A)(t.srcDark||t.src)},l=a.createElement(c.A,{className:t.className,sources:i,height:t.height,width:t.width,alt:n,style:t.style});return r?a.createElement("div",{className:r},l):l}function d(e){const{siteConfig:{title:t}}=(0,l.A)(),{navbar:{title:n,logo:c}}=(0,s.p)(),{imageClassName:d,titleClassName:p,...f}=e,m=(0,o.A)(c?.href||"/"),g=n?"":t,h=c?.alt??g;return a.createElement(i.A,(0,r.A)({to:m},f,c?.target&&{target:c.target}),c&&a.createElement(u,{logo:c,alt:h,imageClassName:d}),null!=n&&a.createElement("b",{className:p},n))}},1463:(e,t,n)=>{"use strict";n.d(t,{A:()=>i});var r=n(6540),a=n(5260);function i(e){let{locale:t,version:n,tag:i}=e;const o=t;return r.createElement(a.A,null,t&&r.createElement("meta",{name:"docusaurus_locale",content:t}),n&&r.createElement("meta",{name:"docusaurus_version",content:n}),i&&r.createElement("meta",{name:"docusaurus_tag",content:i}),o&&r.createElement("meta",{name:"docsearch:language",content:o}),n&&r.createElement("meta",{name:"docsearch:version",content:n}),i&&r.createElement("meta",{name:"docsearch:docusaurus_tag",content:i}))}},1653:(e,t,n)=>{"use strict";n.d(t,{A:()=>c});var r=n(8168),a=n(6540),i=n(53),o=n(2303),l=n(5293);const s={themedImage:"themedImage_ToTc","themedImage--light":"themedImage--light_HNdA","themedImage--dark":"themedImage--dark_i4oU"};function c(e){const t=(0,o.A)(),{colorMode:n}=(0,l.G)(),{sources:c,className:u,alt:d,...p}=e,f=t?"dark"===n?["dark"]:["light"]:["light","dark"];return a.createElement(a.Fragment,null,f.map((e=>a.createElement("img",(0,r.A)({key:e,src:c[e],alt:d,className:(0,i.A)(s.themedImage,s[`themedImage--${e}`],u)},p)))))}},1422:(e,t,n)=>{"use strict";n.d(t,{N:()=>g,u:()=>l});var r=n(8168),a=n(6540),i=n(8193);const o="ease-in-out";function l(e){let{initialState:t}=e;const[n,r]=(0,a.useState)(t??!1),i=(0,a.useCallback)((()=>{r((e=>!e))}),[]);return{collapsed:n,setCollapsed:r,toggleCollapsed:i}}const s={display:"none",overflow:"hidden",height:"0px"},c={display:"block",overflow:"visible",height:"auto"};function u(e,t){const n=t?s:c;e.style.display=n.display,e.style.overflow=n.overflow,e.style.height=n.height}function d(e){let{collapsibleRef:t,collapsed:n,animation:r}=e;const i=(0,a.useRef)(!1);(0,a.useEffect)((()=>{const e=t.current;function a(){const t=e.scrollHeight,n=r?.duration??function(e){const t=e/36;return Math.round(10*(4+15*t**.25+t/5))}(t);return{transition:`height ${n}ms ${r?.easing??o}`,height:`${t}px`}}function l(){const t=a();e.style.transition=t.transition,e.style.height=t.height}if(!i.current)return u(e,n),void(i.current=!0);return e.style.willChange="height",function(){const t=requestAnimationFrame((()=>{n?(l(),requestAnimationFrame((()=>{e.style.height=s.height,e.style.overflow=s.overflow}))):(e.style.display="block",requestAnimationFrame((()=>{l()})))}));return()=>cancelAnimationFrame(t)}()}),[t,n,r])}function p(e){if(!i.A.canUseDOM)return e?s:c}function f(e){let{as:t="div",collapsed:n,children:r,animation:i,onCollapseTransitionEnd:o,className:l,disableSSRStyle:s}=e;const c=(0,a.useRef)(null);return d({collapsibleRef:c,collapsed:n,animation:i}),a.createElement(t,{ref:c,style:s?void 0:p(n),onTransitionEnd:e=>{"height"===e.propertyName&&(u(c.current,n),o?.(n))},className:l},r)}function m(e){let{collapsed:t,...n}=e;const[i,o]=(0,a.useState)(!t),[l,s]=(0,a.useState)(t);return(0,a.useLayoutEffect)((()=>{t||o(!0)}),[t]),(0,a.useLayoutEffect)((()=>{i&&s(t)}),[i,t]),i?a.createElement(f,(0,r.A)({},n,{collapsed:l})):null}function g(e){let{lazy:t,...n}=e;const r=t?m:f;return a.createElement(r,n)}},5041:(e,t,n)=>{"use strict";n.d(t,{Mj:()=>m,oq:()=>f});var r=n(6540),a=n(2303),i=n(9466),o=n(9532),l=n(6342);const s=(0,i.W)("docusaurus.announcement.dismiss"),c=(0,i.W)("docusaurus.announcement.id"),u=()=>"true"===s.get(),d=e=>s.set(String(e)),p=r.createContext(null);function f(e){let{children:t}=e;const n=function(){const{announcementBar:e}=(0,l.p)(),t=(0,a.A)(),[n,i]=(0,r.useState)((()=>!!t&&u()));(0,r.useEffect)((()=>{i(u())}),[]);const o=(0,r.useCallback)((()=>{d(!0),i(!0)}),[]);return(0,r.useEffect)((()=>{if(!e)return;const{id:t}=e;let n=c.get();"annoucement-bar"===n&&(n="announcement-bar");const r=t!==n;c.set(t),r&&d(!1),!r&&u()||i(!1)}),[e]),(0,r.useMemo)((()=>({isActive:!!e&&!n,close:o})),[e,n,o])}();return r.createElement(p.Provider,{value:n},t)}function m(){const e=(0,r.useContext)(p);if(!e)throw new o.dV("AnnouncementBarProvider");return e}},5293:(e,t,n)=>{"use strict";n.d(t,{G:()=>h,a:()=>g});var r=n(6540),a=n(8193),i=n(9532),o=n(9466),l=n(6342);const s=r.createContext(void 0),c="theme",u=(0,o.W)(c),d={light:"light",dark:"dark"},p=e=>e===d.dark?d.dark:d.light,f=e=>a.A.canUseDOM?p(document.documentElement.getAttribute("data-theme")):p(e),m=e=>{u.set(p(e))};function g(e){let{children:t}=e;const n=function(){const{colorMode:{defaultMode:e,disableSwitch:t,respectPrefersColorScheme:n}}=(0,l.p)(),[a,i]=(0,r.useState)(f(e));(0,r.useEffect)((()=>{t&&u.del()}),[t]);const o=(0,r.useCallback)((function(t,r){void 0===r&&(r={});const{persist:a=!0}=r;t?(i(t),a&&m(t)):(i(n?window.matchMedia("(prefers-color-scheme: dark)").matches?d.dark:d.light:e),u.del())}),[n,e]);(0,r.useEffect)((()=>{document.documentElement.setAttribute("data-theme",p(a))}),[a]),(0,r.useEffect)((()=>{if(t)return;const e=e=>{if(e.key!==c)return;const t=u.get();null!==t&&o(p(t))};return window.addEventListener("storage",e),()=>window.removeEventListener("storage",e)}),[t,o]);const s=(0,r.useRef)(!1);return(0,r.useEffect)((()=>{if(t&&!n)return;const e=window.matchMedia("(prefers-color-scheme: dark)"),r=()=>{window.matchMedia("print").matches||s.current?s.current=window.matchMedia("print").matches:o(null)};return e.addListener(r),()=>e.removeListener(r)}),[o,t,n]),(0,r.useMemo)((()=>({colorMode:a,setColorMode:o,get isDarkTheme(){return a===d.dark},setLightTheme(){o(d.light)},setDarkTheme(){o(d.dark)}})),[a,o])}();return r.createElement(s.Provider,{value:n},t)}function h(){const e=(0,r.useContext)(s);if(null==e)throw new i.dV("ColorModeProvider","Please see https://docusaurus.io/docs/api/themes/configuration#use-color-mode.");return e}},5597:(e,t,n)=>{"use strict";n.d(t,{VQ:()=>h,g1:()=>v});var r=n(6540),a=n(4070),i=n(7065),o=n(6342),l=n(1754),s=n(9532),c=n(9466);const u=e=>`docs-preferred-version-${e}`,d={save:(e,t,n)=>{(0,c.W)(u(e),{persistence:t}).set(n)},read:(e,t)=>(0,c.W)(u(e),{persistence:t}).get(),clear:(e,t)=>{(0,c.W)(u(e),{persistence:t}).del()}},p=e=>Object.fromEntries(e.map((e=>[e,{preferredVersionName:null}])));const f=r.createContext(null);function m(){const e=(0,a.Gy)(),t=(0,o.p)().docs.versionPersistence,n=(0,r.useMemo)((()=>Object.keys(e)),[e]),[i,l]=(0,r.useState)((()=>p(n)));(0,r.useEffect)((()=>{l(function(e){let{pluginIds:t,versionPersistence:n,allDocsData:r}=e;function a(e){const t=d.read(e,n);return r[e].versions.some((e=>e.name===t))?{preferredVersionName:t}:(d.clear(e,n),{preferredVersionName:null})}return Object.fromEntries(t.map((e=>[e,a(e)])))}({allDocsData:e,versionPersistence:t,pluginIds:n}))}),[e,t,n]);return[i,(0,r.useMemo)((()=>({savePreferredVersion:function(e,n){d.save(e,t,n),l((t=>({...t,[e]:{preferredVersionName:n}})))}})),[t])]}function g(e){let{children:t}=e;const n=m();return r.createElement(f.Provider,{value:n},t)}function h(e){let{children:t}=e;return l.C5?r.createElement(g,null,t):r.createElement(r.Fragment,null,t)}function b(){const e=(0,r.useContext)(f);if(!e)throw new s.dV("DocsPreferredVersionContextProvider");return e}function v(e){void 0===e&&(e=i.W);const t=(0,a.ht)(e),[n,o]=b(),{preferredVersionName:l}=n[e];return{preferredVersion:t.versions.find((e=>e.name===l))??null,savePreferredVersionName:(0,r.useCallback)((t=>{o.savePreferredVersion(e,t)}),[o,e])}}},6588:(e,t,n)=>{"use strict";n.d(t,{V:()=>l,t:()=>s});var r=n(6540),a=n(9532);const i=Symbol("EmptyContext"),o=r.createContext(i);function l(e){let{children:t,name:n,items:a}=e;const i=(0,r.useMemo)((()=>n&&a?{name:n,items:a}:null),[n,a]);return r.createElement(o.Provider,{value:i},t)}function s(){const e=(0,r.useContext)(o);if(e===i)throw new a.dV("DocsSidebarProvider");return e}},9876:(e,t,n)=>{"use strict";n.d(t,{e:()=>p,M:()=>f});var r=n(6540),a=n(5600),i=n(4581),o=n(6347),l=n(9532);function s(e){!function(e){const t=(0,o.W6)(),n=(0,l._q)(e);(0,r.useEffect)((()=>t.block(((e,t)=>n(e,t)))),[t,n])}(((t,n)=>{if("POP"===n)return e(t,n)}))}var c=n(6342);const u=r.createContext(void 0);function d(){const e=function(){const e=(0,a.YL)(),{items:t}=(0,c.p)().navbar;return 0===t.length&&!e.component}(),t=(0,i.l)(),n=!e&&"mobile"===t,[o,l]=(0,r.useState)(!1);s((()=>{if(o)return l(!1),!1}));const u=(0,r.useCallback)((()=>{l((e=>!e))}),[]);return(0,r.useEffect)((()=>{"desktop"===t&&l(!1)}),[t]),(0,r.useMemo)((()=>({disabled:e,shouldRender:n,toggle:u,shown:o})),[e,n,u,o])}function p(e){let{children:t}=e;const n=d();return r.createElement(u.Provider,{value:n},t)}function f(){const e=r.useContext(u);if(void 0===e)throw new l.dV("NavbarMobileSidebarProvider");return e}},5600:(e,t,n)=>{"use strict";n.d(t,{GX:()=>s,YL:()=>l,y_:()=>o});var r=n(6540),a=n(9532);const i=r.createContext(null);function o(e){let{children:t}=e;const n=(0,r.useState)({component:null,props:null});return r.createElement(i.Provider,{value:n},t)}function l(){const e=(0,r.useContext)(i);if(!e)throw new a.dV("NavbarSecondaryMenuContentProvider");return e[0]}function s(e){let{component:t,props:n}=e;const o=(0,r.useContext)(i);if(!o)throw new a.dV("NavbarSecondaryMenuContentProvider");const[,l]=o,s=(0,a.Be)(n);return(0,r.useEffect)((()=>{l({component:t,props:s})}),[l,t,s]),(0,r.useEffect)((()=>()=>l({component:null,props:null})),[l]),null}},4090:(e,t,n)=>{"use strict";n.d(t,{w:()=>a,J:()=>i});var r=n(6540);const a="navigation-with-keyboard";function i(){(0,r.useEffect)((()=>{function e(e){"keydown"===e.type&&"Tab"===e.key&&document.body.classList.add(a),"mousedown"===e.type&&document.body.classList.remove(a)}return document.addEventListener("keydown",e),document.addEventListener("mousedown",e),()=>{document.body.classList.remove(a),document.removeEventListener("keydown",e),document.removeEventListener("mousedown",e)}}),[])}},4581:(e,t,n)=>{"use strict";n.d(t,{l:()=>c});var r=n(6540),a=n(8193);const i={desktop:"desktop",mobile:"mobile",ssr:"ssr"},o=996;function l(){return a.A.canUseDOM?window.innerWidth>o?i.desktop:i.mobile:i.ssr}const s=!1;function c(){const[e,t]=(0,r.useState)((()=>s?"ssr":l()));return(0,r.useEffect)((()=>{function e(){t(l())}const n=s?window.setTimeout(e,1e3):void 0;return window.addEventListener("resize",e),()=>{window.removeEventListener("resize",e),clearTimeout(n)}}),[]),e}},7559:(e,t,n)=>{"use strict";n.d(t,{G:()=>r});const r={page:{blogListPage:"blog-list-page",blogPostPage:"blog-post-page",blogTagsListPage:"blog-tags-list-page",blogTagPostListPage:"blog-tags-post-list-page",docsDocPage:"docs-doc-page",docsTagsListPage:"docs-tags-list-page",docsTagDocListPage:"docs-tags-doc-list-page",mdxPage:"mdx-page"},wrapper:{main:"main-wrapper",blogPages:"blog-wrapper",docsPages:"docs-wrapper",mdxPages:"mdx-wrapper"},common:{editThisPage:"theme-edit-this-page",lastUpdated:"theme-last-updated",backToTopButton:"theme-back-to-top-button",codeBlock:"theme-code-block",admonition:"theme-admonition",admonitionType:e=>`theme-admonition-${e}`},layout:{},docs:{docVersionBanner:"theme-doc-version-banner",docVersionBadge:"theme-doc-version-badge",docBreadcrumbs:"theme-doc-breadcrumbs",docMarkdown:"theme-doc-markdown",docTocMobile:"theme-doc-toc-mobile",docTocDesktop:"theme-doc-toc-desktop",docFooter:"theme-doc-footer",docFooterTagsRow:"theme-doc-footer-tags-row",docFooterEditMetaRow:"theme-doc-footer-edit-meta-row",docSidebarContainer:"theme-doc-sidebar-container",docSidebarMenu:"theme-doc-sidebar-menu",docSidebarItemCategory:"theme-doc-sidebar-item-category",docSidebarItemLink:"theme-doc-sidebar-item-link",docSidebarItemCategoryLevel:e=>`theme-doc-sidebar-item-category-level-${e}`,docSidebarItemLinkLevel:e=>`theme-doc-sidebar-item-link-level-${e}`},blog:{}}},1754:(e,t,n)=>{"use strict";n.d(t,{_o:()=>p,w8:()=>g,C5:()=>d,mz:()=>x,Vd:()=>v,QB:()=>w,fW:()=>y,OF:()=>b});var r=n(6540),a=n(6347),i=n(2831),o=n(4070),l=n(5597),s=n(6588);function c(e){return Array.from(new Set(e))}var u=n(9169);const d=!!o.Gy;function p(e){if(e.href)return e.href;for(const t of e.items){if("link"===t.type)return t.href;if("category"===t.type){const e=p(t);if(e)return e}}}const f=(e,t)=>void 0!==e&&(0,u.ys)(e,t),m=(e,t)=>e.some((e=>g(e,t)));function g(e,t){return"link"===e.type?f(e.href,t):"category"===e.type&&(f(e.href,t)||m(e.items,t))}function h(e){let{sidebarItems:t,pathname:n,onlyCategories:r=!1}=e;const a=[];return function e(t){for(const i of t)if("category"===i.type&&((0,u.ys)(i.href,n)||e(i.items))||"link"===i.type&&(0,u.ys)(i.href,n)){return r&&"category"!==i.type||a.unshift(i),!0}return!1}(t),a}function b(){const e=(0,s.t)(),{pathname:t}=(0,a.zy)(),n=(0,o.vT)()?.pluginData.breadcrumbs;return!1!==n&&e?h({sidebarItems:e.items,pathname:t}):null}function v(e){const{activeVersion:t}=(0,o.zK)(e),{preferredVersion:n}=(0,l.g1)(e),a=(0,o.r7)(e);return(0,r.useMemo)((()=>c([t,n,a].filter(Boolean))),[t,n,a])}function y(e,t){const n=v(t);return(0,r.useMemo)((()=>{const t=n.flatMap((e=>e.sidebars?Object.entries(e.sidebars):[])),r=t.find((t=>t[0]===e));if(!r)throw new Error(`Can't find any sidebar with id "${e}" in version${n.length>1?"s":""} ${n.map((e=>e.name)).join(", ")}".\n Available sidebar ids are:\n - ${Object.keys(t).join("\n- ")}`);return r[1]}),[e,n])}function w(e,t){const n=v(t);return(0,r.useMemo)((()=>{const t=n.flatMap((e=>e.docs)),r=t.find((t=>t.id===e));if(!r){if(n.flatMap((e=>e.draftIds)).includes(e))return null;throw new Error(`DocNavbarItem: couldn't find any doc with id "${e}" in version${n.length>1?"s":""} ${n.map((e=>e.name)).join(", ")}".\nAvailable doc ids are:\n- ${c(t.map((e=>e.id))).join("\n- ")}`)}return r}),[e,n])}function x(e){let{route:t,versionMetadata:n}=e;const r=(0,a.zy)(),o=t.routes,l=o.find((e=>(0,a.B6)(r.pathname,e)));if(!l)return null;const s=l.sidebar,c=s?n.docsSidebars[s]:void 0;return{docElement:(0,i.v)(o),sidebarName:s,sidebarItems:c}}},1003:(e,t,n)=>{"use strict";n.d(t,{e3:()=>p,be:()=>u,Jx:()=>f});var r=n(6540),a=n(53),i=n(5260),o=n(3102);function l(){const e=r.useContext(o.o);if(!e)throw new Error("Unexpected: no Docusaurus route context found");return e}var s=n(6025),c=n(4586);function u(e){let{title:t,description:n,keywords:a,image:o,children:l}=e;const u=function(e){const{siteConfig:t}=(0,c.A)(),{title:n,titleDelimiter:r}=t;return e?.trim().length?`${e.trim()} ${r} ${n}`:n}(t),{withBaseUrl:d}=(0,s.h)(),p=o?d(o,{absolute:!0}):void 0;return r.createElement(i.A,null,t&&r.createElement("title",null,u),t&&r.createElement("meta",{property:"og:title",content:u}),n&&r.createElement("meta",{name:"description",content:n}),n&&r.createElement("meta",{property:"og:description",content:n}),a&&r.createElement("meta",{name:"keywords",content:Array.isArray(a)?a.join(","):a}),p&&r.createElement("meta",{property:"og:image",content:p}),p&&r.createElement("meta",{name:"twitter:image",content:p}),l)}const d=r.createContext(void 0);function p(e){let{className:t,children:n}=e;const o=r.useContext(d),l=(0,a.A)(o,t);return r.createElement(d.Provider,{value:l},r.createElement(i.A,null,r.createElement("html",{className:l})),n)}function f(e){let{children:t}=e;const n=l(),i=`plugin-${n.plugin.name.replace(/docusaurus-(?:plugin|theme)-(?:content-)?/gi,"")}`;const o=`plugin-id-${n.plugin.id}`;return r.createElement(p,{className:(0,a.A)(i,o)},t)}},9532:(e,t,n)=>{"use strict";n.d(t,{Be:()=>s,ZC:()=>o,_q:()=>i,dV:()=>l,fM:()=>c});var r=n(6540);const a=n(8193).A.canUseDOM?r.useLayoutEffect:r.useEffect;function i(e){const t=(0,r.useRef)(e);return a((()=>{t.current=e}),[e]),(0,r.useCallback)((function(){return t.current(...arguments)}),[])}function o(e){const t=(0,r.useRef)();return a((()=>{t.current=e})),t.current}class l extends Error{constructor(e,t){super(),this.name="ReactContextError",this.message=`Hook ${this.stack?.split("\n")[1]?.match(/at (?:\w+\.)?(?<name>\w+)/)?.groups.name??""} is called outside the <${e}>. ${t??""}`}}function s(e){const t=Object.entries(e);return t.sort(((e,t)=>e[0].localeCompare(t[0]))),(0,r.useMemo)((()=>e),t.flat())}function c(e){return t=>{let{children:n}=t;return r.createElement(r.Fragment,null,e.reduceRight(((e,t)=>r.createElement(t,null,e)),n))}}},9169:(e,t,n)=>{"use strict";n.d(t,{Dt:()=>l,ys:()=>o});var r=n(6540),a=n(8328),i=n(4586);function o(e,t){const n=e=>(!e||e.endsWith("/")?e:`${e}/`)?.toLowerCase();return n(e)===n(t)}function l(){const{baseUrl:e}=(0,i.A)().siteConfig;return(0,r.useMemo)((()=>function(e){let{baseUrl:t,routes:n}=e;function r(e){return e.path===t&&!0===e.exact}function a(e){return e.path===t&&!e.exact}return function e(t){if(0===t.length)return;return t.find(r)||e(t.filter(a).flatMap((e=>e.routes??[])))}(n)}({routes:a.A,baseUrl:e})),[e])}},3104:(e,t,n)=>{"use strict";n.d(t,{Mq:()=>d,Tv:()=>s,gk:()=>p});var r=n(6540),a=n(8193),i=n(2303),o=n(9532);const l=r.createContext(void 0);function s(e){let{children:t}=e;const n=function(){const e=(0,r.useRef)(!0);return(0,r.useMemo)((()=>({scrollEventsEnabledRef:e,enableScrollEvents:()=>{e.current=!0},disableScrollEvents:()=>{e.current=!1}})),[])}();return r.createElement(l.Provider,{value:n},t)}function c(){const e=(0,r.useContext)(l);if(null==e)throw new o.dV("ScrollControllerProvider");return e}const u=()=>a.A.canUseDOM?{scrollX:window.pageXOffset,scrollY:window.pageYOffset}:null;function d(e,t){void 0===t&&(t=[]);const{scrollEventsEnabledRef:n}=c(),a=(0,r.useRef)(u()),i=(0,o._q)(e);(0,r.useEffect)((()=>{const e=()=>{if(!n.current)return;const e=u();i(e,a.current),a.current=e},t={passive:!0};return e(),window.addEventListener("scroll",e,t),()=>window.removeEventListener("scroll",e,t)}),[i,n,...t])}function p(){const e=(0,r.useRef)(null),t=(0,i.A)()&&"smooth"===getComputedStyle(document.documentElement).scrollBehavior;return{startScroll:n=>{e.current=t?function(e){return window.scrollTo({top:e,behavior:"smooth"}),()=>{}}(n):function(e){let t=null;const n=document.documentElement.scrollTop>e;return function r(){const a=document.documentElement.scrollTop;(n&&a>e||!n&&a<e)&&(t=requestAnimationFrame(r),window.scrollTo(0,Math.floor(.85*(a-e))+e))}(),()=>t&&cancelAnimationFrame(t)}(n)},cancelScroll:()=>e.current?.()}}},2967:(e,t,n)=>{"use strict";n.d(t,{Cy:()=>r,tU:()=>a});n(4586);const r="default";function a(e,t){return`docs-${e}-${t}`}},9466:(e,t,n)=>{"use strict";n.d(t,{E:()=>s,W:()=>l});const r="localStorage";function a(e){if(void 0===e&&(e=r),"undefined"==typeof window)throw new Error("Browser storage is not available on Node.js/Docusaurus SSR process.");if("none"===e)return null;try{return window[e]}catch(n){return t=n,i||(console.warn("Docusaurus browser storage is not available.\nPossible reasons: running Docusaurus in an iframe, in an incognito browser session, or using too strict browser privacy settings.",t),i=!0),null}var t}let i=!1;const o={get:()=>null,set:()=>{},del:()=>{}};function l(e,t){if("undefined"==typeof window)return function(e){function t(){throw new Error(`Illegal storage API usage for storage key "${e}".\nDocusaurus storage APIs are not supposed to be called on the server-rendering process.\nPlease only call storage APIs in effects and event handlers.`)}return{get:t,set:t,del:t}}(e);const n=a(t?.persistence);return null===n?o:{get:()=>{try{return n.getItem(e)}catch(t){return console.error(`Docusaurus storage error, can't get key=${e}`,t),null}},set:t=>{try{n.setItem(e,t)}catch(r){console.error(`Docusaurus storage error, can't set ${e}=${t}`,r)}},del:()=>{try{n.removeItem(e)}catch(t){console.error(`Docusaurus storage error, can't delete key=${e}`,t)}}}}function s(e){void 0===e&&(e=r);const t=a(e);if(!t)return[];const n=[];for(let r=0;r<t.length;r+=1){const e=t.key(r);null!==e&&n.push(e)}return n}},2131:(e,t,n)=>{"use strict";n.d(t,{o:()=>i});var r=n(4586),a=n(6347);function i(){const{siteConfig:{baseUrl:e,url:t},i18n:{defaultLocale:n,currentLocale:i}}=(0,r.A)(),{pathname:o}=(0,a.zy)(),l=i===n?e:e.replace(`/${i}/`,"/"),s=o.replace(e,"");return{createUrl:function(e){let{locale:r,fullyQualified:a}=e;return`${a?t:""}${function(e){return e===n?`${l}`:`${l}${e}/`}(r)}${s}`}}}},5062:(e,t,n)=>{"use strict";n.d(t,{$:()=>o});var r=n(6540),a=n(6347),i=n(9532);function o(e){const t=(0,a.zy)(),n=(0,i.ZC)(t),o=(0,i._q)(e);(0,r.useEffect)((()=>{n&&t!==n&&o({location:t,previousLocation:n})}),[o,t,n])}},6342:(e,t,n)=>{"use strict";n.d(t,{p:()=>a});var r=n(4586);function a(){return(0,r.A)().siteConfig.themeConfig}},2983:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e,t){const{trailingSlash:n,baseUrl:r}=t;if(e.startsWith("#"))return e;if(void 0===n)return e;const[a]=e.split(/[#?]/),i="/"===a||a===r?a:(o=a,n?function(e){return e.endsWith("/")?e:`${e}/`}(o):function(e){return e.endsWith("/")?e.slice(0,-1):e}(o));var o;return e.replace(a,i)}},440:function(e,t,n){"use strict";var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.applyTrailingSlash=t.blogPostContainerID=void 0,t.blogPostContainerID="post-content";var a=n(2983);Object.defineProperty(t,"applyTrailingSlash",{enumerable:!0,get:function(){return r(a).default}})},53:(e,t,n)=>{"use strict";function r(e){var t,n,a="";if("string"==typeof e||"number"==typeof e)a+=e;else if("object"==typeof e)if(Array.isArray(e))for(t=0;t<e.length;t++)e[t]&&(n=r(e[t]))&&(a&&(a+=" "),a+=n);else for(t in e)e[t]&&(a&&(a+=" "),a+=t);return a}n.d(t,{A:()=>a});const a=function(){for(var e,t,n=0,a="";n<arguments.length;)(e=arguments[n++])&&(t=r(e))&&(a&&(a+=" "),a+=t);return a}},1513:(e,t,n)=>{"use strict";n.d(t,{zR:()=>w,TM:()=>_,yJ:()=>f,sC:()=>C,AO:()=>p});var r=n(8168);function a(e){return"/"===e.charAt(0)}function i(e,t){for(var n=t,r=n+1,a=e.length;r<a;n+=1,r+=1)e[n]=e[r];e.pop()}const o=function(e,t){void 0===t&&(t="");var n,r=e&&e.split("/")||[],o=t&&t.split("/")||[],l=e&&a(e),s=t&&a(t),c=l||s;if(e&&a(e)?o=r:r.length&&(o.pop(),o=o.concat(r)),!o.length)return"/";if(o.length){var u=o[o.length-1];n="."===u||".."===u||""===u}else n=!1;for(var d=0,p=o.length;p>=0;p--){var f=o[p];"."===f?i(o,p):".."===f?(i(o,p),d++):d&&(i(o,p),d--)}if(!c)for(;d--;d)o.unshift("..");!c||""===o[0]||o[0]&&a(o[0])||o.unshift("");var m=o.join("/");return n&&"/"!==m.substr(-1)&&(m+="/"),m};var l=n(1561);function s(e){return"/"===e.charAt(0)?e:"/"+e}function c(e){return"/"===e.charAt(0)?e.substr(1):e}function u(e,t){return function(e,t){return 0===e.toLowerCase().indexOf(t.toLowerCase())&&-1!=="/?#".indexOf(e.charAt(t.length))}(e,t)?e.substr(t.length):e}function d(e){return"/"===e.charAt(e.length-1)?e.slice(0,-1):e}function p(e){var t=e.pathname,n=e.search,r=e.hash,a=t||"/";return n&&"?"!==n&&(a+="?"===n.charAt(0)?n:"?"+n),r&&"#"!==r&&(a+="#"===r.charAt(0)?r:"#"+r),a}function f(e,t,n,a){var i;"string"==typeof e?(i=function(e){var t=e||"/",n="",r="",a=t.indexOf("#");-1!==a&&(r=t.substr(a),t=t.substr(0,a));var i=t.indexOf("?");return-1!==i&&(n=t.substr(i),t=t.substr(0,i)),{pathname:t,search:"?"===n?"":n,hash:"#"===r?"":r}}(e),i.state=t):(void 0===(i=(0,r.A)({},e)).pathname&&(i.pathname=""),i.search?"?"!==i.search.charAt(0)&&(i.search="?"+i.search):i.search="",i.hash?"#"!==i.hash.charAt(0)&&(i.hash="#"+i.hash):i.hash="",void 0!==t&&void 0===i.state&&(i.state=t));try{i.pathname=decodeURI(i.pathname)}catch(l){throw l instanceof URIError?new URIError('Pathname "'+i.pathname+'" could not be decoded. This is likely caused by an invalid percent-encoding.'):l}return n&&(i.key=n),a?i.pathname?"/"!==i.pathname.charAt(0)&&(i.pathname=o(i.pathname,a.pathname)):i.pathname=a.pathname:i.pathname||(i.pathname="/"),i}function m(){var e=null;var t=[];return{setPrompt:function(t){return e=t,function(){e===t&&(e=null)}},confirmTransitionTo:function(t,n,r,a){if(null!=e){var i="function"==typeof e?e(t,n):e;"string"==typeof i?"function"==typeof r?r(i,a):a(!0):a(!1!==i)}else a(!0)},appendListener:function(e){var n=!0;function r(){n&&e.apply(void 0,arguments)}return t.push(r),function(){n=!1,t=t.filter((function(e){return e!==r}))}},notifyListeners:function(){for(var e=arguments.length,n=new Array(e),r=0;r<e;r++)n[r]=arguments[r];t.forEach((function(e){return e.apply(void 0,n)}))}}}var g=!("undefined"==typeof window||!window.document||!window.document.createElement);function h(e,t){t(window.confirm(e))}var b="popstate",v="hashchange";function y(){try{return window.history.state||{}}catch(e){return{}}}function w(e){void 0===e&&(e={}),g||(0,l.A)(!1);var t,n=window.history,a=(-1===(t=window.navigator.userAgent).indexOf("Android 2.")&&-1===t.indexOf("Android 4.0")||-1===t.indexOf("Mobile Safari")||-1!==t.indexOf("Chrome")||-1!==t.indexOf("Windows Phone"))&&window.history&&"pushState"in window.history,i=!(-1===window.navigator.userAgent.indexOf("Trident")),o=e,c=o.forceRefresh,w=void 0!==c&&c,x=o.getUserConfirmation,k=void 0===x?h:x,E=o.keyLength,S=void 0===E?6:E,T=e.basename?d(s(e.basename)):"";function _(e){var t=e||{},n=t.key,r=t.state,a=window.location,i=a.pathname+a.search+a.hash;return T&&(i=u(i,T)),f(i,r,n)}function A(){return Math.random().toString(36).substr(2,S)}var C=m();function P(e){(0,r.A)(U,e),U.length=n.length,C.notifyListeners(U.location,U.action)}function N(e){(function(e){return void 0===e.state&&-1===navigator.userAgent.indexOf("CriOS")})(e)||R(_(e.state))}function O(){R(_(y()))}var I=!1;function R(e){if(I)I=!1,P();else{C.confirmTransitionTo(e,"POP",k,(function(t){t?P({action:"POP",location:e}):function(e){var t=U.location,n=L.indexOf(t.key);-1===n&&(n=0);var r=L.indexOf(e.key);-1===r&&(r=0);var a=n-r;a&&(I=!0,F(a))}(e)}))}}var D=_(y()),L=[D.key];function M(e){return T+p(e)}function F(e){n.go(e)}var B=0;function $(e){1===(B+=e)&&1===e?(window.addEventListener(b,N),i&&window.addEventListener(v,O)):0===B&&(window.removeEventListener(b,N),i&&window.removeEventListener(v,O))}var z=!1;var U={length:n.length,action:"POP",location:D,createHref:M,push:function(e,t){var r="PUSH",i=f(e,t,A(),U.location);C.confirmTransitionTo(i,r,k,(function(e){if(e){var t=M(i),o=i.key,l=i.state;if(a)if(n.pushState({key:o,state:l},null,t),w)window.location.href=t;else{var s=L.indexOf(U.location.key),c=L.slice(0,s+1);c.push(i.key),L=c,P({action:r,location:i})}else window.location.href=t}}))},replace:function(e,t){var r="REPLACE",i=f(e,t,A(),U.location);C.confirmTransitionTo(i,r,k,(function(e){if(e){var t=M(i),o=i.key,l=i.state;if(a)if(n.replaceState({key:o,state:l},null,t),w)window.location.replace(t);else{var s=L.indexOf(U.location.key);-1!==s&&(L[s]=i.key),P({action:r,location:i})}else window.location.replace(t)}}))},go:F,goBack:function(){F(-1)},goForward:function(){F(1)},block:function(e){void 0===e&&(e=!1);var t=C.setPrompt(e);return z||($(1),z=!0),function(){return z&&(z=!1,$(-1)),t()}},listen:function(e){var t=C.appendListener(e);return $(1),function(){$(-1),t()}}};return U}var x="hashchange",k={hashbang:{encodePath:function(e){return"!"===e.charAt(0)?e:"!/"+c(e)},decodePath:function(e){return"!"===e.charAt(0)?e.substr(1):e}},noslash:{encodePath:c,decodePath:s},slash:{encodePath:s,decodePath:s}};function E(e){var t=e.indexOf("#");return-1===t?e:e.slice(0,t)}function S(){var e=window.location.href,t=e.indexOf("#");return-1===t?"":e.substring(t+1)}function T(e){window.location.replace(E(window.location.href)+"#"+e)}function _(e){void 0===e&&(e={}),g||(0,l.A)(!1);var t=window.history,n=(window.navigator.userAgent.indexOf("Firefox"),e),a=n.getUserConfirmation,i=void 0===a?h:a,o=n.hashType,c=void 0===o?"slash":o,b=e.basename?d(s(e.basename)):"",v=k[c],y=v.encodePath,w=v.decodePath;function _(){var e=w(S());return b&&(e=u(e,b)),f(e)}var A=m();function C(e){(0,r.A)(z,e),z.length=t.length,A.notifyListeners(z.location,z.action)}var P=!1,N=null;function O(){var e,t,n=S(),r=y(n);if(n!==r)T(r);else{var a=_(),o=z.location;if(!P&&(t=a,(e=o).pathname===t.pathname&&e.search===t.search&&e.hash===t.hash))return;if(N===p(a))return;N=null,function(e){if(P)P=!1,C();else{var t="POP";A.confirmTransitionTo(e,t,i,(function(n){n?C({action:t,location:e}):function(e){var t=z.location,n=L.lastIndexOf(p(t));-1===n&&(n=0);var r=L.lastIndexOf(p(e));-1===r&&(r=0);var a=n-r;a&&(P=!0,M(a))}(e)}))}}(a)}}var I=S(),R=y(I);I!==R&&T(R);var D=_(),L=[p(D)];function M(e){t.go(e)}var F=0;function B(e){1===(F+=e)&&1===e?window.addEventListener(x,O):0===F&&window.removeEventListener(x,O)}var $=!1;var z={length:t.length,action:"POP",location:D,createHref:function(e){var t=document.querySelector("base"),n="";return t&&t.getAttribute("href")&&(n=E(window.location.href)),n+"#"+y(b+p(e))},push:function(e,t){var n="PUSH",r=f(e,void 0,void 0,z.location);A.confirmTransitionTo(r,n,i,(function(e){if(e){var t=p(r),a=y(b+t);if(S()!==a){N=t,function(e){window.location.hash=e}(a);var i=L.lastIndexOf(p(z.location)),o=L.slice(0,i+1);o.push(t),L=o,C({action:n,location:r})}else C()}}))},replace:function(e,t){var n="REPLACE",r=f(e,void 0,void 0,z.location);A.confirmTransitionTo(r,n,i,(function(e){if(e){var t=p(r),a=y(b+t);S()!==a&&(N=t,T(a));var i=L.indexOf(p(z.location));-1!==i&&(L[i]=t),C({action:n,location:r})}}))},go:M,goBack:function(){M(-1)},goForward:function(){M(1)},block:function(e){void 0===e&&(e=!1);var t=A.setPrompt(e);return $||(B(1),$=!0),function(){return $&&($=!1,B(-1)),t()}},listen:function(e){var t=A.appendListener(e);return B(1),function(){B(-1),t()}}};return z}function A(e,t,n){return Math.min(Math.max(e,t),n)}function C(e){void 0===e&&(e={});var t=e,n=t.getUserConfirmation,a=t.initialEntries,i=void 0===a?["/"]:a,o=t.initialIndex,l=void 0===o?0:o,s=t.keyLength,c=void 0===s?6:s,u=m();function d(e){(0,r.A)(w,e),w.length=w.entries.length,u.notifyListeners(w.location,w.action)}function g(){return Math.random().toString(36).substr(2,c)}var h=A(l,0,i.length-1),b=i.map((function(e){return f(e,void 0,"string"==typeof e?g():e.key||g())})),v=p;function y(e){var t=A(w.index+e,0,w.entries.length-1),r=w.entries[t];u.confirmTransitionTo(r,"POP",n,(function(e){e?d({action:"POP",location:r,index:t}):d()}))}var w={length:b.length,action:"POP",location:b[h],index:h,entries:b,createHref:v,push:function(e,t){var r="PUSH",a=f(e,t,g(),w.location);u.confirmTransitionTo(a,r,n,(function(e){if(e){var t=w.index+1,n=w.entries.slice(0);n.length>t?n.splice(t,n.length-t,a):n.push(a),d({action:r,location:a,index:t,entries:n})}}))},replace:function(e,t){var r="REPLACE",a=f(e,t,g(),w.location);u.confirmTransitionTo(a,r,n,(function(e){e&&(w.entries[w.index]=a,d({action:r,location:a}))}))},go:y,goBack:function(){y(-1)},goForward:function(){y(1)},canGo:function(e){var t=w.index+e;return t>=0&&t<w.entries.length},block:function(e){return void 0===e&&(e=!1),u.setPrompt(e)},listen:function(e){return u.appendListener(e)}};return w}},4146:(e,t,n)=>{"use strict";var r=n(4363),a={childContextTypes:!0,contextType:!0,contextTypes:!0,defaultProps:!0,displayName:!0,getDefaultProps:!0,getDerivedStateFromError:!0,getDerivedStateFromProps:!0,mixins:!0,propTypes:!0,type:!0},i={name:!0,length:!0,prototype:!0,caller:!0,callee:!0,arguments:!0,arity:!0},o={$$typeof:!0,compare:!0,defaultProps:!0,displayName:!0,propTypes:!0,type:!0},l={};function s(e){return r.isMemo(e)?o:l[e.$$typeof]||a}l[r.ForwardRef]={$$typeof:!0,render:!0,defaultProps:!0,displayName:!0,propTypes:!0},l[r.Memo]=o;var c=Object.defineProperty,u=Object.getOwnPropertyNames,d=Object.getOwnPropertySymbols,p=Object.getOwnPropertyDescriptor,f=Object.getPrototypeOf,m=Object.prototype;e.exports=function e(t,n,r){if("string"!=typeof n){if(m){var a=f(n);a&&a!==m&&e(t,a,r)}var o=u(n);d&&(o=o.concat(d(n)));for(var l=s(t),g=s(n),h=0;h<o.length;++h){var b=o[h];if(!(i[b]||r&&r[b]||g&&g[b]||l&&l[b])){var v=p(n,b);try{c(t,b,v)}catch(y){}}}}return t}},311:e=>{"use strict";e.exports=function(e,t,n,r,a,i,o,l){if(!e){var s;if(void 0===t)s=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var c=[n,r,a,i,o,l],u=0;(s=new Error(t.replace(/%s/g,(function(){return c[u++]})))).name="Invariant Violation"}throw s.framesToPop=1,s}}},4634:e=>{e.exports=Array.isArray||function(e){return"[object Array]"==Object.prototype.toString.call(e)}},119:(e,t,n)=>{"use strict";n.r(t)},1043:(e,t,n)=>{"use strict";n.r(t)},5947:function(e,t,n){var r,a;r=function(){var e,t,n={version:"0.2.0"},r=n.settings={minimum:.08,easing:"ease",positionUsing:"",speed:200,trickle:!0,trickleRate:.02,trickleSpeed:800,showSpinner:!0,barSelector:'[role="bar"]',spinnerSelector:'[role="spinner"]',parent:"body",template:'<div class="bar" role="bar"><div class="peg"></div></div><div class="spinner" role="spinner"><div class="spinner-icon"></div></div>'};function a(e,t,n){return e<t?t:e>n?n:e}function i(e){return 100*(-1+e)}function o(e,t,n){var a;return(a="translate3d"===r.positionUsing?{transform:"translate3d("+i(e)+"%,0,0)"}:"translate"===r.positionUsing?{transform:"translate("+i(e)+"%,0)"}:{"margin-left":i(e)+"%"}).transition="all "+t+"ms "+n,a}n.configure=function(e){var t,n;for(t in e)void 0!==(n=e[t])&&e.hasOwnProperty(t)&&(r[t]=n);return this},n.status=null,n.set=function(e){var t=n.isStarted();e=a(e,r.minimum,1),n.status=1===e?null:e;var i=n.render(!t),c=i.querySelector(r.barSelector),u=r.speed,d=r.easing;return i.offsetWidth,l((function(t){""===r.positionUsing&&(r.positionUsing=n.getPositioningCSS()),s(c,o(e,u,d)),1===e?(s(i,{transition:"none",opacity:1}),i.offsetWidth,setTimeout((function(){s(i,{transition:"all "+u+"ms linear",opacity:0}),setTimeout((function(){n.remove(),t()}),u)}),u)):setTimeout(t,u)})),this},n.isStarted=function(){return"number"==typeof n.status},n.start=function(){n.status||n.set(0);var e=function(){setTimeout((function(){n.status&&(n.trickle(),e())}),r.trickleSpeed)};return r.trickle&&e(),this},n.done=function(e){return e||n.status?n.inc(.3+.5*Math.random()).set(1):this},n.inc=function(e){var t=n.status;return t?("number"!=typeof e&&(e=(1-t)*a(Math.random()*t,.1,.95)),t=a(t+e,0,.994),n.set(t)):n.start()},n.trickle=function(){return n.inc(Math.random()*r.trickleRate)},e=0,t=0,n.promise=function(r){return r&&"resolved"!==r.state()?(0===t&&n.start(),e++,t++,r.always((function(){0==--t?(e=0,n.done()):n.set((e-t)/e)})),this):this},n.render=function(e){if(n.isRendered())return document.getElementById("nprogress");u(document.documentElement,"nprogress-busy");var t=document.createElement("div");t.id="nprogress",t.innerHTML=r.template;var a,o=t.querySelector(r.barSelector),l=e?"-100":i(n.status||0),c=document.querySelector(r.parent);return s(o,{transition:"all 0 linear",transform:"translate3d("+l+"%,0,0)"}),r.showSpinner||(a=t.querySelector(r.spinnerSelector))&&f(a),c!=document.body&&u(c,"nprogress-custom-parent"),c.appendChild(t),t},n.remove=function(){d(document.documentElement,"nprogress-busy"),d(document.querySelector(r.parent),"nprogress-custom-parent");var e=document.getElementById("nprogress");e&&f(e)},n.isRendered=function(){return!!document.getElementById("nprogress")},n.getPositioningCSS=function(){var e=document.body.style,t="WebkitTransform"in e?"Webkit":"MozTransform"in e?"Moz":"msTransform"in e?"ms":"OTransform"in e?"O":"";return t+"Perspective"in e?"translate3d":t+"Transform"in e?"translate":"margin"};var l=function(){var e=[];function t(){var n=e.shift();n&&n(t)}return function(n){e.push(n),1==e.length&&t()}}(),s=function(){var e=["Webkit","O","Moz","ms"],t={};function n(e){return e.replace(/^-ms-/,"ms-").replace(/-([\da-z])/gi,(function(e,t){return t.toUpperCase()}))}function r(t){var n=document.body.style;if(t in n)return t;for(var r,a=e.length,i=t.charAt(0).toUpperCase()+t.slice(1);a--;)if((r=e[a]+i)in n)return r;return t}function a(e){return e=n(e),t[e]||(t[e]=r(e))}function i(e,t,n){t=a(t),e.style[t]=n}return function(e,t){var n,r,a=arguments;if(2==a.length)for(n in t)void 0!==(r=t[n])&&t.hasOwnProperty(n)&&i(e,n,r);else i(e,a[1],a[2])}}();function c(e,t){return("string"==typeof e?e:p(e)).indexOf(" "+t+" ")>=0}function u(e,t){var n=p(e),r=n+t;c(n,t)||(e.className=r.substring(1))}function d(e,t){var n,r=p(e);c(e,t)&&(n=r.replace(" "+t+" "," "),e.className=n.substring(1,n.length-1))}function p(e){return(" "+(e.className||"")+" ").replace(/\s+/gi," ")}function f(e){e&&e.parentNode&&e.parentNode.removeChild(e)}return n},void 0===(a="function"==typeof r?r.call(t,n,t,e):r)||(e.exports=a)},5228:e=>{"use strict";var t=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,r=Object.prototype.propertyIsEnumerable;e.exports=function(){try{if(!Object.assign)return!1;var e=new String("abc");if(e[5]="de","5"===Object.getOwnPropertyNames(e)[0])return!1;for(var t={},n=0;n<10;n++)t["_"+String.fromCharCode(n)]=n;if("0123456789"!==Object.getOwnPropertyNames(t).map((function(e){return t[e]})).join(""))return!1;var r={};return"abcdefghijklmnopqrst".split("").forEach((function(e){r[e]=e})),"abcdefghijklmnopqrst"===Object.keys(Object.assign({},r)).join("")}catch(a){return!1}}()?Object.assign:function(e,a){for(var i,o,l=function(e){if(null==e)throw new TypeError("Object.assign cannot be called with null or undefined");return Object(e)}(e),s=1;s<arguments.length;s++){for(var c in i=Object(arguments[s]))n.call(i,c)&&(l[c]=i[c]);if(t){o=t(i);for(var u=0;u<o.length;u++)r.call(i,o[u])&&(l[o[u]]=i[o[u]])}}return l}},5302:(e,t,n)=>{var r=n(4634);e.exports=f,e.exports.parse=i,e.exports.compile=function(e,t){return l(i(e,t),t)},e.exports.tokensToFunction=l,e.exports.tokensToRegExp=p;var a=new RegExp(["(\\\\.)","([\\/.])?(?:(?:\\:(\\w+)(?:\\(((?:\\\\.|[^\\\\()])+)\\))?|\\(((?:\\\\.|[^\\\\()])+)\\))([+*?])?|(\\*))"].join("|"),"g");function i(e,t){for(var n,r=[],i=0,o=0,l="",u=t&&t.delimiter||"/";null!=(n=a.exec(e));){var d=n[0],p=n[1],f=n.index;if(l+=e.slice(o,f),o=f+d.length,p)l+=p[1];else{var m=e[o],g=n[2],h=n[3],b=n[4],v=n[5],y=n[6],w=n[7];l&&(r.push(l),l="");var x=null!=g&&null!=m&&m!==g,k="+"===y||"*"===y,E="?"===y||"*"===y,S=n[2]||u,T=b||v;r.push({name:h||i++,prefix:g||"",delimiter:S,optional:E,repeat:k,partial:x,asterisk:!!w,pattern:T?c(T):w?".*":"[^"+s(S)+"]+?"})}}return o<e.length&&(l+=e.substr(o)),l&&r.push(l),r}function o(e){return encodeURI(e).replace(/[\/?#]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}function l(e,t){for(var n=new Array(e.length),a=0;a<e.length;a++)"object"==typeof e[a]&&(n[a]=new RegExp("^(?:"+e[a].pattern+")$",d(t)));return function(t,a){for(var i="",l=t||{},s=(a||{}).pretty?o:encodeURIComponent,c=0;c<e.length;c++){var u=e[c];if("string"!=typeof u){var d,p=l[u.name];if(null==p){if(u.optional){u.partial&&(i+=u.prefix);continue}throw new TypeError('Expected "'+u.name+'" to be defined')}if(r(p)){if(!u.repeat)throw new TypeError('Expected "'+u.name+'" to not repeat, but received `'+JSON.stringify(p)+"`");if(0===p.length){if(u.optional)continue;throw new TypeError('Expected "'+u.name+'" to not be empty')}for(var f=0;f<p.length;f++){if(d=s(p[f]),!n[c].test(d))throw new TypeError('Expected all "'+u.name+'" to match "'+u.pattern+'", but received `'+JSON.stringify(d)+"`");i+=(0===f?u.prefix:u.delimiter)+d}}else{if(d=u.asterisk?encodeURI(p).replace(/[?#]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()})):s(p),!n[c].test(d))throw new TypeError('Expected "'+u.name+'" to match "'+u.pattern+'", but received "'+d+'"');i+=u.prefix+d}}else i+=u}return i}}function s(e){return e.replace(/([.+*?=^!:${}()[\]|\/\\])/g,"\\$1")}function c(e){return e.replace(/([=!:$\/()])/g,"\\$1")}function u(e,t){return e.keys=t,e}function d(e){return e&&e.sensitive?"":"i"}function p(e,t,n){r(t)||(n=t||n,t=[]);for(var a=(n=n||{}).strict,i=!1!==n.end,o="",l=0;l<e.length;l++){var c=e[l];if("string"==typeof c)o+=s(c);else{var p=s(c.prefix),f="(?:"+c.pattern+")";t.push(c),c.repeat&&(f+="(?:"+p+f+")*"),o+=f=c.optional?c.partial?p+"("+f+")?":"(?:"+p+"("+f+"))?":p+"("+f+")"}}var m=s(n.delimiter||"/"),g=o.slice(-m.length)===m;return a||(o=(g?o.slice(0,-m.length):o)+"(?:"+m+"(?=$))?"),o+=i?"$":a&&g?"":"(?="+m+"|$)",u(new RegExp("^"+o,d(n)),t)}function f(e,t,n){return r(t)||(n=t||n,t=[]),n=n||{},e instanceof RegExp?function(e,t){var n=e.source.match(/\((?!\?)/g);if(n)for(var r=0;r<n.length;r++)t.push({name:r,prefix:null,delimiter:null,optional:!1,repeat:!1,partial:!1,asterisk:!1,pattern:null});return u(e,t)}(e,t):r(e)?function(e,t,n){for(var r=[],a=0;a<e.length;a++)r.push(f(e[a],t,n).source);return u(new RegExp("(?:"+r.join("|")+")",d(n)),t)}(e,t,n):function(e,t,n){return p(i(e,n),t,n)}(e,t,n)}},1258:(e,t,n)=>{"use strict";n.d(t,{A:()=>i});var r=function(){var e=/(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i,t=0,n={},r={util:{encode:function e(t){return t instanceof a?new a(t.type,e(t.content),t.alias):Array.isArray(t)?t.map(e):t.replace(/&/g,"&").replace(/</g,"<").replace(/\u00a0/g," ")},type:function(e){return Object.prototype.toString.call(e).slice(8,-1)},objId:function(e){return e.__id||Object.defineProperty(e,"__id",{value:++t}),e.__id},clone:function e(t,n){var a,i;switch(n=n||{},r.util.type(t)){case"Object":if(i=r.util.objId(t),n[i])return n[i];for(var o in a={},n[i]=a,t)t.hasOwnProperty(o)&&(a[o]=e(t[o],n));return a;case"Array":return i=r.util.objId(t),n[i]?n[i]:(a=[],n[i]=a,t.forEach((function(t,r){a[r]=e(t,n)})),a);default:return t}},getLanguage:function(t){for(;t;){var n=e.exec(t.className);if(n)return n[1].toLowerCase();t=t.parentElement}return"none"},setLanguage:function(t,n){t.className=t.className.replace(RegExp(e,"gi"),""),t.classList.add("language-"+n)},isActive:function(e,t,n){for(var r="no-"+t;e;){var a=e.classList;if(a.contains(t))return!0;if(a.contains(r))return!1;e=e.parentElement}return!!n}},languages:{plain:n,plaintext:n,text:n,txt:n,extend:function(e,t){var n=r.util.clone(r.languages[e]);for(var a in t)n[a]=t[a];return n},insertBefore:function(e,t,n,a){var i=(a=a||r.languages)[e],o={};for(var l in i)if(i.hasOwnProperty(l)){if(l==t)for(var s in n)n.hasOwnProperty(s)&&(o[s]=n[s]);n.hasOwnProperty(l)||(o[l]=i[l])}var c=a[e];return a[e]=o,r.languages.DFS(r.languages,(function(t,n){n===c&&t!=e&&(this[t]=o)})),o},DFS:function e(t,n,a,i){i=i||{};var o=r.util.objId;for(var l in t)if(t.hasOwnProperty(l)){n.call(t,l,t[l],a||l);var s=t[l],c=r.util.type(s);"Object"!==c||i[o(s)]?"Array"!==c||i[o(s)]||(i[o(s)]=!0,e(s,n,l,i)):(i[o(s)]=!0,e(s,n,null,i))}}},plugins:{},highlight:function(e,t,n){var i={code:e,grammar:t,language:n};return r.hooks.run("before-tokenize",i),i.tokens=r.tokenize(i.code,i.grammar),r.hooks.run("after-tokenize",i),a.stringify(r.util.encode(i.tokens),i.language)},tokenize:function(e,t){var n=t.rest;if(n){for(var r in n)t[r]=n[r];delete t.rest}var a=new l;return s(a,a.head,e),o(e,a,t,a.head,0),function(e){var t=[],n=e.head.next;for(;n!==e.tail;)t.push(n.value),n=n.next;return t}(a)},hooks:{all:{},add:function(e,t){var n=r.hooks.all;n[e]=n[e]||[],n[e].push(t)},run:function(e,t){var n=r.hooks.all[e];if(n&&n.length)for(var a,i=0;a=n[i++];)a(t)}},Token:a};function a(e,t,n,r){this.type=e,this.content=t,this.alias=n,this.length=0|(r||"").length}function i(e,t,n,r){e.lastIndex=t;var a=e.exec(n);if(a&&r&&a[1]){var i=a[1].length;a.index+=i,a[0]=a[0].slice(i)}return a}function o(e,t,n,l,u,d){for(var p in n)if(n.hasOwnProperty(p)&&n[p]){var f=n[p];f=Array.isArray(f)?f:[f];for(var m=0;m<f.length;++m){if(d&&d.cause==p+","+m)return;var g=f[m],h=g.inside,b=!!g.lookbehind,v=!!g.greedy,y=g.alias;if(v&&!g.pattern.global){var w=g.pattern.toString().match(/[imsuy]*$/)[0];g.pattern=RegExp(g.pattern.source,w+"g")}for(var x=g.pattern||g,k=l.next,E=u;k!==t.tail&&!(d&&E>=d.reach);E+=k.value.length,k=k.next){var S=k.value;if(t.length>e.length)return;if(!(S instanceof a)){var T,_=1;if(v){if(!(T=i(x,E,e,b))||T.index>=e.length)break;var A=T.index,C=T.index+T[0].length,P=E;for(P+=k.value.length;A>=P;)P+=(k=k.next).value.length;if(E=P-=k.value.length,k.value instanceof a)continue;for(var N=k;N!==t.tail&&(P<C||"string"==typeof N.value);N=N.next)_++,P+=N.value.length;_--,S=e.slice(E,P),T.index-=E}else if(!(T=i(x,0,S,b)))continue;A=T.index;var O=T[0],I=S.slice(0,A),R=S.slice(A+O.length),D=E+S.length;d&&D>d.reach&&(d.reach=D);var L=k.prev;if(I&&(L=s(t,L,I),E+=I.length),c(t,L,_),k=s(t,L,new a(p,h?r.tokenize(O,h):O,y,O)),R&&s(t,k,R),_>1){var M={cause:p+","+m,reach:D};o(e,t,n,k.prev,E,M),d&&M.reach>d.reach&&(d.reach=M.reach)}}}}}}function l(){var e={value:null,prev:null,next:null},t={value:null,prev:e,next:null};e.next=t,this.head=e,this.tail=t,this.length=0}function s(e,t,n){var r=t.next,a={value:n,prev:t,next:r};return t.next=a,r.prev=a,e.length++,a}function c(e,t,n){for(var r=t.next,a=0;a<n&&r!==e.tail;a++)r=r.next;t.next=r,r.prev=t,e.length-=a}return a.stringify=function e(t,n){if("string"==typeof t)return t;if(Array.isArray(t)){var a="";return t.forEach((function(t){a+=e(t,n)})),a}var i={type:t.type,content:e(t.content,n),tag:"span",classes:["token",t.type],attributes:{},language:n},o=t.alias;o&&(Array.isArray(o)?Array.prototype.push.apply(i.classes,o):i.classes.push(o)),r.hooks.run("wrap",i);var l="";for(var s in i.attributes)l+=" "+s+'="'+(i.attributes[s]||"").replace(/"/g,""")+'"';return"<"+i.tag+' class="'+i.classes.join(" ")+'"'+l+">"+i.content+"</"+i.tag+">"},r}(),a=r;r.default=r,a.languages.markup={comment:{pattern:/<!--(?:(?!<!--)[\s\S])*?-->/,greedy:!0},prolog:{pattern:/<\?[\s\S]+?\?>/,greedy:!0},doctype:{pattern:/<!DOCTYPE(?:[^>"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|<!--(?:[^-]|-(?!->))*-->)*\]\s*)?>/i,greedy:!0,inside:{"internal-subset":{pattern:/(^[^\[]*\[)[\s\S]+(?=\]>$)/,lookbehind:!0,greedy:!0,inside:null},string:{pattern:/"[^"]*"|'[^']*'/,greedy:!0},punctuation:/^<!|>$|[[\]]/,"doctype-tag":/^DOCTYPE/i,name:/[^\s<>'"]+/}},cdata:{pattern:/<!\[CDATA\[[\s\S]*?\]\]>/i,greedy:!0},tag:{pattern:/<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/,greedy:!0,inside:{tag:{pattern:/^<\/?[^\s>\/]+/,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"special-attr":[],"attr-value":{pattern:/=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,inside:{punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:[{pattern:/&[\da-z]{1,8};/i,alias:"named-entity"},/&#x?[\da-f]{1,8};/i]},a.languages.markup.tag.inside["attr-value"].inside.entity=a.languages.markup.entity,a.languages.markup.doctype.inside["internal-subset"].inside=a.languages.markup,a.hooks.add("wrap",(function(e){"entity"===e.type&&(e.attributes.title=e.content.replace(/&/,"&"))})),Object.defineProperty(a.languages.markup.tag,"addInlined",{value:function(e,t){var n={};n["language-"+t]={pattern:/(^<!\[CDATA\[)[\s\S]+?(?=\]\]>$)/i,lookbehind:!0,inside:a.languages[t]},n.cdata=/^<!\[CDATA\[|\]\]>$/i;var r={"included-cdata":{pattern:/<!\[CDATA\[[\s\S]*?\]\]>/i,inside:n}};r["language-"+t]={pattern:/[\s\S]+/,inside:a.languages[t]};var i={};i[e]={pattern:RegExp(/(<__[^>]*>)(?:<!\[CDATA\[(?:[^\]]|\](?!\]>))*\]\]>|(?!<!\[CDATA\[)[\s\S])*?(?=<\/__>)/.source.replace(/__/g,(function(){return e})),"i"),lookbehind:!0,greedy:!0,inside:r},a.languages.insertBefore("markup","cdata",i)}}),Object.defineProperty(a.languages.markup.tag,"addAttribute",{value:function(e,t){a.languages.markup.tag.inside["special-attr"].push({pattern:RegExp(/(^|["'\s])/.source+"(?:"+e+")"+/\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))/.source,"i"),lookbehind:!0,inside:{"attr-name":/^[^\s=]+/,"attr-value":{pattern:/=[\s\S]+/,inside:{value:{pattern:/(^=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/,lookbehind:!0,alias:[t,"language-"+t],inside:a.languages[t]},punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}}}})}}),a.languages.html=a.languages.markup,a.languages.mathml=a.languages.markup,a.languages.svg=a.languages.markup,a.languages.xml=a.languages.extend("markup",{}),a.languages.ssml=a.languages.xml,a.languages.atom=a.languages.xml,a.languages.rss=a.languages.xml,function(e){var t="\\b(?:BASH|BASHOPTS|BASH_ALIASES|BASH_ARGC|BASH_ARGV|BASH_CMDS|BASH_COMPLETION_COMPAT_DIR|BASH_LINENO|BASH_REMATCH|BASH_SOURCE|BASH_VERSINFO|BASH_VERSION|COLORTERM|COLUMNS|COMP_WORDBREAKS|DBUS_SESSION_BUS_ADDRESS|DEFAULTS_PATH|DESKTOP_SESSION|DIRSTACK|DISPLAY|EUID|GDMSESSION|GDM_LANG|GNOME_KEYRING_CONTROL|GNOME_KEYRING_PID|GPG_AGENT_INFO|GROUPS|HISTCONTROL|HISTFILE|HISTFILESIZE|HISTSIZE|HOME|HOSTNAME|HOSTTYPE|IFS|INSTANCE|JOB|LANG|LANGUAGE|LC_ADDRESS|LC_ALL|LC_IDENTIFICATION|LC_MEASUREMENT|LC_MONETARY|LC_NAME|LC_NUMERIC|LC_PAPER|LC_TELEPHONE|LC_TIME|LESSCLOSE|LESSOPEN|LINES|LOGNAME|LS_COLORS|MACHTYPE|MAILCHECK|MANDATORY_PATH|NO_AT_BRIDGE|OLDPWD|OPTERR|OPTIND|ORBIT_SOCKETDIR|OSTYPE|PAPERSIZE|PATH|PIPESTATUS|PPID|PS1|PS2|PS3|PS4|PWD|RANDOM|REPLY|SECONDS|SELINUX_INIT|SESSION|SESSIONTYPE|SESSION_MANAGER|SHELL|SHELLOPTS|SHLVL|SSH_AUTH_SOCK|TERM|UID|UPSTART_EVENTS|UPSTART_INSTANCE|UPSTART_JOB|UPSTART_SESSION|USER|WINDOWID|XAUTHORITY|XDG_CONFIG_DIRS|XDG_CURRENT_DESKTOP|XDG_DATA_DIRS|XDG_GREETER_DATA_DIR|XDG_MENU_PREFIX|XDG_RUNTIME_DIR|XDG_SEAT|XDG_SEAT_PATH|XDG_SESSION_DESKTOP|XDG_SESSION_ID|XDG_SESSION_PATH|XDG_SESSION_TYPE|XDG_VTNR|XMODIFIERS)\\b",n={pattern:/(^(["']?)\w+\2)[ \t]+\S.*/,lookbehind:!0,alias:"punctuation",inside:null},r={bash:n,environment:{pattern:RegExp("\\$"+t),alias:"constant"},variable:[{pattern:/\$?\(\([\s\S]+?\)\)/,greedy:!0,inside:{variable:[{pattern:/(^\$\(\([\s\S]+)\)\)/,lookbehind:!0},/^\$\(\(/],number:/\b0x[\dA-Fa-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[Ee]-?\d+)?/,operator:/--|\+\+|\*\*=?|<<=?|>>=?|&&|\|\||[=!+\-*/%<>^&|]=?|[?~:]/,punctuation:/\(\(?|\)\)?|,|;/}},{pattern:/\$\((?:\([^)]+\)|[^()])+\)|`[^`]+`/,greedy:!0,inside:{variable:/^\$\(|^`|\)$|`$/}},{pattern:/\$\{[^}]+\}/,greedy:!0,inside:{operator:/:[-=?+]?|[!\/]|##?|%%?|\^\^?|,,?/,punctuation:/[\[\]]/,environment:{pattern:RegExp("(\\{)"+t),lookbehind:!0,alias:"constant"}}},/\$(?:\w+|[#?*!@$])/],entity:/\\(?:[abceEfnrtv\\"]|O?[0-7]{1,3}|U[0-9a-fA-F]{8}|u[0-9a-fA-F]{4}|x[0-9a-fA-F]{1,2})/};e.languages.bash={shebang:{pattern:/^#!\s*\/.*/,alias:"important"},comment:{pattern:/(^|[^"{\\$])#.*/,lookbehind:!0},"function-name":[{pattern:/(\bfunction\s+)[\w-]+(?=(?:\s*\(?:\s*\))?\s*\{)/,lookbehind:!0,alias:"function"},{pattern:/\b[\w-]+(?=\s*\(\s*\)\s*\{)/,alias:"function"}],"for-or-select":{pattern:/(\b(?:for|select)\s+)\w+(?=\s+in\s)/,alias:"variable",lookbehind:!0},"assign-left":{pattern:/(^|[\s;|&]|[<>]\()\w+(?=\+?=)/,inside:{environment:{pattern:RegExp("(^|[\\s;|&]|[<>]\\()"+t),lookbehind:!0,alias:"constant"}},alias:"variable",lookbehind:!0},string:[{pattern:/((?:^|[^<])<<-?\s*)(\w+)\s[\s\S]*?(?:\r?\n|\r)\2/,lookbehind:!0,greedy:!0,inside:r},{pattern:/((?:^|[^<])<<-?\s*)(["'])(\w+)\2\s[\s\S]*?(?:\r?\n|\r)\3/,lookbehind:!0,greedy:!0,inside:{bash:n}},{pattern:/(^|[^\\](?:\\\\)*)"(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|[^"\\`$])*"/,lookbehind:!0,greedy:!0,inside:r},{pattern:/(^|[^$\\])'[^']*'/,lookbehind:!0,greedy:!0},{pattern:/\$'(?:[^'\\]|\\[\s\S])*'/,greedy:!0,inside:{entity:r.entity}}],environment:{pattern:RegExp("\\$?"+t),alias:"constant"},variable:r.variable,function:{pattern:/(^|[\s;|&]|[<>]\()(?:add|apropos|apt|apt-cache|apt-get|aptitude|aspell|automysqlbackup|awk|basename|bash|bc|bconsole|bg|bzip2|cal|cat|cfdisk|chgrp|chkconfig|chmod|chown|chroot|cksum|clear|cmp|column|comm|composer|cp|cron|crontab|csplit|curl|cut|date|dc|dd|ddrescue|debootstrap|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|docker|docker-compose|du|egrep|eject|env|ethtool|expand|expect|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|git|gparted|grep|groupadd|groupdel|groupmod|groups|grub-mkconfig|gzip|halt|head|hg|history|host|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|ip|jobs|join|kill|killall|less|link|ln|locate|logname|logrotate|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|lynx|make|man|mc|mdadm|mkconfig|mkdir|mke2fs|mkfifo|mkfs|mkisofs|mknod|mkswap|mmv|more|most|mount|mtools|mtr|mutt|mv|nano|nc|netstat|nice|nl|node|nohup|notify-send|npm|nslookup|op|open|parted|passwd|paste|pathchk|ping|pkill|pnpm|podman|podman-compose|popd|pr|printcap|printenv|ps|pushd|pv|quota|quotacheck|quotactl|ram|rar|rcp|reboot|remsync|rename|renice|rev|rm|rmdir|rpm|rsync|scp|screen|sdiff|sed|sendmail|seq|service|sftp|sh|shellcheck|shuf|shutdown|sleep|slocate|sort|split|ssh|stat|strace|su|sudo|sum|suspend|swapon|sync|tac|tail|tar|tee|time|timeout|top|touch|tr|traceroute|tsort|tty|umount|uname|unexpand|uniq|units|unrar|unshar|unzip|update-grub|uptime|useradd|userdel|usermod|users|uudecode|uuencode|v|vcpkg|vdir|vi|vim|virsh|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yarn|yes|zenity|zip|zsh|zypper)(?=$|[)\s;|&])/,lookbehind:!0},keyword:{pattern:/(^|[\s;|&]|[<>]\()(?:case|do|done|elif|else|esac|fi|for|function|if|in|select|then|until|while)(?=$|[)\s;|&])/,lookbehind:!0},builtin:{pattern:/(^|[\s;|&]|[<>]\()(?:\.|:|alias|bind|break|builtin|caller|cd|command|continue|declare|echo|enable|eval|exec|exit|export|getopts|hash|help|let|local|logout|mapfile|printf|pwd|read|readarray|readonly|return|set|shift|shopt|source|test|times|trap|type|typeset|ulimit|umask|unalias|unset)(?=$|[)\s;|&])/,lookbehind:!0,alias:"class-name"},boolean:{pattern:/(^|[\s;|&]|[<>]\()(?:false|true)(?=$|[)\s;|&])/,lookbehind:!0},"file-descriptor":{pattern:/\B&\d\b/,alias:"important"},operator:{pattern:/\d?<>|>\||\+=|=[=~]?|!=?|<<[<-]?|[&\d]?>>|\d[<>]&?|[<>][&=]?|&[>&]?|\|[&|]?/,inside:{"file-descriptor":{pattern:/^\d/,alias:"important"}}},punctuation:/\$?\(\(?|\)\)?|\.\.|[{}[\];\\]/,number:{pattern:/(^|\s)(?:[1-9]\d*|0)(?:[.,]\d+)?\b/,lookbehind:!0}},n.inside=e.languages.bash;for(var a=["comment","function-name","for-or-select","assign-left","string","environment","function","keyword","builtin","boolean","file-descriptor","operator","punctuation","number"],i=r.variable[1].inside,o=0;o<a.length;o++)i[a[o]]=e.languages.bash[a[o]];e.languages.shell=e.languages.bash}(a),a.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0,greedy:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/(\b(?:class|extends|implements|instanceof|interface|new|trait)\s+|\bcatch\s+\()[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:break|catch|continue|do|else|finally|for|function|if|in|instanceof|new|null|return|throw|try|while)\b/,boolean:/\b(?:false|true)\b/,function:/\b\w+(?=\()/,number:/\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i,operator:/[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,punctuation:/[{}[\];(),.:]/},a.languages.c=a.languages.extend("clike",{comment:{pattern:/\/\/(?:[^\r\n\\]|\\(?:\r\n?|\n|(?![\r\n])))*|\/\*[\s\S]*?(?:\*\/|$)/,greedy:!0},string:{pattern:/"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"/,greedy:!0},"class-name":{pattern:/(\b(?:enum|struct)\s+(?:__attribute__\s*\(\([\s\S]*?\)\)\s*)?)\w+|\b[a-z]\w*_t\b/,lookbehind:!0},keyword:/\b(?:_Alignas|_Alignof|_Atomic|_Bool|_Complex|_Generic|_Imaginary|_Noreturn|_Static_assert|_Thread_local|__attribute__|asm|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|inline|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|typeof|union|unsigned|void|volatile|while)\b/,function:/\b[a-z_]\w*(?=\s*\()/i,number:/(?:\b0x(?:[\da-f]+(?:\.[\da-f]*)?|\.[\da-f]+)(?:p[+-]?\d+)?|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?)[ful]{0,4}/i,operator:/>>=?|<<=?|->|([-+&|:])\1|[?:~]|[-+*/%&|^!=<>]=?/}),a.languages.insertBefore("c","string",{char:{pattern:/'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n]){0,32}'/,greedy:!0}}),a.languages.insertBefore("c","string",{macro:{pattern:/(^[\t ]*)#\s*[a-z](?:[^\r\n\\/]|\/(?!\*)|\/\*(?:[^*]|\*(?!\/))*\*\/|\\(?:\r\n|[\s\S]))*/im,lookbehind:!0,greedy:!0,alias:"property",inside:{string:[{pattern:/^(#\s*include\s*)<[^>]+>/,lookbehind:!0},a.languages.c.string],char:a.languages.c.char,comment:a.languages.c.comment,"macro-name":[{pattern:/(^#\s*define\s+)\w+\b(?!\()/i,lookbehind:!0},{pattern:/(^#\s*define\s+)\w+\b(?=\()/i,lookbehind:!0,alias:"function"}],directive:{pattern:/^(#\s*)[a-z]+/,lookbehind:!0,alias:"keyword"},"directive-hash":/^#/,punctuation:/##|\\(?=[\r\n])/,expression:{pattern:/\S[\s\S]*/,inside:a.languages.c}}}}),a.languages.insertBefore("c","function",{constant:/\b(?:EOF|NULL|SEEK_CUR|SEEK_END|SEEK_SET|__DATE__|__FILE__|__LINE__|__TIMESTAMP__|__TIME__|__func__|stderr|stdin|stdout)\b/}),delete a.languages.c.boolean,function(e){var t=/\b(?:alignas|alignof|asm|auto|bool|break|case|catch|char|char16_t|char32_t|char8_t|class|co_await|co_return|co_yield|compl|concept|const|const_cast|consteval|constexpr|constinit|continue|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|final|float|for|friend|goto|if|import|inline|int|int16_t|int32_t|int64_t|int8_t|long|module|mutable|namespace|new|noexcept|nullptr|operator|override|private|protected|public|register|reinterpret_cast|requires|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|uint16_t|uint32_t|uint64_t|uint8_t|union|unsigned|using|virtual|void|volatile|wchar_t|while)\b/,n=/\b(?!<keyword>)\w+(?:\s*\.\s*\w+)*\b/.source.replace(/<keyword>/g,(function(){return t.source}));e.languages.cpp=e.languages.extend("c",{"class-name":[{pattern:RegExp(/(\b(?:class|concept|enum|struct|typename)\s+)(?!<keyword>)\w+/.source.replace(/<keyword>/g,(function(){return t.source}))),lookbehind:!0},/\b[A-Z]\w*(?=\s*::\s*\w+\s*\()/,/\b[A-Z_]\w*(?=\s*::\s*~\w+\s*\()/i,/\b\w+(?=\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>\s*::\s*\w+\s*\()/],keyword:t,number:{pattern:/(?:\b0b[01']+|\b0x(?:[\da-f']+(?:\.[\da-f']*)?|\.[\da-f']+)(?:p[+-]?[\d']+)?|(?:\b[\d']+(?:\.[\d']*)?|\B\.[\d']+)(?:e[+-]?[\d']+)?)[ful]{0,4}/i,greedy:!0},operator:/>>=?|<<=?|->|--|\+\+|&&|\|\||[?:~]|<=>|[-+*/%&|^!=<>]=?|\b(?:and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/,boolean:/\b(?:false|true)\b/}),e.languages.insertBefore("cpp","string",{module:{pattern:RegExp(/(\b(?:import|module)\s+)/.source+"(?:"+/"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|<[^<>\r\n]*>/.source+"|"+/<mod-name>(?:\s*:\s*<mod-name>)?|:\s*<mod-name>/.source.replace(/<mod-name>/g,(function(){return n}))+")"),lookbehind:!0,greedy:!0,inside:{string:/^[<"][\s\S]+/,operator:/:/,punctuation:/\./}},"raw-string":{pattern:/R"([^()\\ ]{0,16})\([\s\S]*?\)\1"/,alias:"string",greedy:!0}}),e.languages.insertBefore("cpp","keyword",{"generic-function":{pattern:/\b(?!operator\b)[a-z_]\w*\s*<(?:[^<>]|<[^<>]*>)*>(?=\s*\()/i,inside:{function:/^\w+/,generic:{pattern:/<[\s\S]+/,alias:"class-name",inside:e.languages.cpp}}}}),e.languages.insertBefore("cpp","operator",{"double-colon":{pattern:/::/,alias:"punctuation"}}),e.languages.insertBefore("cpp","class-name",{"base-clause":{pattern:/(\b(?:class|struct)\s+\w+\s*:\s*)[^;{}"'\s]+(?:\s+[^;{}"'\s]+)*(?=\s*[;{])/,lookbehind:!0,greedy:!0,inside:e.languages.extend("cpp",{})}}),e.languages.insertBefore("inside","double-colon",{"class-name":/\b[a-z_]\w*\b(?!\s*::)/i},e.languages.cpp["base-clause"])}(a),function(e){var t=/(?:"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n])*')/;e.languages.css={comment:/\/\*[\s\S]*?\*\//,atrule:{pattern:/@[\w-](?:[^;{\s]|\s+(?![\s{]))*(?:;|(?=\s*\{))/,inside:{rule:/^@[\w-]+/,"selector-function-argument":{pattern:/(\bselector\s*\(\s*(?![\s)]))(?:[^()\s]|\s+(?![\s)])|\((?:[^()]|\([^()]*\))*\))+(?=\s*\))/,lookbehind:!0,alias:"selector"},keyword:{pattern:/(^|[^\w-])(?:and|not|only|or)(?![\w-])/,lookbehind:!0}}},url:{pattern:RegExp("\\burl\\((?:"+t.source+"|"+/(?:[^\\\r\n()"']|\\[\s\S])*/.source+")\\)","i"),greedy:!0,inside:{function:/^url/i,punctuation:/^\(|\)$/,string:{pattern:RegExp("^"+t.source+"$"),alias:"url"}}},selector:{pattern:RegExp("(^|[{}\\s])[^{}\\s](?:[^{};\"'\\s]|\\s+(?![\\s{])|"+t.source+")*(?=\\s*\\{)"),lookbehind:!0},string:{pattern:t,greedy:!0},property:{pattern:/(^|[^-\w\xA0-\uFFFF])(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*(?=\s*:)/i,lookbehind:!0},important:/!important\b/i,function:{pattern:/(^|[^-a-z0-9])[-a-z0-9]+(?=\()/i,lookbehind:!0},punctuation:/[(){};:,]/},e.languages.css.atrule.inside.rest=e.languages.css;var n=e.languages.markup;n&&(n.tag.addInlined("style","css"),n.tag.addAttribute("style","css"))}(a),function(e){var t,n=/("|')(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/;e.languages.css.selector={pattern:e.languages.css.selector.pattern,lookbehind:!0,inside:t={"pseudo-element":/:(?:after|before|first-letter|first-line|selection)|::[-\w]+/,"pseudo-class":/:[-\w]+/,class:/\.[-\w]+/,id:/#[-\w]+/,attribute:{pattern:RegExp("\\[(?:[^[\\]\"']|"+n.source+")*\\]"),greedy:!0,inside:{punctuation:/^\[|\]$/,"case-sensitivity":{pattern:/(\s)[si]$/i,lookbehind:!0,alias:"keyword"},namespace:{pattern:/^(\s*)(?:(?!\s)[-*\w\xA0-\uFFFF])*\|(?!=)/,lookbehind:!0,inside:{punctuation:/\|$/}},"attr-name":{pattern:/^(\s*)(?:(?!\s)[-\w\xA0-\uFFFF])+/,lookbehind:!0},"attr-value":[n,{pattern:/(=\s*)(?:(?!\s)[-\w\xA0-\uFFFF])+(?=\s*$)/,lookbehind:!0}],operator:/[|~*^$]?=/}},"n-th":[{pattern:/(\(\s*)[+-]?\d*[\dn](?:\s*[+-]\s*\d+)?(?=\s*\))/,lookbehind:!0,inside:{number:/[\dn]+/,operator:/[+-]/}},{pattern:/(\(\s*)(?:even|odd)(?=\s*\))/i,lookbehind:!0}],combinator:/>|\+|~|\|\|/,punctuation:/[(),]/}},e.languages.css.atrule.inside["selector-function-argument"].inside=t,e.languages.insertBefore("css","property",{variable:{pattern:/(^|[^-\w\xA0-\uFFFF])--(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*/i,lookbehind:!0}});var r={pattern:/(\b\d+)(?:%|[a-z]+(?![\w-]))/,lookbehind:!0},a={pattern:/(^|[^\w.-])-?(?:\d+(?:\.\d+)?|\.\d+)/,lookbehind:!0};e.languages.insertBefore("css","function",{operator:{pattern:/(\s)[+\-*\/](?=\s)/,lookbehind:!0},hexcode:{pattern:/\B#[\da-f]{3,8}\b/i,alias:"color"},color:[{pattern:/(^|[^\w-])(?:AliceBlue|AntiqueWhite|Aqua|Aquamarine|Azure|Beige|Bisque|Black|BlanchedAlmond|Blue|BlueViolet|Brown|BurlyWood|CadetBlue|Chartreuse|Chocolate|Coral|CornflowerBlue|Cornsilk|Crimson|Cyan|DarkBlue|DarkCyan|DarkGoldenRod|DarkGr[ae]y|DarkGreen|DarkKhaki|DarkMagenta|DarkOliveGreen|DarkOrange|DarkOrchid|DarkRed|DarkSalmon|DarkSeaGreen|DarkSlateBlue|DarkSlateGr[ae]y|DarkTurquoise|DarkViolet|DeepPink|DeepSkyBlue|DimGr[ae]y|DodgerBlue|FireBrick|FloralWhite|ForestGreen|Fuchsia|Gainsboro|GhostWhite|Gold|GoldenRod|Gr[ae]y|Green|GreenYellow|HoneyDew|HotPink|IndianRed|Indigo|Ivory|Khaki|Lavender|LavenderBlush|LawnGreen|LemonChiffon|LightBlue|LightCoral|LightCyan|LightGoldenRodYellow|LightGr[ae]y|LightGreen|LightPink|LightSalmon|LightSeaGreen|LightSkyBlue|LightSlateGr[ae]y|LightSteelBlue|LightYellow|Lime|LimeGreen|Linen|Magenta|Maroon|MediumAquaMarine|MediumBlue|MediumOrchid|MediumPurple|MediumSeaGreen|MediumSlateBlue|MediumSpringGreen|MediumTurquoise|MediumVioletRed|MidnightBlue|MintCream|MistyRose|Moccasin|NavajoWhite|Navy|OldLace|Olive|OliveDrab|Orange|OrangeRed|Orchid|PaleGoldenRod|PaleGreen|PaleTurquoise|PaleVioletRed|PapayaWhip|PeachPuff|Peru|Pink|Plum|PowderBlue|Purple|Red|RosyBrown|RoyalBlue|SaddleBrown|Salmon|SandyBrown|SeaGreen|SeaShell|Sienna|Silver|SkyBlue|SlateBlue|SlateGr[ae]y|Snow|SpringGreen|SteelBlue|Tan|Teal|Thistle|Tomato|Transparent|Turquoise|Violet|Wheat|White|WhiteSmoke|Yellow|YellowGreen)(?![\w-])/i,lookbehind:!0},{pattern:/\b(?:hsl|rgb)\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*\)\B|\b(?:hsl|rgb)a\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*,\s*(?:0|0?\.\d+|1)\s*\)\B/i,inside:{unit:r,number:a,function:/[\w-]+(?=\()/,punctuation:/[(),]/}}],entity:/\\[\da-f]{1,8}/i,unit:r,number:a})}(a),a.languages.javascript=a.languages.extend("clike",{"class-name":[a.languages.clike["class-name"],{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$A-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\.(?:constructor|prototype))/,lookbehind:!0}],keyword:[{pattern:/((?:^|\})\s*)catch\b/,lookbehind:!0},{pattern:/(^|[^.]|\.\.\.\s*)\b(?:as|assert(?=\s*\{)|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally(?=\s*(?:\{|$))|for|from(?=\s*(?:['"]|$))|function|(?:get|set)(?=\s*(?:[#\[$\w\xA0-\uFFFF]|$))|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/,lookbehind:!0}],function:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,number:{pattern:RegExp(/(^|[^\w$])/.source+"(?:"+/NaN|Infinity/.source+"|"+/0[bB][01]+(?:_[01]+)*n?/.source+"|"+/0[oO][0-7]+(?:_[0-7]+)*n?/.source+"|"+/0[xX][\dA-Fa-f]+(?:_[\dA-Fa-f]+)*n?/.source+"|"+/\d+(?:_\d+)*n/.source+"|"+/(?:\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\.\d+(?:_\d+)*)(?:[Ee][+-]?\d+(?:_\d+)*)?/.source+")"+/(?![\w$])/.source),lookbehind:!0},operator:/--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/}),a.languages.javascript["class-name"][0].pattern=/(\b(?:class|extends|implements|instanceof|interface|new)\s+)[\w.\\]+/,a.languages.insertBefore("javascript","keyword",{regex:{pattern:/((?:^|[^$\w\xA0-\uFFFF."'\])\s]|\b(?:return|yield))\s*)\/(?:\[(?:[^\]\\\r\n]|\\.)*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}(?=(?:\s|\/\*(?:[^*]|\*(?!\/))*\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/,lookbehind:!0,greedy:!0,inside:{"regex-source":{pattern:/^(\/)[\s\S]+(?=\/[a-z]*$)/,lookbehind:!0,alias:"language-regex",inside:a.languages.regex},"regex-delimiter":/^\/|\/$/,"regex-flags":/^[a-z]+$/}},"function-variable":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/,alias:"function"},parameter:[{pattern:/(function(?:\s+(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)?\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\))/,lookbehind:!0,inside:a.languages.javascript},{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=>)/i,lookbehind:!0,inside:a.languages.javascript},{pattern:/(\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*=>)/,lookbehind:!0,inside:a.languages.javascript},{pattern:/((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*\{)/,lookbehind:!0,inside:a.languages.javascript}],constant:/\b[A-Z](?:[A-Z_]|\dx?)*\b/}),a.languages.insertBefore("javascript","string",{hashbang:{pattern:/^#!.*/,greedy:!0,alias:"comment"},"template-string":{pattern:/`(?:\\[\s\S]|\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}|(?!\$\{)[^\\`])*`/,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}/,lookbehind:!0,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:a.languages.javascript}},string:/[\s\S]+/}},"string-property":{pattern:/((?:^|[,{])[ \t]*)(["'])(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2(?=\s*:)/m,lookbehind:!0,greedy:!0,alias:"property"}}),a.languages.insertBefore("javascript","operator",{"literal-property":{pattern:/((?:^|[,{])[ \t]*)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*:)/m,lookbehind:!0,alias:"property"}}),a.languages.markup&&(a.languages.markup.tag.addInlined("script","javascript"),a.languages.markup.tag.addAttribute(/on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)/.source,"javascript")),a.languages.js=a.languages.javascript,function(e){var t=/#(?!\{).+/,n={pattern:/#\{[^}]+\}/,alias:"variable"};e.languages.coffeescript=e.languages.extend("javascript",{comment:t,string:[{pattern:/'(?:\\[\s\S]|[^\\'])*'/,greedy:!0},{pattern:/"(?:\\[\s\S]|[^\\"])*"/,greedy:!0,inside:{interpolation:n}}],keyword:/\b(?:and|break|by|catch|class|continue|debugger|delete|do|each|else|extend|extends|false|finally|for|if|in|instanceof|is|isnt|let|loop|namespace|new|no|not|null|of|off|on|or|own|return|super|switch|then|this|throw|true|try|typeof|undefined|unless|until|when|while|window|with|yes|yield)\b/,"class-member":{pattern:/@(?!\d)\w+/,alias:"variable"}}),e.languages.insertBefore("coffeescript","comment",{"multiline-comment":{pattern:/###[\s\S]+?###/,alias:"comment"},"block-regex":{pattern:/\/{3}[\s\S]*?\/{3}/,alias:"regex",inside:{comment:t,interpolation:n}}}),e.languages.insertBefore("coffeescript","string",{"inline-javascript":{pattern:/`(?:\\[\s\S]|[^\\`])*`/,inside:{delimiter:{pattern:/^`|`$/,alias:"punctuation"},script:{pattern:/[\s\S]+/,alias:"language-javascript",inside:e.languages.javascript}}},"multiline-string":[{pattern:/'''[\s\S]*?'''/,greedy:!0,alias:"string"},{pattern:/"""[\s\S]*?"""/,greedy:!0,alias:"string",inside:{interpolation:n}}]}),e.languages.insertBefore("coffeescript","keyword",{property:/(?!\d)\w+(?=\s*:(?!:))/}),delete e.languages.coffeescript["template-string"],e.languages.coffee=e.languages.coffeescript}(a),function(e){var t=/[*&][^\s[\]{},]+/,n=/!(?:<[\w\-%#;/?:@&=+$,.!~*'()[\]]+>|(?:[a-zA-Z\d-]*!)?[\w\-%#;/?:@&=+$.~*'()]+)?/,r="(?:"+n.source+"(?:[ \t]+"+t.source+")?|"+t.source+"(?:[ \t]+"+n.source+")?)",a=/(?:[^\s\x00-\x08\x0e-\x1f!"#%&'*,\-:>?@[\]`{|}\x7f-\x84\x86-\x9f\ud800-\udfff\ufffe\uffff]|[?:-]<PLAIN>)(?:[ \t]*(?:(?![#:])<PLAIN>|:<PLAIN>))*/.source.replace(/<PLAIN>/g,(function(){return/[^\s\x00-\x08\x0e-\x1f,[\]{}\x7f-\x84\x86-\x9f\ud800-\udfff\ufffe\uffff]/.source})),i=/"(?:[^"\\\r\n]|\\.)*"|'(?:[^'\\\r\n]|\\.)*'/.source;function o(e,t){t=(t||"").replace(/m/g,"")+"m";var n=/([:\-,[{]\s*(?:\s<<prop>>[ \t]+)?)(?:<<value>>)(?=[ \t]*(?:$|,|\]|\}|(?:[\r\n]\s*)?#))/.source.replace(/<<prop>>/g,(function(){return r})).replace(/<<value>>/g,(function(){return e}));return RegExp(n,t)}e.languages.yaml={scalar:{pattern:RegExp(/([\-:]\s*(?:\s<<prop>>[ \t]+)?[|>])[ \t]*(?:((?:\r?\n|\r)[ \t]+)\S[^\r\n]*(?:\2[^\r\n]+)*)/.source.replace(/<<prop>>/g,(function(){return r}))),lookbehind:!0,alias:"string"},comment:/#.*/,key:{pattern:RegExp(/((?:^|[:\-,[{\r\n?])[ \t]*(?:<<prop>>[ \t]+)?)<<key>>(?=\s*:\s)/.source.replace(/<<prop>>/g,(function(){return r})).replace(/<<key>>/g,(function(){return"(?:"+a+"|"+i+")"}))),lookbehind:!0,greedy:!0,alias:"atrule"},directive:{pattern:/(^[ \t]*)%.+/m,lookbehind:!0,alias:"important"},datetime:{pattern:o(/\d{4}-\d\d?-\d\d?(?:[tT]|[ \t]+)\d\d?:\d{2}:\d{2}(?:\.\d*)?(?:[ \t]*(?:Z|[-+]\d\d?(?::\d{2})?))?|\d{4}-\d{2}-\d{2}|\d\d?:\d{2}(?::\d{2}(?:\.\d*)?)?/.source),lookbehind:!0,alias:"number"},boolean:{pattern:o(/false|true/.source,"i"),lookbehind:!0,alias:"important"},null:{pattern:o(/null|~/.source,"i"),lookbehind:!0,alias:"important"},string:{pattern:o(i),lookbehind:!0,greedy:!0},number:{pattern:o(/[+-]?(?:0x[\da-f]+|0o[0-7]+|(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?|\.inf|\.nan)/.source,"i"),lookbehind:!0},tag:n,important:t,punctuation:/---|[:[\]{}\-,|>?]|\.\.\./},e.languages.yml=e.languages.yaml}(a),function(e){var t=/(?:\\.|[^\\\n\r]|(?:\n|\r\n?)(?![\r\n]))/.source;function n(e){return e=e.replace(/<inner>/g,(function(){return t})),RegExp(/((?:^|[^\\])(?:\\{2})*)/.source+"(?:"+e+")")}var r=/(?:\\.|``(?:[^`\r\n]|`(?!`))+``|`[^`\r\n]+`|[^\\|\r\n`])+/.source,a=/\|?__(?:\|__)+\|?(?:(?:\n|\r\n?)|(?![\s\S]))/.source.replace(/__/g,(function(){return r})),i=/\|?[ \t]*:?-{3,}:?[ \t]*(?:\|[ \t]*:?-{3,}:?[ \t]*)+\|?(?:\n|\r\n?)/.source;e.languages.markdown=e.languages.extend("markup",{}),e.languages.insertBefore("markdown","prolog",{"front-matter-block":{pattern:/(^(?:\s*[\r\n])?)---(?!.)[\s\S]*?[\r\n]---(?!.)/,lookbehind:!0,greedy:!0,inside:{punctuation:/^---|---$/,"front-matter":{pattern:/\S+(?:\s+\S+)*/,alias:["yaml","language-yaml"],inside:e.languages.yaml}}},blockquote:{pattern:/^>(?:[\t ]*>)*/m,alias:"punctuation"},table:{pattern:RegExp("^"+a+i+"(?:"+a+")*","m"),inside:{"table-data-rows":{pattern:RegExp("^("+a+i+")(?:"+a+")*$"),lookbehind:!0,inside:{"table-data":{pattern:RegExp(r),inside:e.languages.markdown},punctuation:/\|/}},"table-line":{pattern:RegExp("^("+a+")"+i+"$"),lookbehind:!0,inside:{punctuation:/\||:?-{3,}:?/}},"table-header-row":{pattern:RegExp("^"+a+"$"),inside:{"table-header":{pattern:RegExp(r),alias:"important",inside:e.languages.markdown},punctuation:/\|/}}}},code:[{pattern:/((?:^|\n)[ \t]*\n|(?:^|\r\n?)[ \t]*\r\n?)(?: {4}|\t).+(?:(?:\n|\r\n?)(?: {4}|\t).+)*/,lookbehind:!0,alias:"keyword"},{pattern:/^```[\s\S]*?^```$/m,greedy:!0,inside:{"code-block":{pattern:/^(```.*(?:\n|\r\n?))[\s\S]+?(?=(?:\n|\r\n?)^```$)/m,lookbehind:!0},"code-language":{pattern:/^(```).+/,lookbehind:!0},punctuation:/```/}}],title:[{pattern:/\S.*(?:\n|\r\n?)(?:==+|--+)(?=[ \t]*$)/m,alias:"important",inside:{punctuation:/==+$|--+$/}},{pattern:/(^\s*)#.+/m,lookbehind:!0,alias:"important",inside:{punctuation:/^#+|#+$/}}],hr:{pattern:/(^\s*)([*-])(?:[\t ]*\2){2,}(?=\s*$)/m,lookbehind:!0,alias:"punctuation"},list:{pattern:/(^\s*)(?:[*+-]|\d+\.)(?=[\t ].)/m,lookbehind:!0,alias:"punctuation"},"url-reference":{pattern:/!?\[[^\]]+\]:[\t ]+(?:\S+|<(?:\\.|[^>\\])+>)(?:[\t ]+(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\)))?/,inside:{variable:{pattern:/^(!?\[)[^\]]+/,lookbehind:!0},string:/(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\))$/,punctuation:/^[\[\]!:]|[<>]/},alias:"url"},bold:{pattern:n(/\b__(?:(?!_)<inner>|_(?:(?!_)<inner>)+_)+__\b|\*\*(?:(?!\*)<inner>|\*(?:(?!\*)<inner>)+\*)+\*\*/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^..)[\s\S]+(?=..$)/,lookbehind:!0,inside:{}},punctuation:/\*\*|__/}},italic:{pattern:n(/\b_(?:(?!_)<inner>|__(?:(?!_)<inner>)+__)+_\b|\*(?:(?!\*)<inner>|\*\*(?:(?!\*)<inner>)+\*\*)+\*/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^.)[\s\S]+(?=.$)/,lookbehind:!0,inside:{}},punctuation:/[*_]/}},strike:{pattern:n(/(~~?)(?:(?!~)<inner>)+\2/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^~~?)[\s\S]+(?=\1$)/,lookbehind:!0,inside:{}},punctuation:/~~?/}},"code-snippet":{pattern:/(^|[^\\`])(?:``[^`\r\n]+(?:`[^`\r\n]+)*``(?!`)|`[^`\r\n]+`(?!`))/,lookbehind:!0,greedy:!0,alias:["code","keyword"]},url:{pattern:n(/!?\[(?:(?!\])<inner>)+\](?:\([^\s)]+(?:[\t ]+"(?:\\.|[^"\\])*")?\)|[ \t]?\[(?:(?!\])<inner>)+\])/.source),lookbehind:!0,greedy:!0,inside:{operator:/^!/,content:{pattern:/(^\[)[^\]]+(?=\])/,lookbehind:!0,inside:{}},variable:{pattern:/(^\][ \t]?\[)[^\]]+(?=\]$)/,lookbehind:!0},url:{pattern:/(^\]\()[^\s)]+/,lookbehind:!0},string:{pattern:/(^[ \t]+)"(?:\\.|[^"\\])*"(?=\)$)/,lookbehind:!0}}}}),["url","bold","italic","strike"].forEach((function(t){["url","bold","italic","strike","code-snippet"].forEach((function(n){t!==n&&(e.languages.markdown[t].inside.content.inside[n]=e.languages.markdown[n])}))})),e.hooks.add("after-tokenize",(function(e){"markdown"!==e.language&&"md"!==e.language||function e(t){if(t&&"string"!=typeof t)for(var n=0,r=t.length;n<r;n++){var a=t[n];if("code"===a.type){var i=a.content[1],o=a.content[3];if(i&&o&&"code-language"===i.type&&"code-block"===o.type&&"string"==typeof i.content){var l=i.content.replace(/\b#/g,"sharp").replace(/\b\+\+/g,"pp"),s="language-"+(l=(/[a-z][\w-]*/i.exec(l)||[""])[0].toLowerCase());o.alias?"string"==typeof o.alias?o.alias=[o.alias,s]:o.alias.push(s):o.alias=[s]}}else e(a.content)}}(e.tokens)})),e.hooks.add("wrap",(function(t){if("code-block"===t.type){for(var n="",r=0,a=t.classes.length;r<a;r++){var i=t.classes[r],c=/language-(.+)/.exec(i);if(c){n=c[1];break}}var u,d=e.languages[n];if(d)t.content=e.highlight((u=t.content,u.replace(o,"").replace(/&(\w{1,8}|#x?[\da-f]{1,8});/gi,(function(e,t){var n;if("#"===(t=t.toLowerCase())[0])return n="x"===t[1]?parseInt(t.slice(2),16):Number(t.slice(1)),s(n);var r=l[t];return r||e}))),d,n);else if(n&&"none"!==n&&e.plugins.autoloader){var p="md-"+(new Date).valueOf()+"-"+Math.floor(1e16*Math.random());t.attributes.id=p,e.plugins.autoloader.loadLanguages(n,(function(){var t=document.getElementById(p);t&&(t.innerHTML=e.highlight(t.textContent,e.languages[n],n))}))}}}));var o=RegExp(e.languages.markup.tag.pattern.source,"gi"),l={amp:"&",lt:"<",gt:">",quot:'"'},s=String.fromCodePoint||String.fromCharCode;e.languages.md=e.languages.markdown}(a),a.languages.graphql={comment:/#.*/,description:{pattern:/(?:"""(?:[^"]|(?!""")")*"""|"(?:\\.|[^\\"\r\n])*")(?=\s*[a-z_])/i,greedy:!0,alias:"string",inside:{"language-markdown":{pattern:/(^"(?:"")?)(?!\1)[\s\S]+(?=\1$)/,lookbehind:!0,inside:a.languages.markdown}}},string:{pattern:/"""(?:[^"]|(?!""")")*"""|"(?:\\.|[^\\"\r\n])*"/,greedy:!0},number:/(?:\B-|\b)\d+(?:\.\d+)?(?:e[+-]?\d+)?\b/i,boolean:/\b(?:false|true)\b/,variable:/\$[a-z_]\w*/i,directive:{pattern:/@[a-z_]\w*/i,alias:"function"},"attr-name":{pattern:/\b[a-z_]\w*(?=\s*(?:\((?:[^()"]|"(?:\\.|[^\\"\r\n])*")*\))?:)/i,greedy:!0},"atom-input":{pattern:/\b[A-Z]\w*Input\b/,alias:"class-name"},scalar:/\b(?:Boolean|Float|ID|Int|String)\b/,constant:/\b[A-Z][A-Z_\d]*\b/,"class-name":{pattern:/(\b(?:enum|implements|interface|on|scalar|type|union)\s+|&\s*|:\s*|\[)[A-Z_]\w*/,lookbehind:!0},fragment:{pattern:/(\bfragment\s+|\.{3}\s*(?!on\b))[a-zA-Z_]\w*/,lookbehind:!0,alias:"function"},"definition-mutation":{pattern:/(\bmutation\s+)[a-zA-Z_]\w*/,lookbehind:!0,alias:"function"},"definition-query":{pattern:/(\bquery\s+)[a-zA-Z_]\w*/,lookbehind:!0,alias:"function"},keyword:/\b(?:directive|enum|extend|fragment|implements|input|interface|mutation|on|query|repeatable|scalar|schema|subscription|type|union)\b/,operator:/[!=|&]|\.{3}/,"property-query":/\w+(?=\s*\()/,object:/\w+(?=\s*\{)/,punctuation:/[!(){}\[\]:=,]/,property:/\w+/},a.hooks.add("after-tokenize",(function(e){if("graphql"===e.language)for(var t=e.tokens.filter((function(e){return"string"!=typeof e&&"comment"!==e.type&&"scalar"!==e.type})),n=0;n<t.length;){var r=t[n++];if("keyword"===r.type&&"mutation"===r.content){var a=[];if(d(["definition-mutation","punctuation"])&&"("===u(1).content){n+=2;var i=p(/^\($/,/^\)$/);if(-1===i)continue;for(;n<i;n++){var o=u(0);"variable"===o.type&&(f(o,"variable-input"),a.push(o.content))}n=i+1}if(d(["punctuation","property-query"])&&"{"===u(0).content&&(n++,f(u(0),"property-mutation"),a.length>0)){var l=p(/^\{$/,/^\}$/);if(-1===l)continue;for(var s=n;s<l;s++){var c=t[s];"variable"===c.type&&a.indexOf(c.content)>=0&&f(c,"variable-input")}}}}function u(e){return t[n+e]}function d(e,t){t=t||0;for(var n=0;n<e.length;n++){var r=u(n+t);if(!r||r.type!==e[n])return!1}return!0}function p(e,r){for(var a=1,i=n;i<t.length;i++){var o=t[i],l=o.content;if("punctuation"===o.type&&"string"==typeof l)if(e.test(l))a++;else if(r.test(l)&&0===--a)return i}return-1}function f(e,t){var n=e.alias;n?Array.isArray(n)||(e.alias=n=[n]):e.alias=n=[],n.push(t)}})),a.languages.sql={comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|(?:--|\/\/|#).*)/,lookbehind:!0},variable:[{pattern:/@(["'`])(?:\\[\s\S]|(?!\1)[^\\])+\1/,greedy:!0},/@[\w.$]+/],string:{pattern:/(^|[^@\\])("|')(?:\\[\s\S]|(?!\2)[^\\]|\2\2)*\2/,greedy:!0,lookbehind:!0},identifier:{pattern:/(^|[^@\\])`(?:\\[\s\S]|[^`\\]|``)*`/,greedy:!0,lookbehind:!0,inside:{punctuation:/^`|`$/}},function:/\b(?:AVG|COUNT|FIRST|FORMAT|LAST|LCASE|LEN|MAX|MID|MIN|MOD|NOW|ROUND|SUM|UCASE)(?=\s*\()/i,keyword:/\b(?:ACTION|ADD|AFTER|ALGORITHM|ALL|ALTER|ANALYZE|ANY|APPLY|AS|ASC|AUTHORIZATION|AUTO_INCREMENT|BACKUP|BDB|BEGIN|BERKELEYDB|BIGINT|BINARY|BIT|BLOB|BOOL|BOOLEAN|BREAK|BROWSE|BTREE|BULK|BY|CALL|CASCADED?|CASE|CHAIN|CHAR(?:ACTER|SET)?|CHECK(?:POINT)?|CLOSE|CLUSTERED|COALESCE|COLLATE|COLUMNS?|COMMENT|COMMIT(?:TED)?|COMPUTE|CONNECT|CONSISTENT|CONSTRAINT|CONTAINS(?:TABLE)?|CONTINUE|CONVERT|CREATE|CROSS|CURRENT(?:_DATE|_TIME|_TIMESTAMP|_USER)?|CURSOR|CYCLE|DATA(?:BASES?)?|DATE(?:TIME)?|DAY|DBCC|DEALLOCATE|DEC|DECIMAL|DECLARE|DEFAULT|DEFINER|DELAYED|DELETE|DELIMITERS?|DENY|DESC|DESCRIBE|DETERMINISTIC|DISABLE|DISCARD|DISK|DISTINCT|DISTINCTROW|DISTRIBUTED|DO|DOUBLE|DROP|DUMMY|DUMP(?:FILE)?|DUPLICATE|ELSE(?:IF)?|ENABLE|ENCLOSED|END|ENGINE|ENUM|ERRLVL|ERRORS|ESCAPED?|EXCEPT|EXEC(?:UTE)?|EXISTS|EXIT|EXPLAIN|EXTENDED|FETCH|FIELDS|FILE|FILLFACTOR|FIRST|FIXED|FLOAT|FOLLOWING|FOR(?: EACH ROW)?|FORCE|FOREIGN|FREETEXT(?:TABLE)?|FROM|FULL|FUNCTION|GEOMETRY(?:COLLECTION)?|GLOBAL|GOTO|GRANT|GROUP|HANDLER|HASH|HAVING|HOLDLOCK|HOUR|IDENTITY(?:COL|_INSERT)?|IF|IGNORE|IMPORT|INDEX|INFILE|INNER|INNODB|INOUT|INSERT|INT|INTEGER|INTERSECT|INTERVAL|INTO|INVOKER|ISOLATION|ITERATE|JOIN|KEYS?|KILL|LANGUAGE|LAST|LEAVE|LEFT|LEVEL|LIMIT|LINENO|LINES|LINESTRING|LOAD|LOCAL|LOCK|LONG(?:BLOB|TEXT)|LOOP|MATCH(?:ED)?|MEDIUM(?:BLOB|INT|TEXT)|MERGE|MIDDLEINT|MINUTE|MODE|MODIFIES|MODIFY|MONTH|MULTI(?:LINESTRING|POINT|POLYGON)|NATIONAL|NATURAL|NCHAR|NEXT|NO|NONCLUSTERED|NULLIF|NUMERIC|OFF?|OFFSETS?|ON|OPEN(?:DATASOURCE|QUERY|ROWSET)?|OPTIMIZE|OPTION(?:ALLY)?|ORDER|OUT(?:ER|FILE)?|OVER|PARTIAL|PARTITION|PERCENT|PIVOT|PLAN|POINT|POLYGON|PRECEDING|PRECISION|PREPARE|PREV|PRIMARY|PRINT|PRIVILEGES|PROC(?:EDURE)?|PUBLIC|PURGE|QUICK|RAISERROR|READS?|REAL|RECONFIGURE|REFERENCES|RELEASE|RENAME|REPEAT(?:ABLE)?|REPLACE|REPLICATION|REQUIRE|RESIGNAL|RESTORE|RESTRICT|RETURN(?:ING|S)?|REVOKE|RIGHT|ROLLBACK|ROUTINE|ROW(?:COUNT|GUIDCOL|S)?|RTREE|RULE|SAVE(?:POINT)?|SCHEMA|SECOND|SELECT|SERIAL(?:IZABLE)?|SESSION(?:_USER)?|SET(?:USER)?|SHARE|SHOW|SHUTDOWN|SIMPLE|SMALLINT|SNAPSHOT|SOME|SONAME|SQL|START(?:ING)?|STATISTICS|STATUS|STRIPED|SYSTEM_USER|TABLES?|TABLESPACE|TEMP(?:ORARY|TABLE)?|TERMINATED|TEXT(?:SIZE)?|THEN|TIME(?:STAMP)?|TINY(?:BLOB|INT|TEXT)|TOP?|TRAN(?:SACTIONS?)?|TRIGGER|TRUNCATE|TSEQUAL|TYPES?|UNBOUNDED|UNCOMMITTED|UNDEFINED|UNION|UNIQUE|UNLOCK|UNPIVOT|UNSIGNED|UPDATE(?:TEXT)?|USAGE|USE|USER|USING|VALUES?|VAR(?:BINARY|CHAR|CHARACTER|YING)|VIEW|WAITFOR|WARNINGS|WHEN|WHERE|WHILE|WITH(?: ROLLUP|IN)?|WORK|WRITE(?:TEXT)?|YEAR)\b/i,boolean:/\b(?:FALSE|NULL|TRUE)\b/i,number:/\b0x[\da-f]+\b|\b\d+(?:\.\d*)?|\B\.\d+\b/i,operator:/[-+*\/=%^~]|&&?|\|\|?|!=?|<(?:=>?|<|>)?|>[>=]?|\b(?:AND|BETWEEN|DIV|ILIKE|IN|IS|LIKE|NOT|OR|REGEXP|RLIKE|SOUNDS LIKE|XOR)\b/i,punctuation:/[;[\]()`,.]/},function(e){var t=e.languages.javascript["template-string"],n=t.pattern.source,r=t.inside.interpolation,a=r.inside["interpolation-punctuation"],i=r.pattern.source;function o(t,r){if(e.languages[t])return{pattern:RegExp("((?:"+r+")\\s*)"+n),lookbehind:!0,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},"embedded-code":{pattern:/[\s\S]+/,alias:t}}}}function l(e,t){return"___"+t.toUpperCase()+"_"+e+"___"}function s(t,n,r){var a={code:t,grammar:n,language:r};return e.hooks.run("before-tokenize",a),a.tokens=e.tokenize(a.code,a.grammar),e.hooks.run("after-tokenize",a),a.tokens}function c(t){var n={};n["interpolation-punctuation"]=a;var i=e.tokenize(t,n);if(3===i.length){var o=[1,1];o.push.apply(o,s(i[1],e.languages.javascript,"javascript")),i.splice.apply(i,o)}return new e.Token("interpolation",i,r.alias,t)}function u(t,n,r){var a=e.tokenize(t,{interpolation:{pattern:RegExp(i),lookbehind:!0}}),o=0,u={},d=s(a.map((function(e){if("string"==typeof e)return e;for(var n,a=e.content;-1!==t.indexOf(n=l(o++,r)););return u[n]=a,n})).join(""),n,r),p=Object.keys(u);return o=0,function e(t){for(var n=0;n<t.length;n++){if(o>=p.length)return;var r=t[n];if("string"==typeof r||"string"==typeof r.content){var a=p[o],i="string"==typeof r?r:r.content,l=i.indexOf(a);if(-1!==l){++o;var s=i.substring(0,l),d=c(u[a]),f=i.substring(l+a.length),m=[];if(s&&m.push(s),m.push(d),f){var g=[f];e(g),m.push.apply(m,g)}"string"==typeof r?(t.splice.apply(t,[n,1].concat(m)),n+=m.length-1):r.content=m}}else{var h=r.content;Array.isArray(h)?e(h):e([h])}}}(d),new e.Token(r,d,"language-"+r,t)}e.languages.javascript["template-string"]=[o("css",/\b(?:styled(?:\([^)]*\))?(?:\s*\.\s*\w+(?:\([^)]*\))*)*|css(?:\s*\.\s*(?:global|resolve))?|createGlobalStyle|keyframes)/.source),o("html",/\bhtml|\.\s*(?:inner|outer)HTML\s*\+?=/.source),o("svg",/\bsvg/.source),o("markdown",/\b(?:markdown|md)/.source),o("graphql",/\b(?:gql|graphql(?:\s*\.\s*experimental)?)/.source),o("sql",/\bsql/.source),t].filter(Boolean);var d={javascript:!0,js:!0,typescript:!0,ts:!0,jsx:!0,tsx:!0};function p(e){return"string"==typeof e?e:Array.isArray(e)?e.map(p).join(""):p(e.content)}e.hooks.add("after-tokenize",(function(t){t.language in d&&function t(n){for(var r=0,a=n.length;r<a;r++){var i=n[r];if("string"!=typeof i){var o=i.content;if(Array.isArray(o))if("template-string"===i.type){var l=o[1];if(3===o.length&&"string"!=typeof l&&"embedded-code"===l.type){var s=p(l),c=l.alias,d=Array.isArray(c)?c[0]:c,f=e.languages[d];if(!f)continue;o[1]=u(s,f,d)}}else t(o);else"string"!=typeof o&&t([o])}}}(t.tokens)}))}(a),function(e){e.languages.typescript=e.languages.extend("javascript",{"class-name":{pattern:/(\b(?:class|extends|implements|instanceof|interface|new|type)\s+)(?!keyof\b)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?:\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>)?/,lookbehind:!0,greedy:!0,inside:null},builtin:/\b(?:Array|Function|Promise|any|boolean|console|never|number|string|symbol|unknown)\b/}),e.languages.typescript.keyword.push(/\b(?:abstract|declare|is|keyof|readonly|require)\b/,/\b(?:asserts|infer|interface|module|namespace|type)\b(?=\s*(?:[{_$a-zA-Z\xA0-\uFFFF]|$))/,/\btype\b(?=\s*(?:[\{*]|$))/),delete e.languages.typescript.parameter,delete e.languages.typescript["literal-property"];var t=e.languages.extend("typescript",{});delete t["class-name"],e.languages.typescript["class-name"].inside=t,e.languages.insertBefore("typescript","function",{decorator:{pattern:/@[$\w\xA0-\uFFFF]+/,inside:{at:{pattern:/^@/,alias:"operator"},function:/^[\s\S]+/}},"generic-function":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>(?=\s*\()/,greedy:!0,inside:{function:/^#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*/,generic:{pattern:/<[\s\S]+/,alias:"class-name",inside:t}}}}),e.languages.ts=e.languages.typescript}(a),function(e){function t(e,t){return RegExp(e.replace(/<ID>/g,(function(){return/(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*/.source})),t)}e.languages.insertBefore("javascript","function-variable",{"method-variable":{pattern:RegExp("(\\.\\s*)"+e.languages.javascript["function-variable"].pattern.source),lookbehind:!0,alias:["function-variable","method","function","property-access"]}}),e.languages.insertBefore("javascript","function",{method:{pattern:RegExp("(\\.\\s*)"+e.languages.javascript.function.source),lookbehind:!0,alias:["function","property-access"]}}),e.languages.insertBefore("javascript","constant",{"known-class-name":[{pattern:/\b(?:(?:Float(?:32|64)|(?:Int|Uint)(?:8|16|32)|Uint8Clamped)?Array|ArrayBuffer|BigInt|Boolean|DataView|Date|Error|Function|Intl|JSON|(?:Weak)?(?:Map|Set)|Math|Number|Object|Promise|Proxy|Reflect|RegExp|String|Symbol|WebAssembly)\b/,alias:"class-name"},{pattern:/\b(?:[A-Z]\w*)Error\b/,alias:"class-name"}]}),e.languages.insertBefore("javascript","keyword",{imports:{pattern:t(/(\bimport\b\s*)(?:<ID>(?:\s*,\s*(?:\*\s*as\s+<ID>|\{[^{}]*\}))?|\*\s*as\s+<ID>|\{[^{}]*\})(?=\s*\bfrom\b)/.source),lookbehind:!0,inside:e.languages.javascript},exports:{pattern:t(/(\bexport\b\s*)(?:\*(?:\s*as\s+<ID>)?(?=\s*\bfrom\b)|\{[^{}]*\})/.source),lookbehind:!0,inside:e.languages.javascript}}),e.languages.javascript.keyword.unshift({pattern:/\b(?:as|default|export|from|import)\b/,alias:"module"},{pattern:/\b(?:await|break|catch|continue|do|else|finally|for|if|return|switch|throw|try|while|yield)\b/,alias:"control-flow"},{pattern:/\bnull\b/,alias:["null","nil"]},{pattern:/\bundefined\b/,alias:"nil"}),e.languages.insertBefore("javascript","operator",{spread:{pattern:/\.{3}/,alias:"operator"},arrow:{pattern:/=>/,alias:"operator"}}),e.languages.insertBefore("javascript","punctuation",{"property-access":{pattern:t(/(\.\s*)#?<ID>/.source),lookbehind:!0},"maybe-class-name":{pattern:/(^|[^$\w\xA0-\uFFFF])[A-Z][$\w\xA0-\uFFFF]+/,lookbehind:!0},dom:{pattern:/\b(?:document|(?:local|session)Storage|location|navigator|performance|window)\b/,alias:"variable"},console:{pattern:/\bconsole(?=\s*\.)/,alias:"class-name"}});for(var n=["function","function-variable","method","method-variable","property-access"],r=0;r<n.length;r++){var a=n[r],i=e.languages.javascript[a];"RegExp"===e.util.type(i)&&(i=e.languages.javascript[a]={pattern:i});var o=i.inside||{};i.inside=o,o["maybe-class-name"]=/^[A-Z][\s\S]*/}}(a),function(e){var t=e.util.clone(e.languages.javascript),n=/(?:\s|\/\/.*(?!.)|\/\*(?:[^*]|\*(?!\/))\*\/)/.source,r=/(?:\{(?:\{(?:\{[^{}]*\}|[^{}])*\}|[^{}])*\})/.source,a=/(?:\{<S>*\.{3}(?:[^{}]|<BRACES>)*\})/.source;function i(e,t){return e=e.replace(/<S>/g,(function(){return n})).replace(/<BRACES>/g,(function(){return r})).replace(/<SPREAD>/g,(function(){return a})),RegExp(e,t)}a=i(a).source,e.languages.jsx=e.languages.extend("markup",t),e.languages.jsx.tag.pattern=i(/<\/?(?:[\w.:-]+(?:<S>+(?:[\w.:$-]+(?:=(?:"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*'|[^\s{'"/>=]+|<BRACES>))?|<SPREAD>))*<S>*\/?)?>/.source),e.languages.jsx.tag.inside.tag.pattern=/^<\/?[^\s>\/]*/,e.languages.jsx.tag.inside["attr-value"].pattern=/=(?!\{)(?:"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*'|[^\s'">]+)/,e.languages.jsx.tag.inside.tag.inside["class-name"]=/^[A-Z]\w*(?:\.[A-Z]\w*)*$/,e.languages.jsx.tag.inside.comment=t.comment,e.languages.insertBefore("inside","attr-name",{spread:{pattern:i(/<SPREAD>/.source),inside:e.languages.jsx}},e.languages.jsx.tag),e.languages.insertBefore("inside","special-attr",{script:{pattern:i(/=<BRACES>/.source),alias:"language-javascript",inside:{"script-punctuation":{pattern:/^=(?=\{)/,alias:"punctuation"},rest:e.languages.jsx}}},e.languages.jsx.tag);var o=function(e){return e?"string"==typeof e?e:"string"==typeof e.content?e.content:e.content.map(o).join(""):""},l=function(t){for(var n=[],r=0;r<t.length;r++){var a=t[r],i=!1;if("string"!=typeof a&&("tag"===a.type&&a.content[0]&&"tag"===a.content[0].type?"</"===a.content[0].content[0].content?n.length>0&&n[n.length-1].tagName===o(a.content[0].content[1])&&n.pop():"/>"===a.content[a.content.length-1].content||n.push({tagName:o(a.content[0].content[1]),openedBraces:0}):n.length>0&&"punctuation"===a.type&&"{"===a.content?n[n.length-1].openedBraces++:n.length>0&&n[n.length-1].openedBraces>0&&"punctuation"===a.type&&"}"===a.content?n[n.length-1].openedBraces--:i=!0),(i||"string"==typeof a)&&n.length>0&&0===n[n.length-1].openedBraces){var s=o(a);r<t.length-1&&("string"==typeof t[r+1]||"plain-text"===t[r+1].type)&&(s+=o(t[r+1]),t.splice(r+1,1)),r>0&&("string"==typeof t[r-1]||"plain-text"===t[r-1].type)&&(s=o(t[r-1])+s,t.splice(r-1,1),r--),t[r]=new e.Token("plain-text",s,null,s)}a.content&&"string"!=typeof a.content&&l(a.content)}};e.hooks.add("after-tokenize",(function(e){"jsx"!==e.language&&"tsx"!==e.language||l(e.tokens)}))}(a),function(e){e.languages.diff={coord:[/^(?:\*{3}|-{3}|\+{3}).*$/m,/^@@.*@@$/m,/^\d.*$/m]};var t={"deleted-sign":"-","deleted-arrow":"<","inserted-sign":"+","inserted-arrow":">",unchanged:" ",diff:"!"};Object.keys(t).forEach((function(n){var r=t[n],a=[];/^\w+$/.test(n)||a.push(/\w+/.exec(n)[0]),"diff"===n&&a.push("bold"),e.languages.diff[n]={pattern:RegExp("^(?:["+r+"].*(?:\r\n?|\n|(?![\\s\\S])))+","m"),alias:a,inside:{line:{pattern:/(.)(?=[\s\S]).*(?:\r\n?|\n)?/,lookbehind:!0},prefix:{pattern:/[\s\S]/,alias:/\w+/.exec(n)[0]}}}})),Object.defineProperty(e.languages.diff,"PREFIXES",{value:t})}(a),a.languages.git={comment:/^#.*/m,deleted:/^[-\u2013].*/m,inserted:/^\+.*/m,string:/("|')(?:\\.|(?!\1)[^\\\r\n])*\1/,command:{pattern:/^.*\$ git .*$/m,inside:{parameter:/\s--?\w+/}},coord:/^@@.*@@$/m,"commit-sha1":/^commit \w{40}$/m},a.languages.go=a.languages.extend("clike",{string:{pattern:/(^|[^\\])"(?:\\.|[^"\\\r\n])*"|`[^`]*`/,lookbehind:!0,greedy:!0},keyword:/\b(?:break|case|chan|const|continue|default|defer|else|fallthrough|for|func|go(?:to)?|if|import|interface|map|package|range|return|select|struct|switch|type|var)\b/,boolean:/\b(?:_|false|iota|nil|true)\b/,number:[/\b0(?:b[01_]+|o[0-7_]+)i?\b/i,/\b0x(?:[a-f\d_]+(?:\.[a-f\d_]*)?|\.[a-f\d_]+)(?:p[+-]?\d+(?:_\d+)*)?i?(?!\w)/i,/(?:\b\d[\d_]*(?:\.[\d_]*)?|\B\.\d[\d_]*)(?:e[+-]?[\d_]+)?i?(?!\w)/i],operator:/[*\/%^!=]=?|\+[=+]?|-[=-]?|\|[=|]?|&(?:=|&|\^=?)?|>(?:>=?|=)?|<(?:<=?|=|-)?|:=|\.\.\./,builtin:/\b(?:append|bool|byte|cap|close|complex|complex(?:64|128)|copy|delete|error|float(?:32|64)|u?int(?:8|16|32|64)?|imag|len|make|new|panic|print(?:ln)?|real|recover|rune|string|uintptr)\b/}),a.languages.insertBefore("go","string",{char:{pattern:/'(?:\\.|[^'\\\r\n]){0,10}'/,greedy:!0}}),delete a.languages.go["class-name"],function(e){function t(e,t){return"___"+e.toUpperCase()+t+"___"}Object.defineProperties(e.languages["markup-templating"]={},{buildPlaceholders:{value:function(n,r,a,i){if(n.language===r){var o=n.tokenStack=[];n.code=n.code.replace(a,(function(e){if("function"==typeof i&&!i(e))return e;for(var a,l=o.length;-1!==n.code.indexOf(a=t(r,l));)++l;return o[l]=e,a})),n.grammar=e.languages.markup}}},tokenizePlaceholders:{value:function(n,r){if(n.language===r&&n.tokenStack){n.grammar=e.languages[r];var a=0,i=Object.keys(n.tokenStack);!function o(l){for(var s=0;s<l.length&&!(a>=i.length);s++){var c=l[s];if("string"==typeof c||c.content&&"string"==typeof c.content){var u=i[a],d=n.tokenStack[u],p="string"==typeof c?c:c.content,f=t(r,u),m=p.indexOf(f);if(m>-1){++a;var g=p.substring(0,m),h=new e.Token(r,e.tokenize(d,n.grammar),"language-"+r,d),b=p.substring(m+f.length),v=[];g&&v.push.apply(v,o([g])),v.push(h),b&&v.push.apply(v,o([b])),"string"==typeof c?l.splice.apply(l,[s,1].concat(v)):c.content=v}}else c.content&&o(c.content)}return l}(n.tokens)}}}})}(a),function(e){e.languages.handlebars={comment:/\{\{![\s\S]*?\}\}/,delimiter:{pattern:/^\{\{\{?|\}\}\}?$/,alias:"punctuation"},string:/(["'])(?:\\.|(?!\1)[^\\\r\n])*\1/,number:/\b0x[\dA-Fa-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[Ee][+-]?\d+)?/,boolean:/\b(?:false|true)\b/,block:{pattern:/^(\s*(?:~\s*)?)[#\/]\S+?(?=\s*(?:~\s*)?$|\s)/,lookbehind:!0,alias:"keyword"},brackets:{pattern:/\[[^\]]+\]/,inside:{punctuation:/\[|\]/,variable:/[\s\S]+/}},punctuation:/[!"#%&':()*+,.\/;<=>@\[\\\]^`{|}~]/,variable:/[^!"#%&'()*+,\/;<=>@\[\\\]^`{|}~\s]+/},e.hooks.add("before-tokenize",(function(t){e.languages["markup-templating"].buildPlaceholders(t,"handlebars",/\{\{\{[\s\S]+?\}\}\}|\{\{[\s\S]+?\}\}/g)})),e.hooks.add("after-tokenize",(function(t){e.languages["markup-templating"].tokenizePlaceholders(t,"handlebars")})),e.languages.hbs=e.languages.handlebars}(a),a.languages.json={property:{pattern:/(^|[^\\])"(?:\\.|[^\\"\r\n])*"(?=\s*:)/,lookbehind:!0,greedy:!0},string:{pattern:/(^|[^\\])"(?:\\.|[^\\"\r\n])*"(?!\s*:)/,lookbehind:!0,greedy:!0},comment:{pattern:/\/\/.*|\/\*[\s\S]*?(?:\*\/|$)/,greedy:!0},number:/-?\b\d+(?:\.\d+)?(?:e[+-]?\d+)?\b/i,punctuation:/[{}[\],]/,operator:/:/,boolean:/\b(?:false|true)\b/,null:{pattern:/\bnull\b/,alias:"keyword"}},a.languages.webmanifest=a.languages.json,a.languages.less=a.languages.extend("css",{comment:[/\/\*[\s\S]*?\*\//,{pattern:/(^|[^\\])\/\/.*/,lookbehind:!0}],atrule:{pattern:/@[\w-](?:\((?:[^(){}]|\([^(){}]*\))*\)|[^(){};\s]|\s+(?!\s))*?(?=\s*\{)/,inside:{punctuation:/[:()]/}},selector:{pattern:/(?:@\{[\w-]+\}|[^{};\s@])(?:@\{[\w-]+\}|\((?:[^(){}]|\([^(){}]*\))*\)|[^(){};@\s]|\s+(?!\s))*?(?=\s*\{)/,inside:{variable:/@+[\w-]+/}},property:/(?:@\{[\w-]+\}|[\w-])+(?:\+_?)?(?=\s*:)/,operator:/[+\-*\/]/}),a.languages.insertBefore("less","property",{variable:[{pattern:/@[\w-]+\s*:/,inside:{punctuation:/:/}},/@@?[\w-]+/],"mixin-usage":{pattern:/([{;]\s*)[.#](?!\d)[\w-].*?(?=[(;])/,lookbehind:!0,alias:"function"}}),a.languages.makefile={comment:{pattern:/(^|[^\\])#(?:\\(?:\r\n|[\s\S])|[^\\\r\n])*/,lookbehind:!0},string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"builtin-target":{pattern:/\.[A-Z][^:#=\s]+(?=\s*:(?!=))/,alias:"builtin"},target:{pattern:/^(?:[^:=\s]|[ \t]+(?![\s:]))+(?=\s*:(?!=))/m,alias:"symbol",inside:{variable:/\$+(?:(?!\$)[^(){}:#=\s]+|(?=[({]))/}},variable:/\$+(?:(?!\$)[^(){}:#=\s]+|\([@*%<^+?][DF]\)|(?=[({]))/,keyword:/-include\b|\b(?:define|else|endef|endif|export|ifn?def|ifn?eq|include|override|private|sinclude|undefine|unexport|vpath)\b/,function:{pattern:/(\()(?:abspath|addsuffix|and|basename|call|dir|error|eval|file|filter(?:-out)?|findstring|firstword|flavor|foreach|guile|if|info|join|lastword|load|notdir|or|origin|patsubst|realpath|shell|sort|strip|subst|suffix|value|warning|wildcard|word(?:list|s)?)(?=[ \t])/,lookbehind:!0},operator:/(?:::|[?:+!])?=|[|@]/,punctuation:/[:;(){}]/},a.languages.objectivec=a.languages.extend("c",{string:{pattern:/@?"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"/,greedy:!0},keyword:/\b(?:asm|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|in|inline|int|long|register|return|self|short|signed|sizeof|static|struct|super|switch|typedef|typeof|union|unsigned|void|volatile|while)\b|(?:@interface|@end|@implementation|@protocol|@class|@public|@protected|@private|@property|@try|@catch|@finally|@throw|@synthesize|@dynamic|@selector)\b/,operator:/-[->]?|\+\+?|!=?|<<?=?|>>?=?|==?|&&?|\|\|?|[~^%?*\/@]/}),delete a.languages.objectivec["class-name"],a.languages.objc=a.languages.objectivec,a.languages.ocaml={comment:{pattern:/\(\*[\s\S]*?\*\)/,greedy:!0},char:{pattern:/'(?:[^\\\r\n']|\\(?:.|[ox]?[0-9a-f]{1,3}))'/i,greedy:!0},string:[{pattern:/"(?:\\(?:[\s\S]|\r\n)|[^\\\r\n"])*"/,greedy:!0},{pattern:/\{([a-z_]*)\|[\s\S]*?\|\1\}/,greedy:!0}],number:[/\b(?:0b[01][01_]*|0o[0-7][0-7_]*)\b/i,/\b0x[a-f0-9][a-f0-9_]*(?:\.[a-f0-9_]*)?(?:p[+-]?\d[\d_]*)?(?!\w)/i,/\b\d[\d_]*(?:\.[\d_]*)?(?:e[+-]?\d[\d_]*)?(?!\w)/i],directive:{pattern:/\B#\w+/,alias:"property"},label:{pattern:/\B~\w+/,alias:"property"},"type-variable":{pattern:/\B'\w+/,alias:"function"},variant:{pattern:/`\w+/,alias:"symbol"},keyword:/\b(?:as|assert|begin|class|constraint|do|done|downto|else|end|exception|external|for|fun|function|functor|if|in|include|inherit|initializer|lazy|let|match|method|module|mutable|new|nonrec|object|of|open|private|rec|sig|struct|then|to|try|type|val|value|virtual|when|where|while|with)\b/,boolean:/\b(?:false|true)\b/,"operator-like-punctuation":{pattern:/\[[<>|]|[>|]\]|\{<|>\}/,alias:"punctuation"},operator:/\.[.~]|:[=>]|[=<>@^|&+\-*\/$%!?~][!$%&*+\-.\/:<=>?@^|~]*|\b(?:and|asr|land|lor|lsl|lsr|lxor|mod|or)\b/,punctuation:/;;|::|[(){}\[\].,:;#]|\b_\b/},a.languages.python={comment:{pattern:/(^|[^\\])#.*/,lookbehind:!0,greedy:!0},"string-interpolation":{pattern:/(?:f|fr|rf)(?:("""|''')[\s\S]*?\1|("|')(?:\\.|(?!\2)[^\\\r\n])*\2)/i,greedy:!0,inside:{interpolation:{pattern:/((?:^|[^{])(?:\{\{)*)\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}])+\})+\})+\}/,lookbehind:!0,inside:{"format-spec":{pattern:/(:)[^:(){}]+(?=\}$)/,lookbehind:!0},"conversion-option":{pattern:/![sra](?=[:}]$)/,alias:"punctuation"},rest:null}},string:/[\s\S]+/}},"triple-quoted-string":{pattern:/(?:[rub]|br|rb)?("""|''')[\s\S]*?\1/i,greedy:!0,alias:"string"},string:{pattern:/(?:[rub]|br|rb)?("|')(?:\\.|(?!\1)[^\\\r\n])*\1/i,greedy:!0},function:{pattern:/((?:^|\s)def[ \t]+)[a-zA-Z_]\w*(?=\s*\()/g,lookbehind:!0},"class-name":{pattern:/(\bclass\s+)\w+/i,lookbehind:!0},decorator:{pattern:/(^[\t ]*)@\w+(?:\.\w+)*/m,lookbehind:!0,alias:["annotation","punctuation"],inside:{punctuation:/\./}},keyword:/\b(?:_(?=\s*:)|and|as|assert|async|await|break|case|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|match|nonlocal|not|or|pass|print|raise|return|try|while|with|yield)\b/,builtin:/\b(?:__import__|abs|all|any|apply|ascii|basestring|bin|bool|buffer|bytearray|bytes|callable|chr|classmethod|cmp|coerce|compile|complex|delattr|dict|dir|divmod|enumerate|eval|execfile|file|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|intern|isinstance|issubclass|iter|len|list|locals|long|map|max|memoryview|min|next|object|oct|open|ord|pow|property|range|raw_input|reduce|reload|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|unichr|unicode|vars|xrange|zip)\b/,boolean:/\b(?:False|None|True)\b/,number:/\b0(?:b(?:_?[01])+|o(?:_?[0-7])+|x(?:_?[a-f0-9])+)\b|(?:\b\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\B\.\d+(?:_\d+)*)(?:e[+-]?\d+(?:_\d+)*)?j?(?!\w)/i,operator:/[-+%=]=?|!=|:=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]/,punctuation:/[{}[\];(),.:]/},a.languages.python["string-interpolation"].inside.interpolation.inside.rest=a.languages.python,a.languages.py=a.languages.python,a.languages.reason=a.languages.extend("clike",{string:{pattern:/"(?:\\(?:\r\n|[\s\S])|[^\\\r\n"])*"/,greedy:!0},"class-name":/\b[A-Z]\w*/,keyword:/\b(?:and|as|assert|begin|class|constraint|do|done|downto|else|end|exception|external|for|fun|function|functor|if|in|include|inherit|initializer|lazy|let|method|module|mutable|new|nonrec|object|of|open|or|private|rec|sig|struct|switch|then|to|try|type|val|virtual|when|while|with)\b/,operator:/\.{3}|:[:=]|\|>|->|=(?:==?|>)?|<=?|>=?|[|^?'#!~`]|[+\-*\/]\.?|\b(?:asr|land|lor|lsl|lsr|lxor|mod)\b/}),a.languages.insertBefore("reason","class-name",{char:{pattern:/'(?:\\x[\da-f]{2}|\\o[0-3][0-7][0-7]|\\\d{3}|\\.|[^'\\\r\n])'/,greedy:!0},constructor:/\b[A-Z]\w*\b(?!\s*\.)/,label:{pattern:/\b[a-z]\w*(?=::)/,alias:"symbol"}}),delete a.languages.reason.function,function(e){e.languages.sass=e.languages.extend("css",{comment:{pattern:/^([ \t]*)\/[\/*].*(?:(?:\r?\n|\r)\1[ \t].+)*/m,lookbehind:!0,greedy:!0}}),e.languages.insertBefore("sass","atrule",{"atrule-line":{pattern:/^(?:[ \t]*)[@+=].+/m,greedy:!0,inside:{atrule:/(?:@[\w-]+|[+=])/}}}),delete e.languages.sass.atrule;var t=/\$[-\w]+|#\{\$[-\w]+\}/,n=[/[+*\/%]|[=!]=|<=?|>=?|\b(?:and|not|or)\b/,{pattern:/(\s)-(?=\s)/,lookbehind:!0}];e.languages.insertBefore("sass","property",{"variable-line":{pattern:/^[ \t]*\$.+/m,greedy:!0,inside:{punctuation:/:/,variable:t,operator:n}},"property-line":{pattern:/^[ \t]*(?:[^:\s]+ *:.*|:[^:\s].*)/m,greedy:!0,inside:{property:[/[^:\s]+(?=\s*:)/,{pattern:/(:)[^:\s]+/,lookbehind:!0}],punctuation:/:/,variable:t,operator:n,important:e.languages.sass.important}}}),delete e.languages.sass.property,delete e.languages.sass.important,e.languages.insertBefore("sass","punctuation",{selector:{pattern:/^([ \t]*)\S(?:,[^,\r\n]+|[^,\r\n]*)(?:,[^,\r\n]+)*(?:,(?:\r?\n|\r)\1[ \t]+\S(?:,[^,\r\n]+|[^,\r\n]*)(?:,[^,\r\n]+)*)*/m,lookbehind:!0,greedy:!0}})}(a),a.languages.scss=a.languages.extend("css",{comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|\/\/.*)/,lookbehind:!0},atrule:{pattern:/@[\w-](?:\([^()]+\)|[^()\s]|\s+(?!\s))*?(?=\s+[{;])/,inside:{rule:/@[\w-]+/}},url:/(?:[-a-z]+-)?url(?=\()/i,selector:{pattern:/(?=\S)[^@;{}()]?(?:[^@;{}()\s]|\s+(?!\s)|#\{\$[-\w]+\})+(?=\s*\{(?:\}|\s|[^}][^:{}]*[:{][^}]))/,inside:{parent:{pattern:/&/,alias:"important"},placeholder:/%[-\w]+/,variable:/\$[-\w]+|#\{\$[-\w]+\}/}},property:{pattern:/(?:[-\w]|\$[-\w]|#\{\$[-\w]+\})+(?=\s*:)/,inside:{variable:/\$[-\w]+|#\{\$[-\w]+\}/}}}),a.languages.insertBefore("scss","atrule",{keyword:[/@(?:content|debug|each|else(?: if)?|extend|for|forward|function|if|import|include|mixin|return|use|warn|while)\b/i,{pattern:/( )(?:from|through)(?= )/,lookbehind:!0}]}),a.languages.insertBefore("scss","important",{variable:/\$[-\w]+|#\{\$[-\w]+\}/}),a.languages.insertBefore("scss","function",{"module-modifier":{pattern:/\b(?:as|hide|show|with)\b/i,alias:"keyword"},placeholder:{pattern:/%[-\w]+/,alias:"selector"},statement:{pattern:/\B!(?:default|optional)\b/i,alias:"keyword"},boolean:/\b(?:false|true)\b/,null:{pattern:/\bnull\b/,alias:"keyword"},operator:{pattern:/(\s)(?:[-+*\/%]|[=!]=|<=?|>=?|and|not|or)(?=\s)/,lookbehind:!0}}),a.languages.scss.atrule.inside.rest=a.languages.scss,function(e){var t={pattern:/(\b\d+)(?:%|[a-z]+)/,lookbehind:!0},n={pattern:/(^|[^\w.-])-?(?:\d+(?:\.\d+)?|\.\d+)/,lookbehind:!0},r={comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|\/\/.*)/,lookbehind:!0},url:{pattern:/\burl\((["']?).*?\1\)/i,greedy:!0},string:{pattern:/("|')(?:(?!\1)[^\\\r\n]|\\(?:\r\n|[\s\S]))*\1/,greedy:!0},interpolation:null,func:null,important:/\B!(?:important|optional)\b/i,keyword:{pattern:/(^|\s+)(?:(?:else|for|if|return|unless)(?=\s|$)|@[\w-]+)/,lookbehind:!0},hexcode:/#[\da-f]{3,6}/i,color:[/\b(?:AliceBlue|AntiqueWhite|Aqua|Aquamarine|Azure|Beige|Bisque|Black|BlanchedAlmond|Blue|BlueViolet|Brown|BurlyWood|CadetBlue|Chartreuse|Chocolate|Coral|CornflowerBlue|Cornsilk|Crimson|Cyan|DarkBlue|DarkCyan|DarkGoldenRod|DarkGr[ae]y|DarkGreen|DarkKhaki|DarkMagenta|DarkOliveGreen|DarkOrange|DarkOrchid|DarkRed|DarkSalmon|DarkSeaGreen|DarkSlateBlue|DarkSlateGr[ae]y|DarkTurquoise|DarkViolet|DeepPink|DeepSkyBlue|DimGr[ae]y|DodgerBlue|FireBrick|FloralWhite|ForestGreen|Fuchsia|Gainsboro|GhostWhite|Gold|GoldenRod|Gr[ae]y|Green|GreenYellow|HoneyDew|HotPink|IndianRed|Indigo|Ivory|Khaki|Lavender|LavenderBlush|LawnGreen|LemonChiffon|LightBlue|LightCoral|LightCyan|LightGoldenRodYellow|LightGr[ae]y|LightGreen|LightPink|LightSalmon|LightSeaGreen|LightSkyBlue|LightSlateGr[ae]y|LightSteelBlue|LightYellow|Lime|LimeGreen|Linen|Magenta|Maroon|MediumAquaMarine|MediumBlue|MediumOrchid|MediumPurple|MediumSeaGreen|MediumSlateBlue|MediumSpringGreen|MediumTurquoise|MediumVioletRed|MidnightBlue|MintCream|MistyRose|Moccasin|NavajoWhite|Navy|OldLace|Olive|OliveDrab|Orange|OrangeRed|Orchid|PaleGoldenRod|PaleGreen|PaleTurquoise|PaleVioletRed|PapayaWhip|PeachPuff|Peru|Pink|Plum|PowderBlue|Purple|Red|RosyBrown|RoyalBlue|SaddleBrown|Salmon|SandyBrown|SeaGreen|SeaShell|Sienna|Silver|SkyBlue|SlateBlue|SlateGr[ae]y|Snow|SpringGreen|SteelBlue|Tan|Teal|Thistle|Tomato|Transparent|Turquoise|Violet|Wheat|White|WhiteSmoke|Yellow|YellowGreen)\b/i,{pattern:/\b(?:hsl|rgb)\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*\)\B|\b(?:hsl|rgb)a\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*,\s*(?:0|0?\.\d+|1)\s*\)\B/i,inside:{unit:t,number:n,function:/[\w-]+(?=\()/,punctuation:/[(),]/}}],entity:/\\[\da-f]{1,8}/i,unit:t,boolean:/\b(?:false|true)\b/,operator:[/~|[+!\/%<>?=]=?|[-:]=|\*[*=]?|\.{2,3}|&&|\|\||\B-\B|\b(?:and|in|is(?: a| defined| not|nt)?|not|or)\b/],number:n,punctuation:/[{}()\[\];:,]/};r.interpolation={pattern:/\{[^\r\n}:]+\}/,alias:"variable",inside:{delimiter:{pattern:/^\{|\}$/,alias:"punctuation"},rest:r}},r.func={pattern:/[\w-]+\([^)]*\).*/,inside:{function:/^[^(]+/,rest:r}},e.languages.stylus={"atrule-declaration":{pattern:/(^[ \t]*)@.+/m,lookbehind:!0,inside:{atrule:/^@[\w-]+/,rest:r}},"variable-declaration":{pattern:/(^[ \t]*)[\w$-]+\s*.?=[ \t]*(?:\{[^{}]*\}|\S.*|$)/m,lookbehind:!0,inside:{variable:/^\S+/,rest:r}},statement:{pattern:/(^[ \t]*)(?:else|for|if|return|unless)[ \t].+/m,lookbehind:!0,inside:{keyword:/^\S+/,rest:r}},"property-declaration":{pattern:/((?:^|\{)([ \t]*))(?:[\w-]|\{[^}\r\n]+\})+(?:\s*:\s*|[ \t]+)(?!\s)[^{\r\n]*(?:;|[^{\r\n,]$(?!(?:\r?\n|\r)(?:\{|\2[ \t])))/m,lookbehind:!0,inside:{property:{pattern:/^[^\s:]+/,inside:{interpolation:r.interpolation}},rest:r}},selector:{pattern:/(^[ \t]*)(?:(?=\S)(?:[^{}\r\n:()]|::?[\w-]+(?:\([^)\r\n]*\)|(?![\w-]))|\{[^}\r\n]+\})+)(?:(?:\r?\n|\r)(?:\1(?:(?=\S)(?:[^{}\r\n:()]|::?[\w-]+(?:\([^)\r\n]*\)|(?![\w-]))|\{[^}\r\n]+\})+)))*(?:,$|\{|(?=(?:\r?\n|\r)(?:\{|\1[ \t])))/m,lookbehind:!0,inside:{interpolation:r.interpolation,comment:r.comment,punctuation:/[{},]/}},func:r.func,string:r.string,comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|\/\/.*)/,lookbehind:!0,greedy:!0},interpolation:r.interpolation,punctuation:/[{}()\[\];:.]/}}(a),function(e){var t=e.util.clone(e.languages.typescript);e.languages.tsx=e.languages.extend("jsx",t),delete e.languages.tsx.parameter,delete e.languages.tsx["literal-property"];var n=e.languages.tsx.tag;n.pattern=RegExp(/(^|[^\w$]|(?=<\/))/.source+"(?:"+n.pattern.source+")",n.pattern.flags),n.lookbehind=!0}(a),a.languages.wasm={comment:[/\(;[\s\S]*?;\)/,{pattern:/;;.*/,greedy:!0}],string:{pattern:/"(?:\\[\s\S]|[^"\\])*"/,greedy:!0},keyword:[{pattern:/\b(?:align|offset)=/,inside:{operator:/=/}},{pattern:/\b(?:(?:f32|f64|i32|i64)(?:\.(?:abs|add|and|ceil|clz|const|convert_[su]\/i(?:32|64)|copysign|ctz|demote\/f64|div(?:_[su])?|eqz?|extend_[su]\/i32|floor|ge(?:_[su])?|gt(?:_[su])?|le(?:_[su])?|load(?:(?:8|16|32)_[su])?|lt(?:_[su])?|max|min|mul|neg?|nearest|or|popcnt|promote\/f32|reinterpret\/[fi](?:32|64)|rem_[su]|rot[lr]|shl|shr_[su]|sqrt|store(?:8|16|32)?|sub|trunc(?:_[su]\/f(?:32|64))?|wrap\/i64|xor))?|memory\.(?:grow|size))\b/,inside:{punctuation:/\./}},/\b(?:anyfunc|block|br(?:_if|_table)?|call(?:_indirect)?|data|drop|elem|else|end|export|func|get_(?:global|local)|global|if|import|local|loop|memory|module|mut|nop|offset|param|result|return|select|set_(?:global|local)|start|table|tee_local|then|type|unreachable)\b/],variable:/\$[\w!#$%&'*+\-./:<=>?@\\^`|~]+/,number:/[+-]?\b(?:\d(?:_?\d)*(?:\.\d(?:_?\d)*)?(?:[eE][+-]?\d(?:_?\d)*)?|0x[\da-fA-F](?:_?[\da-fA-F])*(?:\.[\da-fA-F](?:_?[\da-fA-D])*)?(?:[pP][+-]?\d(?:_?\d)*)?)\b|\binf\b|\bnan(?::0x[\da-fA-F](?:_?[\da-fA-D])*)?\b/,punctuation:/[()]/};const i=a},5538:()=>{!function(e){var t={pattern:/((?:^|[^\\$])(?:\\{2})*)\$(?:\w+|\{[^{}]*\})/,lookbehind:!0,inside:{"interpolation-punctuation":{pattern:/^\$\{?|\}$/,alias:"punctuation"},expression:{pattern:/[\s\S]+/,inside:null}}};e.languages.groovy=e.languages.extend("clike",{string:{pattern:/'''(?:[^\\]|\\[\s\S])*?'''|'(?:\\.|[^\\'\r\n])*'/,greedy:!0},keyword:/\b(?:abstract|as|assert|boolean|break|byte|case|catch|char|class|const|continue|def|default|do|double|else|enum|extends|final|finally|float|for|goto|if|implements|import|in|instanceof|int|interface|long|native|new|package|private|protected|public|return|short|static|strictfp|super|switch|synchronized|this|throw|throws|trait|transient|try|void|volatile|while)\b/,number:/\b(?:0b[01_]+|0x[\da-f_]+(?:\.[\da-f_p\-]+)?|[\d_]+(?:\.[\d_]+)?(?:e[+-]?\d+)?)[glidf]?\b/i,operator:{pattern:/(^|[^.])(?:~|==?~?|\?[.:]?|\*(?:[.=]|\*=?)?|\.[@&]|\.\.<|\.\.(?!\.)|-[-=>]?|\+[+=]?|!=?|<(?:<=?|=>?)?|>(?:>>?=?|=)?|&[&=]?|\|[|=]?|\/=?|\^=?|%=?)/,lookbehind:!0},punctuation:/\.+|[{}[\];(),:$]/}),e.languages.insertBefore("groovy","string",{shebang:{pattern:/#!.+/,alias:"comment",greedy:!0},"interpolation-string":{pattern:/"""(?:[^\\]|\\[\s\S])*?"""|(["/])(?:\\.|(?!\1)[^\\\r\n])*\1|\$\/(?:[^/$]|\$(?:[/$]|(?![/$]))|\/(?!\$))*\/\$/,greedy:!0,inside:{interpolation:t,string:/[\s\S]+/}}}),e.languages.insertBefore("groovy","punctuation",{"spock-block":/\b(?:and|cleanup|expect|given|setup|then|when|where):/}),e.languages.insertBefore("groovy","function",{annotation:{pattern:/(^|[^.])@\w+/,lookbehind:!0,alias:"punctuation"}}),t.inside.expression.inside=e.languages.groovy}(Prism)},6976:()=>{!function(e){var t=/\b(?:abstract|assert|boolean|break|byte|case|catch|char|class|const|continue|default|do|double|else|enum|exports|extends|final|finally|float|for|goto|if|implements|import|instanceof|int|interface|long|module|native|new|non-sealed|null|open|opens|package|permits|private|protected|provides|public|record(?!\s*[(){}[\]<>=%~.:,;?+\-*/&|^])|requires|return|sealed|short|static|strictfp|super|switch|synchronized|this|throw|throws|to|transient|transitive|try|uses|var|void|volatile|while|with|yield)\b/,n=/(?:[a-z]\w*\s*\.\s*)*(?:[A-Z]\w*\s*\.\s*)*/.source,r={pattern:RegExp(/(^|[^\w.])/.source+n+/[A-Z](?:[\d_A-Z]*[a-z]\w*)?\b/.source),lookbehind:!0,inside:{namespace:{pattern:/^[a-z]\w*(?:\s*\.\s*[a-z]\w*)*(?:\s*\.)?/,inside:{punctuation:/\./}},punctuation:/\./}};e.languages.java=e.languages.extend("clike",{string:{pattern:/(^|[^\\])"(?:\\.|[^"\\\r\n])*"/,lookbehind:!0,greedy:!0},"class-name":[r,{pattern:RegExp(/(^|[^\w.])/.source+n+/[A-Z]\w*(?=\s+\w+\s*[;,=()]|\s*(?:\[[\s,]*\]\s*)?::\s*new\b)/.source),lookbehind:!0,inside:r.inside},{pattern:RegExp(/(\b(?:class|enum|extends|implements|instanceof|interface|new|record|throws)\s+)/.source+n+/[A-Z]\w*\b/.source),lookbehind:!0,inside:r.inside}],keyword:t,function:[e.languages.clike.function,{pattern:/(::\s*)[a-z_]\w*/,lookbehind:!0}],number:/\b0b[01][01_]*L?\b|\b0x(?:\.[\da-f_p+-]+|[\da-f_]+(?:\.[\da-f_p+-]+)?)\b|(?:\b\d[\d_]*(?:\.[\d_]*)?|\B\.\d[\d_]*)(?:e[+-]?\d[\d_]*)?[dfl]?/i,operator:{pattern:/(^|[^.])(?:<<=?|>>>?=?|->|--|\+\+|&&|\|\||::|[?:~]|[-+*/%&|^!=<>]=?)/m,lookbehind:!0},constant:/\b[A-Z][A-Z_\d]+\b/}),e.languages.insertBefore("java","string",{"triple-quoted-string":{pattern:/"""[ \t]*[\r\n](?:(?:"|"")?(?:\\.|[^"\\]))*"""/,greedy:!0,alias:"string"},char:{pattern:/'(?:\\.|[^'\\\r\n]){1,6}'/,greedy:!0}}),e.languages.insertBefore("java","class-name",{annotation:{pattern:/(^|[^.])@\w+(?:\s*\.\s*\w+)*/,lookbehind:!0,alias:"punctuation"},generics:{pattern:/<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&))*>)*>)*>)*>/,inside:{"class-name":r,keyword:t,punctuation:/[<>(),.:]/,operator:/[?&|]/}},import:[{pattern:RegExp(/(\bimport\s+)/.source+n+/(?:[A-Z]\w*|\*)(?=\s*;)/.source),lookbehind:!0,inside:{namespace:r.inside.namespace,punctuation:/\./,operator:/\*/,"class-name":/\w+/}},{pattern:RegExp(/(\bimport\s+static\s+)/.source+n+/(?:\w+|\*)(?=\s*;)/.source),lookbehind:!0,alias:"static",inside:{namespace:r.inside.namespace,static:/\b\w+$/,punctuation:/\./,operator:/\*/,"class-name":/\w+/}}],namespace:{pattern:RegExp(/(\b(?:exports|import(?:\s+static)?|module|open|opens|package|provides|requires|to|transitive|uses|with)\s+)(?!<keyword>)[a-z]\w*(?:\.[a-z]\w*)*\.?/.source.replace(/<keyword>/g,(function(){return t.source}))),lookbehind:!0,inside:{punctuation:/\./}}})}(Prism)},9913:()=>{!function(e){e.languages.kotlin=e.languages.extend("clike",{keyword:{pattern:/(^|[^.])\b(?:abstract|actual|annotation|as|break|by|catch|class|companion|const|constructor|continue|crossinline|data|do|dynamic|else|enum|expect|external|final|finally|for|fun|get|if|import|in|infix|init|inline|inner|interface|internal|is|lateinit|noinline|null|object|open|operator|out|override|package|private|protected|public|reified|return|sealed|set|super|suspend|tailrec|this|throw|to|try|typealias|val|var|vararg|when|where|while)\b/,lookbehind:!0},function:[{pattern:/(?:`[^\r\n`]+`|\b\w+)(?=\s*\()/,greedy:!0},{pattern:/(\.)(?:`[^\r\n`]+`|\w+)(?=\s*\{)/,lookbehind:!0,greedy:!0}],number:/\b(?:0[xX][\da-fA-F]+(?:_[\da-fA-F]+)*|0[bB][01]+(?:_[01]+)*|\d+(?:_\d+)*(?:\.\d+(?:_\d+)*)?(?:[eE][+-]?\d+(?:_\d+)*)?[fFL]?)\b/,operator:/\+[+=]?|-[-=>]?|==?=?|!(?:!|==?)?|[\/*%<>]=?|[?:]:?|\.\.|&&|\|\||\b(?:and|inv|or|shl|shr|ushr|xor)\b/}),delete e.languages.kotlin["class-name"];var t={"interpolation-punctuation":{pattern:/^\$\{?|\}$/,alias:"punctuation"},expression:{pattern:/[\s\S]+/,inside:e.languages.kotlin}};e.languages.insertBefore("kotlin","string",{"string-literal":[{pattern:/"""(?:[^$]|\$(?:(?!\{)|\{[^{}]*\}))*?"""/,alias:"multiline",inside:{interpolation:{pattern:/\$(?:[a-z_]\w*|\{[^{}]*\})/i,inside:t},string:/[\s\S]+/}},{pattern:/"(?:[^"\\\r\n$]|\\.|\$(?:(?!\{)|\{[^{}]*\}))*"/,alias:"singleline",inside:{interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\$(?:[a-z_]\w*|\{[^{}]*\})/i,lookbehind:!0,inside:t},string:/[\s\S]+/}}],char:{pattern:/'(?:[^'\\\r\n]|\\(?:.|u[a-fA-F0-9]{0,4}))'/,greedy:!0}}),delete e.languages.kotlin.string,e.languages.insertBefore("kotlin","keyword",{annotation:{pattern:/\B@(?:\w+:)?(?:[A-Z]\w*|\[[^\]]+\])/,alias:"builtin"}}),e.languages.insertBefore("kotlin","function",{label:{pattern:/\b\w+@|@\w+\b/,alias:"symbol"}}),e.languages.kt=e.languages.kotlin,e.languages.kts=e.languages.kotlin}(Prism)},132:()=>{!function(e){var t=/(?:[\w-]+|'[^'\n\r]*'|"(?:\\.|[^\\"\r\n])*")/.source;function n(e){return e.replace(/__/g,(function(){return t}))}e.languages.toml={comment:{pattern:/#.*/,greedy:!0},table:{pattern:RegExp(n(/(^[\t ]*\[\s*(?:\[\s*)?)__(?:\s*\.\s*__)*(?=\s*\])/.source),"m"),lookbehind:!0,greedy:!0,alias:"class-name"},key:{pattern:RegExp(n(/(^[\t ]*|[{,]\s*)__(?:\s*\.\s*__)*(?=\s*=)/.source),"m"),lookbehind:!0,greedy:!0,alias:"property"},string:{pattern:/"""(?:\\[\s\S]|[^\\])*?"""|'''[\s\S]*?'''|'[^'\n\r]*'|"(?:\\.|[^\\"\r\n])*"/,greedy:!0},date:[{pattern:/\b\d{4}-\d{2}-\d{2}(?:[T\s]\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})?)?\b/i,alias:"number"},{pattern:/\b\d{2}:\d{2}:\d{2}(?:\.\d+)?\b/,alias:"number"}],number:/(?:\b0(?:x[\da-zA-Z]+(?:_[\da-zA-Z]+)*|o[0-7]+(?:_[0-7]+)*|b[10]+(?:_[10]+)*))\b|[-+]?\b\d+(?:_\d+)*(?:\.\d+(?:_\d+)*)?(?:[eE][+-]?\d+(?:_\d+)*)?\b|[-+]?\b(?:inf|nan)\b/,boolean:/\b(?:false|true)\b/,punctuation:/[.,=[\]{}]/}}(Prism)},4176:(e,t,n)=>{var r={"./prism-groovy":5538,"./prism-java":6976,"./prism-kotlin":9913,"./prism-toml":132};function a(e){var t=i(e);return n(t)}function i(e){if(!n.o(r,e)){var t=new Error("Cannot find module '"+e+"'");throw t.code="MODULE_NOT_FOUND",t}return r[e]}a.keys=function(){return Object.keys(r)},a.resolve=i,e.exports=a,a.id=4176},2694:(e,t,n)=>{"use strict";var r=n(6925);function a(){}function i(){}i.resetWarningCache=a,e.exports=function(){function e(e,t,n,a,i,o){if(o!==r){var l=new Error("Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types");throw l.name="Invariant Violation",l}}function t(){return e}e.isRequired=e;var n={array:e,bigint:e,bool:e,func:e,number:e,object:e,string:e,symbol:e,any:e,arrayOf:t,element:e,elementType:e,instanceOf:t,node:e,objectOf:t,oneOf:t,oneOfType:t,shape:t,exact:t,checkPropTypes:i,resetWarningCache:a};return n.PropTypes=n,n}},5556:(e,t,n)=>{e.exports=n(2694)()},6925:e=>{"use strict";e.exports="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"},2551:(e,t,n)=>{"use strict";var r=n(6540),a=n(5228),i=n(9982);function o(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n<arguments.length;n++)t+="&args[]="+encodeURIComponent(arguments[n]);return"Minified React error #"+e+"; visit "+t+" for the full message or use the non-minified dev environment for full errors and additional helpful warnings."}if(!r)throw Error(o(227));function l(e,t,n,r,a,i,o,l,s){var c=Array.prototype.slice.call(arguments,3);try{t.apply(n,c)}catch(u){this.onError(u)}}var s=!1,c=null,u=!1,d=null,p={onError:function(e){s=!0,c=e}};function f(e,t,n,r,a,i,o,u,d){s=!1,c=null,l.apply(p,arguments)}var m=null,g=null,h=null;function b(e,t,n){var r=e.type||"unknown-event";e.currentTarget=h(n),function(e,t,n,r,a,i,l,p,m){if(f.apply(this,arguments),s){if(!s)throw Error(o(198));var g=c;s=!1,c=null,u||(u=!0,d=g)}}(r,t,void 0,e),e.currentTarget=null}var v=null,y={};function w(){if(v)for(var e in y){var t=y[e],n=v.indexOf(e);if(!(-1<n))throw Error(o(96,e));if(!k[n]){if(!t.extractEvents)throw Error(o(97,e));for(var r in k[n]=t,n=t.eventTypes){var a=void 0,i=n[r],l=t,s=r;if(E.hasOwnProperty(s))throw Error(o(99,s));E[s]=i;var c=i.phasedRegistrationNames;if(c){for(a in c)c.hasOwnProperty(a)&&x(c[a],l,s);a=!0}else i.registrationName?(x(i.registrationName,l,s),a=!0):a=!1;if(!a)throw Error(o(98,r,e))}}}}function x(e,t,n){if(S[e])throw Error(o(100,e));S[e]=t,T[e]=t.eventTypes[n].dependencies}var k=[],E={},S={},T={};function _(e){var t,n=!1;for(t in e)if(e.hasOwnProperty(t)){var r=e[t];if(!y.hasOwnProperty(t)||y[t]!==r){if(y[t])throw Error(o(102,t));y[t]=r,n=!0}}n&&w()}var A=!("undefined"==typeof window||void 0===window.document||void 0===window.document.createElement),C=null,P=null,N=null;function O(e){if(e=g(e)){if("function"!=typeof C)throw Error(o(280));var t=e.stateNode;t&&(t=m(t),C(e.stateNode,e.type,t))}}function I(e){P?N?N.push(e):N=[e]:P=e}function R(){if(P){var e=P,t=N;if(N=P=null,O(e),t)for(e=0;e<t.length;e++)O(t[e])}}function D(e,t){return e(t)}function L(e,t,n,r,a){return e(t,n,r,a)}function M(){}var F=D,B=!1,$=!1;function z(){null===P&&null===N||(M(),R())}function U(e,t,n){if($)return e(t,n);$=!0;try{return F(e,t,n)}finally{$=!1,z()}}var j=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,H=Object.prototype.hasOwnProperty,W={},V={};function G(e,t,n,r,a,i){this.acceptsBooleans=2===t||3===t||4===t,this.attributeName=r,this.attributeNamespace=a,this.mustUseProperty=n,this.propertyName=e,this.type=t,this.sanitizeURL=i}var q={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach((function(e){q[e]=new G(e,0,!1,e,null,!1)})),[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach((function(e){var t=e[0];q[t]=new G(t,1,!1,e[1],null,!1)})),["contentEditable","draggable","spellCheck","value"].forEach((function(e){q[e]=new G(e,2,!1,e.toLowerCase(),null,!1)})),["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach((function(e){q[e]=new G(e,2,!1,e,null,!1)})),"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach((function(e){q[e]=new G(e,3,!1,e.toLowerCase(),null,!1)})),["checked","multiple","muted","selected"].forEach((function(e){q[e]=new G(e,3,!0,e,null,!1)})),["capture","download"].forEach((function(e){q[e]=new G(e,4,!1,e,null,!1)})),["cols","rows","size","span"].forEach((function(e){q[e]=new G(e,6,!1,e,null,!1)})),["rowSpan","start"].forEach((function(e){q[e]=new G(e,5,!1,e.toLowerCase(),null,!1)}));var K=/[\-:]([a-z])/g;function Y(e){return e[1].toUpperCase()}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach((function(e){var t=e.replace(K,Y);q[t]=new G(t,1,!1,e,null,!1)})),"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach((function(e){var t=e.replace(K,Y);q[t]=new G(t,1,!1,e,"http://www.w3.org/1999/xlink",!1)})),["xml:base","xml:lang","xml:space"].forEach((function(e){var t=e.replace(K,Y);q[t]=new G(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1)})),["tabIndex","crossOrigin"].forEach((function(e){q[e]=new G(e,1,!1,e.toLowerCase(),null,!1)})),q.xlinkHref=new G("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0),["src","href","action","formAction"].forEach((function(e){q[e]=new G(e,1,!1,e.toLowerCase(),null,!0)}));var Q=r.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;function Z(e,t,n,r){var a=q.hasOwnProperty(t)?q[t]:null;(null!==a?0===a.type:!r&&(2<t.length&&("o"===t[0]||"O"===t[0])&&("n"===t[1]||"N"===t[1])))||(function(e,t,n,r){if(null==t||function(e,t,n,r){if(null!==n&&0===n.type)return!1;switch(typeof t){case"function":case"symbol":return!0;case"boolean":return!r&&(null!==n?!n.acceptsBooleans:"data-"!==(e=e.toLowerCase().slice(0,5))&&"aria-"!==e);default:return!1}}(e,t,n,r))return!0;if(r)return!1;if(null!==n)switch(n.type){case 3:return!t;case 4:return!1===t;case 5:return isNaN(t);case 6:return isNaN(t)||1>t}return!1}(t,n,a,r)&&(n=null),r||null===a?function(e){return!!H.call(V,e)||!H.call(W,e)&&(j.test(e)?V[e]=!0:(W[e]=!0,!1))}(t)&&(null===n?e.removeAttribute(t):e.setAttribute(t,""+n)):a.mustUseProperty?e[a.propertyName]=null===n?3!==a.type&&"":n:(t=a.attributeName,r=a.attributeNamespace,null===n?e.removeAttribute(t):(n=3===(a=a.type)||4===a&&!0===n?"":""+n,r?e.setAttributeNS(r,t,n):e.setAttribute(t,n))))}Q.hasOwnProperty("ReactCurrentDispatcher")||(Q.ReactCurrentDispatcher={current:null}),Q.hasOwnProperty("ReactCurrentBatchConfig")||(Q.ReactCurrentBatchConfig={suspense:null});var X=/^(.*)[\\\/]/,J="function"==typeof Symbol&&Symbol.for,ee=J?Symbol.for("react.element"):60103,te=J?Symbol.for("react.portal"):60106,ne=J?Symbol.for("react.fragment"):60107,re=J?Symbol.for("react.strict_mode"):60108,ae=J?Symbol.for("react.profiler"):60114,ie=J?Symbol.for("react.provider"):60109,oe=J?Symbol.for("react.context"):60110,le=J?Symbol.for("react.concurrent_mode"):60111,se=J?Symbol.for("react.forward_ref"):60112,ce=J?Symbol.for("react.suspense"):60113,ue=J?Symbol.for("react.suspense_list"):60120,de=J?Symbol.for("react.memo"):60115,pe=J?Symbol.for("react.lazy"):60116,fe=J?Symbol.for("react.block"):60121,me="function"==typeof Symbol&&Symbol.iterator;function ge(e){return null===e||"object"!=typeof e?null:"function"==typeof(e=me&&e[me]||e["@@iterator"])?e:null}function he(e){if(null==e)return null;if("function"==typeof e)return e.displayName||e.name||null;if("string"==typeof e)return e;switch(e){case ne:return"Fragment";case te:return"Portal";case ae:return"Profiler";case re:return"StrictMode";case ce:return"Suspense";case ue:return"SuspenseList"}if("object"==typeof e)switch(e.$$typeof){case oe:return"Context.Consumer";case ie:return"Context.Provider";case se:var t=e.render;return t=t.displayName||t.name||"",e.displayName||(""!==t?"ForwardRef("+t+")":"ForwardRef");case de:return he(e.type);case fe:return he(e.render);case pe:if(e=1===e._status?e._result:null)return he(e)}return null}function be(e){var t="";do{e:switch(e.tag){case 3:case 4:case 6:case 7:case 10:case 9:var n="";break e;default:var r=e._debugOwner,a=e._debugSource,i=he(e.type);n=null,r&&(n=he(r.type)),r=i,i="",a?i=" (at "+a.fileName.replace(X,"")+":"+a.lineNumber+")":n&&(i=" (created by "+n+")"),n="\n in "+(r||"Unknown")+i}t+=n,e=e.return}while(e);return t}function ve(e){switch(typeof e){case"boolean":case"number":case"object":case"string":case"undefined":return e;default:return""}}function ye(e){var t=e.type;return(e=e.nodeName)&&"input"===e.toLowerCase()&&("checkbox"===t||"radio"===t)}function we(e){e._valueTracker||(e._valueTracker=function(e){var t=ye(e)?"checked":"value",n=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),r=""+e[t];if(!e.hasOwnProperty(t)&&void 0!==n&&"function"==typeof n.get&&"function"==typeof n.set){var a=n.get,i=n.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return a.call(this)},set:function(e){r=""+e,i.call(this,e)}}),Object.defineProperty(e,t,{enumerable:n.enumerable}),{getValue:function(){return r},setValue:function(e){r=""+e},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}(e))}function xe(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var n=t.getValue(),r="";return e&&(r=ye(e)?e.checked?"true":"false":e.value),(e=r)!==n&&(t.setValue(e),!0)}function ke(e,t){var n=t.checked;return a({},t,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:null!=n?n:e._wrapperState.initialChecked})}function Ee(e,t){var n=null==t.defaultValue?"":t.defaultValue,r=null!=t.checked?t.checked:t.defaultChecked;n=ve(null!=t.value?t.value:n),e._wrapperState={initialChecked:r,initialValue:n,controlled:"checkbox"===t.type||"radio"===t.type?null!=t.checked:null!=t.value}}function Se(e,t){null!=(t=t.checked)&&Z(e,"checked",t,!1)}function Te(e,t){Se(e,t);var n=ve(t.value),r=t.type;if(null!=n)"number"===r?(0===n&&""===e.value||e.value!=n)&&(e.value=""+n):e.value!==""+n&&(e.value=""+n);else if("submit"===r||"reset"===r)return void e.removeAttribute("value");t.hasOwnProperty("value")?Ae(e,t.type,n):t.hasOwnProperty("defaultValue")&&Ae(e,t.type,ve(t.defaultValue)),null==t.checked&&null!=t.defaultChecked&&(e.defaultChecked=!!t.defaultChecked)}function _e(e,t,n){if(t.hasOwnProperty("value")||t.hasOwnProperty("defaultValue")){var r=t.type;if(!("submit"!==r&&"reset"!==r||void 0!==t.value&&null!==t.value))return;t=""+e._wrapperState.initialValue,n||t===e.value||(e.value=t),e.defaultValue=t}""!==(n=e.name)&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,""!==n&&(e.name=n)}function Ae(e,t,n){"number"===t&&e.ownerDocument.activeElement===e||(null==n?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+n&&(e.defaultValue=""+n))}function Ce(e,t){return e=a({children:void 0},t),(t=function(e){var t="";return r.Children.forEach(e,(function(e){null!=e&&(t+=e)})),t}(t.children))&&(e.children=t),e}function Pe(e,t,n,r){if(e=e.options,t){t={};for(var a=0;a<n.length;a++)t["$"+n[a]]=!0;for(n=0;n<e.length;n++)a=t.hasOwnProperty("$"+e[n].value),e[n].selected!==a&&(e[n].selected=a),a&&r&&(e[n].defaultSelected=!0)}else{for(n=""+ve(n),t=null,a=0;a<e.length;a++){if(e[a].value===n)return e[a].selected=!0,void(r&&(e[a].defaultSelected=!0));null!==t||e[a].disabled||(t=e[a])}null!==t&&(t.selected=!0)}}function Ne(e,t){if(null!=t.dangerouslySetInnerHTML)throw Error(o(91));return a({},t,{value:void 0,defaultValue:void 0,children:""+e._wrapperState.initialValue})}function Oe(e,t){var n=t.value;if(null==n){if(n=t.children,t=t.defaultValue,null!=n){if(null!=t)throw Error(o(92));if(Array.isArray(n)){if(!(1>=n.length))throw Error(o(93));n=n[0]}t=n}null==t&&(t=""),n=t}e._wrapperState={initialValue:ve(n)}}function Ie(e,t){var n=ve(t.value),r=ve(t.defaultValue);null!=n&&((n=""+n)!==e.value&&(e.value=n),null==t.defaultValue&&e.defaultValue!==n&&(e.defaultValue=n)),null!=r&&(e.defaultValue=""+r)}function Re(e){var t=e.textContent;t===e._wrapperState.initialValue&&""!==t&&null!==t&&(e.value=t)}var De="http://www.w3.org/1999/xhtml",Le="http://www.w3.org/2000/svg";function Me(e){switch(e){case"svg":return"http://www.w3.org/2000/svg";case"math":return"http://www.w3.org/1998/Math/MathML";default:return"http://www.w3.org/1999/xhtml"}}function Fe(e,t){return null==e||"http://www.w3.org/1999/xhtml"===e?Me(t):"http://www.w3.org/2000/svg"===e&&"foreignObject"===t?"http://www.w3.org/1999/xhtml":e}var Be,$e,ze=($e=function(e,t){if(e.namespaceURI!==Le||"innerHTML"in e)e.innerHTML=t;else{for((Be=Be||document.createElement("div")).innerHTML="<svg>"+t.valueOf().toString()+"</svg>",t=Be.firstChild;e.firstChild;)e.removeChild(e.firstChild);for(;t.firstChild;)e.appendChild(t.firstChild)}},"undefined"!=typeof MSApp&&MSApp.execUnsafeLocalFunction?function(e,t,n,r){MSApp.execUnsafeLocalFunction((function(){return $e(e,t)}))}:$e);function Ue(e,t){if(t){var n=e.firstChild;if(n&&n===e.lastChild&&3===n.nodeType)return void(n.nodeValue=t)}e.textContent=t}function je(e,t){var n={};return n[e.toLowerCase()]=t.toLowerCase(),n["Webkit"+e]="webkit"+t,n["Moz"+e]="moz"+t,n}var He={animationend:je("Animation","AnimationEnd"),animationiteration:je("Animation","AnimationIteration"),animationstart:je("Animation","AnimationStart"),transitionend:je("Transition","TransitionEnd")},We={},Ve={};function Ge(e){if(We[e])return We[e];if(!He[e])return e;var t,n=He[e];for(t in n)if(n.hasOwnProperty(t)&&t in Ve)return We[e]=n[t];return e}A&&(Ve=document.createElement("div").style,"AnimationEvent"in window||(delete He.animationend.animation,delete He.animationiteration.animation,delete He.animationstart.animation),"TransitionEvent"in window||delete He.transitionend.transition);var qe=Ge("animationend"),Ke=Ge("animationiteration"),Ye=Ge("animationstart"),Qe=Ge("transitionend"),Ze="abort canplay canplaythrough durationchange emptied encrypted ended error loadeddata loadedmetadata loadstart pause play playing progress ratechange seeked seeking stalled suspend timeupdate volumechange waiting".split(" "),Xe=new("function"==typeof WeakMap?WeakMap:Map);function Je(e){var t=Xe.get(e);return void 0===t&&(t=new Map,Xe.set(e,t)),t}function et(e){var t=e,n=e;if(e.alternate)for(;t.return;)t=t.return;else{e=t;do{!!(1026&(t=e).effectTag)&&(n=t.return),e=t.return}while(e)}return 3===t.tag?n:null}function tt(e){if(13===e.tag){var t=e.memoizedState;if(null===t&&(null!==(e=e.alternate)&&(t=e.memoizedState)),null!==t)return t.dehydrated}return null}function nt(e){if(et(e)!==e)throw Error(o(188))}function rt(e){if(e=function(e){var t=e.alternate;if(!t){if(null===(t=et(e)))throw Error(o(188));return t!==e?null:e}for(var n=e,r=t;;){var a=n.return;if(null===a)break;var i=a.alternate;if(null===i){if(null!==(r=a.return)){n=r;continue}break}if(a.child===i.child){for(i=a.child;i;){if(i===n)return nt(a),e;if(i===r)return nt(a),t;i=i.sibling}throw Error(o(188))}if(n.return!==r.return)n=a,r=i;else{for(var l=!1,s=a.child;s;){if(s===n){l=!0,n=a,r=i;break}if(s===r){l=!0,r=a,n=i;break}s=s.sibling}if(!l){for(s=i.child;s;){if(s===n){l=!0,n=i,r=a;break}if(s===r){l=!0,r=i,n=a;break}s=s.sibling}if(!l)throw Error(o(189))}}if(n.alternate!==r)throw Error(o(190))}if(3!==n.tag)throw Error(o(188));return n.stateNode.current===n?e:t}(e),!e)return null;for(var t=e;;){if(5===t.tag||6===t.tag)return t;if(t.child)t.child.return=t,t=t.child;else{if(t===e)break;for(;!t.sibling;){if(!t.return||t.return===e)return null;t=t.return}t.sibling.return=t.return,t=t.sibling}}return null}function at(e,t){if(null==t)throw Error(o(30));return null==e?t:Array.isArray(e)?Array.isArray(t)?(e.push.apply(e,t),e):(e.push(t),e):Array.isArray(t)?[e].concat(t):[e,t]}function it(e,t,n){Array.isArray(e)?e.forEach(t,n):e&&t.call(n,e)}var ot=null;function lt(e){if(e){var t=e._dispatchListeners,n=e._dispatchInstances;if(Array.isArray(t))for(var r=0;r<t.length&&!e.isPropagationStopped();r++)b(e,t[r],n[r]);else t&&b(e,t,n);e._dispatchListeners=null,e._dispatchInstances=null,e.isPersistent()||e.constructor.release(e)}}function st(e){if(null!==e&&(ot=at(ot,e)),e=ot,ot=null,e){if(it(e,lt),ot)throw Error(o(95));if(u)throw e=d,u=!1,d=null,e}}function ct(e){return(e=e.target||e.srcElement||window).correspondingUseElement&&(e=e.correspondingUseElement),3===e.nodeType?e.parentNode:e}function ut(e){if(!A)return!1;var t=(e="on"+e)in document;return t||((t=document.createElement("div")).setAttribute(e,"return;"),t="function"==typeof t[e]),t}var dt=[];function pt(e){e.topLevelType=null,e.nativeEvent=null,e.targetInst=null,e.ancestors.length=0,10>dt.length&&dt.push(e)}function ft(e,t,n,r){if(dt.length){var a=dt.pop();return a.topLevelType=e,a.eventSystemFlags=r,a.nativeEvent=t,a.targetInst=n,a}return{topLevelType:e,eventSystemFlags:r,nativeEvent:t,targetInst:n,ancestors:[]}}function mt(e){var t=e.targetInst,n=t;do{if(!n){e.ancestors.push(n);break}var r=n;if(3===r.tag)r=r.stateNode.containerInfo;else{for(;r.return;)r=r.return;r=3!==r.tag?null:r.stateNode.containerInfo}if(!r)break;5!==(t=n.tag)&&6!==t||e.ancestors.push(n),n=Rn(r)}while(n);for(n=0;n<e.ancestors.length;n++){t=e.ancestors[n];var a=ct(e.nativeEvent);r=e.topLevelType;var i=e.nativeEvent,o=e.eventSystemFlags;0===n&&(o|=64);for(var l=null,s=0;s<k.length;s++){var c=k[s];c&&(c=c.extractEvents(r,t,i,a,o))&&(l=at(l,c))}st(l)}}function gt(e,t,n){if(!n.has(e)){switch(e){case"scroll":Yt(t,"scroll",!0);break;case"focus":case"blur":Yt(t,"focus",!0),Yt(t,"blur",!0),n.set("blur",null),n.set("focus",null);break;case"cancel":case"close":ut(e)&&Yt(t,e,!0);break;case"invalid":case"submit":case"reset":break;default:-1===Ze.indexOf(e)&&Kt(e,t)}n.set(e,null)}}var ht,bt,vt,yt=!1,wt=[],xt=null,kt=null,Et=null,St=new Map,Tt=new Map,_t=[],At="mousedown mouseup touchcancel touchend touchstart auxclick dblclick pointercancel pointerdown pointerup dragend dragstart drop compositionend compositionstart keydown keypress keyup input textInput close cancel copy cut paste click change contextmenu reset submit".split(" "),Ct="focus blur dragenter dragleave mouseover mouseout pointerover pointerout gotpointercapture lostpointercapture".split(" ");function Pt(e,t,n,r,a){return{blockedOn:e,topLevelType:t,eventSystemFlags:32|n,nativeEvent:a,container:r}}function Nt(e,t){switch(e){case"focus":case"blur":xt=null;break;case"dragenter":case"dragleave":kt=null;break;case"mouseover":case"mouseout":Et=null;break;case"pointerover":case"pointerout":St.delete(t.pointerId);break;case"gotpointercapture":case"lostpointercapture":Tt.delete(t.pointerId)}}function Ot(e,t,n,r,a,i){return null===e||e.nativeEvent!==i?(e=Pt(t,n,r,a,i),null!==t&&(null!==(t=Dn(t))&&bt(t)),e):(e.eventSystemFlags|=r,e)}function It(e){var t=Rn(e.target);if(null!==t){var n=et(t);if(null!==n)if(13===(t=n.tag)){if(null!==(t=tt(n)))return e.blockedOn=t,void i.unstable_runWithPriority(e.priority,(function(){vt(n)}))}else if(3===t&&n.stateNode.hydrate)return void(e.blockedOn=3===n.tag?n.stateNode.containerInfo:null)}e.blockedOn=null}function Rt(e){if(null!==e.blockedOn)return!1;var t=Jt(e.topLevelType,e.eventSystemFlags,e.container,e.nativeEvent);if(null!==t){var n=Dn(t);return null!==n&&bt(n),e.blockedOn=t,!1}return!0}function Dt(e,t,n){Rt(e)&&n.delete(t)}function Lt(){for(yt=!1;0<wt.length;){var e=wt[0];if(null!==e.blockedOn){null!==(e=Dn(e.blockedOn))&&ht(e);break}var t=Jt(e.topLevelType,e.eventSystemFlags,e.container,e.nativeEvent);null!==t?e.blockedOn=t:wt.shift()}null!==xt&&Rt(xt)&&(xt=null),null!==kt&&Rt(kt)&&(kt=null),null!==Et&&Rt(Et)&&(Et=null),St.forEach(Dt),Tt.forEach(Dt)}function Mt(e,t){e.blockedOn===t&&(e.blockedOn=null,yt||(yt=!0,i.unstable_scheduleCallback(i.unstable_NormalPriority,Lt)))}function Ft(e){function t(t){return Mt(t,e)}if(0<wt.length){Mt(wt[0],e);for(var n=1;n<wt.length;n++){var r=wt[n];r.blockedOn===e&&(r.blockedOn=null)}}for(null!==xt&&Mt(xt,e),null!==kt&&Mt(kt,e),null!==Et&&Mt(Et,e),St.forEach(t),Tt.forEach(t),n=0;n<_t.length;n++)(r=_t[n]).blockedOn===e&&(r.blockedOn=null);for(;0<_t.length&&null===(n=_t[0]).blockedOn;)It(n),null===n.blockedOn&&_t.shift()}var Bt={},$t=new Map,zt=new Map,Ut=["abort","abort",qe,"animationEnd",Ke,"animationIteration",Ye,"animationStart","canplay","canPlay","canplaythrough","canPlayThrough","durationchange","durationChange","emptied","emptied","encrypted","encrypted","ended","ended","error","error","gotpointercapture","gotPointerCapture","load","load","loadeddata","loadedData","loadedmetadata","loadedMetadata","loadstart","loadStart","lostpointercapture","lostPointerCapture","playing","playing","progress","progress","seeking","seeking","stalled","stalled","suspend","suspend","timeupdate","timeUpdate",Qe,"transitionEnd","waiting","waiting"];function jt(e,t){for(var n=0;n<e.length;n+=2){var r=e[n],a=e[n+1],i="on"+(a[0].toUpperCase()+a.slice(1));i={phasedRegistrationNames:{bubbled:i,captured:i+"Capture"},dependencies:[r],eventPriority:t},zt.set(r,t),$t.set(r,i),Bt[a]=i}}jt("blur blur cancel cancel click click close close contextmenu contextMenu copy copy cut cut auxclick auxClick dblclick doubleClick dragend dragEnd dragstart dragStart drop drop focus focus input input invalid invalid keydown keyDown keypress keyPress keyup keyUp mousedown mouseDown mouseup mouseUp paste paste pause pause play play pointercancel pointerCancel pointerdown pointerDown pointerup pointerUp ratechange rateChange reset reset seeked seeked submit submit touchcancel touchCancel touchend touchEnd touchstart touchStart volumechange volumeChange".split(" "),0),jt("drag drag dragenter dragEnter dragexit dragExit dragleave dragLeave dragover dragOver mousemove mouseMove mouseout mouseOut mouseover mouseOver pointermove pointerMove pointerout pointerOut pointerover pointerOver scroll scroll toggle toggle touchmove touchMove wheel wheel".split(" "),1),jt(Ut,2);for(var Ht="change selectionchange textInput compositionstart compositionend compositionupdate".split(" "),Wt=0;Wt<Ht.length;Wt++)zt.set(Ht[Wt],0);var Vt=i.unstable_UserBlockingPriority,Gt=i.unstable_runWithPriority,qt=!0;function Kt(e,t){Yt(t,e,!1)}function Yt(e,t,n){var r=zt.get(t);switch(void 0===r?2:r){case 0:r=Qt.bind(null,t,1,e);break;case 1:r=Zt.bind(null,t,1,e);break;default:r=Xt.bind(null,t,1,e)}n?e.addEventListener(t,r,!0):e.addEventListener(t,r,!1)}function Qt(e,t,n,r){B||M();var a=Xt,i=B;B=!0;try{L(a,e,t,n,r)}finally{(B=i)||z()}}function Zt(e,t,n,r){Gt(Vt,Xt.bind(null,e,t,n,r))}function Xt(e,t,n,r){if(qt)if(0<wt.length&&-1<At.indexOf(e))e=Pt(null,e,t,n,r),wt.push(e);else{var a=Jt(e,t,n,r);if(null===a)Nt(e,r);else if(-1<At.indexOf(e))e=Pt(a,e,t,n,r),wt.push(e);else if(!function(e,t,n,r,a){switch(t){case"focus":return xt=Ot(xt,e,t,n,r,a),!0;case"dragenter":return kt=Ot(kt,e,t,n,r,a),!0;case"mouseover":return Et=Ot(Et,e,t,n,r,a),!0;case"pointerover":var i=a.pointerId;return St.set(i,Ot(St.get(i)||null,e,t,n,r,a)),!0;case"gotpointercapture":return i=a.pointerId,Tt.set(i,Ot(Tt.get(i)||null,e,t,n,r,a)),!0}return!1}(a,e,t,n,r)){Nt(e,r),e=ft(e,r,null,t);try{U(mt,e)}finally{pt(e)}}}}function Jt(e,t,n,r){if(null!==(n=Rn(n=ct(r)))){var a=et(n);if(null===a)n=null;else{var i=a.tag;if(13===i){if(null!==(n=tt(a)))return n;n=null}else if(3===i){if(a.stateNode.hydrate)return 3===a.tag?a.stateNode.containerInfo:null;n=null}else a!==n&&(n=null)}}e=ft(e,r,n,t);try{U(mt,e)}finally{pt(e)}return null}var en={animationIterationCount:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},tn=["Webkit","ms","Moz","O"];function nn(e,t,n){return null==t||"boolean"==typeof t||""===t?"":n||"number"!=typeof t||0===t||en.hasOwnProperty(e)&&en[e]?(""+t).trim():t+"px"}function rn(e,t){for(var n in e=e.style,t)if(t.hasOwnProperty(n)){var r=0===n.indexOf("--"),a=nn(n,t[n],r);"float"===n&&(n="cssFloat"),r?e.setProperty(n,a):e[n]=a}}Object.keys(en).forEach((function(e){tn.forEach((function(t){t=t+e.charAt(0).toUpperCase()+e.substring(1),en[t]=en[e]}))}));var an=a({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function on(e,t){if(t){if(an[e]&&(null!=t.children||null!=t.dangerouslySetInnerHTML))throw Error(o(137,e,""));if(null!=t.dangerouslySetInnerHTML){if(null!=t.children)throw Error(o(60));if("object"!=typeof t.dangerouslySetInnerHTML||!("__html"in t.dangerouslySetInnerHTML))throw Error(o(61))}if(null!=t.style&&"object"!=typeof t.style)throw Error(o(62,""))}}function ln(e,t){if(-1===e.indexOf("-"))return"string"==typeof t.is;switch(e){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}var sn=De;function cn(e,t){var n=Je(e=9===e.nodeType||11===e.nodeType?e:e.ownerDocument);t=T[t];for(var r=0;r<t.length;r++)gt(t[r],e,n)}function un(){}function dn(e){if(void 0===(e=e||("undefined"!=typeof document?document:void 0)))return null;try{return e.activeElement||e.body}catch(t){return e.body}}function pn(e){for(;e&&e.firstChild;)e=e.firstChild;return e}function fn(e,t){var n,r=pn(e);for(e=0;r;){if(3===r.nodeType){if(n=e+r.textContent.length,e<=t&&n>=t)return{node:r,offset:t-e};e=n}e:{for(;r;){if(r.nextSibling){r=r.nextSibling;break e}r=r.parentNode}r=void 0}r=pn(r)}}function mn(e,t){return!(!e||!t)&&(e===t||(!e||3!==e.nodeType)&&(t&&3===t.nodeType?mn(e,t.parentNode):"contains"in e?e.contains(t):!!e.compareDocumentPosition&&!!(16&e.compareDocumentPosition(t))))}function gn(){for(var e=window,t=dn();t instanceof e.HTMLIFrameElement;){try{var n="string"==typeof t.contentWindow.location.href}catch(r){n=!1}if(!n)break;t=dn((e=t.contentWindow).document)}return t}function hn(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&("input"===t&&("text"===e.type||"search"===e.type||"tel"===e.type||"url"===e.type||"password"===e.type)||"textarea"===t||"true"===e.contentEditable)}var bn="$",vn="/$",yn="$?",wn="$!",xn=null,kn=null;function En(e,t){switch(e){case"button":case"input":case"select":case"textarea":return!!t.autoFocus}return!1}function Sn(e,t){return"textarea"===e||"option"===e||"noscript"===e||"string"==typeof t.children||"number"==typeof t.children||"object"==typeof t.dangerouslySetInnerHTML&&null!==t.dangerouslySetInnerHTML&&null!=t.dangerouslySetInnerHTML.__html}var Tn="function"==typeof setTimeout?setTimeout:void 0,_n="function"==typeof clearTimeout?clearTimeout:void 0;function An(e){for(;null!=e;e=e.nextSibling){var t=e.nodeType;if(1===t||3===t)break}return e}function Cn(e){e=e.previousSibling;for(var t=0;e;){if(8===e.nodeType){var n=e.data;if(n===bn||n===wn||n===yn){if(0===t)return e;t--}else n===vn&&t++}e=e.previousSibling}return null}var Pn=Math.random().toString(36).slice(2),Nn="__reactInternalInstance$"+Pn,On="__reactEventHandlers$"+Pn,In="__reactContainere$"+Pn;function Rn(e){var t=e[Nn];if(t)return t;for(var n=e.parentNode;n;){if(t=n[In]||n[Nn]){if(n=t.alternate,null!==t.child||null!==n&&null!==n.child)for(e=Cn(e);null!==e;){if(n=e[Nn])return n;e=Cn(e)}return t}n=(e=n).parentNode}return null}function Dn(e){return!(e=e[Nn]||e[In])||5!==e.tag&&6!==e.tag&&13!==e.tag&&3!==e.tag?null:e}function Ln(e){if(5===e.tag||6===e.tag)return e.stateNode;throw Error(o(33))}function Mn(e){return e[On]||null}function Fn(e){do{e=e.return}while(e&&5!==e.tag);return e||null}function Bn(e,t){var n=e.stateNode;if(!n)return null;var r=m(n);if(!r)return null;n=r[t];e:switch(t){case"onClick":case"onClickCapture":case"onDoubleClick":case"onDoubleClickCapture":case"onMouseDown":case"onMouseDownCapture":case"onMouseMove":case"onMouseMoveCapture":case"onMouseUp":case"onMouseUpCapture":case"onMouseEnter":(r=!r.disabled)||(r=!("button"===(e=e.type)||"input"===e||"select"===e||"textarea"===e)),e=!r;break e;default:e=!1}if(e)return null;if(n&&"function"!=typeof n)throw Error(o(231,t,typeof n));return n}function $n(e,t,n){(t=Bn(e,n.dispatchConfig.phasedRegistrationNames[t]))&&(n._dispatchListeners=at(n._dispatchListeners,t),n._dispatchInstances=at(n._dispatchInstances,e))}function zn(e){if(e&&e.dispatchConfig.phasedRegistrationNames){for(var t=e._targetInst,n=[];t;)n.push(t),t=Fn(t);for(t=n.length;0<t--;)$n(n[t],"captured",e);for(t=0;t<n.length;t++)$n(n[t],"bubbled",e)}}function Un(e,t,n){e&&n&&n.dispatchConfig.registrationName&&(t=Bn(e,n.dispatchConfig.registrationName))&&(n._dispatchListeners=at(n._dispatchListeners,t),n._dispatchInstances=at(n._dispatchInstances,e))}function jn(e){e&&e.dispatchConfig.registrationName&&Un(e._targetInst,null,e)}function Hn(e){it(e,zn)}var Wn=null,Vn=null,Gn=null;function qn(){if(Gn)return Gn;var e,t,n=Vn,r=n.length,a="value"in Wn?Wn.value:Wn.textContent,i=a.length;for(e=0;e<r&&n[e]===a[e];e++);var o=r-e;for(t=1;t<=o&&n[r-t]===a[i-t];t++);return Gn=a.slice(e,1<t?1-t:void 0)}function Kn(){return!0}function Yn(){return!1}function Qn(e,t,n,r){for(var a in this.dispatchConfig=e,this._targetInst=t,this.nativeEvent=n,e=this.constructor.Interface)e.hasOwnProperty(a)&&((t=e[a])?this[a]=t(n):"target"===a?this.target=r:this[a]=n[a]);return this.isDefaultPrevented=(null!=n.defaultPrevented?n.defaultPrevented:!1===n.returnValue)?Kn:Yn,this.isPropagationStopped=Yn,this}function Zn(e,t,n,r){if(this.eventPool.length){var a=this.eventPool.pop();return this.call(a,e,t,n,r),a}return new this(e,t,n,r)}function Xn(e){if(!(e instanceof this))throw Error(o(279));e.destructor(),10>this.eventPool.length&&this.eventPool.push(e)}function Jn(e){e.eventPool=[],e.getPooled=Zn,e.release=Xn}a(Qn.prototype,{preventDefault:function(){this.defaultPrevented=!0;var e=this.nativeEvent;e&&(e.preventDefault?e.preventDefault():"unknown"!=typeof e.returnValue&&(e.returnValue=!1),this.isDefaultPrevented=Kn)},stopPropagation:function(){var e=this.nativeEvent;e&&(e.stopPropagation?e.stopPropagation():"unknown"!=typeof e.cancelBubble&&(e.cancelBubble=!0),this.isPropagationStopped=Kn)},persist:function(){this.isPersistent=Kn},isPersistent:Yn,destructor:function(){var e,t=this.constructor.Interface;for(e in t)this[e]=null;this.nativeEvent=this._targetInst=this.dispatchConfig=null,this.isPropagationStopped=this.isDefaultPrevented=Yn,this._dispatchInstances=this._dispatchListeners=null}}),Qn.Interface={type:null,target:null,currentTarget:function(){return null},eventPhase:null,bubbles:null,cancelable:null,timeStamp:function(e){return e.timeStamp||Date.now()},defaultPrevented:null,isTrusted:null},Qn.extend=function(e){function t(){}function n(){return r.apply(this,arguments)}var r=this;t.prototype=r.prototype;var i=new t;return a(i,n.prototype),n.prototype=i,n.prototype.constructor=n,n.Interface=a({},r.Interface,e),n.extend=r.extend,Jn(n),n},Jn(Qn);var er=Qn.extend({data:null}),tr=Qn.extend({data:null}),nr=[9,13,27,32],rr=A&&"CompositionEvent"in window,ar=null;A&&"documentMode"in document&&(ar=document.documentMode);var ir=A&&"TextEvent"in window&&!ar,or=A&&(!rr||ar&&8<ar&&11>=ar),lr=String.fromCharCode(32),sr={beforeInput:{phasedRegistrationNames:{bubbled:"onBeforeInput",captured:"onBeforeInputCapture"},dependencies:["compositionend","keypress","textInput","paste"]},compositionEnd:{phasedRegistrationNames:{bubbled:"onCompositionEnd",captured:"onCompositionEndCapture"},dependencies:"blur compositionend keydown keypress keyup mousedown".split(" ")},compositionStart:{phasedRegistrationNames:{bubbled:"onCompositionStart",captured:"onCompositionStartCapture"},dependencies:"blur compositionstart keydown keypress keyup mousedown".split(" ")},compositionUpdate:{phasedRegistrationNames:{bubbled:"onCompositionUpdate",captured:"onCompositionUpdateCapture"},dependencies:"blur compositionupdate keydown keypress keyup mousedown".split(" ")}},cr=!1;function ur(e,t){switch(e){case"keyup":return-1!==nr.indexOf(t.keyCode);case"keydown":return 229!==t.keyCode;case"keypress":case"mousedown":case"blur":return!0;default:return!1}}function dr(e){return"object"==typeof(e=e.detail)&&"data"in e?e.data:null}var pr=!1;var fr={eventTypes:sr,extractEvents:function(e,t,n,r){var a;if(rr)e:{switch(e){case"compositionstart":var i=sr.compositionStart;break e;case"compositionend":i=sr.compositionEnd;break e;case"compositionupdate":i=sr.compositionUpdate;break e}i=void 0}else pr?ur(e,n)&&(i=sr.compositionEnd):"keydown"===e&&229===n.keyCode&&(i=sr.compositionStart);return i?(or&&"ko"!==n.locale&&(pr||i!==sr.compositionStart?i===sr.compositionEnd&&pr&&(a=qn()):(Vn="value"in(Wn=r)?Wn.value:Wn.textContent,pr=!0)),i=er.getPooled(i,t,n,r),a?i.data=a:null!==(a=dr(n))&&(i.data=a),Hn(i),a=i):a=null,(e=ir?function(e,t){switch(e){case"compositionend":return dr(t);case"keypress":return 32!==t.which?null:(cr=!0,lr);case"textInput":return(e=t.data)===lr&&cr?null:e;default:return null}}(e,n):function(e,t){if(pr)return"compositionend"===e||!rr&&ur(e,t)?(e=qn(),Gn=Vn=Wn=null,pr=!1,e):null;switch(e){case"paste":default:return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1<t.char.length)return t.char;if(t.which)return String.fromCharCode(t.which)}return null;case"compositionend":return or&&"ko"!==t.locale?null:t.data}}(e,n))?((t=tr.getPooled(sr.beforeInput,t,n,r)).data=e,Hn(t)):t=null,null===a?t:null===t?a:[a,t]}},mr={color:!0,date:!0,datetime:!0,"datetime-local":!0,email:!0,month:!0,number:!0,password:!0,range:!0,search:!0,tel:!0,text:!0,time:!0,url:!0,week:!0};function gr(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return"input"===t?!!mr[e.type]:"textarea"===t}var hr={change:{phasedRegistrationNames:{bubbled:"onChange",captured:"onChangeCapture"},dependencies:"blur change click focus input keydown keyup selectionchange".split(" ")}};function br(e,t,n){return(e=Qn.getPooled(hr.change,e,t,n)).type="change",I(n),Hn(e),e}var vr=null,yr=null;function wr(e){st(e)}function xr(e){if(xe(Ln(e)))return e}function kr(e,t){if("change"===e)return t}var Er=!1;function Sr(){vr&&(vr.detachEvent("onpropertychange",Tr),yr=vr=null)}function Tr(e){if("value"===e.propertyName&&xr(yr))if(e=br(yr,e,ct(e)),B)st(e);else{B=!0;try{D(wr,e)}finally{B=!1,z()}}}function _r(e,t,n){"focus"===e?(Sr(),yr=n,(vr=t).attachEvent("onpropertychange",Tr)):"blur"===e&&Sr()}function Ar(e){if("selectionchange"===e||"keyup"===e||"keydown"===e)return xr(yr)}function Cr(e,t){if("click"===e)return xr(t)}function Pr(e,t){if("input"===e||"change"===e)return xr(t)}A&&(Er=ut("input")&&(!document.documentMode||9<document.documentMode));var Nr={eventTypes:hr,_isInputEventSupported:Er,extractEvents:function(e,t,n,r){var a=t?Ln(t):window,i=a.nodeName&&a.nodeName.toLowerCase();if("select"===i||"input"===i&&"file"===a.type)var o=kr;else if(gr(a))if(Er)o=Pr;else{o=Ar;var l=_r}else(i=a.nodeName)&&"input"===i.toLowerCase()&&("checkbox"===a.type||"radio"===a.type)&&(o=Cr);if(o&&(o=o(e,t)))return br(o,n,r);l&&l(e,a,t),"blur"===e&&(e=a._wrapperState)&&e.controlled&&"number"===a.type&&Ae(a,"number",a.value)}},Or=Qn.extend({view:null,detail:null}),Ir={Alt:"altKey",Control:"ctrlKey",Meta:"metaKey",Shift:"shiftKey"};function Rr(e){var t=this.nativeEvent;return t.getModifierState?t.getModifierState(e):!!(e=Ir[e])&&!!t[e]}function Dr(){return Rr}var Lr=0,Mr=0,Fr=!1,Br=!1,$r=Or.extend({screenX:null,screenY:null,clientX:null,clientY:null,pageX:null,pageY:null,ctrlKey:null,shiftKey:null,altKey:null,metaKey:null,getModifierState:Dr,button:null,buttons:null,relatedTarget:function(e){return e.relatedTarget||(e.fromElement===e.srcElement?e.toElement:e.fromElement)},movementX:function(e){if("movementX"in e)return e.movementX;var t=Lr;return Lr=e.screenX,Fr?"mousemove"===e.type?e.screenX-t:0:(Fr=!0,0)},movementY:function(e){if("movementY"in e)return e.movementY;var t=Mr;return Mr=e.screenY,Br?"mousemove"===e.type?e.screenY-t:0:(Br=!0,0)}}),zr=$r.extend({pointerId:null,width:null,height:null,pressure:null,tangentialPressure:null,tiltX:null,tiltY:null,twist:null,pointerType:null,isPrimary:null}),Ur={mouseEnter:{registrationName:"onMouseEnter",dependencies:["mouseout","mouseover"]},mouseLeave:{registrationName:"onMouseLeave",dependencies:["mouseout","mouseover"]},pointerEnter:{registrationName:"onPointerEnter",dependencies:["pointerout","pointerover"]},pointerLeave:{registrationName:"onPointerLeave",dependencies:["pointerout","pointerover"]}},jr={eventTypes:Ur,extractEvents:function(e,t,n,r,a){var i="mouseover"===e||"pointerover"===e,o="mouseout"===e||"pointerout"===e;if(i&&!(32&a)&&(n.relatedTarget||n.fromElement)||!o&&!i)return null;(i=r.window===r?r:(i=r.ownerDocument)?i.defaultView||i.parentWindow:window,o)?(o=t,null!==(t=(t=n.relatedTarget||n.toElement)?Rn(t):null)&&(t!==et(t)||5!==t.tag&&6!==t.tag)&&(t=null)):o=null;if(o===t)return null;if("mouseout"===e||"mouseover"===e)var l=$r,s=Ur.mouseLeave,c=Ur.mouseEnter,u="mouse";else"pointerout"!==e&&"pointerover"!==e||(l=zr,s=Ur.pointerLeave,c=Ur.pointerEnter,u="pointer");if(e=null==o?i:Ln(o),i=null==t?i:Ln(t),(s=l.getPooled(s,o,n,r)).type=u+"leave",s.target=e,s.relatedTarget=i,(n=l.getPooled(c,t,n,r)).type=u+"enter",n.target=i,n.relatedTarget=e,u=t,(r=o)&&u)e:{for(c=u,o=0,e=l=r;e;e=Fn(e))o++;for(e=0,t=c;t;t=Fn(t))e++;for(;0<o-e;)l=Fn(l),o--;for(;0<e-o;)c=Fn(c),e--;for(;o--;){if(l===c||l===c.alternate)break e;l=Fn(l),c=Fn(c)}l=null}else l=null;for(c=l,l=[];r&&r!==c&&(null===(o=r.alternate)||o!==c);)l.push(r),r=Fn(r);for(r=[];u&&u!==c&&(null===(o=u.alternate)||o!==c);)r.push(u),u=Fn(u);for(u=0;u<l.length;u++)Un(l[u],"bubbled",s);for(u=r.length;0<u--;)Un(r[u],"captured",n);return 64&a?[s,n]:[s]}};var Hr="function"==typeof Object.is?Object.is:function(e,t){return e===t&&(0!==e||1/e==1/t)||e!=e&&t!=t},Wr=Object.prototype.hasOwnProperty;function Vr(e,t){if(Hr(e,t))return!0;if("object"!=typeof e||null===e||"object"!=typeof t||null===t)return!1;var n=Object.keys(e),r=Object.keys(t);if(n.length!==r.length)return!1;for(r=0;r<n.length;r++)if(!Wr.call(t,n[r])||!Hr(e[n[r]],t[n[r]]))return!1;return!0}var Gr=A&&"documentMode"in document&&11>=document.documentMode,qr={select:{phasedRegistrationNames:{bubbled:"onSelect",captured:"onSelectCapture"},dependencies:"blur contextmenu dragend focus keydown keyup mousedown mouseup selectionchange".split(" ")}},Kr=null,Yr=null,Qr=null,Zr=!1;function Xr(e,t){var n=t.window===t?t.document:9===t.nodeType?t:t.ownerDocument;return Zr||null==Kr||Kr!==dn(n)?null:("selectionStart"in(n=Kr)&&hn(n)?n={start:n.selectionStart,end:n.selectionEnd}:n={anchorNode:(n=(n.ownerDocument&&n.ownerDocument.defaultView||window).getSelection()).anchorNode,anchorOffset:n.anchorOffset,focusNode:n.focusNode,focusOffset:n.focusOffset},Qr&&Vr(Qr,n)?null:(Qr=n,(e=Qn.getPooled(qr.select,Yr,e,t)).type="select",e.target=Kr,Hn(e),e))}var Jr={eventTypes:qr,extractEvents:function(e,t,n,r,a,i){if(!(i=!(a=i||(r.window===r?r.document:9===r.nodeType?r:r.ownerDocument)))){e:{a=Je(a),i=T.onSelect;for(var o=0;o<i.length;o++)if(!a.has(i[o])){a=!1;break e}a=!0}i=!a}if(i)return null;switch(a=t?Ln(t):window,e){case"focus":(gr(a)||"true"===a.contentEditable)&&(Kr=a,Yr=t,Qr=null);break;case"blur":Qr=Yr=Kr=null;break;case"mousedown":Zr=!0;break;case"contextmenu":case"mouseup":case"dragend":return Zr=!1,Xr(n,r);case"selectionchange":if(Gr)break;case"keydown":case"keyup":return Xr(n,r)}return null}},ea=Qn.extend({animationName:null,elapsedTime:null,pseudoElement:null}),ta=Qn.extend({clipboardData:function(e){return"clipboardData"in e?e.clipboardData:window.clipboardData}}),na=Or.extend({relatedTarget:null});function ra(e){var t=e.keyCode;return"charCode"in e?0===(e=e.charCode)&&13===t&&(e=13):e=t,10===e&&(e=13),32<=e||13===e?e:0}var aa={Esc:"Escape",Spacebar:" ",Left:"ArrowLeft",Up:"ArrowUp",Right:"ArrowRight",Down:"ArrowDown",Del:"Delete",Win:"OS",Menu:"ContextMenu",Apps:"ContextMenu",Scroll:"ScrollLock",MozPrintableKey:"Unidentified"},ia={8:"Backspace",9:"Tab",12:"Clear",13:"Enter",16:"Shift",17:"Control",18:"Alt",19:"Pause",20:"CapsLock",27:"Escape",32:" ",33:"PageUp",34:"PageDown",35:"End",36:"Home",37:"ArrowLeft",38:"ArrowUp",39:"ArrowRight",40:"ArrowDown",45:"Insert",46:"Delete",112:"F1",113:"F2",114:"F3",115:"F4",116:"F5",117:"F6",118:"F7",119:"F8",120:"F9",121:"F10",122:"F11",123:"F12",144:"NumLock",145:"ScrollLock",224:"Meta"},oa=Or.extend({key:function(e){if(e.key){var t=aa[e.key]||e.key;if("Unidentified"!==t)return t}return"keypress"===e.type?13===(e=ra(e))?"Enter":String.fromCharCode(e):"keydown"===e.type||"keyup"===e.type?ia[e.keyCode]||"Unidentified":""},location:null,ctrlKey:null,shiftKey:null,altKey:null,metaKey:null,repeat:null,locale:null,getModifierState:Dr,charCode:function(e){return"keypress"===e.type?ra(e):0},keyCode:function(e){return"keydown"===e.type||"keyup"===e.type?e.keyCode:0},which:function(e){return"keypress"===e.type?ra(e):"keydown"===e.type||"keyup"===e.type?e.keyCode:0}}),la=$r.extend({dataTransfer:null}),sa=Or.extend({touches:null,targetTouches:null,changedTouches:null,altKey:null,metaKey:null,ctrlKey:null,shiftKey:null,getModifierState:Dr}),ca=Qn.extend({propertyName:null,elapsedTime:null,pseudoElement:null}),ua=$r.extend({deltaX:function(e){return"deltaX"in e?e.deltaX:"wheelDeltaX"in e?-e.wheelDeltaX:0},deltaY:function(e){return"deltaY"in e?e.deltaY:"wheelDeltaY"in e?-e.wheelDeltaY:"wheelDelta"in e?-e.wheelDelta:0},deltaZ:null,deltaMode:null}),da={eventTypes:Bt,extractEvents:function(e,t,n,r){var a=$t.get(e);if(!a)return null;switch(e){case"keypress":if(0===ra(n))return null;case"keydown":case"keyup":e=oa;break;case"blur":case"focus":e=na;break;case"click":if(2===n.button)return null;case"auxclick":case"dblclick":case"mousedown":case"mousemove":case"mouseup":case"mouseout":case"mouseover":case"contextmenu":e=$r;break;case"drag":case"dragend":case"dragenter":case"dragexit":case"dragleave":case"dragover":case"dragstart":case"drop":e=la;break;case"touchcancel":case"touchend":case"touchmove":case"touchstart":e=sa;break;case qe:case Ke:case Ye:e=ea;break;case Qe:e=ca;break;case"scroll":e=Or;break;case"wheel":e=ua;break;case"copy":case"cut":case"paste":e=ta;break;case"gotpointercapture":case"lostpointercapture":case"pointercancel":case"pointerdown":case"pointermove":case"pointerout":case"pointerover":case"pointerup":e=zr;break;default:e=Qn}return Hn(t=e.getPooled(a,t,n,r)),t}};if(v)throw Error(o(101));v=Array.prototype.slice.call("ResponderEventPlugin SimpleEventPlugin EnterLeaveEventPlugin ChangeEventPlugin SelectEventPlugin BeforeInputEventPlugin".split(" ")),w(),m=Mn,g=Dn,h=Ln,_({SimpleEventPlugin:da,EnterLeaveEventPlugin:jr,ChangeEventPlugin:Nr,SelectEventPlugin:Jr,BeforeInputEventPlugin:fr});var pa=[],fa=-1;function ma(e){0>fa||(e.current=pa[fa],pa[fa]=null,fa--)}function ga(e,t){fa++,pa[fa]=e.current,e.current=t}var ha={},ba={current:ha},va={current:!1},ya=ha;function wa(e,t){var n=e.type.contextTypes;if(!n)return ha;var r=e.stateNode;if(r&&r.__reactInternalMemoizedUnmaskedChildContext===t)return r.__reactInternalMemoizedMaskedChildContext;var a,i={};for(a in n)i[a]=t[a];return r&&((e=e.stateNode).__reactInternalMemoizedUnmaskedChildContext=t,e.__reactInternalMemoizedMaskedChildContext=i),i}function xa(e){return null!=(e=e.childContextTypes)}function ka(){ma(va),ma(ba)}function Ea(e,t,n){if(ba.current!==ha)throw Error(o(168));ga(ba,t),ga(va,n)}function Sa(e,t,n){var r=e.stateNode;if(e=t.childContextTypes,"function"!=typeof r.getChildContext)return n;for(var i in r=r.getChildContext())if(!(i in e))throw Error(o(108,he(t)||"Unknown",i));return a({},n,{},r)}function Ta(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||ha,ya=ba.current,ga(ba,e),ga(va,va.current),!0}function _a(e,t,n){var r=e.stateNode;if(!r)throw Error(o(169));n?(e=Sa(e,t,ya),r.__reactInternalMemoizedMergedChildContext=e,ma(va),ma(ba),ga(ba,e)):ma(va),ga(va,n)}var Aa=i.unstable_runWithPriority,Ca=i.unstable_scheduleCallback,Pa=i.unstable_cancelCallback,Na=i.unstable_requestPaint,Oa=i.unstable_now,Ia=i.unstable_getCurrentPriorityLevel,Ra=i.unstable_ImmediatePriority,Da=i.unstable_UserBlockingPriority,La=i.unstable_NormalPriority,Ma=i.unstable_LowPriority,Fa=i.unstable_IdlePriority,Ba={},$a=i.unstable_shouldYield,za=void 0!==Na?Na:function(){},Ua=null,ja=null,Ha=!1,Wa=Oa(),Va=1e4>Wa?Oa:function(){return Oa()-Wa};function Ga(){switch(Ia()){case Ra:return 99;case Da:return 98;case La:return 97;case Ma:return 96;case Fa:return 95;default:throw Error(o(332))}}function qa(e){switch(e){case 99:return Ra;case 98:return Da;case 97:return La;case 96:return Ma;case 95:return Fa;default:throw Error(o(332))}}function Ka(e,t){return e=qa(e),Aa(e,t)}function Ya(e,t,n){return e=qa(e),Ca(e,t,n)}function Qa(e){return null===Ua?(Ua=[e],ja=Ca(Ra,Xa)):Ua.push(e),Ba}function Za(){if(null!==ja){var e=ja;ja=null,Pa(e)}Xa()}function Xa(){if(!Ha&&null!==Ua){Ha=!0;var e=0;try{var t=Ua;Ka(99,(function(){for(;e<t.length;e++){var n=t[e];do{n=n(!0)}while(null!==n)}})),Ua=null}catch(n){throw null!==Ua&&(Ua=Ua.slice(e+1)),Ca(Ra,Za),n}finally{Ha=!1}}}function Ja(e,t,n){return 1073741821-(1+((1073741821-e+t/10)/(n/=10)|0))*n}function ei(e,t){if(e&&e.defaultProps)for(var n in t=a({},t),e=e.defaultProps)void 0===t[n]&&(t[n]=e[n]);return t}var ti={current:null},ni=null,ri=null,ai=null;function ii(){ai=ri=ni=null}function oi(e){var t=ti.current;ma(ti),e.type._context._currentValue=t}function li(e,t){for(;null!==e;){var n=e.alternate;if(e.childExpirationTime<t)e.childExpirationTime=t,null!==n&&n.childExpirationTime<t&&(n.childExpirationTime=t);else{if(!(null!==n&&n.childExpirationTime<t))break;n.childExpirationTime=t}e=e.return}}function si(e,t){ni=e,ai=ri=null,null!==(e=e.dependencies)&&null!==e.firstContext&&(e.expirationTime>=t&&(Mo=!0),e.firstContext=null)}function ci(e,t){if(ai!==e&&!1!==t&&0!==t)if("number"==typeof t&&1073741823!==t||(ai=e,t=1073741823),t={context:e,observedBits:t,next:null},null===ri){if(null===ni)throw Error(o(308));ri=t,ni.dependencies={expirationTime:0,firstContext:t,responders:null}}else ri=ri.next=t;return e._currentValue}var ui=!1;function di(e){e.updateQueue={baseState:e.memoizedState,baseQueue:null,shared:{pending:null},effects:null}}function pi(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,baseQueue:e.baseQueue,shared:e.shared,effects:e.effects})}function fi(e,t){return(e={expirationTime:e,suspenseConfig:t,tag:0,payload:null,callback:null,next:null}).next=e}function mi(e,t){if(null!==(e=e.updateQueue)){var n=(e=e.shared).pending;null===n?t.next=t:(t.next=n.next,n.next=t),e.pending=t}}function gi(e,t){var n=e.alternate;null!==n&&pi(n,e),null===(n=(e=e.updateQueue).baseQueue)?(e.baseQueue=t.next=t,t.next=t):(t.next=n.next,n.next=t)}function hi(e,t,n,r){var i=e.updateQueue;ui=!1;var o=i.baseQueue,l=i.shared.pending;if(null!==l){if(null!==o){var s=o.next;o.next=l.next,l.next=s}o=l,i.shared.pending=null,null!==(s=e.alternate)&&(null!==(s=s.updateQueue)&&(s.baseQueue=l))}if(null!==o){s=o.next;var c=i.baseState,u=0,d=null,p=null,f=null;if(null!==s)for(var m=s;;){if((l=m.expirationTime)<r){var g={expirationTime:m.expirationTime,suspenseConfig:m.suspenseConfig,tag:m.tag,payload:m.payload,callback:m.callback,next:null};null===f?(p=f=g,d=c):f=f.next=g,l>u&&(u=l)}else{null!==f&&(f=f.next={expirationTime:1073741823,suspenseConfig:m.suspenseConfig,tag:m.tag,payload:m.payload,callback:m.callback,next:null}),ks(l,m.suspenseConfig);e:{var h=e,b=m;switch(l=t,g=n,b.tag){case 1:if("function"==typeof(h=b.payload)){c=h.call(g,c,l);break e}c=h;break e;case 3:h.effectTag=-4097&h.effectTag|64;case 0:if(null==(l="function"==typeof(h=b.payload)?h.call(g,c,l):h))break e;c=a({},c,l);break e;case 2:ui=!0}}null!==m.callback&&(e.effectTag|=32,null===(l=i.effects)?i.effects=[m]:l.push(m))}if(null===(m=m.next)||m===s){if(null===(l=i.shared.pending))break;m=o.next=l.next,l.next=s,i.baseQueue=o=l,i.shared.pending=null}}null===f?d=c:f.next=p,i.baseState=d,i.baseQueue=f,Es(u),e.expirationTime=u,e.memoizedState=c}}function bi(e,t,n){if(e=t.effects,t.effects=null,null!==e)for(t=0;t<e.length;t++){var r=e[t],a=r.callback;if(null!==a){if(r.callback=null,r=a,a=n,"function"!=typeof r)throw Error(o(191,r));r.call(a)}}}var vi=Q.ReactCurrentBatchConfig,yi=(new r.Component).refs;function wi(e,t,n,r){n=null==(n=n(r,t=e.memoizedState))?t:a({},t,n),e.memoizedState=n,0===e.expirationTime&&(e.updateQueue.baseState=n)}var xi={isMounted:function(e){return!!(e=e._reactInternalFiber)&&et(e)===e},enqueueSetState:function(e,t,n){e=e._reactInternalFiber;var r=cs(),a=vi.suspense;(a=fi(r=us(r,e,a),a)).payload=t,null!=n&&(a.callback=n),mi(e,a),ds(e,r)},enqueueReplaceState:function(e,t,n){e=e._reactInternalFiber;var r=cs(),a=vi.suspense;(a=fi(r=us(r,e,a),a)).tag=1,a.payload=t,null!=n&&(a.callback=n),mi(e,a),ds(e,r)},enqueueForceUpdate:function(e,t){e=e._reactInternalFiber;var n=cs(),r=vi.suspense;(r=fi(n=us(n,e,r),r)).tag=2,null!=t&&(r.callback=t),mi(e,r),ds(e,n)}};function ki(e,t,n,r,a,i,o){return"function"==typeof(e=e.stateNode).shouldComponentUpdate?e.shouldComponentUpdate(r,i,o):!t.prototype||!t.prototype.isPureReactComponent||(!Vr(n,r)||!Vr(a,i))}function Ei(e,t,n){var r=!1,a=ha,i=t.contextType;return"object"==typeof i&&null!==i?i=ci(i):(a=xa(t)?ya:ba.current,i=(r=null!=(r=t.contextTypes))?wa(e,a):ha),t=new t(n,i),e.memoizedState=null!==t.state&&void 0!==t.state?t.state:null,t.updater=xi,e.stateNode=t,t._reactInternalFiber=e,r&&((e=e.stateNode).__reactInternalMemoizedUnmaskedChildContext=a,e.__reactInternalMemoizedMaskedChildContext=i),t}function Si(e,t,n,r){e=t.state,"function"==typeof t.componentWillReceiveProps&&t.componentWillReceiveProps(n,r),"function"==typeof t.UNSAFE_componentWillReceiveProps&&t.UNSAFE_componentWillReceiveProps(n,r),t.state!==e&&xi.enqueueReplaceState(t,t.state,null)}function Ti(e,t,n,r){var a=e.stateNode;a.props=n,a.state=e.memoizedState,a.refs=yi,di(e);var i=t.contextType;"object"==typeof i&&null!==i?a.context=ci(i):(i=xa(t)?ya:ba.current,a.context=wa(e,i)),hi(e,n,a,r),a.state=e.memoizedState,"function"==typeof(i=t.getDerivedStateFromProps)&&(wi(e,t,i,n),a.state=e.memoizedState),"function"==typeof t.getDerivedStateFromProps||"function"==typeof a.getSnapshotBeforeUpdate||"function"!=typeof a.UNSAFE_componentWillMount&&"function"!=typeof a.componentWillMount||(t=a.state,"function"==typeof a.componentWillMount&&a.componentWillMount(),"function"==typeof a.UNSAFE_componentWillMount&&a.UNSAFE_componentWillMount(),t!==a.state&&xi.enqueueReplaceState(a,a.state,null),hi(e,n,a,r),a.state=e.memoizedState),"function"==typeof a.componentDidMount&&(e.effectTag|=4)}var _i=Array.isArray;function Ai(e,t,n){if(null!==(e=n.ref)&&"function"!=typeof e&&"object"!=typeof e){if(n._owner){if(n=n._owner){if(1!==n.tag)throw Error(o(309));var r=n.stateNode}if(!r)throw Error(o(147,e));var a=""+e;return null!==t&&null!==t.ref&&"function"==typeof t.ref&&t.ref._stringRef===a?t.ref:(t=function(e){var t=r.refs;t===yi&&(t=r.refs={}),null===e?delete t[a]:t[a]=e},t._stringRef=a,t)}if("string"!=typeof e)throw Error(o(284));if(!n._owner)throw Error(o(290,e))}return e}function Ci(e,t){if("textarea"!==e.type)throw Error(o(31,"[object Object]"===Object.prototype.toString.call(t)?"object with keys {"+Object.keys(t).join(", ")+"}":t,""))}function Pi(e){function t(t,n){if(e){var r=t.lastEffect;null!==r?(r.nextEffect=n,t.lastEffect=n):t.firstEffect=t.lastEffect=n,n.nextEffect=null,n.effectTag=8}}function n(n,r){if(!e)return null;for(;null!==r;)t(n,r),r=r.sibling;return null}function r(e,t){for(e=new Map;null!==t;)null!==t.key?e.set(t.key,t):e.set(t.index,t),t=t.sibling;return e}function a(e,t){return(e=Hs(e,t)).index=0,e.sibling=null,e}function i(t,n,r){return t.index=r,e?null!==(r=t.alternate)?(r=r.index)<n?(t.effectTag=2,n):r:(t.effectTag=2,n):n}function l(t){return e&&null===t.alternate&&(t.effectTag=2),t}function s(e,t,n,r){return null===t||6!==t.tag?((t=Gs(n,e.mode,r)).return=e,t):((t=a(t,n)).return=e,t)}function c(e,t,n,r){return null!==t&&t.elementType===n.type?((r=a(t,n.props)).ref=Ai(e,t,n),r.return=e,r):((r=Ws(n.type,n.key,n.props,null,e.mode,r)).ref=Ai(e,t,n),r.return=e,r)}function u(e,t,n,r){return null===t||4!==t.tag||t.stateNode.containerInfo!==n.containerInfo||t.stateNode.implementation!==n.implementation?((t=qs(n,e.mode,r)).return=e,t):((t=a(t,n.children||[])).return=e,t)}function d(e,t,n,r,i){return null===t||7!==t.tag?((t=Vs(n,e.mode,r,i)).return=e,t):((t=a(t,n)).return=e,t)}function p(e,t,n){if("string"==typeof t||"number"==typeof t)return(t=Gs(""+t,e.mode,n)).return=e,t;if("object"==typeof t&&null!==t){switch(t.$$typeof){case ee:return(n=Ws(t.type,t.key,t.props,null,e.mode,n)).ref=Ai(e,null,t),n.return=e,n;case te:return(t=qs(t,e.mode,n)).return=e,t}if(_i(t)||ge(t))return(t=Vs(t,e.mode,n,null)).return=e,t;Ci(e,t)}return null}function f(e,t,n,r){var a=null!==t?t.key:null;if("string"==typeof n||"number"==typeof n)return null!==a?null:s(e,t,""+n,r);if("object"==typeof n&&null!==n){switch(n.$$typeof){case ee:return n.key===a?n.type===ne?d(e,t,n.props.children,r,a):c(e,t,n,r):null;case te:return n.key===a?u(e,t,n,r):null}if(_i(n)||ge(n))return null!==a?null:d(e,t,n,r,null);Ci(e,n)}return null}function m(e,t,n,r,a){if("string"==typeof r||"number"==typeof r)return s(t,e=e.get(n)||null,""+r,a);if("object"==typeof r&&null!==r){switch(r.$$typeof){case ee:return e=e.get(null===r.key?n:r.key)||null,r.type===ne?d(t,e,r.props.children,a,r.key):c(t,e,r,a);case te:return u(t,e=e.get(null===r.key?n:r.key)||null,r,a)}if(_i(r)||ge(r))return d(t,e=e.get(n)||null,r,a,null);Ci(t,r)}return null}function g(a,o,l,s){for(var c=null,u=null,d=o,g=o=0,h=null;null!==d&&g<l.length;g++){d.index>g?(h=d,d=null):h=d.sibling;var b=f(a,d,l[g],s);if(null===b){null===d&&(d=h);break}e&&d&&null===b.alternate&&t(a,d),o=i(b,o,g),null===u?c=b:u.sibling=b,u=b,d=h}if(g===l.length)return n(a,d),c;if(null===d){for(;g<l.length;g++)null!==(d=p(a,l[g],s))&&(o=i(d,o,g),null===u?c=d:u.sibling=d,u=d);return c}for(d=r(a,d);g<l.length;g++)null!==(h=m(d,a,g,l[g],s))&&(e&&null!==h.alternate&&d.delete(null===h.key?g:h.key),o=i(h,o,g),null===u?c=h:u.sibling=h,u=h);return e&&d.forEach((function(e){return t(a,e)})),c}function h(a,l,s,c){var u=ge(s);if("function"!=typeof u)throw Error(o(150));if(null==(s=u.call(s)))throw Error(o(151));for(var d=u=null,g=l,h=l=0,b=null,v=s.next();null!==g&&!v.done;h++,v=s.next()){g.index>h?(b=g,g=null):b=g.sibling;var y=f(a,g,v.value,c);if(null===y){null===g&&(g=b);break}e&&g&&null===y.alternate&&t(a,g),l=i(y,l,h),null===d?u=y:d.sibling=y,d=y,g=b}if(v.done)return n(a,g),u;if(null===g){for(;!v.done;h++,v=s.next())null!==(v=p(a,v.value,c))&&(l=i(v,l,h),null===d?u=v:d.sibling=v,d=v);return u}for(g=r(a,g);!v.done;h++,v=s.next())null!==(v=m(g,a,h,v.value,c))&&(e&&null!==v.alternate&&g.delete(null===v.key?h:v.key),l=i(v,l,h),null===d?u=v:d.sibling=v,d=v);return e&&g.forEach((function(e){return t(a,e)})),u}return function(e,r,i,s){var c="object"==typeof i&&null!==i&&i.type===ne&&null===i.key;c&&(i=i.props.children);var u="object"==typeof i&&null!==i;if(u)switch(i.$$typeof){case ee:e:{for(u=i.key,c=r;null!==c;){if(c.key===u){if(7===c.tag){if(i.type===ne){n(e,c.sibling),(r=a(c,i.props.children)).return=e,e=r;break e}}else if(c.elementType===i.type){n(e,c.sibling),(r=a(c,i.props)).ref=Ai(e,c,i),r.return=e,e=r;break e}n(e,c);break}t(e,c),c=c.sibling}i.type===ne?((r=Vs(i.props.children,e.mode,s,i.key)).return=e,e=r):((s=Ws(i.type,i.key,i.props,null,e.mode,s)).ref=Ai(e,r,i),s.return=e,e=s)}return l(e);case te:e:{for(c=i.key;null!==r;){if(r.key===c){if(4===r.tag&&r.stateNode.containerInfo===i.containerInfo&&r.stateNode.implementation===i.implementation){n(e,r.sibling),(r=a(r,i.children||[])).return=e,e=r;break e}n(e,r);break}t(e,r),r=r.sibling}(r=qs(i,e.mode,s)).return=e,e=r}return l(e)}if("string"==typeof i||"number"==typeof i)return i=""+i,null!==r&&6===r.tag?(n(e,r.sibling),(r=a(r,i)).return=e,e=r):(n(e,r),(r=Gs(i,e.mode,s)).return=e,e=r),l(e);if(_i(i))return g(e,r,i,s);if(ge(i))return h(e,r,i,s);if(u&&Ci(e,i),void 0===i&&!c)switch(e.tag){case 1:case 0:throw e=e.type,Error(o(152,e.displayName||e.name||"Component"))}return n(e,r)}}var Ni=Pi(!0),Oi=Pi(!1),Ii={},Ri={current:Ii},Di={current:Ii},Li={current:Ii};function Mi(e){if(e===Ii)throw Error(o(174));return e}function Fi(e,t){switch(ga(Li,t),ga(Di,e),ga(Ri,Ii),e=t.nodeType){case 9:case 11:t=(t=t.documentElement)?t.namespaceURI:Fe(null,"");break;default:t=Fe(t=(e=8===e?t.parentNode:t).namespaceURI||null,e=e.tagName)}ma(Ri),ga(Ri,t)}function Bi(){ma(Ri),ma(Di),ma(Li)}function $i(e){Mi(Li.current);var t=Mi(Ri.current),n=Fe(t,e.type);t!==n&&(ga(Di,e),ga(Ri,n))}function zi(e){Di.current===e&&(ma(Ri),ma(Di))}var Ui={current:0};function ji(e){for(var t=e;null!==t;){if(13===t.tag){var n=t.memoizedState;if(null!==n&&(null===(n=n.dehydrated)||n.data===yn||n.data===wn))return t}else if(19===t.tag&&void 0!==t.memoizedProps.revealOrder){if(64&t.effectTag)return t}else if(null!==t.child){t.child.return=t,t=t.child;continue}if(t===e)break;for(;null===t.sibling;){if(null===t.return||t.return===e)return null;t=t.return}t.sibling.return=t.return,t=t.sibling}return null}function Hi(e,t){return{responder:e,props:t}}var Wi=Q.ReactCurrentDispatcher,Vi=Q.ReactCurrentBatchConfig,Gi=0,qi=null,Ki=null,Yi=null,Qi=!1;function Zi(){throw Error(o(321))}function Xi(e,t){if(null===t)return!1;for(var n=0;n<t.length&&n<e.length;n++)if(!Hr(e[n],t[n]))return!1;return!0}function Ji(e,t,n,r,a,i){if(Gi=i,qi=t,t.memoizedState=null,t.updateQueue=null,t.expirationTime=0,Wi.current=null===e||null===e.memoizedState?Eo:So,e=n(r,a),t.expirationTime===Gi){i=0;do{if(t.expirationTime=0,!(25>i))throw Error(o(301));i+=1,Yi=Ki=null,t.updateQueue=null,Wi.current=To,e=n(r,a)}while(t.expirationTime===Gi)}if(Wi.current=ko,t=null!==Ki&&null!==Ki.next,Gi=0,Yi=Ki=qi=null,Qi=!1,t)throw Error(o(300));return e}function eo(){var e={memoizedState:null,baseState:null,baseQueue:null,queue:null,next:null};return null===Yi?qi.memoizedState=Yi=e:Yi=Yi.next=e,Yi}function to(){if(null===Ki){var e=qi.alternate;e=null!==e?e.memoizedState:null}else e=Ki.next;var t=null===Yi?qi.memoizedState:Yi.next;if(null!==t)Yi=t,Ki=e;else{if(null===e)throw Error(o(310));e={memoizedState:(Ki=e).memoizedState,baseState:Ki.baseState,baseQueue:Ki.baseQueue,queue:Ki.queue,next:null},null===Yi?qi.memoizedState=Yi=e:Yi=Yi.next=e}return Yi}function no(e,t){return"function"==typeof t?t(e):t}function ro(e){var t=to(),n=t.queue;if(null===n)throw Error(o(311));n.lastRenderedReducer=e;var r=Ki,a=r.baseQueue,i=n.pending;if(null!==i){if(null!==a){var l=a.next;a.next=i.next,i.next=l}r.baseQueue=a=i,n.pending=null}if(null!==a){a=a.next,r=r.baseState;var s=l=i=null,c=a;do{var u=c.expirationTime;if(u<Gi){var d={expirationTime:c.expirationTime,suspenseConfig:c.suspenseConfig,action:c.action,eagerReducer:c.eagerReducer,eagerState:c.eagerState,next:null};null===s?(l=s=d,i=r):s=s.next=d,u>qi.expirationTime&&(qi.expirationTime=u,Es(u))}else null!==s&&(s=s.next={expirationTime:1073741823,suspenseConfig:c.suspenseConfig,action:c.action,eagerReducer:c.eagerReducer,eagerState:c.eagerState,next:null}),ks(u,c.suspenseConfig),r=c.eagerReducer===e?c.eagerState:e(r,c.action);c=c.next}while(null!==c&&c!==a);null===s?i=r:s.next=l,Hr(r,t.memoizedState)||(Mo=!0),t.memoizedState=r,t.baseState=i,t.baseQueue=s,n.lastRenderedState=r}return[t.memoizedState,n.dispatch]}function ao(e){var t=to(),n=t.queue;if(null===n)throw Error(o(311));n.lastRenderedReducer=e;var r=n.dispatch,a=n.pending,i=t.memoizedState;if(null!==a){n.pending=null;var l=a=a.next;do{i=e(i,l.action),l=l.next}while(l!==a);Hr(i,t.memoizedState)||(Mo=!0),t.memoizedState=i,null===t.baseQueue&&(t.baseState=i),n.lastRenderedState=i}return[i,r]}function io(e){var t=eo();return"function"==typeof e&&(e=e()),t.memoizedState=t.baseState=e,e=(e=t.queue={pending:null,dispatch:null,lastRenderedReducer:no,lastRenderedState:e}).dispatch=xo.bind(null,qi,e),[t.memoizedState,e]}function oo(e,t,n,r){return e={tag:e,create:t,destroy:n,deps:r,next:null},null===(t=qi.updateQueue)?(t={lastEffect:null},qi.updateQueue=t,t.lastEffect=e.next=e):null===(n=t.lastEffect)?t.lastEffect=e.next=e:(r=n.next,n.next=e,e.next=r,t.lastEffect=e),e}function lo(){return to().memoizedState}function so(e,t,n,r){var a=eo();qi.effectTag|=e,a.memoizedState=oo(1|t,n,void 0,void 0===r?null:r)}function co(e,t,n,r){var a=to();r=void 0===r?null:r;var i=void 0;if(null!==Ki){var o=Ki.memoizedState;if(i=o.destroy,null!==r&&Xi(r,o.deps))return void oo(t,n,i,r)}qi.effectTag|=e,a.memoizedState=oo(1|t,n,i,r)}function uo(e,t){return so(516,4,e,t)}function po(e,t){return co(516,4,e,t)}function fo(e,t){return co(4,2,e,t)}function mo(e,t){return"function"==typeof t?(e=e(),t(e),function(){t(null)}):null!=t?(e=e(),t.current=e,function(){t.current=null}):void 0}function go(e,t,n){return n=null!=n?n.concat([e]):null,co(4,2,mo.bind(null,t,e),n)}function ho(){}function bo(e,t){return eo().memoizedState=[e,void 0===t?null:t],e}function vo(e,t){var n=to();t=void 0===t?null:t;var r=n.memoizedState;return null!==r&&null!==t&&Xi(t,r[1])?r[0]:(n.memoizedState=[e,t],e)}function yo(e,t){var n=to();t=void 0===t?null:t;var r=n.memoizedState;return null!==r&&null!==t&&Xi(t,r[1])?r[0]:(e=e(),n.memoizedState=[e,t],e)}function wo(e,t,n){var r=Ga();Ka(98>r?98:r,(function(){e(!0)})),Ka(97<r?97:r,(function(){var r=Vi.suspense;Vi.suspense=void 0===t?null:t;try{e(!1),n()}finally{Vi.suspense=r}}))}function xo(e,t,n){var r=cs(),a=vi.suspense;a={expirationTime:r=us(r,e,a),suspenseConfig:a,action:n,eagerReducer:null,eagerState:null,next:null};var i=t.pending;if(null===i?a.next=a:(a.next=i.next,i.next=a),t.pending=a,i=e.alternate,e===qi||null!==i&&i===qi)Qi=!0,a.expirationTime=Gi,qi.expirationTime=Gi;else{if(0===e.expirationTime&&(null===i||0===i.expirationTime)&&null!==(i=t.lastRenderedReducer))try{var o=t.lastRenderedState,l=i(o,n);if(a.eagerReducer=i,a.eagerState=l,Hr(l,o))return}catch(s){}ds(e,r)}}var ko={readContext:ci,useCallback:Zi,useContext:Zi,useEffect:Zi,useImperativeHandle:Zi,useLayoutEffect:Zi,useMemo:Zi,useReducer:Zi,useRef:Zi,useState:Zi,useDebugValue:Zi,useResponder:Zi,useDeferredValue:Zi,useTransition:Zi},Eo={readContext:ci,useCallback:bo,useContext:ci,useEffect:uo,useImperativeHandle:function(e,t,n){return n=null!=n?n.concat([e]):null,so(4,2,mo.bind(null,t,e),n)},useLayoutEffect:function(e,t){return so(4,2,e,t)},useMemo:function(e,t){var n=eo();return t=void 0===t?null:t,e=e(),n.memoizedState=[e,t],e},useReducer:function(e,t,n){var r=eo();return t=void 0!==n?n(t):t,r.memoizedState=r.baseState=t,e=(e=r.queue={pending:null,dispatch:null,lastRenderedReducer:e,lastRenderedState:t}).dispatch=xo.bind(null,qi,e),[r.memoizedState,e]},useRef:function(e){return e={current:e},eo().memoizedState=e},useState:io,useDebugValue:ho,useResponder:Hi,useDeferredValue:function(e,t){var n=io(e),r=n[0],a=n[1];return uo((function(){var n=Vi.suspense;Vi.suspense=void 0===t?null:t;try{a(e)}finally{Vi.suspense=n}}),[e,t]),r},useTransition:function(e){var t=io(!1),n=t[0];return t=t[1],[bo(wo.bind(null,t,e),[t,e]),n]}},So={readContext:ci,useCallback:vo,useContext:ci,useEffect:po,useImperativeHandle:go,useLayoutEffect:fo,useMemo:yo,useReducer:ro,useRef:lo,useState:function(){return ro(no)},useDebugValue:ho,useResponder:Hi,useDeferredValue:function(e,t){var n=ro(no),r=n[0],a=n[1];return po((function(){var n=Vi.suspense;Vi.suspense=void 0===t?null:t;try{a(e)}finally{Vi.suspense=n}}),[e,t]),r},useTransition:function(e){var t=ro(no),n=t[0];return t=t[1],[vo(wo.bind(null,t,e),[t,e]),n]}},To={readContext:ci,useCallback:vo,useContext:ci,useEffect:po,useImperativeHandle:go,useLayoutEffect:fo,useMemo:yo,useReducer:ao,useRef:lo,useState:function(){return ao(no)},useDebugValue:ho,useResponder:Hi,useDeferredValue:function(e,t){var n=ao(no),r=n[0],a=n[1];return po((function(){var n=Vi.suspense;Vi.suspense=void 0===t?null:t;try{a(e)}finally{Vi.suspense=n}}),[e,t]),r},useTransition:function(e){var t=ao(no),n=t[0];return t=t[1],[vo(wo.bind(null,t,e),[t,e]),n]}},_o=null,Ao=null,Co=!1;function Po(e,t){var n=Us(5,null,null,0);n.elementType="DELETED",n.type="DELETED",n.stateNode=t,n.return=e,n.effectTag=8,null!==e.lastEffect?(e.lastEffect.nextEffect=n,e.lastEffect=n):e.firstEffect=e.lastEffect=n}function No(e,t){switch(e.tag){case 5:var n=e.type;return null!==(t=1!==t.nodeType||n.toLowerCase()!==t.nodeName.toLowerCase()?null:t)&&(e.stateNode=t,!0);case 6:return null!==(t=""===e.pendingProps||3!==t.nodeType?null:t)&&(e.stateNode=t,!0);default:return!1}}function Oo(e){if(Co){var t=Ao;if(t){var n=t;if(!No(e,t)){if(!(t=An(n.nextSibling))||!No(e,t))return e.effectTag=-1025&e.effectTag|2,Co=!1,void(_o=e);Po(_o,n)}_o=e,Ao=An(t.firstChild)}else e.effectTag=-1025&e.effectTag|2,Co=!1,_o=e}}function Io(e){for(e=e.return;null!==e&&5!==e.tag&&3!==e.tag&&13!==e.tag;)e=e.return;_o=e}function Ro(e){if(e!==_o)return!1;if(!Co)return Io(e),Co=!0,!1;var t=e.type;if(5!==e.tag||"head"!==t&&"body"!==t&&!Sn(t,e.memoizedProps))for(t=Ao;t;)Po(e,t),t=An(t.nextSibling);if(Io(e),13===e.tag){if(!(e=null!==(e=e.memoizedState)?e.dehydrated:null))throw Error(o(317));e:{for(e=e.nextSibling,t=0;e;){if(8===e.nodeType){var n=e.data;if(n===vn){if(0===t){Ao=An(e.nextSibling);break e}t--}else n!==bn&&n!==wn&&n!==yn||t++}e=e.nextSibling}Ao=null}}else Ao=_o?An(e.stateNode.nextSibling):null;return!0}function Do(){Ao=_o=null,Co=!1}var Lo=Q.ReactCurrentOwner,Mo=!1;function Fo(e,t,n,r){t.child=null===e?Oi(t,null,n,r):Ni(t,e.child,n,r)}function Bo(e,t,n,r,a){n=n.render;var i=t.ref;return si(t,a),r=Ji(e,t,n,r,i,a),null===e||Mo?(t.effectTag|=1,Fo(e,t,r,a),t.child):(t.updateQueue=e.updateQueue,t.effectTag&=-517,e.expirationTime<=a&&(e.expirationTime=0),tl(e,t,a))}function $o(e,t,n,r,a,i){if(null===e){var o=n.type;return"function"!=typeof o||js(o)||void 0!==o.defaultProps||null!==n.compare||void 0!==n.defaultProps?((e=Ws(n.type,null,r,null,t.mode,i)).ref=t.ref,e.return=t,t.child=e):(t.tag=15,t.type=o,zo(e,t,o,r,a,i))}return o=e.child,a<i&&(a=o.memoizedProps,(n=null!==(n=n.compare)?n:Vr)(a,r)&&e.ref===t.ref)?tl(e,t,i):(t.effectTag|=1,(e=Hs(o,r)).ref=t.ref,e.return=t,t.child=e)}function zo(e,t,n,r,a,i){return null!==e&&Vr(e.memoizedProps,r)&&e.ref===t.ref&&(Mo=!1,a<i)?(t.expirationTime=e.expirationTime,tl(e,t,i)):jo(e,t,n,r,i)}function Uo(e,t){var n=t.ref;(null===e&&null!==n||null!==e&&e.ref!==n)&&(t.effectTag|=128)}function jo(e,t,n,r,a){var i=xa(n)?ya:ba.current;return i=wa(t,i),si(t,a),n=Ji(e,t,n,r,i,a),null===e||Mo?(t.effectTag|=1,Fo(e,t,n,a),t.child):(t.updateQueue=e.updateQueue,t.effectTag&=-517,e.expirationTime<=a&&(e.expirationTime=0),tl(e,t,a))}function Ho(e,t,n,r,a){if(xa(n)){var i=!0;Ta(t)}else i=!1;if(si(t,a),null===t.stateNode)null!==e&&(e.alternate=null,t.alternate=null,t.effectTag|=2),Ei(t,n,r),Ti(t,n,r,a),r=!0;else if(null===e){var o=t.stateNode,l=t.memoizedProps;o.props=l;var s=o.context,c=n.contextType;"object"==typeof c&&null!==c?c=ci(c):c=wa(t,c=xa(n)?ya:ba.current);var u=n.getDerivedStateFromProps,d="function"==typeof u||"function"==typeof o.getSnapshotBeforeUpdate;d||"function"!=typeof o.UNSAFE_componentWillReceiveProps&&"function"!=typeof o.componentWillReceiveProps||(l!==r||s!==c)&&Si(t,o,r,c),ui=!1;var p=t.memoizedState;o.state=p,hi(t,r,o,a),s=t.memoizedState,l!==r||p!==s||va.current||ui?("function"==typeof u&&(wi(t,n,u,r),s=t.memoizedState),(l=ui||ki(t,n,l,r,p,s,c))?(d||"function"!=typeof o.UNSAFE_componentWillMount&&"function"!=typeof o.componentWillMount||("function"==typeof o.componentWillMount&&o.componentWillMount(),"function"==typeof o.UNSAFE_componentWillMount&&o.UNSAFE_componentWillMount()),"function"==typeof o.componentDidMount&&(t.effectTag|=4)):("function"==typeof o.componentDidMount&&(t.effectTag|=4),t.memoizedProps=r,t.memoizedState=s),o.props=r,o.state=s,o.context=c,r=l):("function"==typeof o.componentDidMount&&(t.effectTag|=4),r=!1)}else o=t.stateNode,pi(e,t),l=t.memoizedProps,o.props=t.type===t.elementType?l:ei(t.type,l),s=o.context,"object"==typeof(c=n.contextType)&&null!==c?c=ci(c):c=wa(t,c=xa(n)?ya:ba.current),(d="function"==typeof(u=n.getDerivedStateFromProps)||"function"==typeof o.getSnapshotBeforeUpdate)||"function"!=typeof o.UNSAFE_componentWillReceiveProps&&"function"!=typeof o.componentWillReceiveProps||(l!==r||s!==c)&&Si(t,o,r,c),ui=!1,s=t.memoizedState,o.state=s,hi(t,r,o,a),p=t.memoizedState,l!==r||s!==p||va.current||ui?("function"==typeof u&&(wi(t,n,u,r),p=t.memoizedState),(u=ui||ki(t,n,l,r,s,p,c))?(d||"function"!=typeof o.UNSAFE_componentWillUpdate&&"function"!=typeof o.componentWillUpdate||("function"==typeof o.componentWillUpdate&&o.componentWillUpdate(r,p,c),"function"==typeof o.UNSAFE_componentWillUpdate&&o.UNSAFE_componentWillUpdate(r,p,c)),"function"==typeof o.componentDidUpdate&&(t.effectTag|=4),"function"==typeof o.getSnapshotBeforeUpdate&&(t.effectTag|=256)):("function"!=typeof o.componentDidUpdate||l===e.memoizedProps&&s===e.memoizedState||(t.effectTag|=4),"function"!=typeof o.getSnapshotBeforeUpdate||l===e.memoizedProps&&s===e.memoizedState||(t.effectTag|=256),t.memoizedProps=r,t.memoizedState=p),o.props=r,o.state=p,o.context=c,r=u):("function"!=typeof o.componentDidUpdate||l===e.memoizedProps&&s===e.memoizedState||(t.effectTag|=4),"function"!=typeof o.getSnapshotBeforeUpdate||l===e.memoizedProps&&s===e.memoizedState||(t.effectTag|=256),r=!1);return Wo(e,t,n,r,i,a)}function Wo(e,t,n,r,a,i){Uo(e,t);var o=!!(64&t.effectTag);if(!r&&!o)return a&&_a(t,n,!1),tl(e,t,i);r=t.stateNode,Lo.current=t;var l=o&&"function"!=typeof n.getDerivedStateFromError?null:r.render();return t.effectTag|=1,null!==e&&o?(t.child=Ni(t,e.child,null,i),t.child=Ni(t,null,l,i)):Fo(e,t,l,i),t.memoizedState=r.state,a&&_a(t,n,!0),t.child}function Vo(e){var t=e.stateNode;t.pendingContext?Ea(0,t.pendingContext,t.pendingContext!==t.context):t.context&&Ea(0,t.context,!1),Fi(e,t.containerInfo)}var Go,qo,Ko,Yo,Qo={dehydrated:null,retryTime:0};function Zo(e,t,n){var r,a=t.mode,i=t.pendingProps,o=Ui.current,l=!1;if((r=!!(64&t.effectTag))||(r=!!(2&o)&&(null===e||null!==e.memoizedState)),r?(l=!0,t.effectTag&=-65):null!==e&&null===e.memoizedState||void 0===i.fallback||!0===i.unstable_avoidThisFallback||(o|=1),ga(Ui,1&o),null===e){if(void 0!==i.fallback&&Oo(t),l){if(l=i.fallback,(i=Vs(null,a,0,null)).return=t,!(2&t.mode))for(e=null!==t.memoizedState?t.child.child:t.child,i.child=e;null!==e;)e.return=i,e=e.sibling;return(n=Vs(l,a,n,null)).return=t,i.sibling=n,t.memoizedState=Qo,t.child=i,n}return a=i.children,t.memoizedState=null,t.child=Oi(t,null,a,n)}if(null!==e.memoizedState){if(a=(e=e.child).sibling,l){if(i=i.fallback,(n=Hs(e,e.pendingProps)).return=t,!(2&t.mode)&&(l=null!==t.memoizedState?t.child.child:t.child)!==e.child)for(n.child=l;null!==l;)l.return=n,l=l.sibling;return(a=Hs(a,i)).return=t,n.sibling=a,n.childExpirationTime=0,t.memoizedState=Qo,t.child=n,a}return n=Ni(t,e.child,i.children,n),t.memoizedState=null,t.child=n}if(e=e.child,l){if(l=i.fallback,(i=Vs(null,a,0,null)).return=t,i.child=e,null!==e&&(e.return=i),!(2&t.mode))for(e=null!==t.memoizedState?t.child.child:t.child,i.child=e;null!==e;)e.return=i,e=e.sibling;return(n=Vs(l,a,n,null)).return=t,i.sibling=n,n.effectTag|=2,i.childExpirationTime=0,t.memoizedState=Qo,t.child=i,n}return t.memoizedState=null,t.child=Ni(t,e,i.children,n)}function Xo(e,t){e.expirationTime<t&&(e.expirationTime=t);var n=e.alternate;null!==n&&n.expirationTime<t&&(n.expirationTime=t),li(e.return,t)}function Jo(e,t,n,r,a,i){var o=e.memoizedState;null===o?e.memoizedState={isBackwards:t,rendering:null,renderingStartTime:0,last:r,tail:n,tailExpiration:0,tailMode:a,lastEffect:i}:(o.isBackwards=t,o.rendering=null,o.renderingStartTime=0,o.last=r,o.tail=n,o.tailExpiration=0,o.tailMode=a,o.lastEffect=i)}function el(e,t,n){var r=t.pendingProps,a=r.revealOrder,i=r.tail;if(Fo(e,t,r.children,n),2&(r=Ui.current))r=1&r|2,t.effectTag|=64;else{if(null!==e&&64&e.effectTag)e:for(e=t.child;null!==e;){if(13===e.tag)null!==e.memoizedState&&Xo(e,n);else if(19===e.tag)Xo(e,n);else if(null!==e.child){e.child.return=e,e=e.child;continue}if(e===t)break e;for(;null===e.sibling;){if(null===e.return||e.return===t)break e;e=e.return}e.sibling.return=e.return,e=e.sibling}r&=1}if(ga(Ui,r),2&t.mode)switch(a){case"forwards":for(n=t.child,a=null;null!==n;)null!==(e=n.alternate)&&null===ji(e)&&(a=n),n=n.sibling;null===(n=a)?(a=t.child,t.child=null):(a=n.sibling,n.sibling=null),Jo(t,!1,a,n,i,t.lastEffect);break;case"backwards":for(n=null,a=t.child,t.child=null;null!==a;){if(null!==(e=a.alternate)&&null===ji(e)){t.child=a;break}e=a.sibling,a.sibling=n,n=a,a=e}Jo(t,!0,n,null,i,t.lastEffect);break;case"together":Jo(t,!1,null,null,void 0,t.lastEffect);break;default:t.memoizedState=null}else t.memoizedState=null;return t.child}function tl(e,t,n){null!==e&&(t.dependencies=e.dependencies);var r=t.expirationTime;if(0!==r&&Es(r),t.childExpirationTime<n)return null;if(null!==e&&t.child!==e.child)throw Error(o(153));if(null!==t.child){for(n=Hs(e=t.child,e.pendingProps),t.child=n,n.return=t;null!==e.sibling;)e=e.sibling,(n=n.sibling=Hs(e,e.pendingProps)).return=t;n.sibling=null}return t.child}function nl(e,t){switch(e.tailMode){case"hidden":t=e.tail;for(var n=null;null!==t;)null!==t.alternate&&(n=t),t=t.sibling;null===n?e.tail=null:n.sibling=null;break;case"collapsed":n=e.tail;for(var r=null;null!==n;)null!==n.alternate&&(r=n),n=n.sibling;null===r?t||null===e.tail?e.tail=null:e.tail.sibling=null:r.sibling=null}}function rl(e,t,n){var r=t.pendingProps;switch(t.tag){case 2:case 16:case 15:case 0:case 11:case 7:case 8:case 12:case 9:case 14:return null;case 1:case 17:return xa(t.type)&&ka(),null;case 3:return Bi(),ma(va),ma(ba),(n=t.stateNode).pendingContext&&(n.context=n.pendingContext,n.pendingContext=null),null!==e&&null!==e.child||!Ro(t)||(t.effectTag|=4),qo(t),null;case 5:zi(t),n=Mi(Li.current);var i=t.type;if(null!==e&&null!=t.stateNode)Ko(e,t,i,r,n),e.ref!==t.ref&&(t.effectTag|=128);else{if(!r){if(null===t.stateNode)throw Error(o(166));return null}if(e=Mi(Ri.current),Ro(t)){r=t.stateNode,i=t.type;var l=t.memoizedProps;switch(r[Nn]=t,r[On]=l,i){case"iframe":case"object":case"embed":Kt("load",r);break;case"video":case"audio":for(e=0;e<Ze.length;e++)Kt(Ze[e],r);break;case"source":Kt("error",r);break;case"img":case"image":case"link":Kt("error",r),Kt("load",r);break;case"form":Kt("reset",r),Kt("submit",r);break;case"details":Kt("toggle",r);break;case"input":Ee(r,l),Kt("invalid",r),cn(n,"onChange");break;case"select":r._wrapperState={wasMultiple:!!l.multiple},Kt("invalid",r),cn(n,"onChange");break;case"textarea":Oe(r,l),Kt("invalid",r),cn(n,"onChange")}for(var s in on(i,l),e=null,l)if(l.hasOwnProperty(s)){var c=l[s];"children"===s?"string"==typeof c?r.textContent!==c&&(e=["children",c]):"number"==typeof c&&r.textContent!==""+c&&(e=["children",""+c]):S.hasOwnProperty(s)&&null!=c&&cn(n,s)}switch(i){case"input":we(r),_e(r,l,!0);break;case"textarea":we(r),Re(r);break;case"select":case"option":break;default:"function"==typeof l.onClick&&(r.onclick=un)}n=e,t.updateQueue=n,null!==n&&(t.effectTag|=4)}else{switch(s=9===n.nodeType?n:n.ownerDocument,e===sn&&(e=Me(i)),e===sn?"script"===i?((e=s.createElement("div")).innerHTML="<script><\/script>",e=e.removeChild(e.firstChild)):"string"==typeof r.is?e=s.createElement(i,{is:r.is}):(e=s.createElement(i),"select"===i&&(s=e,r.multiple?s.multiple=!0:r.size&&(s.size=r.size))):e=s.createElementNS(e,i),e[Nn]=t,e[On]=r,Go(e,t,!1,!1),t.stateNode=e,s=ln(i,r),i){case"iframe":case"object":case"embed":Kt("load",e),c=r;break;case"video":case"audio":for(c=0;c<Ze.length;c++)Kt(Ze[c],e);c=r;break;case"source":Kt("error",e),c=r;break;case"img":case"image":case"link":Kt("error",e),Kt("load",e),c=r;break;case"form":Kt("reset",e),Kt("submit",e),c=r;break;case"details":Kt("toggle",e),c=r;break;case"input":Ee(e,r),c=ke(e,r),Kt("invalid",e),cn(n,"onChange");break;case"option":c=Ce(e,r);break;case"select":e._wrapperState={wasMultiple:!!r.multiple},c=a({},r,{value:void 0}),Kt("invalid",e),cn(n,"onChange");break;case"textarea":Oe(e,r),c=Ne(e,r),Kt("invalid",e),cn(n,"onChange");break;default:c=r}on(i,c);var u=c;for(l in u)if(u.hasOwnProperty(l)){var d=u[l];"style"===l?rn(e,d):"dangerouslySetInnerHTML"===l?null!=(d=d?d.__html:void 0)&&ze(e,d):"children"===l?"string"==typeof d?("textarea"!==i||""!==d)&&Ue(e,d):"number"==typeof d&&Ue(e,""+d):"suppressContentEditableWarning"!==l&&"suppressHydrationWarning"!==l&&"autoFocus"!==l&&(S.hasOwnProperty(l)?null!=d&&cn(n,l):null!=d&&Z(e,l,d,s))}switch(i){case"input":we(e),_e(e,r,!1);break;case"textarea":we(e),Re(e);break;case"option":null!=r.value&&e.setAttribute("value",""+ve(r.value));break;case"select":e.multiple=!!r.multiple,null!=(n=r.value)?Pe(e,!!r.multiple,n,!1):null!=r.defaultValue&&Pe(e,!!r.multiple,r.defaultValue,!0);break;default:"function"==typeof c.onClick&&(e.onclick=un)}En(i,r)&&(t.effectTag|=4)}null!==t.ref&&(t.effectTag|=128)}return null;case 6:if(e&&null!=t.stateNode)Yo(e,t,e.memoizedProps,r);else{if("string"!=typeof r&&null===t.stateNode)throw Error(o(166));n=Mi(Li.current),Mi(Ri.current),Ro(t)?(n=t.stateNode,r=t.memoizedProps,n[Nn]=t,n.nodeValue!==r&&(t.effectTag|=4)):((n=(9===n.nodeType?n:n.ownerDocument).createTextNode(r))[Nn]=t,t.stateNode=n)}return null;case 13:return ma(Ui),r=t.memoizedState,64&t.effectTag?(t.expirationTime=n,t):(n=null!==r,r=!1,null===e?void 0!==t.memoizedProps.fallback&&Ro(t):(r=null!==(i=e.memoizedState),n||null===i||null!==(i=e.child.sibling)&&(null!==(l=t.firstEffect)?(t.firstEffect=i,i.nextEffect=l):(t.firstEffect=t.lastEffect=i,i.nextEffect=null),i.effectTag=8)),n&&!r&&2&t.mode&&(null===e&&!0!==t.memoizedProps.unstable_avoidThisFallback||1&Ui.current?Hl===Rl&&(Hl=Ml):(Hl!==Rl&&Hl!==Ml||(Hl=Fl),0!==Kl&&null!==zl&&(Qs(zl,jl),Zs(zl,Kl)))),(n||r)&&(t.effectTag|=4),null);case 4:return Bi(),qo(t),null;case 10:return oi(t),null;case 19:if(ma(Ui),null===(r=t.memoizedState))return null;if(i=!!(64&t.effectTag),null===(l=r.rendering)){if(i)nl(r,!1);else if(Hl!==Rl||null!==e&&64&e.effectTag)for(l=t.child;null!==l;){if(null!==(e=ji(l))){for(t.effectTag|=64,nl(r,!1),null!==(i=e.updateQueue)&&(t.updateQueue=i,t.effectTag|=4),null===r.lastEffect&&(t.firstEffect=null),t.lastEffect=r.lastEffect,r=t.child;null!==r;)l=n,(i=r).effectTag&=2,i.nextEffect=null,i.firstEffect=null,i.lastEffect=null,null===(e=i.alternate)?(i.childExpirationTime=0,i.expirationTime=l,i.child=null,i.memoizedProps=null,i.memoizedState=null,i.updateQueue=null,i.dependencies=null):(i.childExpirationTime=e.childExpirationTime,i.expirationTime=e.expirationTime,i.child=e.child,i.memoizedProps=e.memoizedProps,i.memoizedState=e.memoizedState,i.updateQueue=e.updateQueue,l=e.dependencies,i.dependencies=null===l?null:{expirationTime:l.expirationTime,firstContext:l.firstContext,responders:l.responders}),r=r.sibling;return ga(Ui,1&Ui.current|2),t.child}l=l.sibling}}else{if(!i)if(null!==(e=ji(l))){if(t.effectTag|=64,i=!0,null!==(n=e.updateQueue)&&(t.updateQueue=n,t.effectTag|=4),nl(r,!0),null===r.tail&&"hidden"===r.tailMode&&!l.alternate)return null!==(t=t.lastEffect=r.lastEffect)&&(t.nextEffect=null),null}else 2*Va()-r.renderingStartTime>r.tailExpiration&&1<n&&(t.effectTag|=64,i=!0,nl(r,!1),t.expirationTime=t.childExpirationTime=n-1);r.isBackwards?(l.sibling=t.child,t.child=l):(null!==(n=r.last)?n.sibling=l:t.child=l,r.last=l)}return null!==r.tail?(0===r.tailExpiration&&(r.tailExpiration=Va()+500),n=r.tail,r.rendering=n,r.tail=n.sibling,r.lastEffect=t.lastEffect,r.renderingStartTime=Va(),n.sibling=null,t=Ui.current,ga(Ui,i?1&t|2:1&t),n):null}throw Error(o(156,t.tag))}function al(e){switch(e.tag){case 1:xa(e.type)&&ka();var t=e.effectTag;return 4096&t?(e.effectTag=-4097&t|64,e):null;case 3:if(Bi(),ma(va),ma(ba),64&(t=e.effectTag))throw Error(o(285));return e.effectTag=-4097&t|64,e;case 5:return zi(e),null;case 13:return ma(Ui),4096&(t=e.effectTag)?(e.effectTag=-4097&t|64,e):null;case 19:return ma(Ui),null;case 4:return Bi(),null;case 10:return oi(e),null;default:return null}}function il(e,t){return{value:e,source:t,stack:be(t)}}Go=function(e,t){for(var n=t.child;null!==n;){if(5===n.tag||6===n.tag)e.appendChild(n.stateNode);else if(4!==n.tag&&null!==n.child){n.child.return=n,n=n.child;continue}if(n===t)break;for(;null===n.sibling;){if(null===n.return||n.return===t)return;n=n.return}n.sibling.return=n.return,n=n.sibling}},qo=function(){},Ko=function(e,t,n,r,i){var o=e.memoizedProps;if(o!==r){var l,s,c=t.stateNode;switch(Mi(Ri.current),e=null,n){case"input":o=ke(c,o),r=ke(c,r),e=[];break;case"option":o=Ce(c,o),r=Ce(c,r),e=[];break;case"select":o=a({},o,{value:void 0}),r=a({},r,{value:void 0}),e=[];break;case"textarea":o=Ne(c,o),r=Ne(c,r),e=[];break;default:"function"!=typeof o.onClick&&"function"==typeof r.onClick&&(c.onclick=un)}for(l in on(n,r),n=null,o)if(!r.hasOwnProperty(l)&&o.hasOwnProperty(l)&&null!=o[l])if("style"===l)for(s in c=o[l])c.hasOwnProperty(s)&&(n||(n={}),n[s]="");else"dangerouslySetInnerHTML"!==l&&"children"!==l&&"suppressContentEditableWarning"!==l&&"suppressHydrationWarning"!==l&&"autoFocus"!==l&&(S.hasOwnProperty(l)?e||(e=[]):(e=e||[]).push(l,null));for(l in r){var u=r[l];if(c=null!=o?o[l]:void 0,r.hasOwnProperty(l)&&u!==c&&(null!=u||null!=c))if("style"===l)if(c){for(s in c)!c.hasOwnProperty(s)||u&&u.hasOwnProperty(s)||(n||(n={}),n[s]="");for(s in u)u.hasOwnProperty(s)&&c[s]!==u[s]&&(n||(n={}),n[s]=u[s])}else n||(e||(e=[]),e.push(l,n)),n=u;else"dangerouslySetInnerHTML"===l?(u=u?u.__html:void 0,c=c?c.__html:void 0,null!=u&&c!==u&&(e=e||[]).push(l,u)):"children"===l?c===u||"string"!=typeof u&&"number"!=typeof u||(e=e||[]).push(l,""+u):"suppressContentEditableWarning"!==l&&"suppressHydrationWarning"!==l&&(S.hasOwnProperty(l)?(null!=u&&cn(i,l),e||c===u||(e=[])):(e=e||[]).push(l,u))}n&&(e=e||[]).push("style",n),i=e,(t.updateQueue=i)&&(t.effectTag|=4)}},Yo=function(e,t,n,r){n!==r&&(t.effectTag|=4)};var ol="function"==typeof WeakSet?WeakSet:Set;function ll(e,t){var n=t.source,r=t.stack;null===r&&null!==n&&(r=be(n)),null!==n&&he(n.type),t=t.value,null!==e&&1===e.tag&&he(e.type);try{console.error(t)}catch(a){setTimeout((function(){throw a}))}}function sl(e){var t=e.ref;if(null!==t)if("function"==typeof t)try{t(null)}catch(n){Ls(e,n)}else t.current=null}function cl(e,t){switch(t.tag){case 0:case 11:case 15:case 22:case 3:case 5:case 6:case 4:case 17:return;case 1:if(256&t.effectTag&&null!==e){var n=e.memoizedProps,r=e.memoizedState;t=(e=t.stateNode).getSnapshotBeforeUpdate(t.elementType===t.type?n:ei(t.type,n),r),e.__reactInternalSnapshotBeforeUpdate=t}return}throw Error(o(163))}function ul(e,t){if(null!==(t=null!==(t=t.updateQueue)?t.lastEffect:null)){var n=t=t.next;do{if((n.tag&e)===e){var r=n.destroy;n.destroy=void 0,void 0!==r&&r()}n=n.next}while(n!==t)}}function dl(e,t){if(null!==(t=null!==(t=t.updateQueue)?t.lastEffect:null)){var n=t=t.next;do{if((n.tag&e)===e){var r=n.create;n.destroy=r()}n=n.next}while(n!==t)}}function pl(e,t,n){switch(n.tag){case 0:case 11:case 15:case 22:return void dl(3,n);case 1:if(e=n.stateNode,4&n.effectTag)if(null===t)e.componentDidMount();else{var r=n.elementType===n.type?t.memoizedProps:ei(n.type,t.memoizedProps);e.componentDidUpdate(r,t.memoizedState,e.__reactInternalSnapshotBeforeUpdate)}return void(null!==(t=n.updateQueue)&&bi(n,t,e));case 3:if(null!==(t=n.updateQueue)){if(e=null,null!==n.child)switch(n.child.tag){case 5:case 1:e=n.child.stateNode}bi(n,t,e)}return;case 5:return e=n.stateNode,void(null===t&&4&n.effectTag&&En(n.type,n.memoizedProps)&&e.focus());case 6:case 4:case 12:case 19:case 17:case 20:case 21:return;case 13:return void(null===n.memoizedState&&(n=n.alternate,null!==n&&(n=n.memoizedState,null!==n&&(n=n.dehydrated,null!==n&&Ft(n)))))}throw Error(o(163))}function fl(e,t,n){switch("function"==typeof $s&&$s(t),t.tag){case 0:case 11:case 14:case 15:case 22:if(null!==(e=t.updateQueue)&&null!==(e=e.lastEffect)){var r=e.next;Ka(97<n?97:n,(function(){var e=r;do{var n=e.destroy;if(void 0!==n){var a=t;try{n()}catch(i){Ls(a,i)}}e=e.next}while(e!==r)}))}break;case 1:sl(t),"function"==typeof(n=t.stateNode).componentWillUnmount&&function(e,t){try{t.props=e.memoizedProps,t.state=e.memoizedState,t.componentWillUnmount()}catch(n){Ls(e,n)}}(t,n);break;case 5:sl(t);break;case 4:yl(e,t,n)}}function ml(e){var t=e.alternate;e.return=null,e.child=null,e.memoizedState=null,e.updateQueue=null,e.dependencies=null,e.alternate=null,e.firstEffect=null,e.lastEffect=null,e.pendingProps=null,e.memoizedProps=null,e.stateNode=null,null!==t&&ml(t)}function gl(e){return 5===e.tag||3===e.tag||4===e.tag}function hl(e){e:{for(var t=e.return;null!==t;){if(gl(t)){var n=t;break e}t=t.return}throw Error(o(160))}switch(t=n.stateNode,n.tag){case 5:var r=!1;break;case 3:case 4:t=t.containerInfo,r=!0;break;default:throw Error(o(161))}16&n.effectTag&&(Ue(t,""),n.effectTag&=-17);e:t:for(n=e;;){for(;null===n.sibling;){if(null===n.return||gl(n.return)){n=null;break e}n=n.return}for(n.sibling.return=n.return,n=n.sibling;5!==n.tag&&6!==n.tag&&18!==n.tag;){if(2&n.effectTag)continue t;if(null===n.child||4===n.tag)continue t;n.child.return=n,n=n.child}if(!(2&n.effectTag)){n=n.stateNode;break e}}r?bl(e,n,t):vl(e,n,t)}function bl(e,t,n){var r=e.tag,a=5===r||6===r;if(a)e=a?e.stateNode:e.stateNode.instance,t?8===n.nodeType?n.parentNode.insertBefore(e,t):n.insertBefore(e,t):(8===n.nodeType?(t=n.parentNode).insertBefore(e,n):(t=n).appendChild(e),null!=(n=n._reactRootContainer)||null!==t.onclick||(t.onclick=un));else if(4!==r&&null!==(e=e.child))for(bl(e,t,n),e=e.sibling;null!==e;)bl(e,t,n),e=e.sibling}function vl(e,t,n){var r=e.tag,a=5===r||6===r;if(a)e=a?e.stateNode:e.stateNode.instance,t?n.insertBefore(e,t):n.appendChild(e);else if(4!==r&&null!==(e=e.child))for(vl(e,t,n),e=e.sibling;null!==e;)vl(e,t,n),e=e.sibling}function yl(e,t,n){for(var r,a,i=t,l=!1;;){if(!l){l=i.return;e:for(;;){if(null===l)throw Error(o(160));switch(r=l.stateNode,l.tag){case 5:a=!1;break e;case 3:case 4:r=r.containerInfo,a=!0;break e}l=l.return}l=!0}if(5===i.tag||6===i.tag){e:for(var s=e,c=i,u=n,d=c;;)if(fl(s,d,u),null!==d.child&&4!==d.tag)d.child.return=d,d=d.child;else{if(d===c)break e;for(;null===d.sibling;){if(null===d.return||d.return===c)break e;d=d.return}d.sibling.return=d.return,d=d.sibling}a?(s=r,c=i.stateNode,8===s.nodeType?s.parentNode.removeChild(c):s.removeChild(c)):r.removeChild(i.stateNode)}else if(4===i.tag){if(null!==i.child){r=i.stateNode.containerInfo,a=!0,i.child.return=i,i=i.child;continue}}else if(fl(e,i,n),null!==i.child){i.child.return=i,i=i.child;continue}if(i===t)break;for(;null===i.sibling;){if(null===i.return||i.return===t)return;4===(i=i.return).tag&&(l=!1)}i.sibling.return=i.return,i=i.sibling}}function wl(e,t){switch(t.tag){case 0:case 11:case 14:case 15:case 22:return void ul(3,t);case 1:case 12:case 17:return;case 5:var n=t.stateNode;if(null!=n){var r=t.memoizedProps,a=null!==e?e.memoizedProps:r;e=t.type;var i=t.updateQueue;if(t.updateQueue=null,null!==i){for(n[On]=r,"input"===e&&"radio"===r.type&&null!=r.name&&Se(n,r),ln(e,a),t=ln(e,r),a=0;a<i.length;a+=2){var l=i[a],s=i[a+1];"style"===l?rn(n,s):"dangerouslySetInnerHTML"===l?ze(n,s):"children"===l?Ue(n,s):Z(n,l,s,t)}switch(e){case"input":Te(n,r);break;case"textarea":Ie(n,r);break;case"select":t=n._wrapperState.wasMultiple,n._wrapperState.wasMultiple=!!r.multiple,null!=(e=r.value)?Pe(n,!!r.multiple,e,!1):t!==!!r.multiple&&(null!=r.defaultValue?Pe(n,!!r.multiple,r.defaultValue,!0):Pe(n,!!r.multiple,r.multiple?[]:"",!1))}}}return;case 6:if(null===t.stateNode)throw Error(o(162));return void(t.stateNode.nodeValue=t.memoizedProps);case 3:return void((t=t.stateNode).hydrate&&(t.hydrate=!1,Ft(t.containerInfo)));case 13:if(n=t,null===t.memoizedState?r=!1:(r=!0,n=t.child,Ql=Va()),null!==n)e:for(e=n;;){if(5===e.tag)i=e.stateNode,r?"function"==typeof(i=i.style).setProperty?i.setProperty("display","none","important"):i.display="none":(i=e.stateNode,a=null!=(a=e.memoizedProps.style)&&a.hasOwnProperty("display")?a.display:null,i.style.display=nn("display",a));else if(6===e.tag)e.stateNode.nodeValue=r?"":e.memoizedProps;else{if(13===e.tag&&null!==e.memoizedState&&null===e.memoizedState.dehydrated){(i=e.child.sibling).return=e,e=i;continue}if(null!==e.child){e.child.return=e,e=e.child;continue}}if(e===n)break;for(;null===e.sibling;){if(null===e.return||e.return===n)break e;e=e.return}e.sibling.return=e.return,e=e.sibling}return void xl(t);case 19:return void xl(t)}throw Error(o(163))}function xl(e){var t=e.updateQueue;if(null!==t){e.updateQueue=null;var n=e.stateNode;null===n&&(n=e.stateNode=new ol),t.forEach((function(t){var r=Fs.bind(null,e,t);n.has(t)||(n.add(t),t.then(r,r))}))}}var kl="function"==typeof WeakMap?WeakMap:Map;function El(e,t,n){(n=fi(n,null)).tag=3,n.payload={element:null};var r=t.value;return n.callback=function(){Jl||(Jl=!0,es=r),ll(e,t)},n}function Sl(e,t,n){(n=fi(n,null)).tag=3;var r=e.type.getDerivedStateFromError;if("function"==typeof r){var a=t.value;n.payload=function(){return ll(e,t),r(a)}}var i=e.stateNode;return null!==i&&"function"==typeof i.componentDidCatch&&(n.callback=function(){"function"!=typeof r&&(null===ts?ts=new Set([this]):ts.add(this),ll(e,t));var n=t.stack;this.componentDidCatch(t.value,{componentStack:null!==n?n:""})}),n}var Tl,_l=Math.ceil,Al=Q.ReactCurrentDispatcher,Cl=Q.ReactCurrentOwner,Pl=0,Nl=8,Ol=16,Il=32,Rl=0,Dl=1,Ll=2,Ml=3,Fl=4,Bl=5,$l=Pl,zl=null,Ul=null,jl=0,Hl=Rl,Wl=null,Vl=1073741823,Gl=1073741823,ql=null,Kl=0,Yl=!1,Ql=0,Zl=500,Xl=null,Jl=!1,es=null,ts=null,ns=!1,rs=null,as=90,is=null,os=0,ls=null,ss=0;function cs(){return($l&(Ol|Il))!==Pl?1073741821-(Va()/10|0):0!==ss?ss:ss=1073741821-(Va()/10|0)}function us(e,t,n){if(!(2&(t=t.mode)))return 1073741823;var r=Ga();if(!(4&t))return 99===r?1073741823:1073741822;if(($l&Ol)!==Pl)return jl;if(null!==n)e=Ja(e,0|n.timeoutMs||5e3,250);else switch(r){case 99:e=1073741823;break;case 98:e=Ja(e,150,100);break;case 97:case 96:e=Ja(e,5e3,250);break;case 95:e=2;break;default:throw Error(o(326))}return null!==zl&&e===jl&&--e,e}function ds(e,t){if(50<os)throw os=0,ls=null,Error(o(185));if(null!==(e=ps(e,t))){var n=Ga();1073741823===t?($l&Nl)!==Pl&&($l&(Ol|Il))===Pl?hs(e):(ms(e),$l===Pl&&Za()):ms(e),(4&$l)===Pl||98!==n&&99!==n||(null===is?is=new Map([[e,t]]):(void 0===(n=is.get(e))||n>t)&&is.set(e,t))}}function ps(e,t){e.expirationTime<t&&(e.expirationTime=t);var n=e.alternate;null!==n&&n.expirationTime<t&&(n.expirationTime=t);var r=e.return,a=null;if(null===r&&3===e.tag)a=e.stateNode;else for(;null!==r;){if(n=r.alternate,r.childExpirationTime<t&&(r.childExpirationTime=t),null!==n&&n.childExpirationTime<t&&(n.childExpirationTime=t),null===r.return&&3===r.tag){a=r.stateNode;break}r=r.return}return null!==a&&(zl===a&&(Es(t),Hl===Fl&&Qs(a,jl)),Zs(a,t)),a}function fs(e){var t=e.lastExpiredTime;if(0!==t)return t;if(!Ys(e,t=e.firstPendingTime))return t;var n=e.lastPingedTime;return 2>=(e=n>(e=e.nextKnownPendingLevel)?n:e)&&t!==e?0:e}function ms(e){if(0!==e.lastExpiredTime)e.callbackExpirationTime=1073741823,e.callbackPriority=99,e.callbackNode=Qa(hs.bind(null,e));else{var t=fs(e),n=e.callbackNode;if(0===t)null!==n&&(e.callbackNode=null,e.callbackExpirationTime=0,e.callbackPriority=90);else{var r=cs();if(1073741823===t?r=99:1===t||2===t?r=95:r=0>=(r=10*(1073741821-t)-10*(1073741821-r))?99:250>=r?98:5250>=r?97:95,null!==n){var a=e.callbackPriority;if(e.callbackExpirationTime===t&&a>=r)return;n!==Ba&&Pa(n)}e.callbackExpirationTime=t,e.callbackPriority=r,t=1073741823===t?Qa(hs.bind(null,e)):Ya(r,gs.bind(null,e),{timeout:10*(1073741821-t)-Va()}),e.callbackNode=t}}}function gs(e,t){if(ss=0,t)return Xs(e,t=cs()),ms(e),null;var n=fs(e);if(0!==n){if(t=e.callbackNode,($l&(Ol|Il))!==Pl)throw Error(o(327));if(Is(),e===zl&&n===jl||ys(e,n),null!==Ul){var r=$l;$l|=Ol;for(var a=xs();;)try{Ts();break}catch(s){ws(e,s)}if(ii(),$l=r,Al.current=a,Hl===Dl)throw t=Wl,ys(e,n),Qs(e,n),ms(e),t;if(null===Ul)switch(a=e.finishedWork=e.current.alternate,e.finishedExpirationTime=n,r=Hl,zl=null,r){case Rl:case Dl:throw Error(o(345));case Ll:Xs(e,2<n?2:n);break;case Ml:if(Qs(e,n),n===(r=e.lastSuspendedTime)&&(e.nextKnownPendingLevel=Cs(a)),1073741823===Vl&&10<(a=Ql+Zl-Va())){if(Yl){var i=e.lastPingedTime;if(0===i||i>=n){e.lastPingedTime=n,ys(e,n);break}}if(0!==(i=fs(e))&&i!==n)break;if(0!==r&&r!==n){e.lastPingedTime=r;break}e.timeoutHandle=Tn(Ps.bind(null,e),a);break}Ps(e);break;case Fl:if(Qs(e,n),n===(r=e.lastSuspendedTime)&&(e.nextKnownPendingLevel=Cs(a)),Yl&&(0===(a=e.lastPingedTime)||a>=n)){e.lastPingedTime=n,ys(e,n);break}if(0!==(a=fs(e))&&a!==n)break;if(0!==r&&r!==n){e.lastPingedTime=r;break}if(1073741823!==Gl?r=10*(1073741821-Gl)-Va():1073741823===Vl?r=0:(r=10*(1073741821-Vl)-5e3,0>(r=(a=Va())-r)&&(r=0),(n=10*(1073741821-n)-a)<(r=(120>r?120:480>r?480:1080>r?1080:1920>r?1920:3e3>r?3e3:4320>r?4320:1960*_l(r/1960))-r)&&(r=n)),10<r){e.timeoutHandle=Tn(Ps.bind(null,e),r);break}Ps(e);break;case Bl:if(1073741823!==Vl&&null!==ql){i=Vl;var l=ql;if(0>=(r=0|l.busyMinDurationMs)?r=0:(a=0|l.busyDelayMs,r=(i=Va()-(10*(1073741821-i)-(0|l.timeoutMs||5e3)))<=a?0:a+r-i),10<r){Qs(e,n),e.timeoutHandle=Tn(Ps.bind(null,e),r);break}}Ps(e);break;default:throw Error(o(329))}if(ms(e),e.callbackNode===t)return gs.bind(null,e)}}return null}function hs(e){var t=e.lastExpiredTime;if(t=0!==t?t:1073741823,($l&(Ol|Il))!==Pl)throw Error(o(327));if(Is(),e===zl&&t===jl||ys(e,t),null!==Ul){var n=$l;$l|=Ol;for(var r=xs();;)try{Ss();break}catch(a){ws(e,a)}if(ii(),$l=n,Al.current=r,Hl===Dl)throw n=Wl,ys(e,t),Qs(e,t),ms(e),n;if(null!==Ul)throw Error(o(261));e.finishedWork=e.current.alternate,e.finishedExpirationTime=t,zl=null,Ps(e),ms(e)}return null}function bs(e,t){var n=$l;$l|=1;try{return e(t)}finally{($l=n)===Pl&&Za()}}function vs(e,t){var n=$l;$l&=-2,$l|=Nl;try{return e(t)}finally{($l=n)===Pl&&Za()}}function ys(e,t){e.finishedWork=null,e.finishedExpirationTime=0;var n=e.timeoutHandle;if(-1!==n&&(e.timeoutHandle=-1,_n(n)),null!==Ul)for(n=Ul.return;null!==n;){var r=n;switch(r.tag){case 1:null!=(r=r.type.childContextTypes)&&ka();break;case 3:Bi(),ma(va),ma(ba);break;case 5:zi(r);break;case 4:Bi();break;case 13:case 19:ma(Ui);break;case 10:oi(r)}n=n.return}zl=e,Ul=Hs(e.current,null),jl=t,Hl=Rl,Wl=null,Gl=Vl=1073741823,ql=null,Kl=0,Yl=!1}function ws(e,t){for(;;){try{if(ii(),Wi.current=ko,Qi)for(var n=qi.memoizedState;null!==n;){var r=n.queue;null!==r&&(r.pending=null),n=n.next}if(Gi=0,Yi=Ki=qi=null,Qi=!1,null===Ul||null===Ul.return)return Hl=Dl,Wl=t,Ul=null;e:{var a=e,i=Ul.return,o=Ul,l=t;if(t=jl,o.effectTag|=2048,o.firstEffect=o.lastEffect=null,null!==l&&"object"==typeof l&&"function"==typeof l.then){var s=l;if(!(2&o.mode)){var c=o.alternate;c?(o.updateQueue=c.updateQueue,o.memoizedState=c.memoizedState,o.expirationTime=c.expirationTime):(o.updateQueue=null,o.memoizedState=null)}var u=!!(1&Ui.current),d=i;do{var p;if(p=13===d.tag){var f=d.memoizedState;if(null!==f)p=null!==f.dehydrated;else{var m=d.memoizedProps;p=void 0!==m.fallback&&(!0!==m.unstable_avoidThisFallback||!u)}}if(p){var g=d.updateQueue;if(null===g){var h=new Set;h.add(s),d.updateQueue=h}else g.add(s);if(!(2&d.mode)){if(d.effectTag|=64,o.effectTag&=-2981,1===o.tag)if(null===o.alternate)o.tag=17;else{var b=fi(1073741823,null);b.tag=2,mi(o,b)}o.expirationTime=1073741823;break e}l=void 0,o=t;var v=a.pingCache;if(null===v?(v=a.pingCache=new kl,l=new Set,v.set(s,l)):void 0===(l=v.get(s))&&(l=new Set,v.set(s,l)),!l.has(o)){l.add(o);var y=Ms.bind(null,a,s,o);s.then(y,y)}d.effectTag|=4096,d.expirationTime=t;break e}d=d.return}while(null!==d);l=Error((he(o.type)||"A React component")+" suspended while rendering, but no fallback UI was specified.\n\nAdd a <Suspense fallback=...> component higher in the tree to provide a loading indicator or placeholder to display."+be(o))}Hl!==Bl&&(Hl=Ll),l=il(l,o),d=i;do{switch(d.tag){case 3:s=l,d.effectTag|=4096,d.expirationTime=t,gi(d,El(d,s,t));break e;case 1:s=l;var w=d.type,x=d.stateNode;if(!(64&d.effectTag||"function"!=typeof w.getDerivedStateFromError&&(null===x||"function"!=typeof x.componentDidCatch||null!==ts&&ts.has(x)))){d.effectTag|=4096,d.expirationTime=t,gi(d,Sl(d,s,t));break e}}d=d.return}while(null!==d)}Ul=As(Ul)}catch(k){t=k;continue}break}}function xs(){var e=Al.current;return Al.current=ko,null===e?ko:e}function ks(e,t){e<Vl&&2<e&&(Vl=e),null!==t&&e<Gl&&2<e&&(Gl=e,ql=t)}function Es(e){e>Kl&&(Kl=e)}function Ss(){for(;null!==Ul;)Ul=_s(Ul)}function Ts(){for(;null!==Ul&&!$a();)Ul=_s(Ul)}function _s(e){var t=Tl(e.alternate,e,jl);return e.memoizedProps=e.pendingProps,null===t&&(t=As(e)),Cl.current=null,t}function As(e){Ul=e;do{var t=Ul.alternate;if(e=Ul.return,2048&Ul.effectTag){if(null!==(t=al(Ul)))return t.effectTag&=2047,t;null!==e&&(e.firstEffect=e.lastEffect=null,e.effectTag|=2048)}else{if(t=rl(t,Ul,jl),1===jl||1!==Ul.childExpirationTime){for(var n=0,r=Ul.child;null!==r;){var a=r.expirationTime,i=r.childExpirationTime;a>n&&(n=a),i>n&&(n=i),r=r.sibling}Ul.childExpirationTime=n}if(null!==t)return t;null!==e&&!(2048&e.effectTag)&&(null===e.firstEffect&&(e.firstEffect=Ul.firstEffect),null!==Ul.lastEffect&&(null!==e.lastEffect&&(e.lastEffect.nextEffect=Ul.firstEffect),e.lastEffect=Ul.lastEffect),1<Ul.effectTag&&(null!==e.lastEffect?e.lastEffect.nextEffect=Ul:e.firstEffect=Ul,e.lastEffect=Ul))}if(null!==(t=Ul.sibling))return t;Ul=e}while(null!==Ul);return Hl===Rl&&(Hl=Bl),null}function Cs(e){var t=e.expirationTime;return t>(e=e.childExpirationTime)?t:e}function Ps(e){var t=Ga();return Ka(99,Ns.bind(null,e,t)),null}function Ns(e,t){do{Is()}while(null!==rs);if(($l&(Ol|Il))!==Pl)throw Error(o(327));var n=e.finishedWork,r=e.finishedExpirationTime;if(null===n)return null;if(e.finishedWork=null,e.finishedExpirationTime=0,n===e.current)throw Error(o(177));e.callbackNode=null,e.callbackExpirationTime=0,e.callbackPriority=90,e.nextKnownPendingLevel=0;var a=Cs(n);if(e.firstPendingTime=a,r<=e.lastSuspendedTime?e.firstSuspendedTime=e.lastSuspendedTime=e.nextKnownPendingLevel=0:r<=e.firstSuspendedTime&&(e.firstSuspendedTime=r-1),r<=e.lastPingedTime&&(e.lastPingedTime=0),r<=e.lastExpiredTime&&(e.lastExpiredTime=0),e===zl&&(Ul=zl=null,jl=0),1<n.effectTag?null!==n.lastEffect?(n.lastEffect.nextEffect=n,a=n.firstEffect):a=n:a=n.firstEffect,null!==a){var i=$l;$l|=Il,Cl.current=null,xn=qt;var l=gn();if(hn(l)){if("selectionStart"in l)var s={start:l.selectionStart,end:l.selectionEnd};else e:{var c=(s=(s=l.ownerDocument)&&s.defaultView||window).getSelection&&s.getSelection();if(c&&0!==c.rangeCount){s=c.anchorNode;var u=c.anchorOffset,d=c.focusNode;c=c.focusOffset;try{s.nodeType,d.nodeType}catch(_){s=null;break e}var p=0,f=-1,m=-1,g=0,h=0,b=l,v=null;t:for(;;){for(var y;b!==s||0!==u&&3!==b.nodeType||(f=p+u),b!==d||0!==c&&3!==b.nodeType||(m=p+c),3===b.nodeType&&(p+=b.nodeValue.length),null!==(y=b.firstChild);)v=b,b=y;for(;;){if(b===l)break t;if(v===s&&++g===u&&(f=p),v===d&&++h===c&&(m=p),null!==(y=b.nextSibling))break;v=(b=v).parentNode}b=y}s=-1===f||-1===m?null:{start:f,end:m}}else s=null}s=s||{start:0,end:0}}else s=null;kn={activeElementDetached:null,focusedElem:l,selectionRange:s},qt=!1,Xl=a;do{try{Os()}catch(_){if(null===Xl)throw Error(o(330));Ls(Xl,_),Xl=Xl.nextEffect}}while(null!==Xl);Xl=a;do{try{for(l=e,s=t;null!==Xl;){var w=Xl.effectTag;if(16&w&&Ue(Xl.stateNode,""),128&w){var x=Xl.alternate;if(null!==x){var k=x.ref;null!==k&&("function"==typeof k?k(null):k.current=null)}}switch(1038&w){case 2:hl(Xl),Xl.effectTag&=-3;break;case 6:hl(Xl),Xl.effectTag&=-3,wl(Xl.alternate,Xl);break;case 1024:Xl.effectTag&=-1025;break;case 1028:Xl.effectTag&=-1025,wl(Xl.alternate,Xl);break;case 4:wl(Xl.alternate,Xl);break;case 8:yl(l,u=Xl,s),ml(u)}Xl=Xl.nextEffect}}catch(_){if(null===Xl)throw Error(o(330));Ls(Xl,_),Xl=Xl.nextEffect}}while(null!==Xl);if(k=kn,x=gn(),w=k.focusedElem,s=k.selectionRange,x!==w&&w&&w.ownerDocument&&mn(w.ownerDocument.documentElement,w)){null!==s&&hn(w)&&(x=s.start,void 0===(k=s.end)&&(k=x),"selectionStart"in w?(w.selectionStart=x,w.selectionEnd=Math.min(k,w.value.length)):(k=(x=w.ownerDocument||document)&&x.defaultView||window).getSelection&&(k=k.getSelection(),u=w.textContent.length,l=Math.min(s.start,u),s=void 0===s.end?l:Math.min(s.end,u),!k.extend&&l>s&&(u=s,s=l,l=u),u=fn(w,l),d=fn(w,s),u&&d&&(1!==k.rangeCount||k.anchorNode!==u.node||k.anchorOffset!==u.offset||k.focusNode!==d.node||k.focusOffset!==d.offset)&&((x=x.createRange()).setStart(u.node,u.offset),k.removeAllRanges(),l>s?(k.addRange(x),k.extend(d.node,d.offset)):(x.setEnd(d.node,d.offset),k.addRange(x))))),x=[];for(k=w;k=k.parentNode;)1===k.nodeType&&x.push({element:k,left:k.scrollLeft,top:k.scrollTop});for("function"==typeof w.focus&&w.focus(),w=0;w<x.length;w++)(k=x[w]).element.scrollLeft=k.left,k.element.scrollTop=k.top}qt=!!xn,kn=xn=null,e.current=n,Xl=a;do{try{for(w=e;null!==Xl;){var E=Xl.effectTag;if(36&E&&pl(w,Xl.alternate,Xl),128&E){x=void 0;var S=Xl.ref;if(null!==S){var T=Xl.stateNode;Xl.tag,x=T,"function"==typeof S?S(x):S.current=x}}Xl=Xl.nextEffect}}catch(_){if(null===Xl)throw Error(o(330));Ls(Xl,_),Xl=Xl.nextEffect}}while(null!==Xl);Xl=null,za(),$l=i}else e.current=n;if(ns)ns=!1,rs=e,as=t;else for(Xl=a;null!==Xl;)t=Xl.nextEffect,Xl.nextEffect=null,Xl=t;if(0===(t=e.firstPendingTime)&&(ts=null),1073741823===t?e===ls?os++:(os=0,ls=e):os=0,"function"==typeof Bs&&Bs(n.stateNode,r),ms(e),Jl)throw Jl=!1,e=es,es=null,e;return($l&Nl)!==Pl||Za(),null}function Os(){for(;null!==Xl;){var e=Xl.effectTag;256&e&&cl(Xl.alternate,Xl),!(512&e)||ns||(ns=!0,Ya(97,(function(){return Is(),null}))),Xl=Xl.nextEffect}}function Is(){if(90!==as){var e=97<as?97:as;return as=90,Ka(e,Rs)}}function Rs(){if(null===rs)return!1;var e=rs;if(rs=null,($l&(Ol|Il))!==Pl)throw Error(o(331));var t=$l;for($l|=Il,e=e.current.firstEffect;null!==e;){try{var n=e;if(512&n.effectTag)switch(n.tag){case 0:case 11:case 15:case 22:ul(5,n),dl(5,n)}}catch(r){if(null===e)throw Error(o(330));Ls(e,r)}n=e.nextEffect,e.nextEffect=null,e=n}return $l=t,Za(),!0}function Ds(e,t,n){mi(e,t=El(e,t=il(n,t),1073741823)),null!==(e=ps(e,1073741823))&&ms(e)}function Ls(e,t){if(3===e.tag)Ds(e,e,t);else for(var n=e.return;null!==n;){if(3===n.tag){Ds(n,e,t);break}if(1===n.tag){var r=n.stateNode;if("function"==typeof n.type.getDerivedStateFromError||"function"==typeof r.componentDidCatch&&(null===ts||!ts.has(r))){mi(n,e=Sl(n,e=il(t,e),1073741823)),null!==(n=ps(n,1073741823))&&ms(n);break}}n=n.return}}function Ms(e,t,n){var r=e.pingCache;null!==r&&r.delete(t),zl===e&&jl===n?Hl===Fl||Hl===Ml&&1073741823===Vl&&Va()-Ql<Zl?ys(e,jl):Yl=!0:Ys(e,n)&&(0!==(t=e.lastPingedTime)&&t<n||(e.lastPingedTime=n,ms(e)))}function Fs(e,t){var n=e.stateNode;null!==n&&n.delete(t),0===(t=0)&&(t=us(t=cs(),e,null)),null!==(e=ps(e,t))&&ms(e)}Tl=function(e,t,n){var r=t.expirationTime;if(null!==e){var a=t.pendingProps;if(e.memoizedProps!==a||va.current)Mo=!0;else{if(r<n){switch(Mo=!1,t.tag){case 3:Vo(t),Do();break;case 5:if($i(t),4&t.mode&&1!==n&&a.hidden)return t.expirationTime=t.childExpirationTime=1,null;break;case 1:xa(t.type)&&Ta(t);break;case 4:Fi(t,t.stateNode.containerInfo);break;case 10:r=t.memoizedProps.value,a=t.type._context,ga(ti,a._currentValue),a._currentValue=r;break;case 13:if(null!==t.memoizedState)return 0!==(r=t.child.childExpirationTime)&&r>=n?Zo(e,t,n):(ga(Ui,1&Ui.current),null!==(t=tl(e,t,n))?t.sibling:null);ga(Ui,1&Ui.current);break;case 19:if(r=t.childExpirationTime>=n,64&e.effectTag){if(r)return el(e,t,n);t.effectTag|=64}if(null!==(a=t.memoizedState)&&(a.rendering=null,a.tail=null),ga(Ui,Ui.current),!r)return null}return tl(e,t,n)}Mo=!1}}else Mo=!1;switch(t.expirationTime=0,t.tag){case 2:if(r=t.type,null!==e&&(e.alternate=null,t.alternate=null,t.effectTag|=2),e=t.pendingProps,a=wa(t,ba.current),si(t,n),a=Ji(null,t,r,e,a,n),t.effectTag|=1,"object"==typeof a&&null!==a&&"function"==typeof a.render&&void 0===a.$$typeof){if(t.tag=1,t.memoizedState=null,t.updateQueue=null,xa(r)){var i=!0;Ta(t)}else i=!1;t.memoizedState=null!==a.state&&void 0!==a.state?a.state:null,di(t);var l=r.getDerivedStateFromProps;"function"==typeof l&&wi(t,r,l,e),a.updater=xi,t.stateNode=a,a._reactInternalFiber=t,Ti(t,r,e,n),t=Wo(null,t,r,!0,i,n)}else t.tag=0,Fo(null,t,a,n),t=t.child;return t;case 16:e:{if(a=t.elementType,null!==e&&(e.alternate=null,t.alternate=null,t.effectTag|=2),e=t.pendingProps,function(e){if(-1===e._status){e._status=0;var t=e._ctor;t=t(),e._result=t,t.then((function(t){0===e._status&&(t=t.default,e._status=1,e._result=t)}),(function(t){0===e._status&&(e._status=2,e._result=t)}))}}(a),1!==a._status)throw a._result;switch(a=a._result,t.type=a,i=t.tag=function(e){if("function"==typeof e)return js(e)?1:0;if(null!=e){if((e=e.$$typeof)===se)return 11;if(e===de)return 14}return 2}(a),e=ei(a,e),i){case 0:t=jo(null,t,a,e,n);break e;case 1:t=Ho(null,t,a,e,n);break e;case 11:t=Bo(null,t,a,e,n);break e;case 14:t=$o(null,t,a,ei(a.type,e),r,n);break e}throw Error(o(306,a,""))}return t;case 0:return r=t.type,a=t.pendingProps,jo(e,t,r,a=t.elementType===r?a:ei(r,a),n);case 1:return r=t.type,a=t.pendingProps,Ho(e,t,r,a=t.elementType===r?a:ei(r,a),n);case 3:if(Vo(t),r=t.updateQueue,null===e||null===r)throw Error(o(282));if(r=t.pendingProps,a=null!==(a=t.memoizedState)?a.element:null,pi(e,t),hi(t,r,null,n),(r=t.memoizedState.element)===a)Do(),t=tl(e,t,n);else{if((a=t.stateNode.hydrate)&&(Ao=An(t.stateNode.containerInfo.firstChild),_o=t,a=Co=!0),a)for(n=Oi(t,null,r,n),t.child=n;n;)n.effectTag=-3&n.effectTag|1024,n=n.sibling;else Fo(e,t,r,n),Do();t=t.child}return t;case 5:return $i(t),null===e&&Oo(t),r=t.type,a=t.pendingProps,i=null!==e?e.memoizedProps:null,l=a.children,Sn(r,a)?l=null:null!==i&&Sn(r,i)&&(t.effectTag|=16),Uo(e,t),4&t.mode&&1!==n&&a.hidden?(t.expirationTime=t.childExpirationTime=1,t=null):(Fo(e,t,l,n),t=t.child),t;case 6:return null===e&&Oo(t),null;case 13:return Zo(e,t,n);case 4:return Fi(t,t.stateNode.containerInfo),r=t.pendingProps,null===e?t.child=Ni(t,null,r,n):Fo(e,t,r,n),t.child;case 11:return r=t.type,a=t.pendingProps,Bo(e,t,r,a=t.elementType===r?a:ei(r,a),n);case 7:return Fo(e,t,t.pendingProps,n),t.child;case 8:case 12:return Fo(e,t,t.pendingProps.children,n),t.child;case 10:e:{r=t.type._context,a=t.pendingProps,l=t.memoizedProps,i=a.value;var s=t.type._context;if(ga(ti,s._currentValue),s._currentValue=i,null!==l)if(s=l.value,0===(i=Hr(s,i)?0:0|("function"==typeof r._calculateChangedBits?r._calculateChangedBits(s,i):1073741823))){if(l.children===a.children&&!va.current){t=tl(e,t,n);break e}}else for(null!==(s=t.child)&&(s.return=t);null!==s;){var c=s.dependencies;if(null!==c){l=s.child;for(var u=c.firstContext;null!==u;){if(u.context===r&&u.observedBits&i){1===s.tag&&((u=fi(n,null)).tag=2,mi(s,u)),s.expirationTime<n&&(s.expirationTime=n),null!==(u=s.alternate)&&u.expirationTime<n&&(u.expirationTime=n),li(s.return,n),c.expirationTime<n&&(c.expirationTime=n);break}u=u.next}}else l=10===s.tag&&s.type===t.type?null:s.child;if(null!==l)l.return=s;else for(l=s;null!==l;){if(l===t){l=null;break}if(null!==(s=l.sibling)){s.return=l.return,l=s;break}l=l.return}s=l}Fo(e,t,a.children,n),t=t.child}return t;case 9:return a=t.type,r=(i=t.pendingProps).children,si(t,n),r=r(a=ci(a,i.unstable_observedBits)),t.effectTag|=1,Fo(e,t,r,n),t.child;case 14:return i=ei(a=t.type,t.pendingProps),$o(e,t,a,i=ei(a.type,i),r,n);case 15:return zo(e,t,t.type,t.pendingProps,r,n);case 17:return r=t.type,a=t.pendingProps,a=t.elementType===r?a:ei(r,a),null!==e&&(e.alternate=null,t.alternate=null,t.effectTag|=2),t.tag=1,xa(r)?(e=!0,Ta(t)):e=!1,si(t,n),Ei(t,r,a),Ti(t,r,a,n),Wo(null,t,r,!0,e,n);case 19:return el(e,t,n)}throw Error(o(156,t.tag))};var Bs=null,$s=null;function zs(e,t,n,r){this.tag=e,this.key=n,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=t,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=r,this.effectTag=0,this.lastEffect=this.firstEffect=this.nextEffect=null,this.childExpirationTime=this.expirationTime=0,this.alternate=null}function Us(e,t,n,r){return new zs(e,t,n,r)}function js(e){return!(!(e=e.prototype)||!e.isReactComponent)}function Hs(e,t){var n=e.alternate;return null===n?((n=Us(e.tag,t,e.key,e.mode)).elementType=e.elementType,n.type=e.type,n.stateNode=e.stateNode,n.alternate=e,e.alternate=n):(n.pendingProps=t,n.effectTag=0,n.nextEffect=null,n.firstEffect=null,n.lastEffect=null),n.childExpirationTime=e.childExpirationTime,n.expirationTime=e.expirationTime,n.child=e.child,n.memoizedProps=e.memoizedProps,n.memoizedState=e.memoizedState,n.updateQueue=e.updateQueue,t=e.dependencies,n.dependencies=null===t?null:{expirationTime:t.expirationTime,firstContext:t.firstContext,responders:t.responders},n.sibling=e.sibling,n.index=e.index,n.ref=e.ref,n}function Ws(e,t,n,r,a,i){var l=2;if(r=e,"function"==typeof e)js(e)&&(l=1);else if("string"==typeof e)l=5;else e:switch(e){case ne:return Vs(n.children,a,i,t);case le:l=8,a|=7;break;case re:l=8,a|=1;break;case ae:return(e=Us(12,n,t,8|a)).elementType=ae,e.type=ae,e.expirationTime=i,e;case ce:return(e=Us(13,n,t,a)).type=ce,e.elementType=ce,e.expirationTime=i,e;case ue:return(e=Us(19,n,t,a)).elementType=ue,e.expirationTime=i,e;default:if("object"==typeof e&&null!==e)switch(e.$$typeof){case ie:l=10;break e;case oe:l=9;break e;case se:l=11;break e;case de:l=14;break e;case pe:l=16,r=null;break e;case fe:l=22;break e}throw Error(o(130,null==e?e:typeof e,""))}return(t=Us(l,n,t,a)).elementType=e,t.type=r,t.expirationTime=i,t}function Vs(e,t,n,r){return(e=Us(7,e,r,t)).expirationTime=n,e}function Gs(e,t,n){return(e=Us(6,e,null,t)).expirationTime=n,e}function qs(e,t,n){return(t=Us(4,null!==e.children?e.children:[],e.key,t)).expirationTime=n,t.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},t}function Ks(e,t,n){this.tag=t,this.current=null,this.containerInfo=e,this.pingCache=this.pendingChildren=null,this.finishedExpirationTime=0,this.finishedWork=null,this.timeoutHandle=-1,this.pendingContext=this.context=null,this.hydrate=n,this.callbackNode=null,this.callbackPriority=90,this.lastExpiredTime=this.lastPingedTime=this.nextKnownPendingLevel=this.lastSuspendedTime=this.firstSuspendedTime=this.firstPendingTime=0}function Ys(e,t){var n=e.firstSuspendedTime;return e=e.lastSuspendedTime,0!==n&&n>=t&&e<=t}function Qs(e,t){var n=e.firstSuspendedTime,r=e.lastSuspendedTime;n<t&&(e.firstSuspendedTime=t),(r>t||0===n)&&(e.lastSuspendedTime=t),t<=e.lastPingedTime&&(e.lastPingedTime=0),t<=e.lastExpiredTime&&(e.lastExpiredTime=0)}function Zs(e,t){t>e.firstPendingTime&&(e.firstPendingTime=t);var n=e.firstSuspendedTime;0!==n&&(t>=n?e.firstSuspendedTime=e.lastSuspendedTime=e.nextKnownPendingLevel=0:t>=e.lastSuspendedTime&&(e.lastSuspendedTime=t+1),t>e.nextKnownPendingLevel&&(e.nextKnownPendingLevel=t))}function Xs(e,t){var n=e.lastExpiredTime;(0===n||n>t)&&(e.lastExpiredTime=t)}function Js(e,t,n,r){var a=t.current,i=cs(),l=vi.suspense;i=us(i,a,l);e:if(n){t:{if(et(n=n._reactInternalFiber)!==n||1!==n.tag)throw Error(o(170));var s=n;do{switch(s.tag){case 3:s=s.stateNode.context;break t;case 1:if(xa(s.type)){s=s.stateNode.__reactInternalMemoizedMergedChildContext;break t}}s=s.return}while(null!==s);throw Error(o(171))}if(1===n.tag){var c=n.type;if(xa(c)){n=Sa(n,c,s);break e}}n=s}else n=ha;return null===t.context?t.context=n:t.pendingContext=n,(t=fi(i,l)).payload={element:e},null!==(r=void 0===r?null:r)&&(t.callback=r),mi(a,t),ds(a,i),i}function ec(e){return(e=e.current).child?(e.child.tag,e.child.stateNode):null}function tc(e,t){null!==(e=e.memoizedState)&&null!==e.dehydrated&&e.retryTime<t&&(e.retryTime=t)}function nc(e,t){tc(e,t),(e=e.alternate)&&tc(e,t)}function rc(e,t,n){var r=new Ks(e,t,n=null!=n&&!0===n.hydrate),a=Us(3,null,null,2===t?7:1===t?3:0);r.current=a,a.stateNode=r,di(a),e[In]=r.current,n&&0!==t&&function(e,t){var n=Je(t);At.forEach((function(e){gt(e,t,n)})),Ct.forEach((function(e){gt(e,t,n)}))}(0,9===e.nodeType?e:e.ownerDocument),this._internalRoot=r}function ac(e){return!(!e||1!==e.nodeType&&9!==e.nodeType&&11!==e.nodeType&&(8!==e.nodeType||" react-mount-point-unstable "!==e.nodeValue))}function ic(e,t,n,r,a){var i=n._reactRootContainer;if(i){var o=i._internalRoot;if("function"==typeof a){var l=a;a=function(){var e=ec(o);l.call(e)}}Js(t,o,e,a)}else{if(i=n._reactRootContainer=function(e,t){if(t||(t=!(!(t=e?9===e.nodeType?e.documentElement:e.firstChild:null)||1!==t.nodeType||!t.hasAttribute("data-reactroot"))),!t)for(var n;n=e.lastChild;)e.removeChild(n);return new rc(e,0,t?{hydrate:!0}:void 0)}(n,r),o=i._internalRoot,"function"==typeof a){var s=a;a=function(){var e=ec(o);s.call(e)}}vs((function(){Js(t,o,e,a)}))}return ec(o)}function oc(e,t){var n=2<arguments.length&&void 0!==arguments[2]?arguments[2]:null;if(!ac(t))throw Error(o(200));return function(e,t,n){var r=3<arguments.length&&void 0!==arguments[3]?arguments[3]:null;return{$$typeof:te,key:null==r?null:""+r,children:e,containerInfo:t,implementation:n}}(e,t,null,n)}rc.prototype.render=function(e){Js(e,this._internalRoot,null,null)},rc.prototype.unmount=function(){var e=this._internalRoot,t=e.containerInfo;Js(null,e,null,(function(){t[In]=null}))},ht=function(e){if(13===e.tag){var t=Ja(cs(),150,100);ds(e,t),nc(e,t)}},bt=function(e){13===e.tag&&(ds(e,3),nc(e,3))},vt=function(e){if(13===e.tag){var t=cs();ds(e,t=us(t,e,null)),nc(e,t)}},C=function(e,t,n){switch(t){case"input":if(Te(e,n),t=n.name,"radio"===n.type&&null!=t){for(n=e;n.parentNode;)n=n.parentNode;for(n=n.querySelectorAll("input[name="+JSON.stringify(""+t)+'][type="radio"]'),t=0;t<n.length;t++){var r=n[t];if(r!==e&&r.form===e.form){var a=Mn(r);if(!a)throw Error(o(90));xe(r),Te(r,a)}}}break;case"textarea":Ie(e,n);break;case"select":null!=(t=n.value)&&Pe(e,!!n.multiple,t,!1)}},D=bs,L=function(e,t,n,r,a){var i=$l;$l|=4;try{return Ka(98,e.bind(null,t,n,r,a))}finally{($l=i)===Pl&&Za()}},M=function(){($l&(1|Ol|Il))===Pl&&(function(){if(null!==is){var e=is;is=null,e.forEach((function(e,t){Xs(t,e),ms(t)})),Za()}}(),Is())},F=function(e,t){var n=$l;$l|=2;try{return e(t)}finally{($l=n)===Pl&&Za()}};var lc={Events:[Dn,Ln,Mn,_,E,Hn,function(e){it(e,jn)},I,R,Xt,st,Is,{current:!1}]};!function(e){var t=e.findFiberByHostInstance;(function(e){if("undefined"==typeof __REACT_DEVTOOLS_GLOBAL_HOOK__)return!1;var t=__REACT_DEVTOOLS_GLOBAL_HOOK__;if(t.isDisabled||!t.supportsFiber)return!0;try{var n=t.inject(e);Bs=function(e){try{t.onCommitFiberRoot(n,e,void 0,!(64&~e.current.effectTag))}catch(r){}},$s=function(e){try{t.onCommitFiberUnmount(n,e)}catch(r){}}}catch(r){}})(a({},e,{overrideHookState:null,overrideProps:null,setSuspenseHandler:null,scheduleUpdate:null,currentDispatcherRef:Q.ReactCurrentDispatcher,findHostInstanceByFiber:function(e){return null===(e=rt(e))?null:e.stateNode},findFiberByHostInstance:function(e){return t?t(e):null},findHostInstancesForRefresh:null,scheduleRefresh:null,scheduleRoot:null,setRefreshHandler:null,getCurrentFiber:null}))}({findFiberByHostInstance:Rn,bundleType:0,version:"16.14.0",rendererPackageName:"react-dom"}),t.hydrate=function(e,t,n){if(!ac(t))throw Error(o(200));return ic(null,e,t,!0,n)}},961:(e,t,n)=>{"use strict";!function e(){if("undefined"!=typeof __REACT_DEVTOOLS_GLOBAL_HOOK__&&"function"==typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE)try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(e)}catch(t){console.error(t)}}(),e.exports=n(2551)},115:e=>{var t="undefined"!=typeof Element,n="function"==typeof Map,r="function"==typeof Set,a="function"==typeof ArrayBuffer&&!!ArrayBuffer.isView;function i(e,o){if(e===o)return!0;if(e&&o&&"object"==typeof e&&"object"==typeof o){if(e.constructor!==o.constructor)return!1;var l,s,c,u;if(Array.isArray(e)){if((l=e.length)!=o.length)return!1;for(s=l;0!=s--;)if(!i(e[s],o[s]))return!1;return!0}if(n&&e instanceof Map&&o instanceof Map){if(e.size!==o.size)return!1;for(u=e.entries();!(s=u.next()).done;)if(!o.has(s.value[0]))return!1;for(u=e.entries();!(s=u.next()).done;)if(!i(s.value[1],o.get(s.value[0])))return!1;return!0}if(r&&e instanceof Set&&o instanceof Set){if(e.size!==o.size)return!1;for(u=e.entries();!(s=u.next()).done;)if(!o.has(s.value[0]))return!1;return!0}if(a&&ArrayBuffer.isView(e)&&ArrayBuffer.isView(o)){if((l=e.length)!=o.length)return!1;for(s=l;0!=s--;)if(e[s]!==o[s])return!1;return!0}if(e.constructor===RegExp)return e.source===o.source&&e.flags===o.flags;if(e.valueOf!==Object.prototype.valueOf&&"function"==typeof e.valueOf&&"function"==typeof o.valueOf)return e.valueOf()===o.valueOf();if(e.toString!==Object.prototype.toString&&"function"==typeof e.toString&&"function"==typeof o.toString)return e.toString()===o.toString();if((l=(c=Object.keys(e)).length)!==Object.keys(o).length)return!1;for(s=l;0!=s--;)if(!Object.prototype.hasOwnProperty.call(o,c[s]))return!1;if(t&&e instanceof Element)return!1;for(s=l;0!=s--;)if(("_owner"!==c[s]&&"__v"!==c[s]&&"__o"!==c[s]||!e.$$typeof)&&!i(e[c[s]],o[c[s]]))return!1;return!0}return e!=e&&o!=o}e.exports=function(e,t){try{return i(e,t)}catch(n){if((n.message||"").match(/stack|recursion/i))return console.warn("react-fast-compare cannot handle circular refs"),!1;throw n}}},545:(e,t,n)=>{"use strict";n.d(t,{mg:()=>J,vd:()=>V});var r=n(6540),a=n(5556),i=n.n(a),o=n(115),l=n.n(o),s=n(311),c=n.n(s),u=n(2833),d=n.n(u);function p(){return p=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},p.apply(this,arguments)}function f(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,m(e,t)}function m(e,t){return m=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e},m(e,t)}function g(e,t){if(null==e)return{};var n,r,a={},i=Object.keys(e);for(r=0;r<i.length;r++)t.indexOf(n=i[r])>=0||(a[n]=e[n]);return a}var h={BASE:"base",BODY:"body",HEAD:"head",HTML:"html",LINK:"link",META:"meta",NOSCRIPT:"noscript",SCRIPT:"script",STYLE:"style",TITLE:"title",FRAGMENT:"Symbol(react.fragment)"},b={rel:["amphtml","canonical","alternate"]},v={type:["application/ld+json"]},y={charset:"",name:["robots","description"],property:["og:type","og:title","og:url","og:image","og:image:alt","og:description","twitter:url","twitter:title","twitter:description","twitter:image","twitter:image:alt","twitter:card","twitter:site"]},w=Object.keys(h).map((function(e){return h[e]})),x={accesskey:"accessKey",charset:"charSet",class:"className",contenteditable:"contentEditable",contextmenu:"contextMenu","http-equiv":"httpEquiv",itemprop:"itemProp",tabindex:"tabIndex"},k=Object.keys(x).reduce((function(e,t){return e[x[t]]=t,e}),{}),E=function(e,t){for(var n=e.length-1;n>=0;n-=1){var r=e[n];if(Object.prototype.hasOwnProperty.call(r,t))return r[t]}return null},S=function(e){var t=E(e,h.TITLE),n=E(e,"titleTemplate");if(Array.isArray(t)&&(t=t.join("")),n&&t)return n.replace(/%s/g,(function(){return t}));var r=E(e,"defaultTitle");return t||r||void 0},T=function(e){return E(e,"onChangeClientState")||function(){}},_=function(e,t){return t.filter((function(t){return void 0!==t[e]})).map((function(t){return t[e]})).reduce((function(e,t){return p({},e,t)}),{})},A=function(e,t){return t.filter((function(e){return void 0!==e[h.BASE]})).map((function(e){return e[h.BASE]})).reverse().reduce((function(t,n){if(!t.length)for(var r=Object.keys(n),a=0;a<r.length;a+=1){var i=r[a].toLowerCase();if(-1!==e.indexOf(i)&&n[i])return t.concat(n)}return t}),[])},C=function(e,t,n){var r={};return n.filter((function(t){return!!Array.isArray(t[e])||(void 0!==t[e]&&console&&"function"==typeof console.warn&&console.warn("Helmet: "+e+' should be of type "Array". Instead found type "'+typeof t[e]+'"'),!1)})).map((function(t){return t[e]})).reverse().reduce((function(e,n){var a={};n.filter((function(e){for(var n,i=Object.keys(e),o=0;o<i.length;o+=1){var l=i[o],s=l.toLowerCase();-1===t.indexOf(s)||"rel"===n&&"canonical"===e[n].toLowerCase()||"rel"===s&&"stylesheet"===e[s].toLowerCase()||(n=s),-1===t.indexOf(l)||"innerHTML"!==l&&"cssText"!==l&&"itemprop"!==l||(n=l)}if(!n||!e[n])return!1;var c=e[n].toLowerCase();return r[n]||(r[n]={}),a[n]||(a[n]={}),!r[n][c]&&(a[n][c]=!0,!0)})).reverse().forEach((function(t){return e.push(t)}));for(var i=Object.keys(a),o=0;o<i.length;o+=1){var l=i[o],s=p({},r[l],a[l]);r[l]=s}return e}),[]).reverse()},P=function(e,t){if(Array.isArray(e)&&e.length)for(var n=0;n<e.length;n+=1)if(e[n][t])return!0;return!1},N=function(e){return Array.isArray(e)?e.join(""):e},O=function(e,t){return Array.isArray(e)?e.reduce((function(e,n){return function(e,t){for(var n=Object.keys(e),r=0;r<n.length;r+=1)if(t[n[r]]&&t[n[r]].includes(e[n[r]]))return!0;return!1}(n,t)?e.priority.push(n):e.default.push(n),e}),{priority:[],default:[]}):{default:e}},I=function(e,t){var n;return p({},e,((n={})[t]=void 0,n))},R=[h.NOSCRIPT,h.SCRIPT,h.STYLE],D=function(e,t){return void 0===t&&(t=!0),!1===t?String(e):String(e).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")},L=function(e){return Object.keys(e).reduce((function(t,n){var r=void 0!==e[n]?n+'="'+e[n]+'"':""+n;return t?t+" "+r:r}),"")},M=function(e,t){return void 0===t&&(t={}),Object.keys(e).reduce((function(t,n){return t[x[n]||n]=e[n],t}),t)},F=function(e,t){return t.map((function(t,n){var a,i=((a={key:n})["data-rh"]=!0,a);return Object.keys(t).forEach((function(e){var n=x[e]||e;"innerHTML"===n||"cssText"===n?i.dangerouslySetInnerHTML={__html:t.innerHTML||t.cssText}:i[n]=t[e]})),r.createElement(e,i)}))},B=function(e,t,n){switch(e){case h.TITLE:return{toComponent:function(){return n=t.titleAttributes,(a={key:e=t.title})["data-rh"]=!0,i=M(n,a),[r.createElement(h.TITLE,i,e)];var e,n,a,i},toString:function(){return function(e,t,n,r){var a=L(n),i=N(t);return a?"<"+e+' data-rh="true" '+a+">"+D(i,r)+"</"+e+">":"<"+e+' data-rh="true">'+D(i,r)+"</"+e+">"}(e,t.title,t.titleAttributes,n)}};case"bodyAttributes":case"htmlAttributes":return{toComponent:function(){return M(t)},toString:function(){return L(t)}};default:return{toComponent:function(){return F(e,t)},toString:function(){return function(e,t,n){return t.reduce((function(t,r){var a=Object.keys(r).filter((function(e){return!("innerHTML"===e||"cssText"===e)})).reduce((function(e,t){var a=void 0===r[t]?t:t+'="'+D(r[t],n)+'"';return e?e+" "+a:a}),""),i=r.innerHTML||r.cssText||"",o=-1===R.indexOf(e);return t+"<"+e+' data-rh="true" '+a+(o?"/>":">"+i+"</"+e+">")}),"")}(e,t,n)}}}},$=function(e){var t=e.baseTag,n=e.bodyAttributes,r=e.encode,a=e.htmlAttributes,i=e.noscriptTags,o=e.styleTags,l=e.title,s=void 0===l?"":l,c=e.titleAttributes,u=e.linkTags,d=e.metaTags,p=e.scriptTags,f={toComponent:function(){},toString:function(){return""}};if(e.prioritizeSeoTags){var m=function(e){var t=e.linkTags,n=e.scriptTags,r=e.encode,a=O(e.metaTags,y),i=O(t,b),o=O(n,v);return{priorityMethods:{toComponent:function(){return[].concat(F(h.META,a.priority),F(h.LINK,i.priority),F(h.SCRIPT,o.priority))},toString:function(){return B(h.META,a.priority,r)+" "+B(h.LINK,i.priority,r)+" "+B(h.SCRIPT,o.priority,r)}},metaTags:a.default,linkTags:i.default,scriptTags:o.default}}(e);f=m.priorityMethods,u=m.linkTags,d=m.metaTags,p=m.scriptTags}return{priority:f,base:B(h.BASE,t,r),bodyAttributes:B("bodyAttributes",n,r),htmlAttributes:B("htmlAttributes",a,r),link:B(h.LINK,u,r),meta:B(h.META,d,r),noscript:B(h.NOSCRIPT,i,r),script:B(h.SCRIPT,p,r),style:B(h.STYLE,o,r),title:B(h.TITLE,{title:s,titleAttributes:c},r)}},z=[],U=function(e,t){var n=this;void 0===t&&(t="undefined"!=typeof document),this.instances=[],this.value={setHelmet:function(e){n.context.helmet=e},helmetInstances:{get:function(){return n.canUseDOM?z:n.instances},add:function(e){(n.canUseDOM?z:n.instances).push(e)},remove:function(e){var t=(n.canUseDOM?z:n.instances).indexOf(e);(n.canUseDOM?z:n.instances).splice(t,1)}}},this.context=e,this.canUseDOM=t,t||(e.helmet=$({baseTag:[],bodyAttributes:{},encodeSpecialCharacters:!0,htmlAttributes:{},linkTags:[],metaTags:[],noscriptTags:[],scriptTags:[],styleTags:[],title:"",titleAttributes:{}}))},j=r.createContext({}),H=i().shape({setHelmet:i().func,helmetInstances:i().shape({get:i().func,add:i().func,remove:i().func})}),W="undefined"!=typeof document,V=function(e){function t(n){var r;return(r=e.call(this,n)||this).helmetData=new U(r.props.context,t.canUseDOM),r}return f(t,e),t.prototype.render=function(){return r.createElement(j.Provider,{value:this.helmetData.value},this.props.children)},t}(r.Component);V.canUseDOM=W,V.propTypes={context:i().shape({helmet:i().shape()}),children:i().node.isRequired},V.defaultProps={context:{}},V.displayName="HelmetProvider";var G=function(e,t){var n,r=document.head||document.querySelector(h.HEAD),a=r.querySelectorAll(e+"[data-rh]"),i=[].slice.call(a),o=[];return t&&t.length&&t.forEach((function(t){var r=document.createElement(e);for(var a in t)Object.prototype.hasOwnProperty.call(t,a)&&("innerHTML"===a?r.innerHTML=t.innerHTML:"cssText"===a?r.styleSheet?r.styleSheet.cssText=t.cssText:r.appendChild(document.createTextNode(t.cssText)):r.setAttribute(a,void 0===t[a]?"":t[a]));r.setAttribute("data-rh","true"),i.some((function(e,t){return n=t,r.isEqualNode(e)}))?i.splice(n,1):o.push(r)})),i.forEach((function(e){return e.parentNode.removeChild(e)})),o.forEach((function(e){return r.appendChild(e)})),{oldTags:i,newTags:o}},q=function(e,t){var n=document.getElementsByTagName(e)[0];if(n){for(var r=n.getAttribute("data-rh"),a=r?r.split(","):[],i=[].concat(a),o=Object.keys(t),l=0;l<o.length;l+=1){var s=o[l],c=t[s]||"";n.getAttribute(s)!==c&&n.setAttribute(s,c),-1===a.indexOf(s)&&a.push(s);var u=i.indexOf(s);-1!==u&&i.splice(u,1)}for(var d=i.length-1;d>=0;d-=1)n.removeAttribute(i[d]);a.length===i.length?n.removeAttribute("data-rh"):n.getAttribute("data-rh")!==o.join(",")&&n.setAttribute("data-rh",o.join(","))}},K=function(e,t){var n=e.baseTag,r=e.htmlAttributes,a=e.linkTags,i=e.metaTags,o=e.noscriptTags,l=e.onChangeClientState,s=e.scriptTags,c=e.styleTags,u=e.title,d=e.titleAttributes;q(h.BODY,e.bodyAttributes),q(h.HTML,r),function(e,t){void 0!==e&&document.title!==e&&(document.title=N(e)),q(h.TITLE,t)}(u,d);var p={baseTag:G(h.BASE,n),linkTags:G(h.LINK,a),metaTags:G(h.META,i),noscriptTags:G(h.NOSCRIPT,o),scriptTags:G(h.SCRIPT,s),styleTags:G(h.STYLE,c)},f={},m={};Object.keys(p).forEach((function(e){var t=p[e],n=t.newTags,r=t.oldTags;n.length&&(f[e]=n),r.length&&(m[e]=p[e].oldTags)})),t&&t(),l(e,f,m)},Y=null,Q=function(e){function t(){for(var t,n=arguments.length,r=new Array(n),a=0;a<n;a++)r[a]=arguments[a];return(t=e.call.apply(e,[this].concat(r))||this).rendered=!1,t}f(t,e);var n=t.prototype;return n.shouldComponentUpdate=function(e){return!d()(e,this.props)},n.componentDidUpdate=function(){this.emitChange()},n.componentWillUnmount=function(){this.props.context.helmetInstances.remove(this),this.emitChange()},n.emitChange=function(){var e,t,n=this.props.context,r=n.setHelmet,a=null,i=(e=n.helmetInstances.get().map((function(e){var t=p({},e.props);return delete t.context,t})),{baseTag:A(["href"],e),bodyAttributes:_("bodyAttributes",e),defer:E(e,"defer"),encode:E(e,"encodeSpecialCharacters"),htmlAttributes:_("htmlAttributes",e),linkTags:C(h.LINK,["rel","href"],e),metaTags:C(h.META,["name","charset","http-equiv","property","itemprop"],e),noscriptTags:C(h.NOSCRIPT,["innerHTML"],e),onChangeClientState:T(e),scriptTags:C(h.SCRIPT,["src","innerHTML"],e),styleTags:C(h.STYLE,["cssText"],e),title:S(e),titleAttributes:_("titleAttributes",e),prioritizeSeoTags:P(e,"prioritizeSeoTags")});V.canUseDOM?(t=i,Y&&cancelAnimationFrame(Y),t.defer?Y=requestAnimationFrame((function(){K(t,(function(){Y=null}))})):(K(t),Y=null)):$&&(a=$(i)),r(a)},n.init=function(){this.rendered||(this.rendered=!0,this.props.context.helmetInstances.add(this),this.emitChange())},n.render=function(){return this.init(),null},t}(r.Component);Q.propTypes={context:H.isRequired},Q.displayName="HelmetDispatcher";var Z=["children"],X=["children"],J=function(e){function t(){return e.apply(this,arguments)||this}f(t,e);var n=t.prototype;return n.shouldComponentUpdate=function(e){return!l()(I(this.props,"helmetData"),I(e,"helmetData"))},n.mapNestedChildrenToProps=function(e,t){if(!t)return null;switch(e.type){case h.SCRIPT:case h.NOSCRIPT:return{innerHTML:t};case h.STYLE:return{cssText:t};default:throw new Error("<"+e.type+" /> elements are self-closing and can not contain children. Refer to our API for more information.")}},n.flattenArrayTypeChildren=function(e){var t,n=e.child,r=e.arrayTypeChildren;return p({},r,((t={})[n.type]=[].concat(r[n.type]||[],[p({},e.newChildProps,this.mapNestedChildrenToProps(n,e.nestedChildren))]),t))},n.mapObjectTypeChildren=function(e){var t,n,r=e.child,a=e.newProps,i=e.newChildProps,o=e.nestedChildren;switch(r.type){case h.TITLE:return p({},a,((t={})[r.type]=o,t.titleAttributes=p({},i),t));case h.BODY:return p({},a,{bodyAttributes:p({},i)});case h.HTML:return p({},a,{htmlAttributes:p({},i)});default:return p({},a,((n={})[r.type]=p({},i),n))}},n.mapArrayTypeChildrenToProps=function(e,t){var n=p({},t);return Object.keys(e).forEach((function(t){var r;n=p({},n,((r={})[t]=e[t],r))})),n},n.warnOnInvalidChildren=function(e,t){return c()(w.some((function(t){return e.type===t})),"function"==typeof e.type?"You may be attempting to nest <Helmet> components within each other, which is not allowed. Refer to our API for more information.":"Only elements types "+w.join(", ")+" are allowed. Helmet does not support rendering <"+e.type+"> elements. Refer to our API for more information."),c()(!t||"string"==typeof t||Array.isArray(t)&&!t.some((function(e){return"string"!=typeof e})),"Helmet expects a string as a child of <"+e.type+">. Did you forget to wrap your children in braces? ( <"+e.type+">{``}</"+e.type+"> ) Refer to our API for more information."),!0},n.mapChildrenToProps=function(e,t){var n=this,a={};return r.Children.forEach(e,(function(e){if(e&&e.props){var r=e.props,i=r.children,o=g(r,Z),l=Object.keys(o).reduce((function(e,t){return e[k[t]||t]=o[t],e}),{}),s=e.type;switch("symbol"==typeof s?s=s.toString():n.warnOnInvalidChildren(e,i),s){case h.FRAGMENT:t=n.mapChildrenToProps(i,t);break;case h.LINK:case h.META:case h.NOSCRIPT:case h.SCRIPT:case h.STYLE:a=n.flattenArrayTypeChildren({child:e,arrayTypeChildren:a,newChildProps:l,nestedChildren:i});break;default:t=n.mapObjectTypeChildren({child:e,newProps:t,newChildProps:l,nestedChildren:i})}}})),this.mapArrayTypeChildrenToProps(a,t)},n.render=function(){var e=this.props,t=e.children,n=g(e,X),a=p({},n),i=n.helmetData;return t&&(a=this.mapChildrenToProps(t,a)),!i||i instanceof U||(i=new U(i.context,i.instances)),i?r.createElement(Q,p({},a,{context:i.value,helmetData:void 0})):r.createElement(j.Consumer,null,(function(e){return r.createElement(Q,p({},a,{context:e}))}))},t}(r.Component);J.propTypes={base:i().object,bodyAttributes:i().object,children:i().oneOfType([i().arrayOf(i().node),i().node]),defaultTitle:i().string,defer:i().bool,encodeSpecialCharacters:i().bool,htmlAttributes:i().object,link:i().arrayOf(i().object),meta:i().arrayOf(i().object),noscript:i().arrayOf(i().object),onChangeClientState:i().func,script:i().arrayOf(i().object),style:i().arrayOf(i().object),title:i().string,titleAttributes:i().object,titleTemplate:i().string,prioritizeSeoTags:i().bool,helmetData:i().object},J.defaultProps={defer:!0,encodeSpecialCharacters:!0,prioritizeSeoTags:!1},J.displayName="Helmet"},2799:(e,t)=>{"use strict";var n="function"==typeof Symbol&&Symbol.for,r=n?Symbol.for("react.element"):60103,a=n?Symbol.for("react.portal"):60106,i=n?Symbol.for("react.fragment"):60107,o=n?Symbol.for("react.strict_mode"):60108,l=n?Symbol.for("react.profiler"):60114,s=n?Symbol.for("react.provider"):60109,c=n?Symbol.for("react.context"):60110,u=n?Symbol.for("react.async_mode"):60111,d=n?Symbol.for("react.concurrent_mode"):60111,p=n?Symbol.for("react.forward_ref"):60112,f=n?Symbol.for("react.suspense"):60113,m=n?Symbol.for("react.suspense_list"):60120,g=n?Symbol.for("react.memo"):60115,h=n?Symbol.for("react.lazy"):60116,b=n?Symbol.for("react.block"):60121,v=n?Symbol.for("react.fundamental"):60117,y=n?Symbol.for("react.responder"):60118,w=n?Symbol.for("react.scope"):60119;function x(e){if("object"==typeof e&&null!==e){var t=e.$$typeof;switch(t){case r:switch(e=e.type){case u:case d:case i:case l:case o:case f:return e;default:switch(e=e&&e.$$typeof){case c:case p:case h:case g:case s:return e;default:return t}}case a:return t}}}function k(e){return x(e)===d}t.AsyncMode=u,t.ConcurrentMode=d,t.ContextConsumer=c,t.ContextProvider=s,t.Element=r,t.ForwardRef=p,t.Fragment=i,t.Lazy=h,t.Memo=g,t.Portal=a,t.Profiler=l,t.StrictMode=o,t.Suspense=f,t.isAsyncMode=function(e){return k(e)||x(e)===u},t.isConcurrentMode=k,t.isContextConsumer=function(e){return x(e)===c},t.isContextProvider=function(e){return x(e)===s},t.isElement=function(e){return"object"==typeof e&&null!==e&&e.$$typeof===r},t.isForwardRef=function(e){return x(e)===p},t.isFragment=function(e){return x(e)===i},t.isLazy=function(e){return x(e)===h},t.isMemo=function(e){return x(e)===g},t.isPortal=function(e){return x(e)===a},t.isProfiler=function(e){return x(e)===l},t.isStrictMode=function(e){return x(e)===o},t.isSuspense=function(e){return x(e)===f},t.isValidElementType=function(e){return"string"==typeof e||"function"==typeof e||e===i||e===d||e===l||e===o||e===f||e===m||"object"==typeof e&&null!==e&&(e.$$typeof===h||e.$$typeof===g||e.$$typeof===s||e.$$typeof===c||e.$$typeof===p||e.$$typeof===v||e.$$typeof===y||e.$$typeof===w||e.$$typeof===b)},t.typeOf=x},4363:(e,t,n)=>{"use strict";e.exports=n(2799)},3259:(e,t,n)=>{"use strict";function r(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,e.__proto__=t}function a(e){if(void 0===e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return e}function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(){return o=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},o.apply(this,arguments)}var l=n(6540),s=n(5556),c=[],u=[];function d(e){var t=e(),n={loading:!0,loaded:null,error:null};return n.promise=t.then((function(e){return n.loading=!1,n.loaded=e,e})).catch((function(e){throw n.loading=!1,n.error=e,e})),n}function p(e){var t={loading:!1,loaded:{},error:null},n=[];try{Object.keys(e).forEach((function(r){var a=d(e[r]);a.loading?t.loading=!0:(t.loaded[r]=a.loaded,t.error=a.error),n.push(a.promise),a.promise.then((function(e){t.loaded[r]=e})).catch((function(e){t.error=e}))}))}catch(r){t.error=r}return t.promise=Promise.all(n).then((function(e){return t.loading=!1,e})).catch((function(e){throw t.loading=!1,e})),t}function f(e,t){return l.createElement((n=e)&&n.__esModule?n.default:n,t);var n}function m(e,t){var d,p;if(!t.loading)throw new Error("react-loadable requires a `loading` component");var m=o({loader:null,loading:null,delay:200,timeout:null,render:f,webpack:null,modules:null},t),g=null;function h(){return g||(g=e(m.loader)),g.promise}return c.push(h),"function"==typeof m.webpack&&u.push((function(){if((0,m.webpack)().every((function(e){return void 0!==e&&void 0!==n.m[e]})))return h()})),p=d=function(t){function n(n){var r;return i(a(a(r=t.call(this,n)||this)),"retry",(function(){r.setState({error:null,loading:!0,timedOut:!1}),g=e(m.loader),r._loadModule()})),h(),r.state={error:g.error,pastDelay:!1,timedOut:!1,loading:g.loading,loaded:g.loaded},r}r(n,t),n.preload=function(){return h()};var o=n.prototype;return o.UNSAFE_componentWillMount=function(){this._loadModule()},o.componentDidMount=function(){this._mounted=!0},o._loadModule=function(){var e=this;if(this.context.loadable&&Array.isArray(m.modules)&&m.modules.forEach((function(t){e.context.loadable.report(t)})),g.loading){var t=function(t){e._mounted&&e.setState(t)};"number"==typeof m.delay&&(0===m.delay?this.setState({pastDelay:!0}):this._delay=setTimeout((function(){t({pastDelay:!0})}),m.delay)),"number"==typeof m.timeout&&(this._timeout=setTimeout((function(){t({timedOut:!0})}),m.timeout));var n=function(){t({error:g.error,loaded:g.loaded,loading:g.loading}),e._clearTimeouts()};g.promise.then((function(){return n(),null})).catch((function(e){return n(),null}))}},o.componentWillUnmount=function(){this._mounted=!1,this._clearTimeouts()},o._clearTimeouts=function(){clearTimeout(this._delay),clearTimeout(this._timeout)},o.render=function(){return this.state.loading||this.state.error?l.createElement(m.loading,{isLoading:this.state.loading,pastDelay:this.state.pastDelay,timedOut:this.state.timedOut,error:this.state.error,retry:this.retry}):this.state.loaded?m.render(this.state.loaded,this.props):null},n}(l.Component),i(d,"contextTypes",{loadable:s.shape({report:s.func.isRequired})}),p}function g(e){return m(d,e)}g.Map=function(e){if("function"!=typeof e.render)throw new Error("LoadableMap requires a `render(loaded, props)` function");return m(p,e)};var h=function(e){function t(){return e.apply(this,arguments)||this}r(t,e);var n=t.prototype;return n.getChildContext=function(){return{loadable:{report:this.props.report}}},n.render=function(){return l.Children.only(this.props.children)},t}(l.Component);function b(e){for(var t=[];e.length;){var n=e.pop();t.push(n())}return Promise.all(t).then((function(){if(e.length)return b(e)}))}i(h,"propTypes",{report:s.func.isRequired}),i(h,"childContextTypes",{loadable:s.shape({report:s.func.isRequired}).isRequired}),g.Capture=h,g.preloadAll=function(){return new Promise((function(e,t){b(c).then(e,t)}))},g.preloadReady=function(){return new Promise((function(e,t){b(u).then(e,e)}))},e.exports=g},2831:(e,t,n)=>{"use strict";n.d(t,{u:()=>o,v:()=>l});var r=n(6347),a=n(8168),i=n(6540);function o(e,t,n){return void 0===n&&(n=[]),e.some((function(e){var a=e.path?(0,r.B6)(t,e):n.length?n[n.length-1].match:r.Ix.computeRootMatch(t);return a&&(n.push({route:e,match:a}),e.routes&&o(e.routes,t,n)),a})),n}function l(e,t,n){return void 0===t&&(t={}),void 0===n&&(n={}),e?i.createElement(r.dO,n,e.map((function(e,n){return i.createElement(r.qh,{key:e.key||n,path:e.path,exact:e.exact,strict:e.strict,render:function(n){return e.render?e.render((0,a.A)({},n,{},t,{route:e})):i.createElement(e.component,(0,a.A)({},n,t,{route:e}))}})}))):null}},4625:(e,t,n)=>{"use strict";n.d(t,{Kd:()=>u,N_:()=>h,k2:()=>y});var r=n(6347),a=n(2892),i=n(6540),o=n(1513),l=n(8168),s=n(8587),c=n(1561),u=function(e){function t(){for(var t,n=arguments.length,r=new Array(n),a=0;a<n;a++)r[a]=arguments[a];return(t=e.call.apply(e,[this].concat(r))||this).history=(0,o.zR)(t.props),t}return(0,a.A)(t,e),t.prototype.render=function(){return i.createElement(r.Ix,{history:this.history,children:this.props.children})},t}(i.Component);i.Component;var d=function(e,t){return"function"==typeof e?e(t):e},p=function(e,t){return"string"==typeof e?(0,o.yJ)(e,null,null,t):e},f=function(e){return e},m=i.forwardRef;void 0===m&&(m=f);var g=m((function(e,t){var n=e.innerRef,r=e.navigate,a=e.onClick,o=(0,s.A)(e,["innerRef","navigate","onClick"]),c=o.target,u=(0,l.A)({},o,{onClick:function(e){try{a&&a(e)}catch(t){throw e.preventDefault(),t}e.defaultPrevented||0!==e.button||c&&"_self"!==c||function(e){return!!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)}(e)||(e.preventDefault(),r())}});return u.ref=f!==m&&t||n,i.createElement("a",u)}));var h=m((function(e,t){var n=e.component,a=void 0===n?g:n,u=e.replace,h=e.to,b=e.innerRef,v=(0,s.A)(e,["component","replace","to","innerRef"]);return i.createElement(r.XZ.Consumer,null,(function(e){e||(0,c.A)(!1);var n=e.history,r=p(d(h,e.location),e.location),s=r?n.createHref(r):"",g=(0,l.A)({},v,{href:s,navigate:function(){var t=d(h,e.location),r=(0,o.AO)(e.location)===(0,o.AO)(p(t));(u||r?n.replace:n.push)(t)}});return f!==m?g.ref=t||b:g.innerRef=b,i.createElement(a,g)}))})),b=function(e){return e},v=i.forwardRef;void 0===v&&(v=b);var y=v((function(e,t){var n=e["aria-current"],a=void 0===n?"page":n,o=e.activeClassName,u=void 0===o?"active":o,f=e.activeStyle,m=e.className,g=e.exact,y=e.isActive,w=e.location,x=e.sensitive,k=e.strict,E=e.style,S=e.to,T=e.innerRef,_=(0,s.A)(e,["aria-current","activeClassName","activeStyle","className","exact","isActive","location","sensitive","strict","style","to","innerRef"]);return i.createElement(r.XZ.Consumer,null,(function(e){e||(0,c.A)(!1);var n=w||e.location,o=p(d(S,n),n),s=o.pathname,A=s&&s.replace(/([.+*?=^!:${}()[\]|/\\])/g,"\\$1"),C=A?(0,r.B6)(n.pathname,{path:A,exact:g,sensitive:x,strict:k}):null,P=!!(y?y(C,n):C),N="function"==typeof m?m(P):m,O="function"==typeof E?E(P):E;P&&(N=function(){for(var e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];return t.filter((function(e){return e})).join(" ")}(N,u),O=(0,l.A)({},O,f));var I=(0,l.A)({"aria-current":P&&a||null,className:N,style:O,to:o},_);return b!==v?I.ref=t||T:I.innerRef=T,i.createElement(h,I)}))}))},6347:(e,t,n)=>{"use strict";n.d(t,{B6:()=>E,Ix:()=>y,W6:()=>I,XZ:()=>v,dO:()=>N,qh:()=>S,zy:()=>R});var r=n(2892),a=n(6540),i=n(5556),o=n.n(i),l=n(1513),s=n(1561),c=n(8168),u=n(5302),d=n.n(u),p=(n(4363),n(8587)),f=(n(4146),1073741823),m="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:void 0!==n.g?n.g:{};var g=a.createContext||function(e,t){var n,i,l="__create-react-context-"+function(){var e="__global_unique_id__";return m[e]=(m[e]||0)+1}()+"__",s=function(e){function n(){for(var t,n,r,a=arguments.length,i=new Array(a),o=0;o<a;o++)i[o]=arguments[o];return(t=e.call.apply(e,[this].concat(i))||this).emitter=(n=t.props.value,r=[],{on:function(e){r.push(e)},off:function(e){r=r.filter((function(t){return t!==e}))},get:function(){return n},set:function(e,t){n=e,r.forEach((function(e){return e(n,t)}))}}),t}(0,r.A)(n,e);var a=n.prototype;return a.getChildContext=function(){var e;return(e={})[l]=this.emitter,e},a.componentWillReceiveProps=function(e){if(this.props.value!==e.value){var n,r=this.props.value,a=e.value;((i=r)===(o=a)?0!==i||1/i==1/o:i!=i&&o!=o)?n=0:(n="function"==typeof t?t(r,a):f,0!==(n|=0)&&this.emitter.set(e.value,n))}var i,o},a.render=function(){return this.props.children},n}(a.Component);s.childContextTypes=((n={})[l]=o().object.isRequired,n);var c=function(t){function n(){for(var e,n=arguments.length,r=new Array(n),a=0;a<n;a++)r[a]=arguments[a];return(e=t.call.apply(t,[this].concat(r))||this).observedBits=void 0,e.state={value:e.getValue()},e.onUpdate=function(t,n){(0|e.observedBits)&n&&e.setState({value:e.getValue()})},e}(0,r.A)(n,t);var a=n.prototype;return a.componentWillReceiveProps=function(e){var t=e.observedBits;this.observedBits=null==t?f:t},a.componentDidMount=function(){this.context[l]&&this.context[l].on(this.onUpdate);var e=this.props.observedBits;this.observedBits=null==e?f:e},a.componentWillUnmount=function(){this.context[l]&&this.context[l].off(this.onUpdate)},a.getValue=function(){return this.context[l]?this.context[l].get():e},a.render=function(){return(e=this.props.children,Array.isArray(e)?e[0]:e)(this.state.value);var e},n}(a.Component);return c.contextTypes=((i={})[l]=o().object,i),{Provider:s,Consumer:c}},h=function(e){var t=g();return t.displayName=e,t},b=h("Router-History"),v=h("Router"),y=function(e){function t(t){var n;return(n=e.call(this,t)||this).state={location:t.history.location},n._isMounted=!1,n._pendingLocation=null,t.staticContext||(n.unlisten=t.history.listen((function(e){n._pendingLocation=e}))),n}(0,r.A)(t,e),t.computeRootMatch=function(e){return{path:"/",url:"/",params:{},isExact:"/"===e}};var n=t.prototype;return n.componentDidMount=function(){var e=this;this._isMounted=!0,this.unlisten&&this.unlisten(),this.props.staticContext||(this.unlisten=this.props.history.listen((function(t){e._isMounted&&e.setState({location:t})}))),this._pendingLocation&&this.setState({location:this._pendingLocation})},n.componentWillUnmount=function(){this.unlisten&&(this.unlisten(),this._isMounted=!1,this._pendingLocation=null)},n.render=function(){return a.createElement(v.Provider,{value:{history:this.props.history,location:this.state.location,match:t.computeRootMatch(this.state.location.pathname),staticContext:this.props.staticContext}},a.createElement(b.Provider,{children:this.props.children||null,value:this.props.history}))},t}(a.Component);a.Component;a.Component;var w={},x=1e4,k=0;function E(e,t){void 0===t&&(t={}),("string"==typeof t||Array.isArray(t))&&(t={path:t});var n=t,r=n.path,a=n.exact,i=void 0!==a&&a,o=n.strict,l=void 0!==o&&o,s=n.sensitive,c=void 0!==s&&s;return[].concat(r).reduce((function(t,n){if(!n&&""!==n)return null;if(t)return t;var r=function(e,t){var n=""+t.end+t.strict+t.sensitive,r=w[n]||(w[n]={});if(r[e])return r[e];var a=[],i={regexp:d()(e,a,t),keys:a};return k<x&&(r[e]=i,k++),i}(n,{end:i,strict:l,sensitive:c}),a=r.regexp,o=r.keys,s=a.exec(e);if(!s)return null;var u=s[0],p=s.slice(1),f=e===u;return i&&!f?null:{path:n,url:"/"===n&&""===u?"/":u,isExact:f,params:o.reduce((function(e,t,n){return e[t.name]=p[n],e}),{})}}),null)}var S=function(e){function t(){return e.apply(this,arguments)||this}return(0,r.A)(t,e),t.prototype.render=function(){var e=this;return a.createElement(v.Consumer,null,(function(t){t||(0,s.A)(!1);var n=e.props.location||t.location,r=e.props.computedMatch?e.props.computedMatch:e.props.path?E(n.pathname,e.props):t.match,i=(0,c.A)({},t,{location:n,match:r}),o=e.props,l=o.children,u=o.component,d=o.render;return Array.isArray(l)&&function(e){return 0===a.Children.count(e)}(l)&&(l=null),a.createElement(v.Provider,{value:i},i.match?l?"function"==typeof l?l(i):l:u?a.createElement(u,i):d?d(i):null:"function"==typeof l?l(i):null)}))},t}(a.Component);function T(e){return"/"===e.charAt(0)?e:"/"+e}function _(e,t){if(!e)return t;var n=T(e);return 0!==t.pathname.indexOf(n)?t:(0,c.A)({},t,{pathname:t.pathname.substr(n.length)})}function A(e){return"string"==typeof e?e:(0,l.AO)(e)}function C(e){return function(){(0,s.A)(!1)}}function P(){}a.Component;var N=function(e){function t(){return e.apply(this,arguments)||this}return(0,r.A)(t,e),t.prototype.render=function(){var e=this;return a.createElement(v.Consumer,null,(function(t){t||(0,s.A)(!1);var n,r,i=e.props.location||t.location;return a.Children.forEach(e.props.children,(function(e){if(null==r&&a.isValidElement(e)){n=e;var o=e.props.path||e.props.from;r=o?E(i.pathname,(0,c.A)({},e.props,{path:o})):t.match}})),r?a.cloneElement(n,{location:i,computedMatch:r}):null}))},t}(a.Component);var O=a.useContext;function I(){return O(b)}function R(){return O(v).location}},5287:(e,t,n)=>{"use strict";var r=n(5228),a="function"==typeof Symbol&&Symbol.for,i=a?Symbol.for("react.element"):60103,o=a?Symbol.for("react.portal"):60106,l=a?Symbol.for("react.fragment"):60107,s=a?Symbol.for("react.strict_mode"):60108,c=a?Symbol.for("react.profiler"):60114,u=a?Symbol.for("react.provider"):60109,d=a?Symbol.for("react.context"):60110,p=a?Symbol.for("react.forward_ref"):60112,f=a?Symbol.for("react.suspense"):60113,m=a?Symbol.for("react.memo"):60115,g=a?Symbol.for("react.lazy"):60116,h="function"==typeof Symbol&&Symbol.iterator;function b(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n<arguments.length;n++)t+="&args[]="+encodeURIComponent(arguments[n]);return"Minified React error #"+e+"; visit "+t+" for the full message or use the non-minified dev environment for full errors and additional helpful warnings."}var v={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},y={};function w(e,t,n){this.props=e,this.context=t,this.refs=y,this.updater=n||v}function x(){}function k(e,t,n){this.props=e,this.context=t,this.refs=y,this.updater=n||v}w.prototype.isReactComponent={},w.prototype.setState=function(e,t){if("object"!=typeof e&&"function"!=typeof e&&null!=e)throw Error(b(85));this.updater.enqueueSetState(this,e,t,"setState")},w.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")},x.prototype=w.prototype;var E=k.prototype=new x;E.constructor=k,r(E,w.prototype),E.isPureReactComponent=!0;var S={current:null},T=Object.prototype.hasOwnProperty,_={key:!0,ref:!0,__self:!0,__source:!0};function A(e,t,n){var r,a={},o=null,l=null;if(null!=t)for(r in void 0!==t.ref&&(l=t.ref),void 0!==t.key&&(o=""+t.key),t)T.call(t,r)&&!_.hasOwnProperty(r)&&(a[r]=t[r]);var s=arguments.length-2;if(1===s)a.children=n;else if(1<s){for(var c=Array(s),u=0;u<s;u++)c[u]=arguments[u+2];a.children=c}if(e&&e.defaultProps)for(r in s=e.defaultProps)void 0===a[r]&&(a[r]=s[r]);return{$$typeof:i,type:e,key:o,ref:l,props:a,_owner:S.current}}function C(e){return"object"==typeof e&&null!==e&&e.$$typeof===i}var P=/\/+/g,N=[];function O(e,t,n,r){if(N.length){var a=N.pop();return a.result=e,a.keyPrefix=t,a.func=n,a.context=r,a.count=0,a}return{result:e,keyPrefix:t,func:n,context:r,count:0}}function I(e){e.result=null,e.keyPrefix=null,e.func=null,e.context=null,e.count=0,10>N.length&&N.push(e)}function R(e,t,n,r){var a=typeof e;"undefined"!==a&&"boolean"!==a||(e=null);var l=!1;if(null===e)l=!0;else switch(a){case"string":case"number":l=!0;break;case"object":switch(e.$$typeof){case i:case o:l=!0}}if(l)return n(r,e,""===t?"."+L(e,0):t),1;if(l=0,t=""===t?".":t+":",Array.isArray(e))for(var s=0;s<e.length;s++){var c=t+L(a=e[s],s);l+=R(a,c,n,r)}else if(null===e||"object"!=typeof e?c=null:c="function"==typeof(c=h&&e[h]||e["@@iterator"])?c:null,"function"==typeof c)for(e=c.call(e),s=0;!(a=e.next()).done;)l+=R(a=a.value,c=t+L(a,s++),n,r);else if("object"===a)throw n=""+e,Error(b(31,"[object Object]"===n?"object with keys {"+Object.keys(e).join(", ")+"}":n,""));return l}function D(e,t,n){return null==e?0:R(e,"",t,n)}function L(e,t){return"object"==typeof e&&null!==e&&null!=e.key?function(e){var t={"=":"=0",":":"=2"};return"$"+(""+e).replace(/[=:]/g,(function(e){return t[e]}))}(e.key):t.toString(36)}function M(e,t){e.func.call(e.context,t,e.count++)}function F(e,t,n){var r=e.result,a=e.keyPrefix;e=e.func.call(e.context,t,e.count++),Array.isArray(e)?B(e,r,n,(function(e){return e})):null!=e&&(C(e)&&(e=function(e,t){return{$$typeof:i,type:e.type,key:t,ref:e.ref,props:e.props,_owner:e._owner}}(e,a+(!e.key||t&&t.key===e.key?"":(""+e.key).replace(P,"$&/")+"/")+n)),r.push(e))}function B(e,t,n,r,a){var i="";null!=n&&(i=(""+n).replace(P,"$&/")+"/"),D(e,F,t=O(t,i,r,a)),I(t)}var $={current:null};function z(){var e=$.current;if(null===e)throw Error(b(321));return e}var U={ReactCurrentDispatcher:$,ReactCurrentBatchConfig:{suspense:null},ReactCurrentOwner:S,IsSomeRendererActing:{current:!1},assign:r};t.Children={map:function(e,t,n){if(null==e)return e;var r=[];return B(e,r,null,t,n),r},forEach:function(e,t,n){if(null==e)return e;D(e,M,t=O(null,null,t,n)),I(t)},count:function(e){return D(e,(function(){return null}),null)},toArray:function(e){var t=[];return B(e,t,null,(function(e){return e})),t},only:function(e){if(!C(e))throw Error(b(143));return e}},t.Component=w,t.Fragment=l,t.Profiler=c,t.PureComponent=k,t.StrictMode=s,t.Suspense=f,t.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=U,t.cloneElement=function(e,t,n){if(null==e)throw Error(b(267,e));var a=r({},e.props),o=e.key,l=e.ref,s=e._owner;if(null!=t){if(void 0!==t.ref&&(l=t.ref,s=S.current),void 0!==t.key&&(o=""+t.key),e.type&&e.type.defaultProps)var c=e.type.defaultProps;for(u in t)T.call(t,u)&&!_.hasOwnProperty(u)&&(a[u]=void 0===t[u]&&void 0!==c?c[u]:t[u])}var u=arguments.length-2;if(1===u)a.children=n;else if(1<u){c=Array(u);for(var d=0;d<u;d++)c[d]=arguments[d+2];a.children=c}return{$$typeof:i,type:e.type,key:o,ref:l,props:a,_owner:s}},t.createContext=function(e,t){return void 0===t&&(t=null),(e={$$typeof:d,_calculateChangedBits:t,_currentValue:e,_currentValue2:e,_threadCount:0,Provider:null,Consumer:null}).Provider={$$typeof:u,_context:e},e.Consumer=e},t.createElement=A,t.createFactory=function(e){var t=A.bind(null,e);return t.type=e,t},t.createRef=function(){return{current:null}},t.forwardRef=function(e){return{$$typeof:p,render:e}},t.isValidElement=C,t.lazy=function(e){return{$$typeof:g,_ctor:e,_status:-1,_result:null}},t.memo=function(e,t){return{$$typeof:m,type:e,compare:void 0===t?null:t}},t.useCallback=function(e,t){return z().useCallback(e,t)},t.useContext=function(e,t){return z().useContext(e,t)},t.useDebugValue=function(){},t.useEffect=function(e,t){return z().useEffect(e,t)},t.useImperativeHandle=function(e,t,n){return z().useImperativeHandle(e,t,n)},t.useLayoutEffect=function(e,t){return z().useLayoutEffect(e,t)},t.useMemo=function(e,t){return z().useMemo(e,t)},t.useReducer=function(e,t,n){return z().useReducer(e,t,n)},t.useRef=function(e){return z().useRef(e)},t.useState=function(e){return z().useState(e)},t.version="16.14.0"},6540:(e,t,n)=>{"use strict";e.exports=n(5287)},7463:(e,t)=>{"use strict";var n,r,a,i,o;if("undefined"==typeof window||"function"!=typeof MessageChannel){var l=null,s=null,c=function(){if(null!==l)try{var e=t.unstable_now();l(!0,e),l=null}catch(n){throw setTimeout(c,0),n}},u=Date.now();t.unstable_now=function(){return Date.now()-u},n=function(e){null!==l?setTimeout(n,0,e):(l=e,setTimeout(c,0))},r=function(e,t){s=setTimeout(e,t)},a=function(){clearTimeout(s)},i=function(){return!1},o=t.unstable_forceFrameRate=function(){}}else{var d=window.performance,p=window.Date,f=window.setTimeout,m=window.clearTimeout;if("undefined"!=typeof console){var g=window.cancelAnimationFrame;"function"!=typeof window.requestAnimationFrame&&console.error("This browser doesn't support requestAnimationFrame. Make sure that you load a polyfill in older browsers. https://fb.me/react-polyfills"),"function"!=typeof g&&console.error("This browser doesn't support cancelAnimationFrame. Make sure that you load a polyfill in older browsers. https://fb.me/react-polyfills")}if("object"==typeof d&&"function"==typeof d.now)t.unstable_now=function(){return d.now()};else{var h=p.now();t.unstable_now=function(){return p.now()-h}}var b=!1,v=null,y=-1,w=5,x=0;i=function(){return t.unstable_now()>=x},o=function(){},t.unstable_forceFrameRate=function(e){0>e||125<e?console.error("forceFrameRate takes a positive int between 0 and 125, forcing framerates higher than 125 fps is not unsupported"):w=0<e?Math.floor(1e3/e):5};var k=new MessageChannel,E=k.port2;k.port1.onmessage=function(){if(null!==v){var e=t.unstable_now();x=e+w;try{v(!0,e)?E.postMessage(null):(b=!1,v=null)}catch(n){throw E.postMessage(null),n}}else b=!1},n=function(e){v=e,b||(b=!0,E.postMessage(null))},r=function(e,n){y=f((function(){e(t.unstable_now())}),n)},a=function(){m(y),y=-1}}function S(e,t){var n=e.length;e.push(t);e:for(;;){var r=n-1>>>1,a=e[r];if(!(void 0!==a&&0<A(a,t)))break e;e[r]=t,e[n]=a,n=r}}function T(e){return void 0===(e=e[0])?null:e}function _(e){var t=e[0];if(void 0!==t){var n=e.pop();if(n!==t){e[0]=n;e:for(var r=0,a=e.length;r<a;){var i=2*(r+1)-1,o=e[i],l=i+1,s=e[l];if(void 0!==o&&0>A(o,n))void 0!==s&&0>A(s,o)?(e[r]=s,e[l]=n,r=l):(e[r]=o,e[i]=n,r=i);else{if(!(void 0!==s&&0>A(s,n)))break e;e[r]=s,e[l]=n,r=l}}}return t}return null}function A(e,t){var n=e.sortIndex-t.sortIndex;return 0!==n?n:e.id-t.id}var C=[],P=[],N=1,O=null,I=3,R=!1,D=!1,L=!1;function M(e){for(var t=T(P);null!==t;){if(null===t.callback)_(P);else{if(!(t.startTime<=e))break;_(P),t.sortIndex=t.expirationTime,S(C,t)}t=T(P)}}function F(e){if(L=!1,M(e),!D)if(null!==T(C))D=!0,n(B);else{var t=T(P);null!==t&&r(F,t.startTime-e)}}function B(e,n){D=!1,L&&(L=!1,a()),R=!0;var o=I;try{for(M(n),O=T(C);null!==O&&(!(O.expirationTime>n)||e&&!i());){var l=O.callback;if(null!==l){O.callback=null,I=O.priorityLevel;var s=l(O.expirationTime<=n);n=t.unstable_now(),"function"==typeof s?O.callback=s:O===T(C)&&_(C),M(n)}else _(C);O=T(C)}if(null!==O)var c=!0;else{var u=T(P);null!==u&&r(F,u.startTime-n),c=!1}return c}finally{O=null,I=o,R=!1}}function $(e){switch(e){case 1:return-1;case 2:return 250;case 5:return 1073741823;case 4:return 1e4;default:return 5e3}}var z=o;t.unstable_IdlePriority=5,t.unstable_ImmediatePriority=1,t.unstable_LowPriority=4,t.unstable_NormalPriority=3,t.unstable_Profiling=null,t.unstable_UserBlockingPriority=2,t.unstable_cancelCallback=function(e){e.callback=null},t.unstable_continueExecution=function(){D||R||(D=!0,n(B))},t.unstable_getCurrentPriorityLevel=function(){return I},t.unstable_getFirstCallbackNode=function(){return T(C)},t.unstable_next=function(e){switch(I){case 1:case 2:case 3:var t=3;break;default:t=I}var n=I;I=t;try{return e()}finally{I=n}},t.unstable_pauseExecution=function(){},t.unstable_requestPaint=z,t.unstable_runWithPriority=function(e,t){switch(e){case 1:case 2:case 3:case 4:case 5:break;default:e=3}var n=I;I=e;try{return t()}finally{I=n}},t.unstable_scheduleCallback=function(e,i,o){var l=t.unstable_now();if("object"==typeof o&&null!==o){var s=o.delay;s="number"==typeof s&&0<s?l+s:l,o="number"==typeof o.timeout?o.timeout:$(e)}else o=$(e),s=l;return e={id:N++,callback:i,priorityLevel:e,startTime:s,expirationTime:o=s+o,sortIndex:-1},s>l?(e.sortIndex=s,S(P,e),null===T(C)&&e===T(P)&&(L?a():L=!0,r(F,s-l))):(e.sortIndex=o,S(C,e),D||R||(D=!0,n(B))),e},t.unstable_shouldYield=function(){var e=t.unstable_now();M(e);var n=T(C);return n!==O&&null!==O&&null!==n&&null!==n.callback&&n.startTime<=e&&n.expirationTime<O.expirationTime||i()},t.unstable_wrapCallback=function(e){var t=I;return function(){var n=I;I=t;try{return e.apply(this,arguments)}finally{I=n}}}},9982:(e,t,n)=>{"use strict";e.exports=n(7463)},2833:e=>{e.exports=function(e,t,n,r){var a=n?n.call(r,e,t):void 0;if(void 0!==a)return!!a;if(e===t)return!0;if("object"!=typeof e||!e||"object"!=typeof t||!t)return!1;var i=Object.keys(e),o=Object.keys(t);if(i.length!==o.length)return!1;for(var l=Object.prototype.hasOwnProperty.bind(t),s=0;s<i.length;s++){var c=i[s];if(!l(c))return!1;var u=e[c],d=t[c];if(!1===(a=n?n.call(r,u,d,c):void 0)||void 0===a&&u!==d)return!1}return!0}},4784:(e,t,n)=>{"use strict";n.r(t),n.d(t,{default:()=>r});const r={title:"Weaver: DLT Interoperability Framework",tagline:"Documentation",url:"https://hyperledger-labs.github.io",baseUrl:"/weaver-dlt-interoperability/",onBrokenLinks:"throw",onBrokenMarkdownLinks:"warn",favicon:"shared/favicon.ico",organizationName:"hyperledger-labs",projectName:"hyperledger-labs.github.io",themeConfig:{prism:{additionalLanguages:["java","kotlin","groovy","toml"],theme:{plain:{color:"#bfc7d5",backgroundColor:"#292d3e"},styles:[{types:["comment"],style:{color:"rgb(105, 112, 152)",fontStyle:"italic"}},{types:["string","inserted"],style:{color:"rgb(195, 232, 141)"}},{types:["number"],style:{color:"rgb(247, 140, 108)"}},{types:["builtin","char","constant","function"],style:{color:"rgb(130, 170, 255)"}},{types:["punctuation","selector"],style:{color:"rgb(199, 146, 234)"}},{types:["variable"],style:{color:"rgb(191, 199, 213)"}},{types:["class-name","attr-name"],style:{color:"rgb(255, 203, 107)"}},{types:["tag","deleted"],style:{color:"rgb(255, 85, 114)"}},{types:["operator"],style:{color:"rgb(137, 221, 255)"}},{types:["boolean"],style:{color:"rgb(255, 88, 116)"}},{types:["keyword"],style:{fontStyle:"italic"}},{types:["doctype"],style:{color:"rgb(199, 146, 234)",fontStyle:"italic"}},{types:["namespace"],style:{color:"rgb(178, 204, 214)"}},{types:["url"],style:{color:"rgb(221, 221, 221)"}}]},magicComments:[{className:"theme-code-block-highlighted-line",line:"highlight-next-line",block:{start:"highlight-start",end:"highlight-end"}}]},navbar:{title:"Weaver",logo:{alt:"Weaver",src:"shared/logo.svg"},items:[{to:"docs/external/introduction",activeBasePath:"docs",label:"Docs",position:"left"},{to:"blog",label:"Blog",position:"left"},{href:"https://github.com/hyperledger-labs/weaver-dlt-interoperability",label:"GitHub",position:"right"}],hideOnScroll:!1},footer:{style:"light",links:[],copyright:"Copyright \xa9 2024 Weaver Framework."},colorMode:{defaultMode:"light",disableSwitch:!1,respectPrefersColorScheme:!1},docs:{versionPersistence:"localStorage",sidebar:{hideable:!1,autoCollapseCategories:!1}},metadata:[],tableOfContents:{minHeadingLevel:2,maxHeadingLevel:3}},presets:[["@docusaurus/preset-classic",{docs:{sidebarPath:"/home/runner/work/weaver-dlt-interoperability/weaver-dlt-interoperability/docs/sidebars.js",editUrl:"https://github.com/hyperledger-labs/weaver-dlt-interoperability/edit/main/"},theme:{customCss:"/home/runner/work/weaver-dlt-interoperability/weaver-dlt-interoperability/docs/src/css/custom.css"}}]],baseUrlIssueBanner:!0,i18n:{defaultLocale:"en",path:"i18n",locales:["en"],localeConfigs:{}},onDuplicateRoutes:"warn",staticDirectories:["static"],customFields:{},plugins:[],themes:[],scripts:[],headTags:[],stylesheets:[],clientModules:[],titleDelimiter:"|",noIndex:!1,markdown:{mermaid:!1}}},8168:(e,t,n)=>{"use strict";function r(){return r=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},r.apply(this,arguments)}n.d(t,{A:()=>r})},2892:(e,t,n)=>{"use strict";function r(e,t){return r=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(e,t){return e.__proto__=t,e},r(e,t)}function a(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,r(e,t)}n.d(t,{A:()=>a})},8587:(e,t,n)=>{"use strict";function r(e,t){if(null==e)return{};var n={};for(var r in e)if(Object.prototype.hasOwnProperty.call(e,r)){if(t.indexOf(r)>=0)continue;n[r]=e[r]}return n}n.d(t,{A:()=>r})},1561:(e,t,n)=>{"use strict";n.d(t,{A:()=>i});var r=!0,a="Invariant failed";function i(e,t){if(!e){if(r)throw new Error(a);var n="function"==typeof t?t():t,i=n?"".concat(a,": ").concat(n):a;throw new Error(i)}}},2654:e=>{"use strict";e.exports={}},4054:e=>{"use strict";e.exports=JSON.parse('{"/weaver-dlt-interoperability/blog-fba":{"__comp":"a6aa9e1f","__context":{"plugin":"ee4141e0"},"sidebar":"814f3328","items":[{"content":"bdfaba9c"},{"content":"3d5da5a5"}],"metadata":"591644de"},"/weaver-dlt-interoperability/blog/2021/01/21/cross-chain-asset-014":{"__comp":"ccc49370","__context":{"plugin":"ee4141e0"},"sidebar":"814f3328","content":"378badfe"},"/weaver-dlt-interoperability/blog/2021/01/21/emergence-enterprise-interoperability-e8d":{"__comp":"ccc49370","__context":{"plugin":"ee4141e0"},"sidebar":"814f3328","content":"56182e71"},"/weaver-dlt-interoperability/blog/archive-502":{"__comp":"9e4087bc","__context":{"plugin":"ee4141e0"},"archive":"64b157a3"},"/weaver-dlt-interoperability/docs-ff4":{"__comp":"1be78505","__context":{"plugin":"99b332c9"},"versionMetadata":"935f2afb"},"/weaver-dlt-interoperability/docs/external/architecture-and-design/decentralized-identity-999":{"__comp":"17896441","content":"8758c959"},"/weaver-dlt-interoperability/docs/external/architecture-and-design/drivers-79c":{"__comp":"17896441","content":"7291aaef"},"/weaver-dlt-interoperability/docs/external/architecture-and-design/overview-390":{"__comp":"17896441","content":"b379f194"},"/weaver-dlt-interoperability/docs/external/architecture-and-design/relay-db6":{"__comp":"17896441","content":"e67be6b3"},"/weaver-dlt-interoperability/docs/external/architecture-and-design/weaver-dapps-52c":{"__comp":"17896441","content":"ec8cb05d"},"/weaver-dlt-interoperability/docs/external/deployment-considerations/deployment-patterns-22b":{"__comp":"17896441","content":"9f52c9db"},"/weaver-dlt-interoperability/docs/external/deployment-considerations/governance-and-policies-d9a":{"__comp":"17896441","content":"3ec01bef"},"/weaver-dlt-interoperability/docs/external/deployment-considerations/legal-and-regulation-956":{"__comp":"17896441","content":"ce7e6f90"},"/weaver-dlt-interoperability/docs/external/design-principles-9ec":{"__comp":"17896441","content":"e0bf5ccd"},"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/besu-6b8":{"__comp":"17896441","content":"b545330d"},"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/corda-a90":{"__comp":"17896441","content":"f0c74005"},"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/fabric-8fd":{"__comp":"17896441","content":"98ecfc99"},"/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/overview-90e":{"__comp":"17896441","content":"8379e623"},"/weaver-dlt-interoperability/docs/external/getting-started/guide-465":{"__comp":"17896441","content":"20a6a7d9"},"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/besu-besu-c57":{"__comp":"17896441","content":"f1311735"},"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/corda-besu-eea":{"__comp":"17896441","content":"15db90ce"},"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/corda-corda-929":{"__comp":"17896441","content":"935bcf2a"},"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-besu-51a":{"__comp":"17896441","content":"25e7257c"},"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-corda-752":{"__comp":"17896441","content":"5c41994f"},"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-fabric-7fb":{"__comp":"17896441","content":"bf5dfefe"},"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overview-332":{"__comp":"17896441","content":"59395140"},"/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-transfer-1df":{"__comp":"17896441","content":"2e5dd55e"},"/weaver-dlt-interoperability/docs/external/getting-started/interop/data-sharing-c36":{"__comp":"17896441","content":"da157423"},"/weaver-dlt-interoperability/docs/external/getting-started/interop/overview-91f":{"__comp":"17896441","content":"239a9e81"},"/weaver-dlt-interoperability/docs/external/getting-started/test-network/advanced-configuration-93b":{"__comp":"17896441","content":"2ec21c4a"},"/weaver-dlt-interoperability/docs/external/getting-started/test-network/ledger-initialization-704":{"__comp":"17896441","content":"b0f8195e"},"/weaver-dlt-interoperability/docs/external/getting-started/test-network/overview-067":{"__comp":"17896441","content":"ec2d6a08"},"/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-local-b48":{"__comp":"17896441","content":"36367655"},"/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-local-docker-a86":{"__comp":"17896441","content":"53c981a7"},"/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-packages-452":{"__comp":"17896441","content":"8b2840ea"},"/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-packages-docker-687":{"__comp":"17896441","content":"c9723ef0"},"/weaver-dlt-interoperability/docs/external/interoperability-modes-3ac":{"__comp":"17896441","content":"85de58a0"},"/weaver-dlt-interoperability/docs/external/introduction-02e":{"__comp":"17896441","content":"ba46e1b8"},"/weaver-dlt-interoperability/docs/external/publications-1c5":{"__comp":"17896441","content":"13886346"},"/weaver-dlt-interoperability/docs/external/roadmap-877":{"__comp":"17896441","content":"ac36c4b6"},"/weaver-dlt-interoperability/docs/external/security-model/access-control-4cc":{"__comp":"17896441","content":"ee88fe61"},"/weaver-dlt-interoperability/docs/external/security-model/authentication-5ea":{"__comp":"17896441","content":"a92192c3"},"/weaver-dlt-interoperability/docs/external/security-model/end-to-end-security-0a1":{"__comp":"17896441","content":"a50a7707"},"/weaver-dlt-interoperability/docs/external/security-model/proofs-and-verification-095":{"__comp":"17896441","content":"46d80676"},"/weaver-dlt-interoperability/docs/external/specifications-bd8":{"__comp":"17896441","content":"6835b8cd"},"/weaver-dlt-interoperability/docs/external/user-stories/financial-markets-168":{"__comp":"17896441","content":"071be86b"},"/weaver-dlt-interoperability/docs/external/user-stories/global-trade-01e":{"__comp":"17896441","content":"a3e47e5c"},"/weaver-dlt-interoperability/docs/external/user-stories/legacy-integration-711":{"__comp":"17896441","content":"3d094f56"},"/weaver-dlt-interoperability/docs/external/user-stories/overview-1b3":{"__comp":"17896441","content":"2b962623"},"/weaver-dlt-interoperability/docs/external/what-is-interoperability/integration-patterns-6e2":{"__comp":"17896441","content":"27ea52af"},"/weaver-dlt-interoperability/docs/external/what-is-interoperability/levels-of-interoperability-541":{"__comp":"17896441","content":"f5ed51a1"},"/weaver-dlt-interoperability/docs/external/what-is-interoperability/understanding-interoperability-4c3":{"__comp":"17896441","content":"eeaeeec1"},"/weaver-dlt-interoperability/-6e4":{"__comp":"c4f5d8e4","__context":{"plugin":"61becdbc"},"config":"5e9f5e1a"}}')}},e=>{e.O(0,[1869],(()=>{return t=5660,e(e.s=t);var t}));e.O()}]); \ No newline at end of file diff --git a/assets/js/main.852d9073.js.LICENSE.txt b/assets/js/main.b9723597.js.LICENSE.txt similarity index 100% rename from assets/js/main.852d9073.js.LICENSE.txt rename to assets/js/main.b9723597.js.LICENSE.txt diff --git a/assets/js/runtime~main.71560982.js b/assets/js/runtime~main.71560982.js deleted file mode 100644 index 7958de43f..000000000 --- a/assets/js/runtime~main.71560982.js +++ /dev/null @@ -1 +0,0 @@ -(()=>{"use strict";var e,a,c,f,d,t={},b={};function r(e){var a=b[e];if(void 0!==a)return a.exports;var c=b[e]={exports:{}};return t[e].call(c.exports,c,c.exports,r),c.exports}r.m=t,e=[],r.O=(a,c,f,d)=>{if(!c){var t=1/0;for(i=0;i<e.length;i++){c=e[i][0],f=e[i][1],d=e[i][2];for(var b=!0,o=0;o<c.length;o++)(!1&d||t>=d)&&Object.keys(r.O).every((e=>r.O[e](c[o])))?c.splice(o--,1):(b=!1,d<t&&(t=d));if(b){e.splice(i--,1);var n=f();void 0!==n&&(a=n)}}return a}d=d||0;for(var i=e.length;i>0&&e[i-1][2]>d;i--)e[i]=e[i-1];e[i]=[c,f,d]},r.n=e=>{var a=e&&e.__esModule?()=>e.default:()=>e;return r.d(a,{a:a}),a},c=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,r.t=function(e,f){if(1&f&&(e=this(e)),8&f)return e;if("object"==typeof e&&e){if(4&f&&e.__esModule)return e;if(16&f&&"function"==typeof e.then)return e}var d=Object.create(null);r.r(d);var t={};a=a||[null,c({}),c([]),c(c)];for(var b=2&f&&e;"object"==typeof b&&!~a.indexOf(b);b=c(b))Object.getOwnPropertyNames(b).forEach((a=>t[a]=()=>e[a]));return t.default=()=>e,r.d(d,t),d},r.d=(e,a)=>{for(var c in a)r.o(a,c)&&!r.o(e,c)&&Object.defineProperty(e,c,{enumerable:!0,get:a[c]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce(((a,c)=>(r.f[c](e,a),a)),[])),r.u=e=>"assets/js/"+({53:"935f2afb",54:"e67be6b3",87:"a92192c3",231:"13886346",350:"15bfa0c2",355:"56182e71",369:"378badfe",457:"f0c74005",676:"9a814649",830:"64b157a3",867:"3ec01bef",881:"e0bf5ccd",1323:"7291aaef",1637:"5c41994f",1749:"ee88fe61",1939:"99b332c9",2136:"b379f194",2187:"2e5ddf1e",2238:"eed74c9c",2435:"9f52c9db",2535:"814f3328",2649:"eeaeeec1",2752:"ee4141e0",2981:"bdfaba9c",3089:"a6aa9e1f",3145:"a6da3080",3162:"8379e623",3214:"abd77f53",3278:"3d094f56",3283:"935bcf2a",3299:"2ec21c4a",3395:"da157423",3608:"9e4087bc",3660:"98ecfc99",3773:"53c981a7",3807:"27ea52af",4010:"2e5dd55e",4195:"c4f5d8e4",4330:"20a6a7d9",5261:"cd2e0b0a",5398:"b0f8195e",5622:"ac36c4b6",5651:"d85aeaf8",5671:"c9886a33",6103:"ccc49370",6445:"6835b8cd",6610:"b545330d",6664:"f1311735",6896:"ec2d6a08",7195:"a50a7707",7295:"591644de",7376:"25e7257c",7459:"8758c959",7736:"36367655",7900:"239a9e81",7918:"17896441",8039:"15db90ce",8214:"ba46e1b8",8298:"59395140",8340:"61becdbc",8362:"bf5dfefe",8492:"f5ed51a1",8922:"071be86b",8995:"a3e47e5c",9167:"c9723ef0",9178:"3d5da5a5",9219:"46d80676",9514:"1be78505",9530:"85de58a0",9822:"2b962623",9856:"ec8cb05d",9935:"8b2840ea",9962:"ce7e6f90"}[e]||e)+"."+{53:"1a177595",54:"dd0dd4dd",87:"01c6e0bd",231:"894568f7",350:"76426347",355:"586ce5c7",369:"578d0d9f",457:"1e80f4a8",676:"976c239d",830:"dc655d52",867:"7178ccff",881:"8049887a",1323:"1adc7d99",1637:"ddb8c2c1",1749:"2770da30",1939:"1742e64d",2004:"13abbb5c",2136:"15c4c4e5",2187:"ab6b10ea",2238:"4f784c5c",2435:"5845363a",2535:"b40f362f",2649:"1c1133a0",2752:"dc6336f7",2981:"6d7ad1af",3089:"4986bb6c",3145:"fa7ff818",3162:"676ec9ff",3214:"5609b353",3278:"7cba4bcd",3283:"121fffff",3299:"75cb851a",3395:"5f099098",3608:"8ba881f8",3660:"5108af36",3773:"f1b2bca9",3807:"7c2fc5f7",4010:"71fe4275",4195:"fba3a11a",4330:"70d2e06a",4972:"7556188e",5261:"cfaa347a",5398:"2ae97f7f",5622:"8a0f9722",5651:"86ca9d44",5671:"715d8bed",6103:"753c1031",6445:"cc86f083",6610:"ea6ae7a5",6664:"501f6c98",6896:"3be2a974",7195:"bcb02034",7295:"ca3c9ad9",7376:"57659e76",7459:"729751f4",7736:"972f50cd",7900:"5c089920",7918:"5f598f0f",8039:"e1099e01",8214:"fcee89dd",8218:"60a8b611",8298:"c27b3725",8340:"f7024449",8362:"e6b84837",8492:"b849efe5",8922:"09bd0961",8995:"cdea0430",9167:"f2cba00c",9178:"d09aca1d",9219:"cf24df36",9514:"e390b67c",9530:"4f92ebce",9822:"d12dec53",9856:"8a20dddb",9935:"e4813590",9962:"8f1959db"}[e]+".js",r.miniCssF=e=>{},r.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),r.o=(e,a)=>Object.prototype.hasOwnProperty.call(e,a),f={},d="weaver-dlt-interoperability:",r.l=(e,a,c,t)=>{if(f[e])f[e].push(a);else{var b,o;if(void 0!==c)for(var n=document.getElementsByTagName("script"),i=0;i<n.length;i++){var l=n[i];if(l.getAttribute("src")==e||l.getAttribute("data-webpack")==d+c){b=l;break}}b||(o=!0,(b=document.createElement("script")).charset="utf-8",b.timeout=120,r.nc&&b.setAttribute("nonce",r.nc),b.setAttribute("data-webpack",d+c),b.src=e),f[e]=[a];var u=(a,c)=>{b.onerror=b.onload=null,clearTimeout(s);var d=f[e];if(delete f[e],b.parentNode&&b.parentNode.removeChild(b),d&&d.forEach((e=>e(c))),a)return a(c)},s=setTimeout(u.bind(null,void 0,{type:"timeout",target:b}),12e4);b.onerror=u.bind(null,b.onerror),b.onload=u.bind(null,b.onload),o&&document.head.appendChild(b)}},r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.p="/weaver-dlt-interoperability/",r.gca=function(e){return e={13886346:"231",17896441:"7918",36367655:"7736",59395140:"8298","935f2afb":"53",e67be6b3:"54",a92192c3:"87","15bfa0c2":"350","56182e71":"355","378badfe":"369",f0c74005:"457","9a814649":"676","64b157a3":"830","3ec01bef":"867",e0bf5ccd:"881","7291aaef":"1323","5c41994f":"1637",ee88fe61:"1749","99b332c9":"1939",b379f194:"2136","2e5ddf1e":"2187",eed74c9c:"2238","9f52c9db":"2435","814f3328":"2535",eeaeeec1:"2649",ee4141e0:"2752",bdfaba9c:"2981",a6aa9e1f:"3089",a6da3080:"3145","8379e623":"3162",abd77f53:"3214","3d094f56":"3278","935bcf2a":"3283","2ec21c4a":"3299",da157423:"3395","9e4087bc":"3608","98ecfc99":"3660","53c981a7":"3773","27ea52af":"3807","2e5dd55e":"4010",c4f5d8e4:"4195","20a6a7d9":"4330",cd2e0b0a:"5261",b0f8195e:"5398",ac36c4b6:"5622",d85aeaf8:"5651",c9886a33:"5671",ccc49370:"6103","6835b8cd":"6445",b545330d:"6610",f1311735:"6664",ec2d6a08:"6896",a50a7707:"7195","591644de":"7295","25e7257c":"7376","8758c959":"7459","239a9e81":"7900","15db90ce":"8039",ba46e1b8:"8214","61becdbc":"8340",bf5dfefe:"8362",f5ed51a1:"8492","071be86b":"8922",a3e47e5c:"8995",c9723ef0:"9167","3d5da5a5":"9178","46d80676":"9219","1be78505":"9514","85de58a0":"9530","2b962623":"9822",ec8cb05d:"9856","8b2840ea":"9935",ce7e6f90:"9962"}[e]||e,r.p+r.u(e)},(()=>{var e={1303:0,532:0};r.f.j=(a,c)=>{var f=r.o(e,a)?e[a]:void 0;if(0!==f)if(f)c.push(f[2]);else if(/^(1303|532)$/.test(a))e[a]=0;else{var d=new Promise(((c,d)=>f=e[a]=[c,d]));c.push(f[2]=d);var t=r.p+r.u(a),b=new Error;r.l(t,(c=>{if(r.o(e,a)&&(0!==(f=e[a])&&(e[a]=void 0),f)){var d=c&&("load"===c.type?"missing":c.type),t=c&&c.target&&c.target.src;b.message="Loading chunk "+a+" failed.\n("+d+": "+t+")",b.name="ChunkLoadError",b.type=d,b.request=t,f[1](b)}}),"chunk-"+a,a)}},r.O.j=a=>0===e[a];var a=(a,c)=>{var f,d,t=c[0],b=c[1],o=c[2],n=0;if(t.some((a=>0!==e[a]))){for(f in b)r.o(b,f)&&(r.m[f]=b[f]);if(o)var i=o(r)}for(a&&a(c);n<t.length;n++)d=t[n],r.o(e,d)&&e[d]&&e[d][0](),e[d]=0;return r.O(i)},c=self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[];c.forEach(a.bind(null,0)),c.push=a.bind(null,c.push.bind(c))})()})(); \ No newline at end of file diff --git a/assets/js/runtime~main.91c8768b.js b/assets/js/runtime~main.91c8768b.js new file mode 100644 index 000000000..7c03541f9 --- /dev/null +++ b/assets/js/runtime~main.91c8768b.js @@ -0,0 +1 @@ +(()=>{"use strict";var e,a,c,f,t,r={},d={};function b(e){var a=d[e];if(void 0!==a)return a.exports;var c=d[e]={exports:{}};return r[e].call(c.exports,c,c.exports,b),c.exports}b.m=r,e=[],b.O=(a,c,f,t)=>{if(!c){var r=1/0;for(i=0;i<e.length;i++){c=e[i][0],f=e[i][1],t=e[i][2];for(var d=!0,o=0;o<c.length;o++)(!1&t||r>=t)&&Object.keys(b.O).every((e=>b.O[e](c[o])))?c.splice(o--,1):(d=!1,t<r&&(r=t));if(d){e.splice(i--,1);var n=f();void 0!==n&&(a=n)}}return a}t=t||0;for(var i=e.length;i>0&&e[i-1][2]>t;i--)e[i]=e[i-1];e[i]=[c,f,t]},b.n=e=>{var a=e&&e.__esModule?()=>e.default:()=>e;return b.d(a,{a:a}),a},c=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,b.t=function(e,f){if(1&f&&(e=this(e)),8&f)return e;if("object"==typeof e&&e){if(4&f&&e.__esModule)return e;if(16&f&&"function"==typeof e.then)return e}var t=Object.create(null);b.r(t);var r={};a=a||[null,c({}),c([]),c(c)];for(var d=2&f&&e;"object"==typeof d&&!~a.indexOf(d);d=c(d))Object.getOwnPropertyNames(d).forEach((a=>r[a]=()=>e[a]));return r.default=()=>e,b.d(t,r),t},b.d=(e,a)=>{for(var c in a)b.o(a,c)&&!b.o(e,c)&&Object.defineProperty(e,c,{enumerable:!0,get:a[c]})},b.f={},b.e=e=>Promise.all(Object.keys(b.f).reduce(((a,c)=>(b.f[c](e,a),a)),[])),b.u=e=>"assets/js/"+({31:"98ecfc99",320:"da157423",429:"a50a7707",576:"a3e47e5c",757:"20a6a7d9",1031:"85de58a0",1590:"3ec01bef",1885:"bdfaba9c",2016:"46d80676",2634:"c4f5d8e4",2711:"9e4087bc",2729:"e0bf5ccd",2990:"53c981a7",3062:"ee4141e0",3108:"2e5dd55e",3129:"ec8cb05d",3249:"ccc49370",3292:"27ea52af",3304:"ce7e6f90",3433:"25e7257c",3599:"59395140",3836:"bf5dfefe",3872:"8379e623",3885:"ac36c4b6",3919:"239a9e81",3966:"36367655",4085:"a92192c3",4568:"13886346",4625:"9f52c9db",5058:"5c41994f",5117:"e67be6b3",5120:"3d094f56",5302:"2ec21c4a",5674:"ba46e1b8",5730:"071be86b",5826:"ec2d6a08",5863:"61becdbc",5902:"56182e71",5914:"935bcf2a",5937:"591644de",6062:"b379f194",6325:"8b2840ea",6405:"3d5da5a5",6559:"f5ed51a1",7088:"15db90ce",7472:"814f3328",7477:"ee88fe61",7489:"7291aaef",7643:"a6aa9e1f",7695:"b0f8195e",7910:"c9723ef0",7957:"eeaeeec1",8003:"99b332c9",8110:"64b157a3",8136:"f1311735",8159:"2b962623",8317:"8758c959",8401:"17896441",8454:"f0c74005",8567:"378badfe",8581:"935f2afb",8714:"1be78505",9102:"6835b8cd",9727:"b545330d"}[e]||e)+"."+{31:"de12cc9c",320:"6e722b62",429:"1c991886",576:"db70941b",757:"6326b398",1031:"f37dd4f9",1590:"bb2aa489",1774:"7d4a2879",1885:"b44eba83",2016:"746e3828",2435:"fd066790",2565:"60f9ac1e",2634:"4bc13247",2711:"ec92cfc4",2729:"6a6cefd8",2990:"6e360d3a",3062:"06a2c3bd",3108:"0edaba25",3129:"c43d8a02",3249:"b810f065",3292:"f35ea651",3304:"248e2db7",3433:"5dcf7b40",3599:"916d47ec",3836:"d4550e12",3872:"a4328738",3885:"9319c158",3919:"675cb60f",3966:"51cefe07",4085:"31d579b2",4568:"66fd0c0d",4625:"ff69c241",5058:"0803097a",5117:"d1eae093",5120:"3cdd6474",5302:"12b71632",5674:"161a0983",5730:"0b670ef9",5826:"a3f9a2ee",5863:"31328576",5902:"d6b1cfbf",5914:"6f888297",5937:"1998781c",6062:"d678cc4c",6325:"ce0dc2e8",6405:"fc2e20e6",6559:"78c8cfe5",7088:"85b54811",7472:"f9bdbea6",7477:"bee863c7",7489:"9864c556",7643:"f65ef972",7695:"8a884969",7910:"f1ed0317",7957:"396e8a1a",8003:"88c79114",8110:"8598d1d7",8136:"70c3c239",8159:"b8b3bd6c",8317:"748c2c34",8401:"790eadcd",8454:"4262dd1c",8567:"d591ecc6",8581:"637f96e7",8714:"eb7aad6b",9102:"84a5f344",9727:"c1b451f5"}[e]+".js",b.miniCssF=e=>{},b.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),b.o=(e,a)=>Object.prototype.hasOwnProperty.call(e,a),f={},t="weaver-dlt-interoperability:",b.l=(e,a,c,r)=>{if(f[e])f[e].push(a);else{var d,o;if(void 0!==c)for(var n=document.getElementsByTagName("script"),i=0;i<n.length;i++){var l=n[i];if(l.getAttribute("src")==e||l.getAttribute("data-webpack")==t+c){d=l;break}}d||(o=!0,(d=document.createElement("script")).charset="utf-8",d.timeout=120,b.nc&&d.setAttribute("nonce",b.nc),d.setAttribute("data-webpack",t+c),d.src=e),f[e]=[a];var u=(a,c)=>{d.onerror=d.onload=null,clearTimeout(s);var t=f[e];if(delete f[e],d.parentNode&&d.parentNode.removeChild(d),t&&t.forEach((e=>e(c))),a)return a(c)},s=setTimeout(u.bind(null,void 0,{type:"timeout",target:d}),12e4);d.onerror=u.bind(null,d.onerror),d.onload=u.bind(null,d.onload),o&&document.head.appendChild(d)}},b.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},b.p="/weaver-dlt-interoperability/",b.gca=function(e){return e={13886346:"4568",17896441:"8401",36367655:"3966",59395140:"3599","98ecfc99":"31",da157423:"320",a50a7707:"429",a3e47e5c:"576","20a6a7d9":"757","85de58a0":"1031","3ec01bef":"1590",bdfaba9c:"1885","46d80676":"2016",c4f5d8e4:"2634","9e4087bc":"2711",e0bf5ccd:"2729","53c981a7":"2990",ee4141e0:"3062","2e5dd55e":"3108",ec8cb05d:"3129",ccc49370:"3249","27ea52af":"3292",ce7e6f90:"3304","25e7257c":"3433",bf5dfefe:"3836","8379e623":"3872",ac36c4b6:"3885","239a9e81":"3919",a92192c3:"4085","9f52c9db":"4625","5c41994f":"5058",e67be6b3:"5117","3d094f56":"5120","2ec21c4a":"5302",ba46e1b8:"5674","071be86b":"5730",ec2d6a08:"5826","61becdbc":"5863","56182e71":"5902","935bcf2a":"5914","591644de":"5937",b379f194:"6062","8b2840ea":"6325","3d5da5a5":"6405",f5ed51a1:"6559","15db90ce":"7088","814f3328":"7472",ee88fe61:"7477","7291aaef":"7489",a6aa9e1f:"7643",b0f8195e:"7695",c9723ef0:"7910",eeaeeec1:"7957","99b332c9":"8003","64b157a3":"8110",f1311735:"8136","2b962623":"8159","8758c959":"8317",f0c74005:"8454","378badfe":"8567","935f2afb":"8581","1be78505":"8714","6835b8cd":"9102",b545330d:"9727"}[e]||e,b.p+b.u(e)},(()=>{var e={5354:0,1869:0};b.f.j=(a,c)=>{var f=b.o(e,a)?e[a]:void 0;if(0!==f)if(f)c.push(f[2]);else if(/^(1869|5354)$/.test(a))e[a]=0;else{var t=new Promise(((c,t)=>f=e[a]=[c,t]));c.push(f[2]=t);var r=b.p+b.u(a),d=new Error;b.l(r,(c=>{if(b.o(e,a)&&(0!==(f=e[a])&&(e[a]=void 0),f)){var t=c&&("load"===c.type?"missing":c.type),r=c&&c.target&&c.target.src;d.message="Loading chunk "+a+" failed.\n("+t+": "+r+")",d.name="ChunkLoadError",d.type=t,d.request=r,f[1](d)}}),"chunk-"+a,a)}},b.O.j=a=>0===e[a];var a=(a,c)=>{var f,t,r=c[0],d=c[1],o=c[2],n=0;if(r.some((a=>0!==e[a]))){for(f in d)b.o(d,f)&&(b.m[f]=d[f]);if(o)var i=o(b)}for(a&&a(c);n<r.length;n++)t=r[n],b.o(e,t)&&e[t]&&e[t][0](),e[t]=0;return b.O(i)},c=self.webpackChunkweaver_dlt_interoperability=self.webpackChunkweaver_dlt_interoperability||[];c.forEach(a.bind(null,0)),c.push=a.bind(null,c.push.bind(c))})()})(); \ No newline at end of file diff --git a/blog/2021/01/21/cross-chain-asset/index.html b/blog/2021/01/21/cross-chain-asset/index.html index f0d7b0f6e..fdae1ca33 100644 --- a/blog/2021/01/21/cross-chain-asset/index.html +++ b/blog/2021/01/21/cross-chain-asset/index.html @@ -4,9 +4,9 @@ <meta charset="UTF-8"> <meta name="generator" content="Docusaurus v2.2.0"> <title data-rh="true">cross-chain-asset | Weaver: DLT Interoperability Framework - - - + + +
@@ -15,8 +15,8 @@ author: Yining Hu, Ermyas Abebe, Dileban Karunamoorthy, Venkatraman Ramakrishna author_title: Contributors author_url: https://hyperledger-labs.github.io/weaver-dlt-interoperability/

tags: [enterprise, interoperability, asset-exchange]

Introduction

Recent years have witnessed a growing demand for enabling interoperability across independent blockchains. Cross-chain asset exchange is a significant step towards blockchain interoperability. For public blockchains, the most popular application for asset exchange is cryptocurrency exchange. For permissioned blockchains, cross-chain asset exchange can be useful in Delivery Versus Payment (DvP) and cross-border payment scenarios. There exist various protocols designed for asset exchange on public blockchains. However, a widely adopted standard for designing such protocols for permissioned blockchains still does not exist. Moreover, most existing protocols are designed for public blockchains and their suitability to be applied to permissioned blockchains is unclear.

In this article, we aim to lay out a set of requirements for designing cross-chain asset exchange protocols between permissioned blockchains. First we present a canonical motivating use case and then list the various patterns that such cases will follow in real-life scenarios. We then present a short survey of existing cross-chain exchange protocols for public blockchains, following which we summarise the building blocks, core mechanisms and security properties commonly involved in the protocol designs. We then analyse the requirements imposed by permissioned blockchains in comparison to public blockchains, and discuss the additional properties with respect to these restrictions.

Motivation and Use-case

In traditional financial markets parties trade assets such as securities and derivatives for cash or other assets. To reduce risk, various clearing and settlement processes and intermediaries are often involved. One form of settlement is a DvP where the transfer of securities is performed only in the event of a corresponding payment. This arrangement reduces principal risk by ensuring that both parties receive their end of the exchange. However, settlement in financial markets are slow and time consuming. It also involves counterparty risks and requires intermediaries.

Over the past few years, we have been seeing significant efforts in digitising and tokenising both currencies and securities on Distributed Ledger Technology (DLT) infrastructures. On the one hand we have seen concerted efforts around Central Bank Digital Currencies (CBDC) being added to the landscape of other blockchain based payment networks. On the other hand, we have also seen efforts such as that from the Australian Stock Exchange (ASX) to replace its current settlement system--Clearing House Electronic Subregister System (CHESS) with a DLT based platform by 2021.

Against this backdrop, a number of central banks have been exploring the potential of performing DvP settlement across a currency ledger and a securities ledger. In this article, we use this as a motivating use-case for our discussions. The scenario involves two decentralised ledgers, namely, a currency ledger and a securities ledger, based on different DLT protocols performing a coordinated transfer of assets in their respective ledgers. Figure 1 depicts this scenario in the context of two organisations--Bank A and Bank B--in which Bank B wants to purchase some securities owned by Bank A and both organisations have accounts on both ledgers. To effect this exchange the following two transactions will have to happen atomically across both networks: i) transfer of payment from Bank B's currency account to Bank A while at the same time ii) the entitlements of the designated securities is transferred from Bank A to Bank B. The scenario would need to guarantee that after the transaction execution, either both parties have their end of the exchange or neither does and that this exchange is performed in a timely manner.

alt text

Figure 1. A typical DvP use-case.

Cross-chain transactions involving the movement of assets can generally take the form of either an asset exchange between parties or of value transfer from one network to another. The latter involves a scenario in which an asset in one network is locked or burned and a corresponding asset of similar value is issued in a corresponding network. This process generally involves validators or asset issuers in either or both ends of the network. While there are numerous use cases for this model in permissionless context, in this post we primarily focus on asset exchange scenarios, which are more broadly applicable in enterprise use-cases. Asset exchange scenarios generally involve two users swapping corresponding assets managed by the different networks, as in the example illustrated earlier. In asset exchange scenarios involving only two parties, both parties have accounts on both networks, although this might not be the case for exchanges involving more than two parties or networks.

Cross-Chain Asset Exchange on Public Blockchains

Similar scenarios that involve a pair of transactions being coordinated across distinct blockchains have been studied for public blockchains. One main application area is to enable decentralised exchange across crypto-currency networks. To achieve this, a number of cross-chain asset exchange protocols have been proposed. The original atomic swap protocol was proposed by TierNolan in the Bitcoin Forum. The protocol leverages trusted escrow services on both blockchains and relies on the asset owners for execution. Prestwich later improved the protocol by removing the trusted escrow services and using a smart contract to automatically execute the swap. Both protocols, however, are asymmetric and hence enforce a particular sequence of events. More recently, a group of researchers developed Arwen, which guarantees the symmetricality of the protocol and further eases the asset owners' responsibilities in the protocol execution.

We below first discuss the common patterns involved in the protocol design. More specifically, we present the main building blocks, core mechanisms, and security properties achieved by these protocols.

Building blocks

The design of a cross-chain asset exchange protocol in general contain the following building blocks: 1) the infrastructure for cross-chain state verification, and 2) the asset exchange protocol that specifies parties and sequences involved in the protocol execution. Cross-chain state verification can be performed by the exchanging parties themselves or by an external party.

Core Mechanisms

  • Fund locking: To initialise an asset exchange, it is common for one or both parties to first lock up funds with a fund-withholding party on his or her own blockchain. Temporary fund locking ensures the locked fund cannot be used for other purposes while the exchange is being executed. This scheme is often used with a specified timeout to provide flexibility for reclaiming locked funds if the exchange does not take place.

  • Fund redeeming: In general, the execution requires a pair of transactions to occur on both blockchains, e.g., from User A to User B on Chain A and from User B to User A on Chain B. When certain conditions are met, the locked funds can be redeemed by, or paid to the respective users. The execution of the exchange can be carried out by users themselves, or through other trusted third parties. These trusted third parties can be stand-alone parties that are not otherwise involved in both blockchains, or part of either blockchain.

  • Refund: For protocols that are initialised with a temporary fund-locking, the locked funds can usually be reclaimed by the initial owner after a specified timeout.

Security Properties

  • Atomicity: Atomicity is also sometimes referred to as safety. In general, atomicity implies indivisibility and irreducibility, namely, an atomic operation must be performed entirely or not performed at all. In the case of cross-chain asset exchange, when User A sends a payment to User B on Chain A, User B should also send corresponding delivery to User A on Chain B.

  • Liveness: Specifies the design of an asset exchange protocol should ensure no party can be tricked into locking up funds forever or for a very long time.

Extending Protocol Design To Permissioned Blockchains

Requirements of Permissioned Blockchains -As public blockchains offer decentralisation and transparency, existing cross-chain asset exchange protocols on public blockchains are often designed for users to voluntarily participant and execute. To ensure secure execution of these protocols, their designs usually incorporate economic incentives, together with on-chain punishment schemes. To ensure liveness, these protocols usually leverage group consensus and fault-tolerance.

Permissioned blockchains on the other hand require privacy. Additional economic incentives and punishments are often not required besides the existing business relationships and established legal jurisdictions. Therefore, compared to public blockchains, the design of cross-chain asset exchange protocols on permissioned blockchains allows a higher level of centralisation and requires auditability and individual or group accountability for off-chain dispute resolution rather than economic incentives and on-chain punishments. Moreover, as permissioned blockchains themselves offer a higher throughput and faster transaction processing than public blockchains, the asset exchange protocol ideally should not introduce significant processing overheads that limit the transaction processing capability.

Therefore, the challenges in designing cross-chain asset exchange protocols for permissioned networks can be summarised as follow:

  • Permissioned networks are usually confidential by design, thus restricting access for its internal members and external clients. State verification is hard to achieve across distinct permissioned blockchains. Cross-chain asset exchange protocols must therefore incorporate additional mechanisms to overcome these challenges.
  • Unlike public blockchains, permissioned blockchains derive their security from and the ability to hold parties accountable for their actions. Any party acting maliciously should be identified and penalized during an off-chain dispute resolution process. Thus we can relax some of the constraints of the exchange protocol. For example, we can leverage trusted third-parties instead of having to financially incentivise regular users to participate in running the protocol.

Additional Properties

In addition to following the same set of building blocks, core mechanisms and security properties as public protocols, we also identify an additional set of desired properties for permissioned blockchains.

  • Scalability: Scalability is often restricted by two factors. Firstly, the transaction processing capability of the underlying infrastructures. When a protocol relies on public blockchains, the throughput is consequently limited by the transaction processing of the blockchains themselves. In contrast, some protocols are off-chain, which usually allow faster transaction processing. Secondly, for protocols that involve third parties for fund-locking, such as Xclaim and Dogethereum, the amount of money owned by these third parties limits the number of transaction requests they can process. As permissioned blockchains in general have a higher throughput compared to public blockchains, the protocol design should not trade off scalability.

  • Auditability: Auditability for public blockchains specifies that any party with read right should be able to detect protocol failure. On permissioned blockchains, however, as parties have limited visibility over the ledger state, who can detect protocol failure will most-likely depend on the use-case. In addition, financial regulatory requirements such as AML and CTF might require cross-chain traceability and auditability of exchange transactions (i.e. it should be easy to trace why Alice just transferred Bob $1M on a CBDC network).

  • Accountability: Accountability says faulty parties should be held accountable. This can refer to individual accountability or group accountability. As it is hard to enforce on-chain punishments on permissioned blockchains, the protocol design should at least allow adversaries to be held accountable.

  • Compatibility: Compatibility specifies how easy it is to implement the protocol on other blockchain platforms. The protocol design should be generic and not to be limited to particular blockchain platforms.

  • Extensibility: Extensibility specifies how easy it is to extend the protocol to other use cases, for instance, from two parties to multiple parties, or from one particular transaction pattern to other transaction patterns.

  • Privacy: Privacy is usually not automatically guaranteed by public blockchains. For sensitive use-cases, extra mechanisms such as a trusted execution environment (TEE) can be used. Privacy is also of vital importance when it comes to permissioned blockchains. Most existing cross-chain protocols are designed for public blockchains. As the execution of these protocols may require asset owners or third-parties to access states on either blockchain ledger, executing a cross-chain asset exchange can put user privacy at risk.

  • Low Cost: As many of the cross-chain exchange protocols involve sending on-chain transactions, the concern over number of transactions and transaction fees arises when the protocol design involves a public blockchain.

Conclusion

To summarise, in this article we tackle the problem of enabling cross-chain asset exchange on permissioned blockchains and evaluate the different requirements imposed by public blockchains and permissioned blockchains. We also articulate a set of desired properties to guide the design of cross-chain asset exchange protocols.

For general-purpose interoperability of enterprise blockchains, we have developed the Weaver tool that incorporates a cross-chain state verification engine to enable cross-chain state sharing and verification. Please check out our documentation for implementation details and example applications.

- - +As public blockchains offer decentralisation and transparency, existing cross-chain asset exchange protocols on public blockchains are often designed for users to voluntarily participant and execute. To ensure secure execution of these protocols, their designs usually incorporate economic incentives, together with on-chain punishment schemes. To ensure liveness, these protocols usually leverage group consensus and fault-tolerance.

Permissioned blockchains on the other hand require privacy. Additional economic incentives and punishments are often not required besides the existing business relationships and established legal jurisdictions. Therefore, compared to public blockchains, the design of cross-chain asset exchange protocols on permissioned blockchains allows a higher level of centralisation and requires auditability and individual or group accountability for off-chain dispute resolution rather than economic incentives and on-chain punishments. Moreover, as permissioned blockchains themselves offer a higher throughput and faster transaction processing than public blockchains, the asset exchange protocol ideally should not introduce significant processing overheads that limit the transaction processing capability.

Therefore, the challenges in designing cross-chain asset exchange protocols for permissioned networks can be summarised as follow:

  • Permissioned networks are usually confidential by design, thus restricting access for its internal members and external clients. State verification is hard to achieve across distinct permissioned blockchains. Cross-chain asset exchange protocols must therefore incorporate additional mechanisms to overcome these challenges.
  • Unlike public blockchains, permissioned blockchains derive their security from and the ability to hold parties accountable for their actions. Any party acting maliciously should be identified and penalized during an off-chain dispute resolution process. Thus we can relax some of the constraints of the exchange protocol. For example, we can leverage trusted third-parties instead of having to financially incentivise regular users to participate in running the protocol.

Additional Properties

In addition to following the same set of building blocks, core mechanisms and security properties as public protocols, we also identify an additional set of desired properties for permissioned blockchains.

  • Scalability: Scalability is often restricted by two factors. Firstly, the transaction processing capability of the underlying infrastructures. When a protocol relies on public blockchains, the throughput is consequently limited by the transaction processing of the blockchains themselves. In contrast, some protocols are off-chain, which usually allow faster transaction processing. Secondly, for protocols that involve third parties for fund-locking, such as Xclaim and Dogethereum, the amount of money owned by these third parties limits the number of transaction requests they can process. As permissioned blockchains in general have a higher throughput compared to public blockchains, the protocol design should not trade off scalability.

  • Auditability: Auditability for public blockchains specifies that any party with read right should be able to detect protocol failure. On permissioned blockchains, however, as parties have limited visibility over the ledger state, who can detect protocol failure will most-likely depend on the use-case. In addition, financial regulatory requirements such as AML and CTF might require cross-chain traceability and auditability of exchange transactions (i.e. it should be easy to trace why Alice just transferred Bob $1M on a CBDC network).

  • Accountability: Accountability says faulty parties should be held accountable. This can refer to individual accountability or group accountability. As it is hard to enforce on-chain punishments on permissioned blockchains, the protocol design should at least allow adversaries to be held accountable.

  • Compatibility: Compatibility specifies how easy it is to implement the protocol on other blockchain platforms. The protocol design should be generic and not to be limited to particular blockchain platforms.

  • Extensibility: Extensibility specifies how easy it is to extend the protocol to other use cases, for instance, from two parties to multiple parties, or from one particular transaction pattern to other transaction patterns.

  • Privacy: Privacy is usually not automatically guaranteed by public blockchains. For sensitive use-cases, extra mechanisms such as a trusted execution environment (TEE) can be used. Privacy is also of vital importance when it comes to permissioned blockchains. Most existing cross-chain protocols are designed for public blockchains. As the execution of these protocols may require asset owners or third-parties to access states on either blockchain ledger, executing a cross-chain asset exchange can put user privacy at risk.

  • Low Cost: As many of the cross-chain exchange protocols involve sending on-chain transactions, the concern over number of transactions and transaction fees arises when the protocol design involves a public blockchain.

Conclusion

To summarise, in this article we tackle the problem of enabling cross-chain asset exchange on permissioned blockchains and evaluate the different requirements imposed by public blockchains and permissioned blockchains. We also articulate a set of desired properties to guide the design of cross-chain asset exchange protocols.

For general-purpose interoperability of enterprise blockchains, we have developed the Weaver tool that incorporates a cross-chain state verification engine to enable cross-chain state sharing and verification. Please check out our documentation for implementation details and example applications.

+ + \ No newline at end of file diff --git a/blog/2021/01/21/emergence-enterprise-interoperability/index.html b/blog/2021/01/21/emergence-enterprise-interoperability/index.html index ba9ae2af8..7c92ff357 100644 --- a/blog/2021/01/21/emergence-enterprise-interoperability/index.html +++ b/blog/2021/01/21/emergence-enterprise-interoperability/index.html @@ -4,9 +4,9 @@ emergence-enterprise-interoperability | Weaver: DLT Interoperability Framework - - - + + +
@@ -15,8 +15,8 @@ author: Venkatraman Ramakrishna author_title: Maintainer of Weaver author_url: https://github.com/VRamakrishna -author_image_url: https://avatars2.githubusercontent.com/u/14888211?s=400&v=4

tags: [enterprise, interoperability]

It is instructive to know the course taken by blockchain technology and its applications over the past few years, as this will allow us to understand where we are, where are headed, and thereby motivate the necessity of interoperability.

The Grand Vision

The original vision of blockchain technology called for a global decentralized network of peers and clients that could conduct transactions at scale without requiring intermediation by trusted third parties. The Bitcoin network was the first example of this, and it was purposely left open for anyone to join precisely because its initiators hoped for a single global network somewhat akin to the internet.

But the limitations of Bitcoin as a transaction processing system soon became apparent, and the Ethereum network emerged to fill this gap, retaining the openness and scalability of Bitcoin while supporting arbitrary smart contracts over a shared ledger. But Ethereum too was not destined to be the single canonical global blockchain network that everyone would use.

Sub-groups within the Bitcoin and Ethereum communities dissented from the rest, thereby creating forks, or separate networks with separate chains of blocks. Others found limitations in the usability of the existing networks or their consensus mechanisms (Proof of Work) and decided to build their own networks to which like-minded people could subscribe and in which they could conduct their transactions.

Therefore, the original Bitcoin (or even Ethereum) vision of a single global network was not to be, and networks with different clientele and different consensus protocols proliferated.

And then came private (or permissioned) networks......

Evolution of Private Networks

Sometime in the first half of the previous decade, it was recognized that networks like Bitcoin and Ethereum were not suitable for much of the business that involves private enterprises, governmental institutions, and ordinary clients. Private networks then emerged as a means to retain the trustworthiness and consensus-based decision-making properties of blockchains (and distributed ledgers in general) while ensuring that:

  • Transactions and ledger state are privy only to a selected set of entities,
  • Transactions can be audited by trusted authorities when required for dispute resolutions, and
  • Higher performance and assurance can be gained using consensus protocols other than proof-of-work.

Since companies and consortia were wary of this new and unproven technology, the trend in industry these past few years has been to build minimum viable ecosystems, i.e., networks of limited operational scope and participation. The goal being to evaluate the potential of blockchain, these networks were created to manage selected few assets and records. Needless to say, interoperation with other networks was not high on the priority list when such networks were designed and launched.

Many of these networks have been successfully validated and put into production. But a consequence of the decision to build limited-scope networks is that the processes they run (through smart contracts) and the assets and records they maintain on their ledgers are stuck in siloes, inaccessible to external entitites and networks. Yet, as we are discovering, processes and assets in such networks are inextricably linked in the real enterprise world. With all of the investment (in time and money) made in existing networks, reeingeneering or merging them will generally be hardsells. Also, some networks may wish to restrict operational control and ledger visibility to its current set of administrators and clientele. The only viable solution is to allow networks to interoperate, thereby breaking up the siloes, while retaining operational control.

Diverse Platforms

Our present blockchain landscape (or ecosystem) is characterized not just by a plethora of networks, a mix of open and private, but also by the existence of several distinct blockchain technologies, each with a different storage technology, a different model for contracts and client applications, a different consensus protocol, and a different way of managing identity. Examples include Fabric, Iroha, Sawtooth, and Besu, all in the Hyperledger family, and Ethereum, Multichain, Cardano, and Komodo, outside it. There are also smart contract distributed ledger platforms that serve a similar set of business applications that are not blockchains at all, like R3's Corda.

Since there is no single blockchain, or distributed ledger, technology, the world agrees on, and because each offers a different set of advantages and disadvantages, the networks that exist today are built on a diverse set of such platforms.

Blockchain Landscape

Our present is, and our near future will be, characterized by the existence of independent networks, some of which offer open membership whereas others are restricted, built on diverse platforms that are mutually incompatible. Asking everyone to converge to a single global network running on a single canonical platform is almost impossible. So unless we wish entities and assets to remain trapped within siloes, it should be evident that interoperability amoong different networks and platforms is crucial to the success of blockchain.

Challenges

Interlinking processes distributed across different networks or transferring or sharing assets and data may sound like a straightforward task, but the traditional method of service and API integration will not work in scenarios that involve permissioned networks.

This is because, as you will see in the user stories, entities that are interested in the asset or data record being shared may not be members of both networks. And even if a particular entity happens to be a member of both networks, it may be in its interest to present a false view of one network's ledger state to another.

Therefore, interoperation cannot be allowed to hinge on the trustworthiness of a particular network member, or by extension, a third party. In the stories we will encounter, it will be apparent how such situations may occur. This will make the unreliability of API integration across private networks clear and also motivate the need for consensus-based interoperation protocols.

- - +author_image_url: https://avatars2.githubusercontent.com/u/14888211?s=400&v=4

tags: [enterprise, interoperability]

It is instructive to know the course taken by blockchain technology and its applications over the past few years, as this will allow us to understand where we are, where are headed, and thereby motivate the necessity of interoperability.

The Grand Vision

The original vision of blockchain technology called for a global decentralized network of peers and clients that could conduct transactions at scale without requiring intermediation by trusted third parties. The Bitcoin network was the first example of this, and it was purposely left open for anyone to join precisely because its initiators hoped for a single global network somewhat akin to the internet.

But the limitations of Bitcoin as a transaction processing system soon became apparent, and the Ethereum network emerged to fill this gap, retaining the openness and scalability of Bitcoin while supporting arbitrary smart contracts over a shared ledger. But Ethereum too was not destined to be the single canonical global blockchain network that everyone would use.

Sub-groups within the Bitcoin and Ethereum communities dissented from the rest, thereby creating forks, or separate networks with separate chains of blocks. Others found limitations in the usability of the existing networks or their consensus mechanisms (Proof of Work) and decided to build their own networks to which like-minded people could subscribe and in which they could conduct their transactions.

Therefore, the original Bitcoin (or even Ethereum) vision of a single global network was not to be, and networks with different clientele and different consensus protocols proliferated.

And then came private (or permissioned) networks......

Evolution of Private Networks

Sometime in the first half of the previous decade, it was recognized that networks like Bitcoin and Ethereum were not suitable for much of the business that involves private enterprises, governmental institutions, and ordinary clients. Private networks then emerged as a means to retain the trustworthiness and consensus-based decision-making properties of blockchains (and distributed ledgers in general) while ensuring that:

  • Transactions and ledger state are privy only to a selected set of entities,
  • Transactions can be audited by trusted authorities when required for dispute resolutions, and
  • Higher performance and assurance can be gained using consensus protocols other than proof-of-work.

Since companies and consortia were wary of this new and unproven technology, the trend in industry these past few years has been to build minimum viable ecosystems, i.e., networks of limited operational scope and participation. The goal being to evaluate the potential of blockchain, these networks were created to manage selected few assets and records. Needless to say, interoperation with other networks was not high on the priority list when such networks were designed and launched.

Many of these networks have been successfully validated and put into production. But a consequence of the decision to build limited-scope networks is that the processes they run (through smart contracts) and the assets and records they maintain on their ledgers are stuck in siloes, inaccessible to external entitites and networks. Yet, as we are discovering, processes and assets in such networks are inextricably linked in the real enterprise world. With all of the investment (in time and money) made in existing networks, reeingeneering or merging them will generally be hardsells. Also, some networks may wish to restrict operational control and ledger visibility to its current set of administrators and clientele. The only viable solution is to allow networks to interoperate, thereby breaking up the siloes, while retaining operational control.

Diverse Platforms

Our present blockchain landscape (or ecosystem) is characterized not just by a plethora of networks, a mix of open and private, but also by the existence of several distinct blockchain technologies, each with a different storage technology, a different model for contracts and client applications, a different consensus protocol, and a different way of managing identity. Examples include Fabric, Iroha, Sawtooth, and Besu, all in the Hyperledger family, and Ethereum, Multichain, Cardano, and Komodo, outside it. There are also smart contract distributed ledger platforms that serve a similar set of business applications that are not blockchains at all, like R3's Corda.

Since there is no single blockchain, or distributed ledger, technology, the world agrees on, and because each offers a different set of advantages and disadvantages, the networks that exist today are built on a diverse set of such platforms.

Blockchain Landscape

Our present is, and our near future will be, characterized by the existence of independent networks, some of which offer open membership whereas others are restricted, built on diverse platforms that are mutually incompatible. Asking everyone to converge to a single global network running on a single canonical platform is almost impossible. So unless we wish entities and assets to remain trapped within siloes, it should be evident that interoperability amoong different networks and platforms is crucial to the success of blockchain.

Challenges

Interlinking processes distributed across different networks or transferring or sharing assets and data may sound like a straightforward task, but the traditional method of service and API integration will not work in scenarios that involve permissioned networks.

This is because, as you will see in the user stories, entities that are interested in the asset or data record being shared may not be members of both networks. And even if a particular entity happens to be a member of both networks, it may be in its interest to present a false view of one network's ledger state to another.

Therefore, interoperation cannot be allowed to hinge on the trustworthiness of a particular network member, or by extension, a third party. In the stories we will encounter, it will be apparent how such situations may occur. This will make the unreliability of API integration across private networks clear and also motivate the need for consensus-based interoperation protocols.

+ + \ No newline at end of file diff --git a/blog/archive/index.html b/blog/archive/index.html index 0f39550c7..e03c4770f 100644 --- a/blog/archive/index.html +++ b/blog/archive/index.html @@ -4,14 +4,14 @@ Archive | Weaver: DLT Interoperability Framework - - - + + + - - +
+ + \ No newline at end of file diff --git a/blog/index.html b/blog/index.html index f82b9335d..73160708e 100644 --- a/blog/index.html +++ b/blog/index.html @@ -4,9 +4,9 @@ Blog | Weaver: DLT Interoperability Framework - - - + + +
@@ -20,8 +20,8 @@ author: Venkatraman Ramakrishna author_title: Maintainer of Weaver author_url: https://github.com/VRamakrishna -author_image_url: https://avatars2.githubusercontent.com/u/14888211?s=400&v=4

tags: [enterprise, interoperability]

It is instructive to know the course taken by blockchain technology and its applications over the past few years, as this will allow us to understand where we are, where are headed, and thereby motivate the necessity of interoperability.

The Grand Vision

The original vision of blockchain technology called for a global decentralized network of peers and clients that could conduct transactions at scale without requiring intermediation by trusted third parties. The Bitcoin network was the first example of this, and it was purposely left open for anyone to join precisely because its initiators hoped for a single global network somewhat akin to the internet.

But the limitations of Bitcoin as a transaction processing system soon became apparent, and the Ethereum network emerged to fill this gap, retaining the openness and scalability of Bitcoin while supporting arbitrary smart contracts over a shared ledger. But Ethereum too was not destined to be the single canonical global blockchain network that everyone would use.

Sub-groups within the Bitcoin and Ethereum communities dissented from the rest, thereby creating forks, or separate networks with separate chains of blocks. Others found limitations in the usability of the existing networks or their consensus mechanisms (Proof of Work) and decided to build their own networks to which like-minded people could subscribe and in which they could conduct their transactions.

Therefore, the original Bitcoin (or even Ethereum) vision of a single global network was not to be, and networks with different clientele and different consensus protocols proliferated.

And then came private (or permissioned) networks......

Evolution of Private Networks

Sometime in the first half of the previous decade, it was recognized that networks like Bitcoin and Ethereum were not suitable for much of the business that involves private enterprises, governmental institutions, and ordinary clients. Private networks then emerged as a means to retain the trustworthiness and consensus-based decision-making properties of blockchains (and distributed ledgers in general) while ensuring that:

  • Transactions and ledger state are privy only to a selected set of entities,
  • Transactions can be audited by trusted authorities when required for dispute resolutions, and
  • Higher performance and assurance can be gained using consensus protocols other than proof-of-work.

Since companies and consortia were wary of this new and unproven technology, the trend in industry these past few years has been to build minimum viable ecosystems, i.e., networks of limited operational scope and participation. The goal being to evaluate the potential of blockchain, these networks were created to manage selected few assets and records. Needless to say, interoperation with other networks was not high on the priority list when such networks were designed and launched.

Many of these networks have been successfully validated and put into production. But a consequence of the decision to build limited-scope networks is that the processes they run (through smart contracts) and the assets and records they maintain on their ledgers are stuck in siloes, inaccessible to external entitites and networks. Yet, as we are discovering, processes and assets in such networks are inextricably linked in the real enterprise world. With all of the investment (in time and money) made in existing networks, reeingeneering or merging them will generally be hardsells. Also, some networks may wish to restrict operational control and ledger visibility to its current set of administrators and clientele. The only viable solution is to allow networks to interoperate, thereby breaking up the siloes, while retaining operational control.

Diverse Platforms

Our present blockchain landscape (or ecosystem) is characterized not just by a plethora of networks, a mix of open and private, but also by the existence of several distinct blockchain technologies, each with a different storage technology, a different model for contracts and client applications, a different consensus protocol, and a different way of managing identity. Examples include Fabric, Iroha, Sawtooth, and Besu, all in the Hyperledger family, and Ethereum, Multichain, Cardano, and Komodo, outside it. There are also smart contract distributed ledger platforms that serve a similar set of business applications that are not blockchains at all, like R3's Corda.

Since there is no single blockchain, or distributed ledger, technology, the world agrees on, and because each offers a different set of advantages and disadvantages, the networks that exist today are built on a diverse set of such platforms.

Blockchain Landscape

Our present is, and our near future will be, characterized by the existence of independent networks, some of which offer open membership whereas others are restricted, built on diverse platforms that are mutually incompatible. Asking everyone to converge to a single global network running on a single canonical platform is almost impossible. So unless we wish entities and assets to remain trapped within siloes, it should be evident that interoperability amoong different networks and platforms is crucial to the success of blockchain.

Challenges

Interlinking processes distributed across different networks or transferring or sharing assets and data may sound like a straightforward task, but the traditional method of service and API integration will not work in scenarios that involve permissioned networks.

This is because, as you will see in the user stories, entities that are interested in the asset or data record being shared may not be members of both networks. And even if a particular entity happens to be a member of both networks, it may be in its interest to present a false view of one network's ledger state to another.

Therefore, interoperation cannot be allowed to hinge on the trustworthiness of a particular network member, or by extension, a third party. In the stories we will encounter, it will be apparent how such situations may occur. This will make the unreliability of API integration across private networks clear and also motivate the need for consensus-based interoperation protocols.

- - +author_image_url: https://avatars2.githubusercontent.com/u/14888211?s=400&v=4

tags: [enterprise, interoperability]

It is instructive to know the course taken by blockchain technology and its applications over the past few years, as this will allow us to understand where we are, where are headed, and thereby motivate the necessity of interoperability.

The Grand Vision

The original vision of blockchain technology called for a global decentralized network of peers and clients that could conduct transactions at scale without requiring intermediation by trusted third parties. The Bitcoin network was the first example of this, and it was purposely left open for anyone to join precisely because its initiators hoped for a single global network somewhat akin to the internet.

But the limitations of Bitcoin as a transaction processing system soon became apparent, and the Ethereum network emerged to fill this gap, retaining the openness and scalability of Bitcoin while supporting arbitrary smart contracts over a shared ledger. But Ethereum too was not destined to be the single canonical global blockchain network that everyone would use.

Sub-groups within the Bitcoin and Ethereum communities dissented from the rest, thereby creating forks, or separate networks with separate chains of blocks. Others found limitations in the usability of the existing networks or their consensus mechanisms (Proof of Work) and decided to build their own networks to which like-minded people could subscribe and in which they could conduct their transactions.

Therefore, the original Bitcoin (or even Ethereum) vision of a single global network was not to be, and networks with different clientele and different consensus protocols proliferated.

And then came private (or permissioned) networks......

Evolution of Private Networks

Sometime in the first half of the previous decade, it was recognized that networks like Bitcoin and Ethereum were not suitable for much of the business that involves private enterprises, governmental institutions, and ordinary clients. Private networks then emerged as a means to retain the trustworthiness and consensus-based decision-making properties of blockchains (and distributed ledgers in general) while ensuring that:

  • Transactions and ledger state are privy only to a selected set of entities,
  • Transactions can be audited by trusted authorities when required for dispute resolutions, and
  • Higher performance and assurance can be gained using consensus protocols other than proof-of-work.

Since companies and consortia were wary of this new and unproven technology, the trend in industry these past few years has been to build minimum viable ecosystems, i.e., networks of limited operational scope and participation. The goal being to evaluate the potential of blockchain, these networks were created to manage selected few assets and records. Needless to say, interoperation with other networks was not high on the priority list when such networks were designed and launched.

Many of these networks have been successfully validated and put into production. But a consequence of the decision to build limited-scope networks is that the processes they run (through smart contracts) and the assets and records they maintain on their ledgers are stuck in siloes, inaccessible to external entitites and networks. Yet, as we are discovering, processes and assets in such networks are inextricably linked in the real enterprise world. With all of the investment (in time and money) made in existing networks, reeingeneering or merging them will generally be hardsells. Also, some networks may wish to restrict operational control and ledger visibility to its current set of administrators and clientele. The only viable solution is to allow networks to interoperate, thereby breaking up the siloes, while retaining operational control.

Diverse Platforms

Our present blockchain landscape (or ecosystem) is characterized not just by a plethora of networks, a mix of open and private, but also by the existence of several distinct blockchain technologies, each with a different storage technology, a different model for contracts and client applications, a different consensus protocol, and a different way of managing identity. Examples include Fabric, Iroha, Sawtooth, and Besu, all in the Hyperledger family, and Ethereum, Multichain, Cardano, and Komodo, outside it. There are also smart contract distributed ledger platforms that serve a similar set of business applications that are not blockchains at all, like R3's Corda.

Since there is no single blockchain, or distributed ledger, technology, the world agrees on, and because each offers a different set of advantages and disadvantages, the networks that exist today are built on a diverse set of such platforms.

Blockchain Landscape

Our present is, and our near future will be, characterized by the existence of independent networks, some of which offer open membership whereas others are restricted, built on diverse platforms that are mutually incompatible. Asking everyone to converge to a single global network running on a single canonical platform is almost impossible. So unless we wish entities and assets to remain trapped within siloes, it should be evident that interoperability amoong different networks and platforms is crucial to the success of blockchain.

Challenges

Interlinking processes distributed across different networks or transferring or sharing assets and data may sound like a straightforward task, but the traditional method of service and API integration will not work in scenarios that involve permissioned networks.

This is because, as you will see in the user stories, entities that are interested in the asset or data record being shared may not be members of both networks. And even if a particular entity happens to be a member of both networks, it may be in its interest to present a false view of one network's ledger state to another.

Therefore, interoperation cannot be allowed to hinge on the trustworthiness of a particular network member, or by extension, a third party. In the stories we will encounter, it will be apparent how such situations may occur. This will make the unreliability of API integration across private networks clear and also motivate the need for consensus-based interoperation protocols.

+ + \ No newline at end of file diff --git a/docs/external/architecture-and-design/decentralized-identity/index.html b/docs/external/architecture-and-design/decentralized-identity/index.html index 4bfb606c5..0c6de69f0 100644 --- a/docs/external/architecture-and-design/decentralized-identity/index.html +++ b/docs/external/architecture-and-design/decentralized-identity/index.html @@ -4,14 +4,14 @@ Decentralized Identity | Weaver: DLT Interoperability Framework - - - + + +
-

Decentralized Identity

Interoperation for asset or data transfers/exchanges relies on a message-passing infratructure and pan-network data processing modules, as we have seen in earlier pages. But there is yet another crucial basis these data processing modules need to satisfy our design principles of network independence and avoidance of trust parties. This is the ability of a network as a whole and of its individual members to accurately identify and authenticate another network's members.

Further, for the networks to remain independent and interact ad hoc with each other, we cannot impose a central authority that unifies their private identity management systems. So the identity basis of interoperation must be decentralized, leading inevitably to the requirement of exchanging identity information across networks as a pre-requisite for asset and data transfers/exchanges. This is illustrated in the figure below where interoperation protocols are classified in two planes (or tiers), data and identity, with the former depending on the latter.

alt text

  • In the data plane lies the protocols that effect the actual exchanges of data and assets. The figure above illustrates a typical data-sharing instance, where the network at the left requests a data record from the right. The latter receives the request via the two relays (not explicitly marked in this diagram) and runs an access control check through consensus in its interop module before responding with the data record and supporting proof. The network at the left receives the data and proof, again via the two relays, and verifies the data using the supplied proof. Note: since a core part of both request and proof are digital signatures of network members, the ability to identify and authenticate network members is necessary to perform these endpoint functions.
  • Here is where the identity plane enters the picture, as a trust anchor for the data plane. The most general function of this plane is illustrated in the figure, where the networks get each others' identity and configuration (i.e., membership structure and network topology) information. This exchange has as its own trust basis (or dependency) a set of identity providers and verifiers. (Note: these identity providers and verifiers may belong to the two networks or they could be external entities.) The outcome of the exchange is a record of the other network's identity and configuration information on one's ledger, which can then be looked up in a data plane protocol instance.

Identity Plane: Strawman Approach

The simplest identity plane protocol involves a direct exchange of identity information between representatives of the two networks: in other words, an API integration. But this approach suffers from the same drawbacks that API integration in the data plane would. It diminishes a blockchain network to a single trusted spokesperson, exposing that network to risk. Even if such a spokesperson could be designated, appropriately framing access control policies for potentially every other blockchain network in the world would be very challenging. This approach is therefore insecure and not scalable, and therefore ought to be treated purely as a strawman.

Networks as Groups of Self-Sovereign Members

A secure and sustainable identity plane plaform can be built on the basis of self-sovereign identity and decentralized identifiers. We recognize that:

  • Each constituent member of a blockchain network may already possess an identity from a third-party provider
  • Membership within a network can be treated as a property of a sovereign organization rather than subordination to a network's governing authority
  • DIDs allow members to control who they wish to share their identities with and the levels of exposure
  • Network membership lists and individual members' identities can respectively be validated by different providers, thereby maintaining decentralization of infrastructure

Distributed Identity Management Infrastructure

The distributed identity management infrastructure for interoperation is illustrated in the figure below. We assume the existence of one or more Interoperation Identity Networks (IINs) that act as registries and credential validators for the organizations that form the memberships of blockchain networks.

alt text

An IIN can be built from scratch to facilitate blockchain interoperation, but it can also be an augmentation of an existing decentralized identity provider or registry. Its purpose is to maintain identity records and credentials for organizations and validate these to third parties as per the desire of the identity or credential owner. In this model, an IIN can itself be reputed or it can bring together many reputed and trusted identity providers (called stewards) into a shared network. As long as the members of two blockchain networks have shared trust in one or more IINs, an identity plane exchange can be effected, thereby setting the foundation for data and asset transfers.

Interoperation Identity Network

The ideal IIN architecture is illustrated in the figure below, inspired by Hyperleder Indy, whose architecture is used in our canonical (or reference) implementation. Built on a DLT itself, an Indy-based IIN can provide the combination of assurance and decentralization that a centralized registry cannot. Further, such an IIN will support the entire SSI and DID standard, maintaining credential schemas and verification keys, and issuing verifiable credentials that can be used for privacy-preserving authentications.

alt text

An IIN is modeled as a network with a distributed shared ledger, implemented using an Indy Node Pool and running BFT consensus. The ledger is also (ideally) meant to be publicly accessible, though there is nothing preventing our protocols from working with a private IIN.

A canonical IIN maintains the following:

  • DID records corresponding to organizations that are members of one or more blockchain networks, whose salient attributes include:
    • Unique (within an IIN) identifier or verinym for the identity owner
    • Service endpoint for the identity owner
    • Credential schemas
    • Credential definitions (public keys used to authenticate signed credentials)

Every IIN has a set of bootstrapped trust anchors called stewards. A steward can create other trust anchors by issuing them suitable credentials. The trust anchors are the primary identity providers in our distributed identity management architecture. They can be existing reputed authorities or identity providers who are trusted to certify blockchain networks' memberships, or they can be created ad hoc by a consortium representing the members of a blockchain network.

For one blockchain network to discover and validate another in the identity plane, it must trust one or more IINs and trust anchors who can provide that validation. We envision a shared and mutually reinforcing trust among stewards and other anchors within an IIN. An anchor could gain trust by virtue of joining a well-established IIN. Similarly, an IIN bootstrapped with well-known stewards gains trust because of the collective reputations of those stewards.

Examples of entities that can act as stewards or trust anchors within IINs: the Sovrin Foundation (an organization dedicated to enabling open-source digital ID management, and which also maintains Indy), companies like Maersk or Walmart that have founded real-world blockchain networks, companies like IBM or R3 that maintain popular DLT platforms.

IINs don't have to be built on Indy. Alternatives like Sidetree exist, providing similar functionality. There are also various existing DID registries that are already issuing credentials to existing organizations. To the extent possible, we would like to leverage all of this existing infrastructure and not force any network menmber to find yet another identity provider. Therefore, these existing registries or networks can be used as IINs: the only requirement is that they follow the standards for SSI and DIDs and issuing VCs.

Network Membership Credentials

Two kinds of credentials (each with a schema and a definition) are maintained on an IIN ledger:

  1. Member list: This contains a network name or ID and a set of DIDs of that network's members.
  • This is a per-network credential whose schema and verification key must be maintained on an IIN.
  • This is issued by a steward or trust anchor in an IIN and is associated with that steward's or anchor's DID.
  1. Membership: This contains an oranization's attributes, including the set of IDs of networks to which it belongs.
  • This is designed to be an extensible credential, i.e., support more attributes in the future.
  • An existing membership credential (of the VC form) can be used as long as it matches the schema recorded on an IIN.
  • The issuer must be a steward or trust anchor (or equivalent, if it's a non-Indy registry) in an IIN.
  • This is associated with the member's DID.

Identity Info: Units of Exchange

The IIN is used to discover the membership list of a foreign network and establish the authenticity of its members. Memnbership credentials are independent of blockchain networks.

But data plane transfers and exchanges require knowledge of in-network identities and certificates, which are issued by a network's membership manager(s) to peers and clients. These are not shared through IINs for several reasons. First, the volume of this information can be quite high and further it is subject to change based on a network's internal needs. Also, a network or its members may not wish to expose all this information to an IIN, which is designed to be publicly accessible. Therefore, it is infeasible or undesirable to shared network-specific credentials via established IINs. Instead, we will enable the peer-to-peer exchange of such credentials after the membership discovery and validation procedure is complete.

Specifically, the identity information for a network member consists of the set of certificate chains of the membership managers for that particular member (organization). These consist of one or more hierarchies of root and intermediate CA certificates. For example:

  • In Fabric, each organization uses one or more MSPs (membership service providers), each running one or more root and intermediate Fabric-CA servers. Any network peer belonging to an organization is issued a certificate authorized by one of these certificate chains. To authenticate a network peer or client in a data plane protocol, knowledge of these certificate chains is essential.
  • In Corda, the entire network typically consists of a hierarchy of CAs, from a root to multiple doormen, and from each doorman to multiple nodes. Finally, the certificates used to sign transactions are issued by the node CAs. Therefore, knowledge of the root, doormen, and node CA certificates is essential for authenticating signers.

More generally, each unit of exchange corresponding to a network member is a Security Group, so-called because each network member is an independent organization in its own right with a security domain.

IIN Agents as Member Representatives

Every network member needs a proxy (either an abstraction or a separate module) for communication with IINs and with the members of foreign networks in the identity plane. We use the term "IIN Agent" to refer to this proxy, and illustrate its functioning as a module within a Fabric network through the reference diagram below.

alt text

In the reference implementation, IIN Agents are built as Hyperledger Aries nodes and communicate with each other and with IIN stewards and trust anchors using the Aries protocol. (IIN stewards and trust anchors are also built as Aries nodes.)

The list of trusted IINs is recorded on the local network's shared ledger, as illustrated in the figure (and thereby agreed through network consensus). To be able to interoperate with another network, the latter's members must have identity records maintained by sume subset of these trusted IINs and their VCs must be issued by these IINs stewards and trust anchors.

Protocols

Let us consider a scenario where NETWORK 1 and NETWORK 2 wish to interoperate, and their respective member organizations are as follows:

  • NETWORK 1: Org3, Org4, Org5
  • NETWORK 2: Org1, Org2

Each network discovers the other's member list and obtains and records ech member's security group to the local shared ledger. We can enumerate these as follows:

  • NETWORK 1 discovers and registers NETWORK 2:Org1
  • NETWORK 1 discovers and registers NETWORK 2:Org2
  • NETWORK 2 discovers and registers NETWORK 1:Org3
  • NETWORK 2 discovers and registers NETWORK 1:Org4
  • NETWORK 2 discovers and registers NETWORK 1:Org5

Each of these can be done in parallel and each discovery and registration operation is idempotent as long as the security group of a network member does not change.

The high-level workflow for discovery and registration is illustrated below (using NETWORK 2 as the seeker and NETWORK 1 as the provider).

alt text

(Note: "Network unit" is synonymous with "network member")

Prerequisites for this process are:

  • The member list credential of NETWORK 1 is provided by a steward or trust anchor in a particular IIN which is also on the trust list recorded in the ledger of NETWORK 2.
  • The membership credentials for both organizations in NETWORK 1 are supplied by one or more IINs that are on the trust list of NETWORK 2.
  • Each of the 5 organizations (2 in NETWORK 1 and 3 in NETWORK 2) has an IIN Agent running on their behalf.

Let us take the example of NETWORK 2 having already obtained the security group info for Org4 and Org5 in NETWORK 1. It is now discovering and registering NETWORK 1:Org3. We assume that there is a single IIN with a single Steward for validating member list as well as membership credentials for all members of both the networks.

Note: we assume here for simplicity that a steward as a reputed identity provider has a mechanism to validate the bona fides of an orgganization and its membership in a given network. There are other techniques involving group signatures that could be applied to corroborate an organization's claim to network membership rather than requiring a steward to use an out-of-band security mechanism, but that is presently beyond the scope of this design.

The discovery and registration procedure steps are as follows:

  • The IIN Agent for Org3 registers its membership to NETWORK 1 at the Steward in IIN:
    • NETWORK 1:Org3 gets a DID (verinym) issued
    • The Steward updates the member list credential for NETWORK 1 to include Org3
    • Org3 obtains a membership credential from Steward
  • The IIN Agent for Org3 issues itself a self-signed VC containing its security group info
  • The IIN Agent for NETWORK 2:Org2 (only one organization in the network needs to do this) obtains the new member list credential from Steward in IIN and validates it using the IIN ledger records
  • The IIN Agent for NETWORK 2:Org2 discovers that Org3 is a member of NETWORK 1, fetches Org3's membership credential from Org3's IIN Agent, and validates it using the IIN ledger records
  • The IIN agent for NETWORK 2:Org2 fetches the self-signed security group credential from the IIN agent of NETWORK 1:Org3 and validates it
  • The IIN agent for NETWORK 2:Org2 triggers a flow among the IIN Agents of NETWORK 2 to collect signatures endorsing the security group info for NETWORK 1:Org3 fetched above
    • The IIN Agent for NETWORK 2:Org1 gets this endorsement request, and validates both the membership credential and the security group info for NETWORK 1:Org3 by communicating with the Steward, the IIN ledger, and the IIN Agent for NETWORK 1:Org3
    • The IIN Agent for NETWORK 2:Org1 signs the request from Org2 containing the security group info for NETWORK 1:Org3 after the above check succeeds
  • When the IIN agent for NETWORK 2:Org2 gets signatures from the IIN Agents representing each member of NETWORK 2, it submits the security group info for NETWORK 1:Org3 alon with the signatures to the interop module (typically smart contract) for recording on the ledger of NETWORK 2
    • Now the ledger of NETWORK 2 contains the identities and certificates of all three members of NETWORK 1: Org3,Org4,Org5, and data plane interoperation may ensue.

Note: the last step above (recording to the local ledger via the interop module) may be performed by IIN Agents of both Org1 and Org2 as they have no means of synchronizing their actions, but this recording will be idempotent and hence not cause any harm.

The process above is illustrated with a few more details in the sequence of protocol diagrams below.

alt text

alt text

alt text

References

Bishakh Chandra Ghosh, Venkatraman Ramakrishna, Chander Govindarajan, Dushyant Behl, Dileban Karunamoorthy, Ermyas Abebe, Sandip Chakraborty, Decentralized Cross-Network Identity Management for Blockchain Interoperation, ICBC 2021

- - +

Decentralized Identity

Interoperation for asset or data transfers/exchanges relies on a message-passing infratructure and pan-network data processing modules, as we have seen in earlier pages. But there is yet another crucial basis these data processing modules need to satisfy our design principles of network independence and avoidance of trust parties. This is the ability of a network as a whole and of its individual members to accurately identify and authenticate another network's members.

Further, for the networks to remain independent and interact ad hoc with each other, we cannot impose a central authority that unifies their private identity management systems. So the identity basis of interoperation must be decentralized, leading inevitably to the requirement of exchanging identity information across networks as a pre-requisite for asset and data transfers/exchanges. This is illustrated in the figure below where interoperation protocols are classified in two planes (or tiers), data and identity, with the former depending on the latter.

alt text

  • In the data plane lies the protocols that effect the actual exchanges of data and assets. The figure above illustrates a typical data-sharing instance, where the network at the left requests a data record from the right. The latter receives the request via the two relays (not explicitly marked in this diagram) and runs an access control check through consensus in its interop module before responding with the data record and supporting proof. The network at the left receives the data and proof, again via the two relays, and verifies the data using the supplied proof. Note: since a core part of both request and proof are digital signatures of network members, the ability to identify and authenticate network members is necessary to perform these endpoint functions.
  • Here is where the identity plane enters the picture, as a trust anchor for the data plane. The most general function of this plane is illustrated in the figure, where the networks get each others' identity and configuration (i.e., membership structure and network topology) information. This exchange has as its own trust basis (or dependency) a set of identity providers and verifiers. (Note: these identity providers and verifiers may belong to the two networks or they could be external entities.) The outcome of the exchange is a record of the other network's identity and configuration information on one's ledger, which can then be looked up in a data plane protocol instance.

Identity Plane: Strawman Approach

The simplest identity plane protocol involves a direct exchange of identity information between representatives of the two networks: in other words, an API integration. But this approach suffers from the same drawbacks that API integration in the data plane would. It diminishes a blockchain network to a single trusted spokesperson, exposing that network to risk. Even if such a spokesperson could be designated, appropriately framing access control policies for potentially every other blockchain network in the world would be very challenging. This approach is therefore insecure and not scalable, and therefore ought to be treated purely as a strawman.

Networks as Groups of Self-Sovereign Members

A secure and sustainable identity plane plaform can be built on the basis of self-sovereign identity and decentralized identifiers. We recognize that:

  • Each constituent member of a blockchain network may already possess an identity from a third-party provider
  • Membership within a network can be treated as a property of a sovereign organization rather than subordination to a network's governing authority
  • DIDs allow members to control who they wish to share their identities with and the levels of exposure
  • Network membership lists and individual members' identities can respectively be validated by different providers, thereby maintaining decentralization of infrastructure

Distributed Identity Management Infrastructure

The distributed identity management infrastructure for interoperation is illustrated in the figure below. We assume the existence of one or more Interoperation Identity Networks (IINs) that act as registries and credential validators for the organizations that form the memberships of blockchain networks.

alt text

An IIN can be built from scratch to facilitate blockchain interoperation, but it can also be an augmentation of an existing decentralized identity provider or registry. Its purpose is to maintain identity records and credentials for organizations and validate these to third parties as per the desire of the identity or credential owner. In this model, an IIN can itself be reputed or it can bring together many reputed and trusted identity providers (called stewards) into a shared network. As long as the members of two blockchain networks have shared trust in one or more IINs, an identity plane exchange can be effected, thereby setting the foundation for data and asset transfers.

Interoperation Identity Network

The ideal IIN architecture is illustrated in the figure below, inspired by Hyperleder Indy, whose architecture is used in our canonical (or reference) implementation. Built on a DLT itself, an Indy-based IIN can provide the combination of assurance and decentralization that a centralized registry cannot. Further, such an IIN will support the entire SSI and DID standard, maintaining credential schemas and verification keys, and issuing verifiable credentials that can be used for privacy-preserving authentications.

alt text

An IIN is modeled as a network with a distributed shared ledger, implemented using an Indy Node Pool and running BFT consensus. The ledger is also (ideally) meant to be publicly accessible, though there is nothing preventing our protocols from working with a private IIN.

A canonical IIN maintains the following:

  • DID records corresponding to organizations that are members of one or more blockchain networks, whose salient attributes include:
    • Unique (within an IIN) identifier or verinym for the identity owner
    • Service endpoint for the identity owner
    • Credential schemas
    • Credential definitions (public keys used to authenticate signed credentials)

Every IIN has a set of bootstrapped trust anchors called stewards. A steward can create other trust anchors by issuing them suitable credentials. The trust anchors are the primary identity providers in our distributed identity management architecture. They can be existing reputed authorities or identity providers who are trusted to certify blockchain networks' memberships, or they can be created ad hoc by a consortium representing the members of a blockchain network.

For one blockchain network to discover and validate another in the identity plane, it must trust one or more IINs and trust anchors who can provide that validation. We envision a shared and mutually reinforcing trust among stewards and other anchors within an IIN. An anchor could gain trust by virtue of joining a well-established IIN. Similarly, an IIN bootstrapped with well-known stewards gains trust because of the collective reputations of those stewards.

Examples of entities that can act as stewards or trust anchors within IINs: the Sovrin Foundation (an organization dedicated to enabling open-source digital ID management, and which also maintains Indy), companies like Maersk or Walmart that have founded real-world blockchain networks, companies like IBM or R3 that maintain popular DLT platforms.

IINs don't have to be built on Indy. Alternatives like Sidetree exist, providing similar functionality. There are also various existing DID registries that are already issuing credentials to existing organizations. To the extent possible, we would like to leverage all of this existing infrastructure and not force any network menmber to find yet another identity provider. Therefore, these existing registries or networks can be used as IINs: the only requirement is that they follow the standards for SSI and DIDs and issuing VCs.

Network Membership Credentials

Two kinds of credentials (each with a schema and a definition) are maintained on an IIN ledger:

  1. Member list: This contains a network name or ID and a set of DIDs of that network's members.
  • This is a per-network credential whose schema and verification key must be maintained on an IIN.
  • This is issued by a steward or trust anchor in an IIN and is associated with that steward's or anchor's DID.
  1. Membership: This contains an oranization's attributes, including the set of IDs of networks to which it belongs.
  • This is designed to be an extensible credential, i.e., support more attributes in the future.
  • An existing membership credential (of the VC form) can be used as long as it matches the schema recorded on an IIN.
  • The issuer must be a steward or trust anchor (or equivalent, if it's a non-Indy registry) in an IIN.
  • This is associated with the member's DID.

Identity Info: Units of Exchange

The IIN is used to discover the membership list of a foreign network and establish the authenticity of its members. Memnbership credentials are independent of blockchain networks.

But data plane transfers and exchanges require knowledge of in-network identities and certificates, which are issued by a network's membership manager(s) to peers and clients. These are not shared through IINs for several reasons. First, the volume of this information can be quite high and further it is subject to change based on a network's internal needs. Also, a network or its members may not wish to expose all this information to an IIN, which is designed to be publicly accessible. Therefore, it is infeasible or undesirable to shared network-specific credentials via established IINs. Instead, we will enable the peer-to-peer exchange of such credentials after the membership discovery and validation procedure is complete.

Specifically, the identity information for a network member consists of the set of certificate chains of the membership managers for that particular member (organization). These consist of one or more hierarchies of root and intermediate CA certificates. For example:

  • In Fabric, each organization uses one or more MSPs (membership service providers), each running one or more root and intermediate Fabric-CA servers. Any network peer belonging to an organization is issued a certificate authorized by one of these certificate chains. To authenticate a network peer or client in a data plane protocol, knowledge of these certificate chains is essential.
  • In Corda, the entire network typically consists of a hierarchy of CAs, from a root to multiple doormen, and from each doorman to multiple nodes. Finally, the certificates used to sign transactions are issued by the node CAs. Therefore, knowledge of the root, doormen, and node CA certificates is essential for authenticating signers.

More generally, each unit of exchange corresponding to a network member is a Security Group, so-called because each network member is an independent organization in its own right with a security domain.

IIN Agents as Member Representatives

Every network member needs a proxy (either an abstraction or a separate module) for communication with IINs and with the members of foreign networks in the identity plane. We use the term "IIN Agent" to refer to this proxy, and illustrate its functioning as a module within a Fabric network through the reference diagram below.

alt text

In the reference implementation, IIN Agents are built as Hyperledger Aries nodes and communicate with each other and with IIN stewards and trust anchors using the Aries protocol. (IIN stewards and trust anchors are also built as Aries nodes.)

The list of trusted IINs is recorded on the local network's shared ledger, as illustrated in the figure (and thereby agreed through network consensus). To be able to interoperate with another network, the latter's members must have identity records maintained by sume subset of these trusted IINs and their VCs must be issued by these IINs stewards and trust anchors.

Protocols

Let us consider a scenario where NETWORK 1 and NETWORK 2 wish to interoperate, and their respective member organizations are as follows:

  • NETWORK 1: Org3, Org4, Org5
  • NETWORK 2: Org1, Org2

Each network discovers the other's member list and obtains and records ech member's security group to the local shared ledger. We can enumerate these as follows:

  • NETWORK 1 discovers and registers NETWORK 2:Org1
  • NETWORK 1 discovers and registers NETWORK 2:Org2
  • NETWORK 2 discovers and registers NETWORK 1:Org3
  • NETWORK 2 discovers and registers NETWORK 1:Org4
  • NETWORK 2 discovers and registers NETWORK 1:Org5

Each of these can be done in parallel and each discovery and registration operation is idempotent as long as the security group of a network member does not change.

The high-level workflow for discovery and registration is illustrated below (using NETWORK 2 as the seeker and NETWORK 1 as the provider).

alt text

(Note: "Network unit" is synonymous with "network member")

Prerequisites for this process are:

  • The member list credential of NETWORK 1 is provided by a steward or trust anchor in a particular IIN which is also on the trust list recorded in the ledger of NETWORK 2.
  • The membership credentials for both organizations in NETWORK 1 are supplied by one or more IINs that are on the trust list of NETWORK 2.
  • Each of the 5 organizations (2 in NETWORK 1 and 3 in NETWORK 2) has an IIN Agent running on their behalf.

Let us take the example of NETWORK 2 having already obtained the security group info for Org4 and Org5 in NETWORK 1. It is now discovering and registering NETWORK 1:Org3. We assume that there is a single IIN with a single Steward for validating member list as well as membership credentials for all members of both the networks.

Note: we assume here for simplicity that a steward as a reputed identity provider has a mechanism to validate the bona fides of an orgganization and its membership in a given network. There are other techniques involving group signatures that could be applied to corroborate an organization's claim to network membership rather than requiring a steward to use an out-of-band security mechanism, but that is presently beyond the scope of this design.

The discovery and registration procedure steps are as follows:

  • The IIN Agent for Org3 registers its membership to NETWORK 1 at the Steward in IIN:
    • NETWORK 1:Org3 gets a DID (verinym) issued
    • The Steward updates the member list credential for NETWORK 1 to include Org3
    • Org3 obtains a membership credential from Steward
  • The IIN Agent for Org3 issues itself a self-signed VC containing its security group info
  • The IIN Agent for NETWORK 2:Org2 (only one organization in the network needs to do this) obtains the new member list credential from Steward in IIN and validates it using the IIN ledger records
  • The IIN Agent for NETWORK 2:Org2 discovers that Org3 is a member of NETWORK 1, fetches Org3's membership credential from Org3's IIN Agent, and validates it using the IIN ledger records
  • The IIN agent for NETWORK 2:Org2 fetches the self-signed security group credential from the IIN agent of NETWORK 1:Org3 and validates it
  • The IIN agent for NETWORK 2:Org2 triggers a flow among the IIN Agents of NETWORK 2 to collect signatures endorsing the security group info for NETWORK 1:Org3 fetched above
    • The IIN Agent for NETWORK 2:Org1 gets this endorsement request, and validates both the membership credential and the security group info for NETWORK 1:Org3 by communicating with the Steward, the IIN ledger, and the IIN Agent for NETWORK 1:Org3
    • The IIN Agent for NETWORK 2:Org1 signs the request from Org2 containing the security group info for NETWORK 1:Org3 after the above check succeeds
  • When the IIN agent for NETWORK 2:Org2 gets signatures from the IIN Agents representing each member of NETWORK 2, it submits the security group info for NETWORK 1:Org3 alon with the signatures to the interop module (typically smart contract) for recording on the ledger of NETWORK 2
    • Now the ledger of NETWORK 2 contains the identities and certificates of all three members of NETWORK 1: Org3,Org4,Org5, and data plane interoperation may ensue.

Note: the last step above (recording to the local ledger via the interop module) may be performed by IIN Agents of both Org1 and Org2 as they have no means of synchronizing their actions, but this recording will be idempotent and hence not cause any harm.

The process above is illustrated with a few more details in the sequence of protocol diagrams below.

alt text

alt text

alt text

References

Bishakh Chandra Ghosh, Venkatraman Ramakrishna, Chander Govindarajan, Dushyant Behl, Dileban Karunamoorthy, Ermyas Abebe, Sandip Chakraborty, Decentralized Cross-Network Identity Management for Blockchain Interoperation, ICBC 2021

+ + \ No newline at end of file diff --git a/docs/external/architecture-and-design/drivers/index.html b/docs/external/architecture-and-design/drivers/index.html index 8fc87d3c9..8b4223ddf 100644 --- a/docs/external/architecture-and-design/drivers/index.html +++ b/docs/external/architecture-and-design/drivers/index.html @@ -4,14 +4,14 @@ Drivers | Weaver: DLT Interoperability Framework - - - + + +
-

Drivers

The driver is responsible for all communication between the relay and its network. In the previous sections we have thought about the driver as a component of the relay. We have done this because conceptually it makes sense to think about it like that. However, in our reference implementation we have made it a seperate process which communicates with the relay via gRPC, as shown below. There are two main reasons for this:

  1. There must exist a different driver for each network type (e.g. Fabric, Corda etc.) and therefore having the driver as a seperate process makes it easy to "plug" different drivers into the relay.
  2. A possible use case of the relay is that a single relay instance may have multiple drivers (e.g. if multiple entities in the network want to run their own driver). In this case, this plugin style approach of drivers makes it possible to do without having to modify code for each configuration.

- - +

Drivers

The driver is responsible for all communication between the relay and its network. In the previous sections we have thought about the driver as a component of the relay. We have done this because conceptually it makes sense to think about it like that. However, in our reference implementation we have made it a separate process which communicates with the relay via gRPC, as shown below. There are two main reasons for this:

  1. There must exist a different driver for each network type (e.g. Fabric, Corda etc.) and therefore having the driver as a separate process makes it easy to "plug" different drivers into the relay.
  2. A possible use case of the relay is that a single relay instance may have multiple drivers (e.g. if multiple entities in the network want to run their own driver). In this case, this plugin style approach of drivers makes it possible to do without having to modify code for each configuration.

+ + \ No newline at end of file diff --git a/docs/external/architecture-and-design/overview/index.html b/docs/external/architecture-and-design/overview/index.html index b4f366ce7..41f5f4817 100644 --- a/docs/external/architecture-and-design/overview/index.html +++ b/docs/external/architecture-and-design/overview/index.html @@ -4,14 +4,14 @@ Overview | Weaver: DLT Interoperability Framework - - - + + +
-

Overview

The below diagram shows a high level architecture diagram of the Weaver framework.

Network

The networks in the system can be made up of various heterogenious technologies, including Hyperledger Fabric and Corda. Each network in the system needs to contain an interoperability (IOP) module that enables them to communicate with the relays.

Relay

The relays act as a conduit to facilitate communication of protocols between networks (e.g. data transfer, asset exchange etc). The roles of the relays are described in more detail in relay.

Design Decisions

The high level design decisions that were made for the system are outlined here.

Synchronous vs Asynchronous message communication

We decided to go with an asynchronous message architecture. The primary reason for this is because requests can take an arbitary amount of time to respond, it is not practical for a synchronous message to wait that long for a reply. For example, obtaining a 12 block confirmation on the Bitcoin network can take about 2 hours.

Message vs connection oriented communication

We decided to go with a message oriented architecture. The primary reason for this is because it makes the system more fault tolerant. With a message oriented architecture the requester and responder don't need to be alive at the same time. For example, if the requestor crashes while the responder is processing the request, the communication is not interrupted since the responder will just send a message when it has finished processing the request. The design choice also enables the systen to be made more fault tolerant in the future by implementing message queues between components in the system.

- - +

Overview

The below diagram shows a high level architecture diagram of the Weaver framework.

Network

The networks in the system can be made up of various heterogenious technologies, including Hyperledger Fabric and Corda. Each network in the system needs to contain an interoperability (IOP) module that enables them to communicate with the relays.

Relay

The relays act as a conduit to facilitate communication of protocols between networks (e.g. data transfer, asset exchange etc). The roles of the relays are described in more detail in relay.

Design Decisions

The high level design decisions that were made for the system are outlined here.

Synchronous vs Asynchronous message communication

We decided to go with an asynchronous message architecture. The primary reason for this is because requests can take an arbitary amount of time to respond, it is not practical for a synchronous message to wait that long for a reply. For example, obtaining a 12 block confirmation on the Bitcoin network can take about 2 hours.

Message vs connection oriented communication

We decided to go with a message oriented architecture. The primary reason for this is because it makes the system more fault tolerant. With a message oriented architecture the requester and responder don't need to be alive at the same time. For example, if the requestor crashes while the responder is processing the request, the communication is not interrupted since the responder will just send a message when it has finished processing the request. The design choice also enables the systen to be made more fault tolerant in the future by implementing message queues between components in the system.

+ + \ No newline at end of file diff --git a/docs/external/architecture-and-design/relay/index.html b/docs/external/architecture-and-design/relay/index.html index 676556824..d9071cf3a 100644 --- a/docs/external/architecture-and-design/relay/index.html +++ b/docs/external/architecture-and-design/relay/index.html @@ -4,14 +4,14 @@ Relay | Weaver: DLT Interoperability Framework - - - + + +
-

Relay

As mentioned in the overview, relays facilitate communication of protocols between networks. To do this, they are composed of three main pieces:

  • Relay service - A gRPC server that listens for and handles incoming requests from other relays. For example, a remote network requesting state.
  • App service - A gRPC server that listens for and handles requests from applications that are requesting an asset from a remote network.
  • Driver - The driver is responsible for all communication between the relay and its network. The driver is described in more detail in drivers.

The diagram below shows an example communication between two networks, A and B, where network A is requesting state from network B.

  1. An application sends a request to their networks relay over gRPC
  2. The local relay inspects the query within the request and uses the relevant information to forward the request to the correct remote relay
  3. The remote relay's driver interprets the query and invokes the smart contract for the query
  4. Once network B has returned a response to its relay, the relay forwards the response back to relay A
  5. The application gets the response from the relay, this can either be via a push or pull mechanism
  6. The application invokes a domain specific smart contract to process the response from network B
- - +

Relay

As mentioned in the overview, relays facilitate communication of protocols between networks. To do this, they are composed of three main pieces:

  • Relay service - A gRPC server that listens for and handles incoming requests from other relays. For example, a remote network requesting state.
  • App service - A gRPC server that listens for and handles requests from applications that are requesting an asset from a remote network.
  • Driver - The driver is responsible for all communication between the relay and its network. The driver is described in more detail in drivers.

The diagram below shows an example communication between two networks, A and B, where network A is requesting state from network B.

  1. An application sends a request to their networks relay over gRPC
  2. The local relay inspects the query within the request and uses the relevant information to forward the request to the correct remote relay
  3. The remote relay's driver interprets the query and invokes the smart contract for the query
  4. Once network B has returned a response to its relay, the relay forwards the response back to relay A
  5. The application gets the response from the relay, this can either be via a push or pull mechanism
  6. The application invokes a domain specific smart contract to process the response from network B
+ + \ No newline at end of file diff --git a/docs/external/architecture-and-design/weaver-dapps/index.html b/docs/external/architecture-and-design/weaver-dapps/index.html index 02326ff68..a074dc0e2 100644 --- a/docs/external/architecture-and-design/weaver-dapps/index.html +++ b/docs/external/architecture-and-design/weaver-dapps/index.html @@ -4,14 +4,14 @@ Weaver Dapps | Weaver: DLT Interoperability Framework - - - + + +
-

Weaver Dapps

As mentioned in the overview, DLTs that integrate with Weaver must contain an interop (IOP) module to facilitate interoperation between ledgers. The interop module contains all the logic responsible for membership, verification policies and access control policies (refer to the RFCs for more information on these). Below shows the architecture of how these interop modules work with the two currently supported DLTs, Fabric and Corda.

Fabric

When Fabric is the requesting network, the IOP module is used to verify the proof and then forward the state onto the application chaincode.

When Fabric is the responding network, the IOP module is in charge of verifying the identity of the requester, making sure the requester has access to the state they are requesting, and then finally retrieving the state from the application chaincode to send back to the requesting network.

Verification Policy, Access Control and Membership are modular components within the interop chaincode for seperation of concerns of the code.

Corda

As can be seen from the diagrams below, the architecture for Corda is very similar to that of Fabric. The main difference is that the interop module and the application specific flows are in seperate CorDapps, instead of seperate chaincodes like in Fabric.

- - +

Weaver Dapps

As mentioned in the overview, DLTs that integrate with Weaver must contain an interop (IOP) module to facilitate interoperation between ledgers. The interop module contains all the logic responsible for membership, verification policies and access control policies (refer to the RFCs for more information on these). Below shows the architecture of how these interop modules work with the two currently supported DLTs, Fabric and Corda.

Fabric

When Fabric is the requesting network, the IOP module is used to verify the proof and then forward the state onto the application chaincode.

When Fabric is the responding network, the IOP module is in charge of verifying the identity of the requester, making sure the requester has access to the state they are requesting, and then finally retrieving the state from the application chaincode to send back to the requesting network.

Verification Policy, Access Control and Membership are modular components within the interop chaincode for separation of concerns of the code.

Corda

As can be seen from the diagrams below, the architecture for Corda is very similar to that of Fabric. The main difference is that the interop module and the application specific flows are in separate CorDapps, instead of separate chaincodes like in Fabric.

+ + \ No newline at end of file diff --git a/docs/external/deployment-considerations/deployment-patterns/index.html b/docs/external/deployment-considerations/deployment-patterns/index.html index 7a56770b7..c3ced2317 100644 --- a/docs/external/deployment-considerations/deployment-patterns/index.html +++ b/docs/external/deployment-considerations/deployment-patterns/index.html @@ -4,14 +4,14 @@ Deployment Patterns | Weaver: DLT Interoperability Framework - - - + + + - - +
+ + \ No newline at end of file diff --git a/docs/external/deployment-considerations/governance-and-policies/index.html b/docs/external/deployment-considerations/governance-and-policies/index.html index a277be409..dc33da10e 100644 --- a/docs/external/deployment-considerations/governance-and-policies/index.html +++ b/docs/external/deployment-considerations/governance-and-policies/index.html @@ -4,14 +4,14 @@ Governance and Policies | Weaver: DLT Interoperability Framework - - - + + + - - +
+ + \ No newline at end of file diff --git a/docs/external/deployment-considerations/legal-and-regulation/index.html b/docs/external/deployment-considerations/legal-and-regulation/index.html index 685dd81ff..36723b254 100644 --- a/docs/external/deployment-considerations/legal-and-regulation/index.html +++ b/docs/external/deployment-considerations/legal-and-regulation/index.html @@ -4,14 +4,14 @@ Legal and Regulation | Weaver: DLT Interoperability Framework - - - + + + - - +
+ + \ No newline at end of file diff --git a/docs/external/design-principles/index.html b/docs/external/design-principles/index.html index 6a6cb89ae..fcef1c16c 100644 --- a/docs/external/design-principles/index.html +++ b/docs/external/design-principles/index.html @@ -4,14 +4,14 @@ Design Principles | Weaver: DLT Interoperability Framework - - - + + +
-

Design Principles

We list principles and considerations that guide the design of a framework for interoperability between decentralized networks, along with associated reasoning. Our present solution, though a work-in-progress, attempts to adhere to these principles.

How to determine need for interoperation, and its mode and mechanics?

  • Assess dependence decision (i,e., between networks) to determine goals and required assurances:
    • The decision to depend on a network is a complex one, as a network is itself an affiliation of independent parties.
    • There are different approaches with varying levels of complexity and assurance.
    • Examine structural assurances provided by networks and their participants, and do a cost-benefit analysis to determine a suitable approach.
  • The mechanics of interoperation can be derived from assumptions made in the above assessment.
  • Our assumptions and aproach:
    • Individual network participants are untrustworthy.
    • The network is trustworthy in the collective.
    • The internal consensus mechanism of a network protects it from Byzantine failures.
    • Interoperability needs will not force structural changes or forks in a network nor constrain that network's internal evolution.

Principles and Ideals for Interoperability Solution Design

Here are our guiding principles that accord with our assumptions and approach, in no particular order.

Favor Technical Assurances over Social Assurances

  • Technical assurances are provided by protocols and security mechanisms, including distributed consensus.
  • Social assurances include governance (collectively, through a consortium, or via a hierarchy), legal rules and regulations, reputations and history of past behavior.
  • The reason to favor the former is that it can provide provable guarantees that are independent of the trustworthiness of individual participants, whereas the latter can be brittle and rely on participants' compliance.

Be Inclusive and Accommodate Heterogeneity

  • Avoid approaches for protocol design that are specific to a particular DLT implementation or network structure.
  • Specify the communication protocol in a network-neutral language.
  • Design protocol units that can abstract out common features for information and assurances from diverse DLTs.

Allow Networks to Retain Independence and Collective Sovereignty

  • A network is treated as an independent self-governing system with the freedom of choice to interoperate with another on a need basis.
  • Network members retain collective sovereignty over their internal processes as well as access control rules governing remote interoperation.
  • Networks have full and collective control, via their native consensus and smart contract mechanisms, over exposure of data, assets, and transactions to other networks.
    • A network acts as a unit for framing and enforcing rules controlling access to information held on its ledger(s) by a remote network.
  • Similarly, networks have full and collective control, via their native consensus and smart contract mechanisms, over acceptance of data or assets and verifications of transactions occurring in, other networks.

Minimize Network Coupling

  • Networks/consortia must retain independence for governance and configuration
    • Therefore, interoperation must require loose coupling rather than a merging or overlapping of two networks
  • Loose coupling between dependent networks allows changes to counterparty networks' implementations with minimal or no impact to cross-network dependencies.
  • Domain decoupling:
    • Define standards for contract interfaces
    • Define standards for representing data types and assets types (e.g. https://www.gs1.org/traceability)
    • Define standards for identity portability
  • Communication decoupling:
    • Define standards for network interface/API
    • Define standards for protocol behavior
    • Define standards for messaging formats

Do not Compromise on Privacy and Confidentiality

  • By design, a permissioned network should retain its privacy, and interoperation mechanisms should not leak information outside the bounds of what access control rules allow.
  • Cross-network communications should be kept private and confidential and revealed only to interested parties, applying the principle of least privilege.

Minimize Trust Footprint and Avoid Centralization

  • Design for decentralization across networks as within networks:
    • Avoid introducing centralized services that are easy to compromise
    • Assume that failure scenarios that apply to networks also hold for any service coordinating interoperability.
  • Reduce trust to only what is essential (i.e. identity providers in the network).
  • No trusted third-party intermediary or infrastructure (e.g., Polka Dot, Cosmos) should be relied upon for the purpose of cross network data verification or settlement.
  • Reduce trust and centralization to only essential functions that cannot be completely decentralized:
    • Communicate messages across networks using some networking infrastructure:
      • This communication infrastructure is not trusted to maintain confidentiality or integrity of messages, and it may mount denial of service attacks.
    • Identity provision and verification:
      • This is necessary for permissioned networks that have private memberships governed by a committee that may be centralized or distributed.

Favor dependence on proofs over trust

  • This is also implied by the "No Trusted Intermediaries" principle.
  • Information transferred across networks must carry verifiable proofs.
  • The receiving network must be able to specify a verification policy for proofs that it can independently and collectively (i.e., through consensus) verify.

Minimize Impact and Adaptation

  • Enabling interoperation must not require changes to existing network protocols.
  • Enabling interoperation must not impact existing network operation in any way nor require any blockchain forks.
  • Adaptation in existing smart contracts and applications must be avoided unless absolutely necessary, and follow modular principles.

Maximize Operational Efficiency

  • Minimize payloads in cross-network protocol units.
  • Strive for event-driven asynchronous messaging architectures (this is also implied by the "Minimal Coupling" principle).

Design Guidelines for Network Architects and Developers

  • Architects and application developers (both in the smart contract and services layers) must design with interoperability in mind:
    • This has the advantage of minimizing or eliminating any code adaptations required for interoperability during a network's life cycle.
  • Apply standards when defining assets, data and logic within network apps to maximize external consumption:
    • Networks with well-defined standards-based interfaces simplifies interoperability:
      • Interfaces include: contracts, data/assets, identity, APIs, protocol, messaging.
  • Enables network implementation to evolve while eliminating or minimising external impact:
    • Implement in a modular way: many patterns and principles exist in the field of web services.
    • Decouple interoperability-related application modules as much as possible (this guideline applies to blockchain-related modules within enterprise apps too).
      • This will make maintenance easier and also allow administrators to minimize the amount of code that needs to be deployed in higher-security enterprise zones.
- - +

Design Principles

We list principles and considerations that guide the design of a framework for interoperability between decentralized networks, along with associated reasoning. Our present solution, though a work-in-progress, attempts to adhere to these principles.

How to determine need for interoperation, and its mode and mechanics?

  • Assess dependence decision (i,e., between networks) to determine goals and required assurances:
    • The decision to depend on a network is a complex one, as a network is itself an affiliation of independent parties.
    • There are different approaches with varying levels of complexity and assurance.
    • Examine structural assurances provided by networks and their participants, and do a cost-benefit analysis to determine a suitable approach.
  • The mechanics of interoperation can be derived from assumptions made in the above assessment.
  • Our assumptions and aproach:
    • Individual network participants are untrustworthy.
    • The network is trustworthy in the collective.
    • The internal consensus mechanism of a network protects it from Byzantine failures.
    • Interoperability needs will not force structural changes or forks in a network nor constrain that network's internal evolution.

Principles and Ideals for Interoperability Solution Design

Here are our guiding principles that accord with our assumptions and approach, in no particular order.

Favor Technical Assurances over Social Assurances

  • Technical assurances are provided by protocols and security mechanisms, including distributed consensus.
  • Social assurances include governance (collectively, through a consortium, or via a hierarchy), legal rules and regulations, reputations and history of past behavior.
  • The reason to favor the former is that it can provide provable guarantees that are independent of the trustworthiness of individual participants, whereas the latter can be brittle and rely on participants' compliance.

Be Inclusive and Accommodate Heterogeneity

  • Avoid approaches for protocol design that are specific to a particular DLT implementation or network structure.
  • Specify the communication protocol in a network-neutral language.
  • Design protocol units that can abstract out common features for information and assurances from diverse DLTs.

Allow Networks to Retain Independence and Collective Sovereignty

  • A network is treated as an independent self-governing system with the freedom of choice to interoperate with another on a need basis.
  • Network members retain collective sovereignty over their internal processes as well as access control rules governing remote interoperation.
  • Networks have full and collective control, via their native consensus and smart contract mechanisms, over exposure of data, assets, and transactions to other networks.
    • A network acts as a unit for framing and enforcing rules controlling access to information held on its ledger(s) by a remote network.
  • Similarly, networks have full and collective control, via their native consensus and smart contract mechanisms, over acceptance of data or assets and verifications of transactions occurring in, other networks.

Minimize Network Coupling

  • Networks/consortia must retain independence for governance and configuration
    • Therefore, interoperation must require loose coupling rather than a merging or overlapping of two networks
  • Loose coupling between dependent networks allows changes to counterparty networks' implementations with minimal or no impact to cross-network dependencies.
  • Domain decoupling:
    • Define standards for contract interfaces
    • Define standards for representing data types and assets types (e.g. https://www.gs1.org/traceability)
    • Define standards for identity portability
  • Communication decoupling:
    • Define standards for network interface/API
    • Define standards for protocol behavior
    • Define standards for messaging formats

Do not Compromise on Privacy and Confidentiality

  • By design, a permissioned network should retain its privacy, and interoperation mechanisms should not leak information outside the bounds of what access control rules allow.
  • Cross-network communications should be kept private and confidential and revealed only to interested parties, applying the principle of least privilege.

Minimize Trust Footprint and Avoid Centralization

  • Design for decentralization across networks as within networks:
    • Avoid introducing centralized services that are easy to compromise
    • Assume that failure scenarios that apply to networks also hold for any service coordinating interoperability.
  • Reduce trust to only what is essential (i.e. identity providers in the network).
  • No trusted third-party intermediary or infrastructure (e.g., Polka Dot, Cosmos) should be relied upon for the purpose of cross network data verification or settlement.
  • Reduce trust and centralization to only essential functions that cannot be completely decentralized:
    • Communicate messages across networks using some networking infrastructure:
      • This communication infrastructure is not trusted to maintain confidentiality or integrity of messages, and it may mount denial of service attacks.
    • Identity provision and verification:
      • This is necessary for permissioned networks that have private memberships governed by a committee that may be centralized or distributed.

Favor dependence on proofs over trust

  • This is also implied by the "No Trusted Intermediaries" principle.
  • Information transferred across networks must carry verifiable proofs.
  • The receiving network must be able to specify a verification policy for proofs that it can independently and collectively (i.e., through consensus) verify.

Minimize Impact and Adaptation

  • Enabling interoperation must not require changes to existing network protocols.
  • Enabling interoperation must not impact existing network operation in any way nor require any blockchain forks.
  • Adaptation in existing smart contracts and applications must be avoided unless absolutely necessary, and follow modular principles.

Maximize Operational Efficiency

  • Minimize payloads in cross-network protocol units.
  • Strive for event-driven asynchronous messaging architectures (this is also implied by the "Minimal Coupling" principle).

Design Guidelines for Network Architects and Developers

  • Architects and application developers (both in the smart contract and services layers) must design with interoperability in mind:
    • This has the advantage of minimizing or eliminating any code adaptations required for interoperability during a network's life cycle.
  • Apply standards when defining assets, data and logic within network apps to maximize external consumption:
    • Networks with well-defined standards-based interfaces simplifies interoperability:
      • Interfaces include: contracts, data/assets, identity, APIs, protocol, messaging.
  • Enables network implementation to evolve while eliminating or minimising external impact:
    • Implement in a modular way: many patterns and principles exist in the field of web services.
    • Decouple interoperability-related application modules as much as possible (this guideline applies to blockchain-related modules within enterprise apps too).
      • This will make maintenance easier and also allow administrators to minimize the amount of code that needs to be deployed in higher-security enterprise zones.
+ + \ No newline at end of file diff --git a/docs/external/getting-started/enabling-weaver-network/besu/index.html b/docs/external/getting-started/enabling-weaver-network/besu/index.html index b2147aea2..16d520eb5 100644 --- a/docs/external/getting-started/enabling-weaver-network/besu/index.html +++ b/docs/external/getting-started/enabling-weaver-network/besu/index.html @@ -4,14 +4,14 @@ Hyperledger Besu | Weaver: DLT Interoperability Framework - - - + + + - - +
+ + \ No newline at end of file diff --git a/docs/external/getting-started/enabling-weaver-network/corda/index.html b/docs/external/getting-started/enabling-weaver-network/corda/index.html index 475a49ce2..86758ac24 100644 --- a/docs/external/getting-started/enabling-weaver-network/corda/index.html +++ b/docs/external/getting-started/enabling-weaver-network/corda/index.html @@ -4,23 +4,23 @@ Corda | Weaver: DLT Interoperability Framework - - - + + +
-

Corda

After testing the Weaver interoperation mechanisms on basic sample networks, you may be interested in finding out how you can equip an existing real network, whether in development or in production, to exercise these mechanisms. In this document, we will demonstrate how to equip a Corda network and application with Weaver components and capabilities.

Model

The figure below illustrates a typical Corda network. The infrastructure consists of a set of nodes (each maintaining its share of the global state in a local vault), notaries, and CAs. On the nodes are installed one or more CorDapps, representing shared business logic across subsets of those nodes. The core of a CorDapp consists of a collection of workflows (or flows) and contracts acting on states; we layer the flows above the contracts in thebelow image just to illustrate that flows represent transaction (state update) triggers, and contract validations occur during the executions of flows. Further up in the stack lie client applications associated with CorDapps that can are used to trigger flows (and by implication, contracts).

alt text

Such a network equipped with Weaver components and capabilities will look like the figure below. Legacy components are marked in grey and Weaver and bridging components in green.

alt text

The relay and driver are the only additional infrastructure that need to be installed. One or more relays can be installed, as can one or more drivers. The drivers are illustrated in the client layer rather than in the bottom layer because, though they are coupled with relays, they trigger flows just like any client application does.

Existing CorDapp flows and contracts deployed on the network's nodes remain undisturbed. All that is required is the deployment of an Interoperation CorDapp (flows and contracts) on every node that needs to offer or consume state from foreign networks.

Client applications will need some additional code and configuration because the decisions to exercise interoperation mechanisms (relay queries for data sharing or atomic asset exchanges) are strictly part of business logic. But Weaver's Corda Interoperation Node SDK offers various helper functions to ease this process and keep the adaptation to a minimum, as we wil see later in this document. Finally, an identity service must be offered by the network to expose its CAs' certificate chains to foreign networks, thereby laying the basis for interoperation. This service simply needs to offer a REST endpoint, and can be implemented as a standalone application or (more conveniently) as an augmentation of one or more of the existing client layer applications.

Procedural Overview

A Corda network is typically created in phases, in the following sequence:

  1. Development: This involves writing CorDapp which consists of contracts and workflows, and client layer applications. The cordapp's deployment name/ID and its transaction API must be designed first, but subsequent development of the two layers of applications can then proceed parallelly.
  2. Pre-Configuration: This involves creating a desired specification (as a set of configuration diles) of the network topology and the ledgers it maintains.
  3. Startup and Bootstrap: This is the launch phase, in which the network components and applications are started and bootstrapped (i.e., configured with initial state and operating rules).

Assuming that the reader is familiar with this procedure, we will walk through the changes required in each phase to make your network ready for interoperation using Weaver components and code templates. This will involve code addition and adaptation, deployment of additional modules, additional configuration, and creation of additional ledger state records. The requirements and effort will vary with the mode of interoperation you wish to support in your Fabric network.

Development Phase

A Corda distributed application's business logic code spans three layers as illustrated in the network model:

CorDapp

CorDapps (Corda Distributed Applications) are distributed applications that run on the Corda platform. The goal of a CorDapp is to allow nodes to reach agreement on updates to the ledger. They achieve this goal by defining flows that Corda node owners can invoke over RPC.

For Data Sharing

No code changes are required for Weaver enablement, because data sharing involves:

  • View packaging (and optionally, encryption) logic and access control logic in a source network, and
  • View validation logic in a destination network

This logic is standard and independent of contract, workflow, and state, particulars. It is already implemented in the Interoperation CorDapp offered by Weaver. Hence you just need to deploy that CorDapp to exercise data sharing from, or to, your application CorDapp. Your application CorDapp can be oblivious of the Interoperation CorDapp's workings and of the view request-response protocol.

For Asset Exchange

To exchange an asset using Weaver, the asset's state on the ledger must be controlled in the following ways:

  • Locked in favor of a party
  • Claimed by the party to whom the asset is pledged
  • Returned to the original owner if it is not claimed within a given timeframe

In addition, the state of the asset (i.e., whether it is locked), and its current and targeted owners, must be determinable by looking at the ledger records.

The bookkeeping logic required to maintain records of locks can be abstracted away from the particulars of a digital asset and its workflow. But as such assets and their properties (including ownership) can be, and are, encoded in an arbitrary number of ways, we cannot provide a one-size-fits all set of functions (like in the data sharing protocol) to exchange any kind of asset. Instead, we must rely on the application CorDapp managing an asset, as it knows precisely what the asset's properties are and how they can be updated and queried on the ledger.

What Weaver offers, therefore, is the following:

  • Lock management logic implemented in the Interoperation CorDapp that treats each asset as an abstract object (an instance of generic corda's ContractState) and is agnostic of the assets' internals. It consumes (burns) the asset state and creates a new HTLC state that indicates that the asset is locked, while in claim and unlock new asset state is created (minted) with appropriate owner while consuming HTLC state. This logic can be exercised in by installing Interoperation CorDapp on the nodes.
  • A set of template functions with sample (and extensible) code that must be added to the application CorDapp to augment the above lock management functions.

Below, we list the template functions with sample code that you, as a developer, must use and adapt within your CorDapp.

  • Flow to get Asset State: For non-fungible assets, create a flow like:
    class RetrieveStateAndRef(
    val type: String,
    val id: String
    ): FlowLogic<StateAndRef<AssetState>>
    And for fungible assets, create a flow like:
    class RetrieveStateAndRef(
    val type: String,
    val quantity: Long
    ): FlowLogic<StateAndRef<AssetState>>
    The name of these flows can be anything, but the parameters should be same, and return type should StateAndRef. These flows are supposed to get the StateAndRef object to the asset state that has to be locked, which can be identified by type and id for non-fungible assets, and type and quantity for fungible assets.
  • Flow to update owner in asset state: Create a flow like:
    class UpdateOwnerFromPointer(
    val statePointer: StaticPointer<AssetState>
    ) : FlowLogic<AssetState>()
    Again the name can be anything but the function parameter should be same, i.e. take a StaticPointer and return the ContractState of the asset involved in asset exchange. This flow is supposed to resolve the StaticPointer to actual asset, and update the owner of this asset to the caller of this flow.

For Asset Transfer

TBD

Contracts CorDapp

No code changes are required for Weaver enablement. For asset exchange, Weaver assumes that application CorDapp that manages assets must already have a asset creation (mint) contract command and asset deletion (burn) contract command, which can be invoked when Issuer party is involved in the transaction.

Client Layer applications

Weaver provides an SDK to help you adapt your applications to exercise the various interoperability modes. These are called out as SDK Helpers in the network model illustrated earlier. Your Corda network's Client layer applications have business logic embedded in them that, broadly speaking, accept data from users and other external agents and invoke workflows from CorDapp over RPC. When you use Weaver for network interoperability, other options can be added, namely requesting and accepting data from foreign networks, and triggering locks and claims for atomic exchanges spanning two networks. Weaver's Corda Interoperation SDK offers a library to exercise these options. But this will involve modification to the application's business logic. -To use Weaver's Corda SDK, you need to create a personal access token with read:packages access in Github, to access weaver packages. +

Corda

After testing the Weaver interoperation mechanisms on basic sample networks, you may be interested in finding out how you can equip an existing real network, whether in development or in production, to exercise these mechanisms. In this document, we will demonstrate how to equip a Corda network and application with Weaver components and capabilities.

Model

The figure below illustrates a typical Corda network. The infrastructure consists of a set of nodes (each maintaining its share of the global state in a local vault), notaries, and CAs. On the nodes are installed one or more CorDapps, representing shared business logic across subsets of those nodes. The core of a CorDapp consists of a collection of workflows (or flows) and contracts acting on states; we layer the flows above the contracts in thebelow image just to illustrate that flows represent transaction (state update) triggers, and contract validations occur during the executions of flows. Further up in the stack lie client applications associated with CorDapps that can are used to trigger flows (and by implication, contracts).

alt text

Such a network equipped with Weaver components and capabilities will look like the figure below. Legacy components are marked in grey and Weaver and bridging components in green.

alt text

The relay and driver are the only additional infrastructure that need to be installed. One or more relays can be installed, as can one or more drivers. The drivers are illustrated in the client layer rather than in the bottom layer because, though they are coupled with relays, they trigger flows just like any client application does.

Existing CorDapp flows and contracts deployed on the network's nodes remain undisturbed. All that is required is the deployment of an Interoperation CorDapp (flows and contracts) on every node that needs to offer or consume state from foreign networks.

Client applications will need some additional code and configuration because the decisions to exercise interoperation mechanisms (relay queries for data sharing or atomic asset exchanges) are strictly part of business logic. But Weaver's Corda Interoperation Java-Kotlin SDK offers various helper functions to ease this process and keep the adaptation to a minimum, as we wil see later in this document. Finally, an identity service must be offered by the network to expose its CAs' certificate chains to foreign networks, thereby laying the basis for interoperation. This service simply needs to offer a REST endpoint, and can be implemented as a standalone application or (more conveniently) as an augmentation of one or more of the existing client layer applications.

Procedural Overview

A Corda network is typically created in phases, in the following sequence:

  1. Development: This involves writing CorDapp which consists of contracts and workflows, and client layer applications. The cordapp's deployment name/ID and its transaction API must be designed first, but subsequent development of the two layers of applications can then proceed parallelly.
  2. Pre-Configuration: This involves creating a desired specification (as a set of configuration diles) of the network topology and the ledgers it maintains.
  3. Startup and Bootstrap: This is the launch phase, in which the network components and applications are started and bootstrapped (i.e., configured with initial state and operating rules).

Assuming that the reader is familiar with this procedure, we will walk through the changes required in each phase to make your network ready for interoperation using Weaver components and code templates. This will involve code addition and adaptation, deployment of additional modules, additional configuration, and creation of additional ledger state records. The requirements and effort will vary with the mode of interoperation you wish to support in your Fabric network.

Development Phase

A Corda distributed application's business logic code spans three layers as illustrated in the network model:

CorDapp

CorDapps (Corda Distributed Applications) are distributed applications that run on the Corda platform. The goal of a CorDapp is to allow nodes to reach agreement on updates to the ledger. They achieve this goal by defining flows that Corda node owners can invoke over RPC.

For Data Sharing

No code changes are required for Weaver enablement, because data sharing involves:

  • View packaging (and optionally, encryption) logic and access control logic in a source network, and
  • View validation logic in a destination network

This logic is standard and independent of contract, workflow, and state, particulars. It is already implemented in the Interoperation CorDapp offered by Weaver. Hence you just need to deploy that CorDapp to exercise data sharing from, or to, your application CorDapp. Your application CorDapp can be oblivious of the Interoperation CorDapp's workings and of the view request-response protocol.

For Asset Exchange

To exchange an asset using Weaver, the asset's state on the ledger must be controlled in the following ways:

  • Locked in favor of a party
  • Claimed by the party to whom the asset is pledged
  • Returned to the original owner if it is not claimed within a given timeframe

In addition, the state of the asset (i.e., whether it is locked), and its current and targeted owners, must be determinable by looking at the ledger records.

The bookkeeping logic required to maintain records of locks can be abstracted away from the particulars of a digital asset and its workflow. But as such assets and their properties (including ownership) can be, and are, encoded in an arbitrary number of ways, we cannot provide a one-size-fits all set of functions (like in the data sharing protocol) to exchange any kind of asset. Instead, we must rely on the application CorDapp managing an asset, as it knows precisely what the asset's properties are and how they can be updated and queried on the ledger.

What Weaver offers, therefore, is the following:

  • Lock management logic implemented in the Interoperation CorDapp that treats each asset as an abstract object (an instance of generic corda's ContractState) and is agnostic of the assets' internals. It consumes (burns) the asset state and creates a new HTLC state that indicates that the asset is locked, while in claim and unlock new asset state is created (minted) with appropriate owner while consuming HTLC state. This logic can be exercised in by installing Interoperation CorDapp on the nodes.
  • A set of template functions with sample (and extensible) code that must be added to the application CorDapp to augment the above lock management functions.

Below, we list the template functions with sample code that you, as a developer, must use and adapt within your CorDapp.

  • Flow to get Asset State: For non-fungible assets, create a flow like:
    class RetrieveStateAndRef(
    val type: String,
    val id: String
    ): FlowLogic<StateAndRef<AssetState>>
    And for fungible assets, create a flow like:
    class RetrieveStateAndRef(
    val type: String,
    val quantity: Long
    ): FlowLogic<StateAndRef<AssetState>>
    The name of these flows can be anything, but the parameters should be same, and return type should StateAndRef. These flows are supposed to get the StateAndRef object to the asset state that has to be locked, which can be identified by type and id for non-fungible assets, and type and quantity for fungible assets.
  • Flow to update owner in asset state: Create a flow like:
    class UpdateOwnerFromPointer(
    val statePointer: StaticPointer<AssetState>
    ) : FlowLogic<AssetState>()
    Again the name can be anything but the function parameter should be same, i.e. take a StaticPointer and return the ContractState of the asset involved in asset exchange. This flow is supposed to resolve the StaticPointer to actual asset, and update the owner of this asset to the caller of this flow.

For Asset Transfer

TBD

Contracts CorDapp

No code changes are required for Weaver enablement. For asset exchange, Weaver assumes that application CorDapp that manages assets must already have a asset creation (mint) contract command and asset deletion (burn) contract command, which can be invoked when Issuer party is involved in the transaction.

Client Layer applications

Weaver provides an SDK to help you adapt your applications to exercise the various interoperability modes. These are called out as SDK Helpers in the network model illustrated earlier. Your Corda network's Client layer applications have business logic embedded in them that, broadly speaking, accept data from users and other external agents and invoke workflows from CorDapp over RPC. When you use Weaver for network interoperability, other options can be added, namely requesting and accepting data from foreign networks, and triggering locks and claims for atomic exchanges spanning two networks. Weaver's Corda Interoperation SDK offers a library to exercise these options. But this will involve modification to the application's business logic. +To use Weaver's Corda SDK, you need to create a personal access token with read:packages access in GitHub, to access Weaver packages. You also need to add the following to your application's build.gradle file:

repositories {
maven {
url https://maven.pkg.github.com/hyperledger-labs/weaver-dlt-interoperability
credentials {
username <github-email>
password <github-personal-access-token>
}
}
}
dependencies {
implementation(group: 'com.weaver.corda.sdk', name: 'weaver-corda-sdk', version: "1.2.13")
implementation(group: 'com.weaver.corda.app.interop', name: 'interop-contracts', version: "1.2.13")
implementation(group: 'com.weaver.corda.app.interop', name: 'interop-workflows', version: "1.2.13")
implementation(group: 'com.weaver', name: 'protos-java-kt', version: "1.5.7")
}

(Or check out the package website and select a different version.)

For Identity Administration

A Corda network needs to share its security domain (or membership) configuration, i.e., its nodes' CA certificate chains, with a foreign network with which it seeks to interoperate. Though such sharing can be implemented using several different mechanisms, ranging from manual to automated, the simplest and most modular way is to expose a REST endpoint that agents in foreign networks can reach. Further, this REST endpoint can be implemented as a standalone web application or it can be an extension of one or more of the existing client layer applications. (Multiple apps can expose the same endpoint serving the same information for redundancy.) We will demonstrate an example of this while leaving other implementation modes to the user. Let's say a Corda network consists of two nodes called PartyA and PartyB, each running a client layer application with a web server whose URL prefixes are http://partya.mynetwork.com:9000 and http://partyb.mynetwork.com:9000 respectively. Each app then can expose a REST endpoint (again, as an example) http://partya.mynetwork.com:9000/node_sec_grp and http://partyb.mynetwork.com:9000/node_sec_grp respectively. At each web server's backend, you need to implement logic to retrieve the node's ID and it's associated certificated chains. Sample code is given below for a Kotlin implementation built on weaver-corda-sdk. You can use this code verbatim, except for some minor changes like <path-to-root-corda-net-folder>, other parameters like security domain, and list of names of nodes as appropriate for your environment:

import com.weaver.corda.sdk.CredentialsCreator
import com.google.protobuf.util.JsonFormat


@RestController
@CrossOrigin
@RequestMapping("/") // The paths for HTTP requests are relative to this base path.
class Controller {
// Expose "node_sec_grp" endpoint using Rest Controller
@RequestMapping(value = ["/node_sec_grp"], method = arrayOf(RequestMethod.GET), produces = arrayOf("application/json"))
private fun GetNetworkConfig(): String {
val jsonPrinter = JsonFormat.printer().includingDefaultValueFields()

val credentialsCreator = CredentialsCreator(
"<path-to-root-corda-net-folder>/build/nodes",
"mynetwork", // security domain name
["PartyA", "PartyB"], // list of nodes
"",
""
)

// Generate Membership
val membership = credentialsCreator.createMembership()
return jsonPrinter.print(membership)
}
}

An agent from a foreign network can query either http://partya.mynetwork.com:9000/sec_group or http://partyb.mynetwork.com:9000/sec_group and obtain the security domain (or membership) configuration of the entire network.

For Data Sharing

Consider a scenario inspired by the global trade use case where a letter of credit (L/C) management business logic is installed in the trade-finance-network network, supports a flow named UploadBillOfLading, which validates and records a bill of lading (B/L) supplied by a user via a UI. Weaver will enable such a B/L to be fetched from a different network trade-logistics-network by querying the function GetBillOfLading exposed by the chaincode shipmentcc installed in the tradelogisticschannel channel (The trade logistics network can be built on Corda as well. The steps for Weaver-enablement will mostly be the same, with the exception of view address creation logic. Here, for demonstration purposes, we assume that that counter-party network is built on Fabric).

(In preparation, a suitable access control policy must be recorded on tradelogisticschannel in trade-logistics-network, and a suitable verification policy must be recorded in the vault of trade-finance-network. We will see how to do this in the Startup and Bootstrap Weaver Components section later.)

You will need to insert some code in the client layer application that accepts a B/L and submits a UploadBillOfLading request in trade-finance-network. (No code changes need to be made in any application in the other network.) The logic to accept a B/L should be replaced (or you can simply add an alternative) by a call to the InteroperableHelper.interopFlow function offered by the weaver-corda-sdk library. The following code sample illustrates this:

import com.weaver.corda.sdk.InteroperableHelper
import com.mynetwork.flow.UploadBillOfLading

val viewAddress = InteroperableHelper.createFabricViewAddress(
'trade-logistics-network', // Security Domain/Group
<trade-logistics-relay-url[:<port>], // Replace with remote network's relay
'tradelogisticschannel', // Remote network's channel
'shipmentcc', // Remote network's cc
'GetBillOfLading', // Remote network's cc Fun
[ <shipment-reference> ] // Replace <shipment-reference> with a value that can be used to look up the right B/L
)
try {
val response = InteroperableHelper.interopFlow(
proxy, // CordaRPCOps instance to start flows
viewAddress,
<trade-finance-relay-url>[:<port>] // Replace with local network's relay address and port
).fold({
println("Error in Interop Flow: ${it.message}")
}, {
val linearId = it.toString()
val BoLString = InteroperableHelper.getExternalStatePayloadString(
proxy,
linearId
)
val result = proxy.startFlow(::UploadBillOfLading, BoLString)
println("$result")
}
} catch (e: Exception) {
println("Error: ${e.toString()}")
}

Let us understand this code snippet better. The function UploadBillOfLading expects one argument, the bill of lading contents. The InteroperableHelper.createFabricViewAddress is used to create view address that is to passed to InteroperableHelper.interopFlow function. The equivalent function to create a view address for a remote Corda network is InteroperableHelper.createCordaViewAddress.

The rest of the code ought to be self-explanatory. Values are hardcoded for explanation purposes.

Enabling TLS: By default, the TLS is set to false in interopFlow, i.e. disabled. But if you want to enable TLS, can pass additional parameters to the interopFlow function as follows:

val response = InteroperableHelper.interopFlow(
proxy, // CordaRPCOps instance to start flows
viewAddress,
<trade-finance-relay-url>[:<port>], // Replace with local network's relay address and port
'trade-finance-network', // Local network name (destination)
true, // Boolean indication TLS is enabled.
<relayTlsTrustStorePath> // JKS file path containing relay server TLS CA certificates
<relayTlsTrustStorePassword>, // password used to create the JKS file
)

OR

val response = InteroperableHelper.interopFlow(
proxy, // CordaRPCOps instance to start flows
viewAddress,
<trade-finance-relay-url>[:<port>], // Replace with local network's relay address and port
'trade-finance-network', // Local network name (destination)
true, // Boolean indication TLS is enabled.
<tlsCACertPathsForRelay>, // colon-separated list of CA certificate file paths
)

For Asset exchange

Let's take an example of asset exchange between Alice and Bob, where Bob wants to purchase an asset of type Gold with id A123 from Alice in BondNetwork in exchange for 200 tokens of type CBDC01 in TokenNetwork.

Alice needs to select a secret text (say s), and hash it (say H) using say SHA512, which will be used to lock her asset in BondNetwork. To lock the non-fungible asset using hash H and timeout duration of 10 minutes, you need to add following code snippet in your application:

import com.weaver.corda.sdk.AssetManager
import com.weaver.corda.sdk.HashFunctions

var hash: HashFunctions.Hash = HashFunctions.SHA512
hash.setSerializedHashBase64(H)
val proxy = <CordaRPCOps-instance-created-using-credentials-of-Alice-in-BondNetwork>
val issuer = <Issuer-party-in-BondNetwork>
val recipient = <Bob-party-in-BondNetwork>
val contractId = AssetManager.createHTLC(
proxy,
"Gold", // Type
"A123", // ID
recipient,
hash,
10L, // Duration tmeout in secs, L denotes Long
1, // 1 if timeout is Duration, 0 if timeout is in absolute epochs
"com.cordaSimpleApplication.flow.RetrieveStateAndRef", // full name of "Flow to get Asset State"
AssetContract.Commands.Delete(), // Contract command for Asset to Burn/Delete the state
issuer,
observers // Optional parameter for list of observers for this transaction
)

Now Bob will lock his tokens in TokenNetwork. To lock the fungible asset using same hash H and timeout of 5 minutes (half the timeout duration used by Alice in BondNetwork), add following code snippet in your application:

import com.weaver.corda.sdk.AssetManager
import com.weaver.corda.sdk.HashFunctions

var hash: HashFunctions.Hash = HashFunctions.SHA512
hash.setSerializedHashBase64(H)
val proxy = <CordaRPCOps-instance-created-using-credentials-of-Bob-in-TokenNetwork>
val issuer = <Issuer-party-in-TokenNetwork>
val recipient = <Alice-party-in-TokenNetwork>
val contractId = AssetManager.createFungibleHTLC(
proxy,
"CBDC01", // Type
"200", // Quantity
recipient,
hash,
5L, // Duration timeout in secs, L denotes Long
1, // 1 if timeout is Duration, 0 if timeout is in absolute epochs
"com.cordaSimpleApplication.flow.RetrieveStateAndRef", // full name of "Flow to get Asset State"
AssetContract.Commands.Delete(), // Contract command for Asset to Burn/Delete the state
issuer,
observers // Optional parameter for list of observers for this transaction
)

The above locks will return contractId, that has to be stored and will be used in other HTLC functions.

To query whether the assets are locked or not in any network, use following query function:

val isLockedBoolean = AssetManager.isAssetLockedInHTLC(
rpc.proxy,
contractId
)

Now to claim the asset using the secret text (pre-image of hash) s, add following code snippet:

var hash: HashFunctions.Hash = HashFunctions.SHA512()
hash.setPreimage(s)
val issuer = <Issuer-party>
val proxu = <CordaRPCOps-instance-created-using-credentials-of-claiming-party>
val res = AssetManager.claimAssetInHTLC(
proxy,
contractId, // ContractId obtained during lock
hash,
AssetContract.Commands.Issue(), // Contract command for issuing/minting asset
"com.cordaSimpleApplication.flow.UpdateAssetOwnerFromPointer", // full name of flow to update owner in asset state
issuer,
observers // Optional parameter for list of observers for this transaction
)
// return value is boolean indicating success or failure of claim

The above function can be adapted to both BondNetwork and TokenNetwork.

If the asset has to be unlocked, use following code snippet:

val issuer = <Issuer-party>
val proxu = <CordaRPCOps-instance-created-using-credentials-of-locking-party>
val res = AssetManager.reclaimAssetInHTLC(
rpc.proxy,
contractId, // ContractId obtained during lock
AssetContract.Commands.Issue(), // Contract command for issuing/minting asset
issuer,
observers // Optional parameter for list of observers for this transaction
)
// return value is boolean indicating success or failure of claim

For Asset Transfer

TBD

Pre-Configuration Phase

No changes are required in your network's pre-configuration process for Weaver enablement.

Typically, pre-configuration involves:

  • Generating node folders for each participating node in the network, which contains CorDapps, certificates, persistence db, etc sub directories. Using Gradle task net.corda.plugins.Cordform or net.corda.plugins.Dockerform, the folders get created under the directory build/nodes (this path is used in above sample code for Identity Service). -
  • The RPC address, username and password specified in above task will be used to create an instance of CordaRPCOps, which is the first argument for most weaver-corda-sdk static functions as we saw in previous section. For example, one of them is InteroperableHelper.interopFlow:
val response = InteroperableHelper.interopFlow(
proxy, // CordaRPCOps instance to start flows
viewAddress,
<trade-finance-relay-url>[:<port>], // Replace with local network's relay address and port
)

Also, the Corda Driver (which we will setup in the following sections) needs a specific RPC user to be created, so make sure to add that in the Gradle task above, and note the credentials.

  • Sample net.corda.plugins.Dockerform task:
task prepareDockerNodes(type: net.corda.plugins.Dockerform, dependsOn: ['jar']) {
def HOST_ADDRESS = "0.0.0.0"
nodeDefaults {
projectCordapp {
deploy = false
}
}
node {
name "O=Notary,L=London,C=GB"
notary = [validating : true]
p2pPort 10004
rpcSettings {
address("$HOST_ADDRESS:10003")
adminAddress("$HOST_ADDRESS:10005")
}
cordapps.clear()
}
node {
name "O=PartyA,L=London,C=GB"
p2pPort 10007
rpcSettings {
address("$HOST_ADDRESS:10003")
adminAddress("$HOST_ADDRESS:10005")
}
rpcUsers = [
[ user: "user1", "password": "test", "permissions": ["ALL"]],
[ user: "driverUser1", "password": "test", "permissions": ["ALL"]]] // <-- Driver RPC User
}
node {
name "O=PartyB,L=London,C=GB"
p2pPort 10009
rpcSettings {
address("$HOST_ADDRESS:10003")
adminAddress("$HOST_ADDRESS:10005")
}
rpcUsers = [
[ user: "user1", "password": "test", "permissions": ["ALL"]],
[ user: "driverUser1", "password": "test", "permissions": ["ALL"]]] // <-- Driver RPC User
}
}

Startup and Bootstrap Phase

To launch a network using containerized components, you will typically use a Docker Compose or Kubernetes configuration file. No modifications are needed to the node's configurations. Sample instructions are given below for networks launched using Docker Compose; we leave it to the reader to adapt these to their custom launch processes.

For Asset Exchange

The asset exchange mode currently requires only the Interoperation CorDapp module from Weaver. Relays, drivers are not necessary. In the future, we expect to make the asset exchange protocol moe automated using these components; the instructions here will be updated appropriately.

Install Interoperation CorDapp on Nodes

After bootstrapping the nodes folder, copy the following two CorDapps in build/nodes/PartyA/cordapps and build/nodes/PartyB/cordapps folders (PartyA and PartyB node names are for example only):

Notes
You can follow any installation process for this CorDapp, but make sure it is installed on all the nodes that maintain the states involved in cross-network operations in their vaults.

For Data Sharing or Asset Transfer

Both the data sharing and asset transfer modes require the Interoperation CorDapp, relays, and drivers, to be deployed.

Install Interoperation CorDapp on Nodes

After bootstrapping the nodes folder, copy the following two CorDapps in build/nodes/PartyA/cordapps and build/nodes/PartyB/cordapps folders (PartyA and PartyB node names are for example only):

Notes
You can follow any installation process for this CorDapp, but make sure it is installed on all the nodes that maintain the states involved in cross-network operations in their vaults.

Launch Relay

You need to run one or more relays for network-to-network communication. Here we provide instructions to run one relay running in a Docker container, which is sufficient for data sharing. (Later, we will provide instructions to run multiple relays, which will be useful from a failover perspective.)

Weaver provides a pre-built image for the relay. Before launching a container, you just need to customize its configuration for your Fabric network, which you can do by simply creating a folder (let's call it relay_config) and configuring the following files in it:

  • .env: This sets suitable environment variables within the relay container. Copy the .env.template file from the repository and customize it for your purposes, as indicated in the below sample:

    PATH_TO_CONFIG=./config.toml
    RELAY_NAME=<"name" in config.toml>
    RELAY_PORT=<relay-server-port/"port" in config.toml>
    EXTERNAL_NETWORK=<docker-bridge-network>
    DOCKER_REGISTRY=ghcr.io/hyperledger-labs
    DOCKER_IMAGE_NAME=weaver-relay
    DOCKER_TAG=1.5.4
    • The PATH_TO_CONFIG variable should point to the properties file typically named config.toml (you can name this whatever you wish). See further below for instructions to write this file.
    • The RELAY_NAME variable specifies a unique name for this relay. It should match what's specified in the config.toml (more on that below).
    • The RELAY_PORT variable specifies the port this relay server will listen on. It should match what's specified in the config.toml (more on that below).
    • The EXTERNAL_NETWORK variable should be set to the name of your Fabric network.
    • The DOCKER_* variables are used to specify the image on which the container will be built. Make sure you set DOCKER_TAG to the latest version you see on Github.

    For more details, see the Relay Docker README ("Relay Server Image" and "Running With Docker Compose" sections).

  • config.toml: This is the file specified in the PATH_TO_CONFIG variable in the .env. It specifies properties of this relay and the driver(s) it supports. A sample is given below:

    name=<relay-name>
    port=<relay-port>
    host="0.0.0.0"
    db_path="db/<relay-name>/requests"
    remote_db_path="db/<relay-name>/remote_request"

    # FOR TLS
    cert_path="credentials/fabric_cert.pem"
    key_path="credentials/fabric_key"
    tls=<true/false>

    [networks]
    [networks.<network-name>]
    network="<driver-name>"

    [relays]
    [relays.<foreign-relay-name>]
    hostname="<foreign-relay-hostname-or-ip-address>"
    port="<foreign-relay-port>"

    [drivers]
    [drivers.<driver-name>]
    hostname="<driver-hostname-or-ip-address>"
    port="<driver-port>"
    • <relay-name> should be a unique ID representing this relay; e.g., my_network_relay. It should match the RELAY_NAME value in .env.
    • <relay-port> is the port number the relay server will listen on. It should match the RELAY_PORT value in .env.
    • db_path and remote_db_path are used internally by the relay to store data. Replace <relay-name> with the same value set for the name parameter. (These can point to any filesystem paths in the relay's container.)
    • If you set tls to true, the relay will enforce TLS communication. The cert_path and key_path should point to a Fabric TLS certificate and key respectively, such as those created using the cryptogen tool.
    • <network-name> is a unique identifier for your local network. You can set it to whatever value you wish.
    • <driver-name> refers to the driver used by this relay to respond to requests. This also refers to one of the drivers's specifications in the drivers section further below. In this code snippet, we have defined one driver. (The names in lines 14 and 22 must match.) In lines 23 and 24 respectively, you should specify the hostname and port for the driver (whose configuration we will handle later).
    • The relays section specifies all foreign relays this relay can connect to. The <foreign-relay-name> value should be a unique ID for a given foreign relay, and this value will be used by your Layer-2 applications when constructing view addresses for data sharing requests. In lines 18 and 19, you should specify the hostname and port for the foreign relay.
    • Enabling TLS:
      • You can make your relay accept TLS connections by specifying a TLS certificate file path and private key file path in cert_path and key_path respectively, and set tls to true.
      • To communicate with a foreign relay using TLS, specify that relay's TLS CA certificate path in tlsca_cert_path (currently only one certificate can be configured) and set tls to true by extending that relay's section as follows (Note: this CA certificate should match the one specified in the cert_path property in the foreign relay's config.toml file):
        [relays]
        [relays.<foreign-relay-name>]
        hostname="<foreign-relay-hostname-or-ip-address>"
        port="<foreign-relay-port>"
        tls=<true|false>
        tlsca_cert_path="<relay-tls-ca-certificate-path>"
      • To communicate with a driver using TLS, specify the driver's TLS CA certificate in tlsca_cert_path (currently only one certificate can be configured) and set tls to true by extending that driver's section as follows (Note: this CA certificate must match the certificate used by the driver using the DRIVER_TLS_CERT_PATH property in its .env configuration file, which we will examine later):
        [drivers]
        [drivers.<driver-name>]
        hostname="<driver-hostname-or-ip-address>"
        port="<driver-port>"
        tls=<true|false>
        tlsca_cert_path="<driver-tls-ca-certificate-path>"
    Notes
    You can specify more than one foreign relay instance in the relays section.
    You can specify more than one driver instance in the drivers section.
  • docker-compose.yaml: This specifies the properties of the relay container. You can use the file in the repository verbatim.

To start the relay server, navigate to the folder containing the above files and run the following:

docker-compose up -d relay-server

Launch Driver

You need to run one or more drivers through which your relay can interact with your Corda network. Here we provide instructions to run one Corda driver running in a Docker container, which is sufficient for data sharing. (Later, we will provide instructions to run multiple drivers, which will be useful both from a failover perspective and to interact with different subsets of your Corda network.)

Weaver provides a pre-built image for the Corda driver. Before launching a container, you just need to customize the container configuration for your Corda network, which you can do by simply configuring the following:

  • .env: This sets suitable environment variables within the driver container. Copy the .env.template file from the repository and customize it for your purposes, as indicated in the below sample:

    NETWORK_NAME=<container-name-suffix>
    DRIVER_PORT=<driver-server-port>
    DRIVER_RPC_USERNAME=<driver-rpc-username>
    DRIVER_RPC_PASSWORD=<driver-rpc-username>
    EXTERNAL_NETWORK=<docker-bridge-network>
    DOCKER_IMAGE_NAME=ghcr.io/hyperledger-labs/weaver-corda-driver
    DOCKER_TAG=1.2.13
    RELAY_TLS=<true|false>
    RELAY_TLSCA_TRUST_STORE=<truststore-jks-file-path>
    RELAY_TLSCA_TRUST_STORE_PASSWORD=<truststore-jks-file-password>
    RELAY_TLSCA_CERT_PATHS=<colon-separated-CA-cert-paths>
    DRIVER_TLS=<true|false>
    DRIVER_TLS_CERT_PATH=<cert-path>
    DRIVER_TLS_KEY_PATH=<private-key-path>
    • NETWORK_NAME is only used as suffix for container and has no other significance.
    • DRIVER_PORT variable should be set to the port this driver will listen on.
    • DRIVER_RPC_USERNAME variable should be set to rpc user created above for the driver.
    • DRIVER_RPC_PASSWORD variable should be set to password of above rpc user.
    • EXTERNAL_NETWORK variable should be set to the name of your Corda network.
    • Enabling TLS:
      • You can make your driver accept TLS connections by specifying DRIVER_TLS as true and specifying a TLS certificate file path and private key file path in DRIVER_TLS_CERT_PATH and DRIVER_TLS_KEY_PATH respectively. The same certificate should be specified in this driver's definition in the drivers section in the config.toml file of your relay in the tlsca_cert_path property (see the earlier section on relay configuration).
      • To communicate with your network' relay using TLS (i.e., if the relay is TLS-enabled), specify that relay's TLS CA certificate path in RELAY_TLSCA_CERT_PATH (currently only one certificate can be configured) and set RELAY_TLS to true. This CA certificate should match the one specified in the cert_path property in the relay's config.toml file (see the earlier section on relay configuration):
      • You can point to the folder in your host system containing the certificate and key using the TLS_CREDENTIALS_DIR variable. (This folder will be synced to the /corda-driver/credentials folder in the Fabric Driver container as specified in the docker-compose file.) Make sure you point to the right certificate and key file paths within the container using the DRIVER_TLS_CERT_PATH, DRIVER_TLS_KEY_PATH, and RELAY_TLSCA_CERT_PATH variables.
  • docker-compose.yaml: This specifies the properties of the driver container. You can use the file in the repository verbatim.

To start the driver, navigate to the folder containing the above files and run the following:

docker-compose up -d

Vault Initialization

To prepare your network for interoperation with a foreign network, you need to record the following to your vault using the Corda SDK (com.weaver.corda.sdk):

  • Access control policies: +

  • The RPC address, username and password specified in above task will be used to create an instance of CordaRPCOps, which is the first argument for most weaver-corda-sdk static functions as we saw in previous section. For example, one of them is InteroperableHelper.interopFlow:
val response = InteroperableHelper.interopFlow(
proxy, // CordaRPCOps instance to start flows
viewAddress,
<trade-finance-relay-url>[:<port>], // Replace with local network's relay address and port
)

Also, the Corda Driver (which we will setup in the following sections) needs a specific RPC user to be created, so make sure to add that in the Gradle task above, and note the credentials.

  • Sample net.corda.plugins.Dockerform task:
task prepareDockerNodes(type: net.corda.plugins.Dockerform, dependsOn: ['jar']) {
def HOST_ADDRESS = "0.0.0.0"
nodeDefaults {
projectCordapp {
deploy = false
}
}
node {
name "O=Notary,L=London,C=GB"
notary = [validating : true]
p2pPort 10004
rpcSettings {
address("$HOST_ADDRESS:10003")
adminAddress("$HOST_ADDRESS:10005")
}
cordapps.clear()
}
node {
name "O=PartyA,L=London,C=GB"
p2pPort 10007
rpcSettings {
address("$HOST_ADDRESS:10003")
adminAddress("$HOST_ADDRESS:10005")
}
rpcUsers = [
[ user: "user1", "password": "test", "permissions": ["ALL"]],
[ user: "driverUser1", "password": "test", "permissions": ["ALL"]]] // <-- Driver RPC User
}
node {
name "O=PartyB,L=London,C=GB"
p2pPort 10009
rpcSettings {
address("$HOST_ADDRESS:10003")
adminAddress("$HOST_ADDRESS:10005")
}
rpcUsers = [
[ user: "user1", "password": "test", "permissions": ["ALL"]],
[ user: "driverUser1", "password": "test", "permissions": ["ALL"]]] // <-- Driver RPC User
}
}

Startup and Bootstrap Phase

To launch a network using containerized components, you will typically use a Docker Compose or Kubernetes configuration file. No modifications are needed to the node's configurations. Sample instructions are given below for networks launched using Docker Compose; we leave it to the reader to adapt these to their custom launch processes.

For Asset Exchange

The asset exchange mode currently requires only the Interoperation CorDapp module from Weaver. Relays and drivers are not necessary. In the future, we expect to make the asset exchange protocol moe automated using these components; the instructions here will be updated appropriately.

Install Interoperation CorDapp on Nodes

After bootstrapping the nodes folder, copy the following two CorDapps in build/nodes/PartyA/cordapps and build/nodes/PartyB/cordapps folders (PartyA and PartyB node names are for example only):

Notes
You can follow any installation process for this CorDapp, but make sure it is installed on all the nodes that maintain the states involved in cross-network operations in their vaults.

For Data Sharing or Asset Transfer

Both the data sharing and asset transfer modes require the Interoperation CorDapp, relays, and drivers, to be deployed.

Install Interoperation CorDapp on Nodes

After bootstrapping the nodes folder, copy the following two CorDapps in build/nodes/PartyA/cordapps and build/nodes/PartyB/cordapps folders (PartyA and PartyB node names are for example only):

Notes
You can follow any installation process for this CorDapp, but make sure it is installed on all the nodes that maintain the states involved in cross-network operations in their vaults.

Launch Relay

You need to run one or more relays for network-to-network communication. Here we provide instructions to run one relay running in a Docker container, which is sufficient for data sharing. (Later, we will provide instructions to run multiple relays, which will be useful from a failover perspective.)

Weaver provides a pre-built image for the relay. Before launching a container, you just need to customize its configuration for your Fabric network, which you can do by simply creating a folder (let's call it relay_config) and configuring the following files in it:

  • .env: This sets suitable environment variables within the relay container. Copy the .env.template file from the repository and customize it for your purposes, as indicated in the below sample:

    PATH_TO_CONFIG=./config.toml
    RELAY_NAME=<"name" in config.toml>
    RELAY_PORT=<relay-server-port/"port" in config.toml>
    EXTERNAL_NETWORK=<docker-bridge-network>
    DOCKER_REGISTRY=ghcr.io/hyperledger-labs
    DOCKER_IMAGE_NAME=weaver-relay
    DOCKER_TAG=1.5.4
    • The PATH_TO_CONFIG variable should point to the properties file typically named config.toml (you can name this whatever you wish). See further below for instructions to write this file.
    • The RELAY_NAME variable specifies a unique name for this relay. It should match what's specified in the config.toml (more on that below).
    • The RELAY_PORT variable specifies the port this relay server will listen on. It should match what's specified in the config.toml (more on that below).
    • The EXTERNAL_NETWORK variable should be set to the name of your Fabric network.
    • The DOCKER_* variables are used to specify the image on which the container will be built. Make sure you set DOCKER_TAG to the latest version you see on GitHub.

    For more details, see the Relay Docker README ("Relay Server Image" and "Running With Docker Compose" sections).

  • config.toml: This is the file specified in the PATH_TO_CONFIG variable in the .env. It specifies properties of this relay and the driver(s) it supports. A sample is given below:

    name=<relay-name>
    port=<relay-port>
    host="0.0.0.0"
    db_path="db/<relay-name>/requests"
    remote_db_path="db/<relay-name>/remote_request"

    # FOR TLS
    cert_path="credentials/fabric_cert.pem"
    key_path="credentials/fabric_key"
    tls=<true/false>

    [networks]
    [networks.<network-name>]
    network="<driver-name>"

    [relays]
    [relays.<foreign-relay-name>]
    hostname="<foreign-relay-hostname-or-ip-address>"
    port="<foreign-relay-port>"

    [drivers]
    [drivers.<driver-name>]
    hostname="<driver-hostname-or-ip-address>"
    port="<driver-port>"
    • <relay-name> should be a unique ID representing this relay; e.g., my_network_relay. It should match the RELAY_NAME value in .env.
    • <relay-port> is the port number the relay server will listen on. It should match the RELAY_PORT value in .env.
    • db_path and remote_db_path are used internally by the relay to store data. Replace <relay-name> with the same value set for the name parameter. (These can point to any filesystem paths in the relay's container.)
    • If you set tls to true, the relay will enforce TLS communication. The cert_path and key_path should point to a Fabric TLS certificate and key respectively, such as those created using the cryptogen tool.
    • <network-name> is a unique identifier for your local network. You can set it to whatever value you wish.
    • <driver-name> refers to the driver used by this relay to respond to requests. This also refers to one of the drivers's specifications in the drivers section further below. In this code snippet, we have defined one driver. (The names in lines 14 and 22 must match.) In lines 23 and 24 respectively, you should specify the hostname and port for the driver (whose configuration we will handle later).
    • The relays section specifies all foreign relays this relay can connect to. The <foreign-relay-name> value should be a unique ID for a given foreign relay, and this value will be used by your Layer-2 applications when constructing view addresses for data sharing requests. In lines 18 and 19, you should specify the hostname and port for the foreign relay.
    • Enabling TLS:
      • You can make your relay accept TLS connections by specifying a TLS certificate file path and private key file path in cert_path and key_path respectively, and set tls to true.
      • To communicate with a foreign relay using TLS, specify that relay's TLS CA certificate path in tlsca_cert_path (currently only one certificate can be configured) and set tls to true by extending that relay's section as follows (Note: this CA certificate should match the one specified in the cert_path property in the foreign relay's config.toml file):
        [relays]
        [relays.<foreign-relay-name>]
        hostname="<foreign-relay-hostname-or-ip-address>"
        port="<foreign-relay-port>"
        tls=<true|false>
        tlsca_cert_path="<relay-tls-ca-certificate-path>"
      • To communicate with a driver using TLS, specify the driver's TLS CA certificate in tlsca_cert_path (currently only one certificate can be configured) and set tls to true by extending that driver's section as follows (Note: this CA certificate must match the certificate used by the driver using the DRIVER_TLS_CERT_PATH property in its .env configuration file, which we will examine later):
        [drivers]
        [drivers.<driver-name>]
        hostname="<driver-hostname-or-ip-address>"
        port="<driver-port>"
        tls=<true|false>
        tlsca_cert_path="<driver-tls-ca-certificate-path>"
    Notes
    You can specify more than one foreign relay instance in the relays section.
    You can specify more than one driver instance in the drivers section.
  • docker-compose.yaml: This specifies the properties of the relay container. You can use the file in the repository verbatim.

To start the relay server, navigate to the folder containing the above files and run the following:

docker-compose up -d relay-server

Launch Driver

You need to run one or more drivers through which your relay can interact with your Corda network. Here we provide instructions to run one Corda driver running in a Docker container, which is sufficient for data sharing. (Later, we will provide instructions to run multiple drivers, which will be useful both from a failover perspective and to interact with different subsets of your Corda network.)

Weaver provides a pre-built image for the Corda driver. Before launching a container, you just need to customize the container configuration for your Corda network, which you can do by simply configuring the following:

  • .env: This sets suitable environment variables within the driver container. Copy the .env.template file from the repository and customize it for your purposes, as indicated in the below sample:

    NETWORK_NAME=<container-name-suffix>
    DRIVER_PORT=<driver-server-port>
    DRIVER_RPC_USERNAME=<driver-rpc-username>
    DRIVER_RPC_PASSWORD=<driver-rpc-username>
    EXTERNAL_NETWORK=<docker-bridge-network>
    DOCKER_IMAGE_NAME=ghcr.io/hyperledger-labs/weaver-corda-driver
    DOCKER_TAG=1.2.13
    RELAY_TLS=<true|false>
    RELAY_TLSCA_TRUST_STORE=<truststore-jks-file-path>
    RELAY_TLSCA_TRUST_STORE_PASSWORD=<truststore-jks-file-password>
    RELAY_TLSCA_CERT_PATHS=<colon-separated-CA-cert-paths>
    DRIVER_TLS=<true|false>
    DRIVER_TLS_CERT_PATH=<cert-path>
    DRIVER_TLS_KEY_PATH=<private-key-path>
    • NETWORK_NAME is only used as suffix for container and has no other significance.
    • DRIVER_PORT variable should be set to the port this driver will listen on.
    • DRIVER_RPC_USERNAME variable should be set to rpc user created above for the driver.
    • DRIVER_RPC_PASSWORD variable should be set to password of above rpc user.
    • EXTERNAL_NETWORK variable should be set to the name of your Corda network.
    • Enabling TLS:
      • You can make your driver accept TLS connections by specifying DRIVER_TLS as true and specifying a TLS certificate file path and private key file path in DRIVER_TLS_CERT_PATH and DRIVER_TLS_KEY_PATH respectively. The same certificate should be specified in this driver's definition in the drivers section in the config.toml file of your relay in the tlsca_cert_path property (see the earlier section on relay configuration).
      • To communicate with your network' relay using TLS (i.e., if the relay is TLS-enabled), specify that relay's TLS CA certificate path in RELAY_TLSCA_CERT_PATH (currently only one certificate can be configured) and set RELAY_TLS to true. This CA certificate should match the one specified in the cert_path property in the relay's config.toml file (see the earlier section on relay configuration):
      • You can point to the folder in your host system containing the certificate and key using the TLS_CREDENTIALS_DIR variable. (This folder will be synced to the /corda-driver/credentials folder in the Fabric Driver container as specified in the docker-compose file.) Make sure you point to the right certificate and key file paths within the container using the DRIVER_TLS_CERT_PATH, DRIVER_TLS_KEY_PATH, and RELAY_TLSCA_CERT_PATH variables.
  • docker-compose.yaml: This specifies the properties of the driver container. You can use the file in the repository verbatim.

To start the driver, navigate to the folder containing the above files and run the following:

docker-compose up -d

Vault Initialization

To prepare your network for interoperation with a foreign network, you need to record the following to your vault using the Corda SDK (com.weaver.corda.sdk):

  • Access control policies: Let's take the example of the request made from trade-finance-network to trade-logistics-network for a B/L earlier in this document. trade-logistics-network can have a policy of the following form permitting access to the GetBillOfLading function from a client representing the PartyA node in trade-finance-network as follows:

    {
    "securityDomain":"trade-finance-network",
    "rules":
    [
    {
    "principal":"<PartyA-certificate-pem>",
    "principalType":"certificate",
    "resource":"exporternode:10003;carriernode:10003#com.mynetwork.flow.GetBillOfLading:*",
    "read":true
    }
    ]
    }

    In this sample, a single rule is specified for requests coming from trade-finance-network: it states that a workflow call to com.mynetwork.flow.GetBillOfLading made to exporter and carrier nodes of remote Corda network is permitted for a requestor whose certificate is specified in the principal attribute. The * at the end indicates that any arguments passed to the function will pass the access control check. The exporternode:10003 and carriernode:10003 are of form <hostname/IP>:<RPC_Port>, for exporter and carrier nodes respectively in the remote Corda network.

    You need to record this policy rule on your Corda network's vault by invoking either the AccessControlPolicyManager.createAccessControlPolicyState function or the AccessControlPolicyManager.updateAccessControlPolicyState function on the weaver-corda-sdk; use the former if you are recording a set of rules for the given securityDomain for the first time and the latter to overwrite a set of rules recorded earlier. The above JSON needs to be converted to protobuf object of com.weaver.protos.common.access_control.AccessControl.AccessControlPolicy, using google's protobuf library, and the object is the second argument of above functions (first being the instance of CordaRPCOps).

  • Verification policies: Taking the same example as above, an example of a verification policy for a B/L requested by the trade-finance-network from the trade-logistics-network is as follows:

    {
    "securityDomain":"trade-logistics-network",
    "identifiers":
    [
    {
    "pattern":"tradelogisticschannel:shipmentcc:GetBillOfLading:*",
    "policy":
    {
    "type":"Signature",
    "criteria":
    [
    "ExporterMSP",
    "CarrierMSP"
    ]
    }
    }
    ]
    }

    In this sample, a single verification policy rule is specified for data views coming from trade-logistics-network: it states that the data returned by the GetBillOfLading query made to the shipmentcc chaincode on the tradelogisticschannel channel requires as proof two signatures, one from a peer in the organization whose MSP ID is ExporterMSP and another from a peer in the organization whose MSP ID is CarrierMSP.

    Notes
    If the remote network is built on Corda, the resource specified in the access control policy can be used here as the pattern, with different node names specified in the criteria.

    You need to record this policy rule on your Corda network's vault by invoking Corda sdk's function VerificationPolicyManager.createVerificationPolicyState(proxy, verificationPolicyProto), where proxy is an instance of CordaRPCOps as described in previous sections, and verificationPolicyProto is an object of protobuf com.weaver.protos.common.verification_policy.VerificationPolicyOuterClass.VerificationPolicy. You can examine the full proto structure here. (Google's protobuf library can be used to convert above JSON to protobuf object.)

    Notes
    For any cross-network data request, make sure an access control policy is recorded in the source network (trade-logistics-network in the above example) and a corresponding verification policy is recorded in the destination network (trade-finance-network in the above example) before any relay request is triggered.
  • Foreign network security domain (membership) configuration: -Run the following procedure (pseudocode) to record security domain configuration for every foreign network you wish your Corda network to interoperate with (you will need to collect the identity service URLs for all the foreign networks first):

    for each foreign network:
    send an HTTP GET request to the network's identity service (using 'curl' or 'wget' from a shell script or equivalent programming language APIs).
    convert the response string to protobuf object of 'com.weaver.protos.common.membership.MembershipOuterClass.Membership'.
    invoke 'MembershipManager.createMembershipState(proxy, membershipProto)' or 'MembershipManager.updateMembershipState(proxy, membershipProto)' on Corda sdk.

    As in the above two cases, use createMembershipState to record a confiuration for the first time for a given securityDomain and updateMembershipState to overwrite a configuration.

    Notes
    Security domain configurations (organization lists and their certificate chains) for any Fabric/Corda network are subject to change, so you should run the above procedure periodically in a loop.

Your Corda network is now up and running with the necessary Weaver components, and your network's vault is bootstrapped with the initial configuration necessary for cross-network interactions!

- - +Run the following procedure (pseudocode) to record security domain configuration for every foreign network you wish your Corda network to interoperate with (you will need to collect the identity service URLs for all the foreign networks first):

for each foreign network:
send an HTTP GET request to the network's identity service (using 'curl' or 'wget' from a shell script or equivalent programming language APIs).
convert the response string to protobuf object of 'com.weaver.protos.common.membership.MembershipOuterClass.Membership'.
invoke 'MembershipManager.createMembershipState(proxy, membershipProto)' or 'MembershipManager.updateMembershipState(proxy, membershipProto)' on Corda sdk.

As in the above two cases, use createMembershipState to record a confiuration for the first time for a given securityDomain and updateMembershipState to overwrite a configuration.

Notes
Security domain configurations (organization lists and their certificate chains) for any Fabric/Corda network are subject to change, so you should run the above procedure periodically in a loop.

Your Corda network is now up and running with the necessary Weaver components, and your network's vault is bootstrapped with the initial configuration necessary for cross-network interactions!

+ + \ No newline at end of file diff --git a/docs/external/getting-started/enabling-weaver-network/fabric/index.html b/docs/external/getting-started/enabling-weaver-network/fabric/index.html index 6e532adb0..664335b16 100644 --- a/docs/external/getting-started/enabling-weaver-network/fabric/index.html +++ b/docs/external/getting-started/enabling-weaver-network/fabric/index.html @@ -4,9 +4,9 @@ Hyperledger Fabric | Weaver: DLT Interoperability Framework - - - + + +
@@ -14,12 +14,12 @@ Similarly lockInfoSerializedProto64 is a serialized protobuf in Base64 encoded string of AssetLock protobuf structure. Check the structure definition here.
  • LockFungibleAsset
    func (s *SmartContract) LockFungibleAsset(ctx contractapi.TransactionContextInterface, fungibleAssetExchangeAgreementSerializedProto64 string, lockInfoSerializedProto64 string) (string, error) {
    // Add some safety checks before calling LockFungibleAsset from library
    // Caller of this chaincode is supposed to be the Locker and the owner of the asset being locked.
    contractId, err := assetexchange.LockFungibleAsset(ctx, "", fungibleAssetExchangeAgreementSerializedProto64, lockInfoSerializedProto64)
    if err != nil {
    return "", logThenErrorf(err.Error())
    }
    // Post proccessing of asset after LockFungibleAsset called like reduce the amount of tokens owned by the locker, or mark it locked so that it can't be spent.
    ...
    return contractId, nil
    }
    Here fungibleAssetExchangeAgreementSerializedProto64 is a serialized protobuf in Base64 encoded string of FungibleAssetExchangeAgreement protobuf structure, and can be used to extract details like asset quantity, type of asset and recipient. Check the structure definition here.
  • IsAssetLockedQueryUsingContractId
    func (s *SmartContract) IsAssetLockedQueryUsingContractId(ctx contractapi.TransactionContextInterface, contractId string) (bool, error) {
    return assetexchange.IsAssetLockedQueryUsingContractId(ctx, contractId)
    }
  • ClaimAssetUsingContractId
    func (s *SmartContract) ClaimAssetUsingContractId(ctx contractapi.TransactionContextInterface, contractId, claimInfoSerializedProto64 string) (bool, error) {
    // Note recipient will be the caller for this function
    claimed := false
    err := assetexchange.ClaimAssetUsingContractId(ctx, contractId, claimInfoSerializedProto64)
    if err != nil {
    return false, logThenErrorf(err.Error())
    }
    claimed = true
    // After the above function call, update the owner of the asset with recipeint/caller
    ...
    return claimed, nil
    }
  • UnlockAssetUsingContractId
    func (s *SmartContract) UnlockAssetUsingContractId(ctx contractapi.TransactionContextInterface, contractId string) (bool, error) {
    unlocked := false
    err := assetexchange.UnlockAssetUsingContractId(ctx, contractId)
    if err != nil {
    return false, logThenErrorf(err.Error())
    }
    unlocked = true
    ...
    return true, nil
    }
  • In addition, you should add the following extra utility functions to enable client applications to query and discover asset state:

    func (s *SmartContract) GetHTLCHashByContractId(ctx contractapi.TransactionContextInterface, contractId string) (string, error) {
    return assetexchange.GetHTLCHashByContractId(ctx, contractId)
    }
    func (s *SmartContract) GetHTLCHashPreImageByContractId(ctx contractapi.TransactionContextInterface, contractId string) (string, error) {
    return assetexchange.GetHTLCHashPreImageByContractId(ctx, contractId)
    }

    There is an alternative API to implement asset exchange using this library, which doesn't involve contract IDs. For details, see the Asset Exchange Library README.

  • Using the Fabric Interoperation Chaincode: This method requires the Fabric Interoperation Chaincode to be installed on all peers of the channel, using a special chaincode ID (e.g., interop, which is what we will use later in this document). Your application chaincode needs to implement the interface github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/interfaces/asset-mgmt. In your smart contract's go.mod, add the following in require (update the version according to the latest module version):

    require(
    ...
    github.com/hyperledger-labs/weaver-dlt-interoperability/common/protos-go v1.5.6
    github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/interfaces/asset-mgmt v1.5.3
    ...
    )

    In the SmartContract class definition file, add the following code:

    import (
    ...
    am "github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/interfaces/asset-mgmt"
    )
    type SmartContract struct {
    contractapi.Contract
    amc am.AssetManagementContract
    }

    The following functions need to be added to your chaincode (Note: the function signature, i.e. the name, arguments, and return values, need to be exactly what is given in the below samples; you can have additional code to manage asset state as per need):

    1. LockAsset
      func (s *SmartContract) LockAsset(ctx contractapi.TransactionContextInterface, assetExchangeAgreementSerializedProto64 string, lockInfoSerializedProto64 string) (string, error) {
      // Add some safety checks before calling LockAsset from library
      // Caller of this chaincode is supposed to be the Locker and the owner of the asset being locked.
      contractId, err := s.amc.LockAsset(ctx, "", assetExchangeAgreementSerializedProto64, lockInfoSerializedProto64)
      if err != nil {
      return "", logThenErrorf(err.Error())
      }
      // Post proccessing of asset after LockAsset called like change status of the asset so that it can't be spent.
      ...
      return contractId, nil
      }
      Here assetExchangeAgreementSerializedProto64 is a serialized protobuf in Base64 encoded string of AssetExchangeAgreement protobuf structure, and can be used to extract details like asset id, type of asset and recipient. Check the structure definition here. -Similarly lockInfoSerializedProto64 is a serialized protobuf in Base64 encoded string of AssetLock protobuf structure. Check the structure definition here.
    2. LockFungibleAsset
      func (s *SmartContract) LockFungibleAsset(ctx contractapi.TransactionContextInterface, fungibleAssetExchangeAgreementSerializedProto64 string, lockInfoSerializedProto64 string) (string, error) {
      // Add some safety checks before calling LockFungibleAsset from library
      // Caller of this chaincode is supposed to be the Locker and the owner of the asset being locked.
      contractId, err := s.amc.LockFungibleAsset(ctx, "", fungibleAssetExchangeAgreementSerializedProto64, lockInfoSerializedProto64)
      if err != nil {
      return "", logThenErrorf(err.Error())
      }
      // Post proccessing of asset after LockFungibleAsset called like reduce the amount of tokens owned by the locker, or mark it locked so that it can't be spent.
      ...
      return contractId, nil
      }
      Here fungibleAssetExchangeAgreementSerializedProto64 is a serialized protobuf in Base64 encoded string of FungibleAssetExchangeAgreement protobuf structure, and can be used to extract details like asset quantity, type of asset and recipient. Check the structure definition here.
    3. IsAssetLockedQueryUsingContractId
      func (s *SmartContract) IsAssetLockedQueryUsingContractId(ctx contractapi.TransactionContextInterface, contractId string) (bool, error) {
      return s.amc.IsAssetLockedQueryUsingContractId(ctx, contractId)
      }
    4. ClaimAssetUsingContractId
      func (s *SmartContract) ClaimAssetUsingContractId(ctx contractapi.TransactionContextInterface, contractId, claimInfoSerializedProto64 string) (bool, error) {
      // Note recipient will be the caller for this function
      claimed := false
      err := s.amc.ClaimAssetUsingContractId(ctx, contractId, claimInfoSerializedProto64)
      if err != nil {
      return false, logThenErrorf(err.Error())
      }
      claimed = true
      // After the above function call, update the owner of the asset with recipeint/caller
      ...
      return claimed, nil
      }
    5. UnlockAssetUsingContractId
      func (s *SmartContract) UnlockAssetUsingContractId(ctx contractapi.TransactionContextInterface, contractId string) (bool, error) {
      unlocked := false
      err := s.amc.UnlockAssetUsingContractId(ctx, contractId)
      if err != nil {
      return false, logThenErrorf(err.Error())
      }
      unlocked = true
      ...
      return true, nil
      }
      In addition, you should add the following extra utility functions to enable client applications to query and discover asset state:
    func (s *SmartContract) GetHTLCHashByContractId(ctx contractapi.TransactionContextInterface, contractId string) (string, error) {
    return s.amc.GetHTLCHashByContractId(ctx, contractId)
    }
    func (s *SmartContract) GetHTLCHashPreImageByContractId(ctx contractapi.TransactionContextInterface, contractId string) (string, error) {
    return s.amc.GetHTLCHashPreImageByContractId(ctx, contractId)
    }
  • For Asset Transfer

    TBD

    Client (or Layer-2) Applications

    Weaver provides an SDK to help you adapt your applications to exercise the various interoperability modes. These are called out as Interoperation Helpers in the network model illustrated earlier. Your Fabric network's Layer-2 applications have business logic embedded in them that, broadly speaking, accept data from users and other external agents and invoke smart contracts using library functions and APIs offered by the Fabric SDK. When you use Weaver for network interoperability, other options can be added, namely requesting and accepting data from foreign networks, and triggering locks and claims for atomic exchanges spanning two networks. Weaver's Fabric Interoperation SDK (currently implemented both in Node.js and Golang) offers a library to exercise these options, supplementing the Fabric SDK. But this will involve modification to the application's business logic.

    Notes
    The instructions here apply to applications implemented in Node.js (JavaScript and TypeScript), using the Weaver Node SDK for Fabric. We will add instructions later for Go applications using the Weaver Go SDK for Fabric.

    To import and use the Weaver SDK, you need to add the following dependency to the dependencies section of your Node.js application's package.json file:

    "@hyperledger-labs/weaver-fabric-interop-sdk": "latest",

    (Instead of latest, you can select a particular version from the package website.)

    Before you run npm install to fetch the dependencies, make sure you create a personal access token with read:packages access in Github. Create an .npmrc file in the same folder as the package.json with the following contents:

    registry=https://npm.pkg.github.com/hyperledger-labs
    //npm.pkg.github.com/:_authToken=<personal-access-token>

    Replace <personal-access-token> in this file with the token you created in Github.

    First, you must incorporate some code for Weaver's network administration, specifically identity management. Then, using the given sample code and examples, you can adapt your applications for each interoperability mode.

    For Identity Administration

    A Fabric network channel must share its security domain (or membership) configuration, i.e., its organizations' CA certificate chains, with a foreign network with which it seeks to interoperate. Each organization must run an IIN Agent for this purpose. The set of IIN Agents, a.k.a. the local membership must be recorded in the ledger before those agents can be operational. In your Fabric network application suite, one or more applications will exist for network administration; the following code snippet should be added in at least one of those applications to record local membership as a prerequisite for interoperability:

    import { MembershipManager } from '@hyperledger-labs/weaver-fabric-interop-sdk'

    const gateway = <get-fabric-network-gateway-instance>

    try {
    const response = await MembershipManager.createLocalMembership(
    gateway,
    members, // list of all organization MSPIDs that are part of the channel
    securityDomain, // name of the local network's security domain
    channelName, // Channel Name
    contractName // Fabric Interoperation Chaincode installation ID on the channel
    )
    } catch (e) {
    // On error try updating local membership
    const response = await MembershipManager.updateLocalMembership(gateway, members, securityDomain, channelName, contractName)
    }
    • <get-fabric-network-gateway-instance> should be replaced with standard (boilerplate) code to get a handle to your network's gateway. This requires a special wallet identity, namely one with a network-admin attribute indicating that the caller is a trusted network administrator who is authorized to record local memberships on the channelName channel.
    • members must consist of the list of organizational MSP IDs for the channelName channel.

    For Data Sharing

    Consider a scenario inspired by the global trade use case where a letter of credit (L/C) management business logic (chaincode letterofcreditcc) installed in the tradefinancechannel channel in the trade-finance-network network supports a transaction RecordBillOfLading, which validates and records a bill of lading (B/L) supplied by a user via a UI. Weaver will enable such a B/L to be fetched from a different network trade-logistics-network by querying the function GetBillOfLading exposed by the chaincode shipmentcc installed in the tradelogisticschannel channel.

    (In preparation, a suitable access control policy must be recorded on tradelogisticschannel in trade-logistics-network, and a suitable verification policy must be recorded on tradefinancechannel in trade-finance-network. We will see how to do this in the "Startup and Boostrap" section later.)

    You will need to insert some code in the Layer-2 application that accepts a B/L and submits a RecordBillOfLading transaction in trade-finance-network. (No code changes need to be made in any application in the other network.) The logic to accept a B/L should be replaced (or you can simply add an alternative) by a call to the interopFlow function offered by the weaver-fabric-interop-sdk library (there's an equivalent library in Golang too). The following code sample illustrates this (the Golang equivalent is left to the reader):

    const ihelper = require('@hyperledger-labs/weaver-fabric-interop-sdk').InteroperableHelper;
    const interopcc = <handle-to-fabric-interop-chaincode>; // Use Fabric SDK functions: (new Gateway()).getNetwork(...).getContract(<fabric-interop-chaincode-id>)
    const keyCert = await ihelper.getKeyAndCertForRemoteRequestbyUserName(<wallet>, <user-id>); // Read key and certificate for <user-id> from wallet (get handle using Fabric SDK Wallets API)
    // Collect view addresses for relay requests in the context of an interop flow
    interopJSONs.push({
    NetworkID: 'trade-logistics-network',
    RemoteEndpoint: <trade-logistics-relay-url[:<port>], // Replace with remote network's relay address and port
    ChannelID: 'tradelogisticschannel',
    ChaincodeID: 'shipmentcc',
    ChaincodeFunc: 'GetBillOfLading',
    ccArgs: [ <shipment-reference> ], // Replace <shipment-reference> with a value that can be used to look up the right B/L
    Sign: true
    });
    const indices = [ 1 ];
    // Trigger an end-to-end interoperation (data sharing) protocol
    // Send a request to a foreign network via your relay, receive the response and submit a transaction to a local chaincode
    const flowResponse = await ihelper.interopFlow(
    interopcc,
    'trade-finance-network',
    {
    channel: 'tradefinancechannel',
    contractName: 'letterofcreditcc',
    ccFunc: 'RecordBillOfLading',
    ccArgs: [ <shipment-reference> , '' ]
    },
    <org-msp-id>, // Replace with this Layer-2 application's organization's MSP ID
    <trade-finance-relay-url>[:<port>], // Replace with local network's relay address and port
    indices,
    interopJSONs,
    keyCert,
    <endorsingOrgs>, // List of orgs to submit transaction to local i.e. trade logistics network
    false, // Boolean flag to indicate whether return without submit transaction to local i.e. trade logistics network
    false, // Boolean flag indicating no TLS communication with relay
    [], // Keep it empty when TLS is disabled
    <confidential-flag>, // Boolean flag to indicate whether to use to end-to-end encryption
    );
    // List of errors to check for
    if (!flowResponse.views || flowResponse.views.length === 0 || !flowResponse.result || flowResponse.views.length !== argIndices.length) {
    throw <error>;
    }

    Let us understand this code snippet better. The structure in lines 20-25 specifies the local chaincode transaction that is to be triggered after remote data (view) has been requested and obtained via relays. The function RecordBillOfLading expects two arguments as specified in line 24: the first is the common shipment reference that is used by the letter of credit in trade-finance-network and the bill of lading in trade-logistics-network, and the second is the bill of lading contents. When the interopFlow function is called, this argument is left blank because it is supposed to be filled with contents obtained from a view request. The array list indices, which is passed as an argument to interopFlow therefore contains the index value 1 (line 14), indicating which argument ought to be substituted with view data. The interopJSONs array correspondingly contains a list of view addresses that are to be supplied to the relay. The <confidential-flag> if set to true will enable end-to-end confidentiality, i.e. payload will be encrypted from trade-finance-network's weaver chaincode, and will be decrypted in SDK (i.e. Layer-2 client application) at trade-logistics-network, but relays and drivers in between will not be able to see the payload. By default this flag is set to false.

    Notes
    A local chaincode invocation may require multiple view requests to different networks, which is why indices and interopJSONs are arrays; they therefore must have the same lengths.

    The rest of the code ought to be self-explanatory. Values are hardcoded for explanation purposes, but you can refactor the above code by reading view addresses corresponding to chaincode invocations from a configuration file.

    Enabling TLS: -By default, the TLS is set to false in interopFlow, i.e. disabled. But if you want to enable TLS, can pass additional parameters to the interopFlow function as follows:

    const flowResponse = await ihelper.interopFlow(
    interopcc,
    'trade-finance-network',
    {
    channel: 'tradefinancechannel',
    contractName: 'letterofcreditcc',
    ccFunc: 'RecordBillOfLading',
    ccArgs: [ <shipment-reference> , '' ]
    },
    <org-msp-id>, // Replace with this Layer-2 application's organization's MSP ID
    <trade-finance-relay-url>[:<port>], // Replace with local network's relay address and port
    indices,
    interopJSONs,
    keyCert,
    <endorsingOrgs>, // List of orgs to submit transaction to in trade logistics network
    false, // Boolean flag to indicate whether return without submit transaction to local i.e. trade logistics network
    true, // Boolean indication TLS is enabled.
    <tlsCACertPathsForRelay>, // list of CA certificate file paths
    );

    For Asset Exchange

    Let's take an example of asset exchange between Alice and Bob, where Bob wants to purchase an asset of type Gold with id A123 from Alice in BondNetwork in exchange for 200 tokens of type CBDC01 in TokenNetwork.

    Alice needs to select a secret text (say s), and hash it (say H) using say SHA512, which will be used to lock her asset in BondNetwork. At the place in your application where an asset exchange is to be initiated, you need to add code to enable Alice to lock the non-fungible asset using hash H and timeout duration of 10 minutes:

    import { AssetManager, HashFunctions } from '@hyperledger-labs/weaver-fabric-interop-sdk'

    const hash = HashFunctions.SHA512(); // Create Hash instance of one of the supported Hash Algorithm
    hash.setSerializedHashBase64(H); // Set the Hash
    const timeout = Math.floor(Date.now()/1000) + 10 * 60;

    const bondContract = <handle-to-fabric-application-chaincode-in-bond-network>;

    const result = await AssetManager.createHTLC(
    bondContract,
    "Gold", // Asset ID
    "A123", // Asset Type
    bobCertificate, // Certificate of Bob in Bond Network
    hash, // Hash generated by Alice using her secret s
    timeout, // Timeout in epoch for 10 mins from current time
    null // Optional callback function to be called after the asset is locked
    );
    let bondContractId = result.result; // Unique ID for this asset exchange contract in BondNetwork
    Notes
    Note that 'Alice' and 'Bob' and the asset specifics can be parameterized in the above code, which can be reused for arbitrary asset exchange scenarios in your business workflow. The above code is only meant to be a sample.

    Now Bob will lock his tokens in TokenNetwork. To lock the fungible asset using same hash H and timeout of 5 minutes (half the timeout duration used by Alice in BondNetwork), add the following code snippet in your application:

    const hash = HashFunctions.SHA512();    // Create Hash instance of one of the supported Hash Algorithm
    hash.setSerializedHashBase64(H); // Set the Hash
    const timeout = Math.floor(Date.now()/1000) + 5 * 60;

    const tokenContract = <handle-to-fabric-application-chaincode-in-token-network>;
    const result = await AssetManager.createFungibleHTLC(
    tokenContract,
    "CBDC01", // Token ID
    200, // Token Quantity
    aliceCertificate, // Certificate of Alice in Token Network
    hash, // Hash H used by Alice in Bond Network
    timeout, // Timeout in epoch for 5 mins from current time
    null // Optional callback function to be called after the asset is locked
    )
    const tokenContractId = result.result // Unique ID for this asset exchange contract in TokenNetwork

    Wherever the lock status of the asset is required in your application, you should insert a query function call as follows:

    const contract = <handle-to-fabric-application-chaincode>;
    // Below contractId is the ID obtained during lock
    const isLocked = AssetManager.isAssetLockedInHTLCqueryUsingContractId(contract, contractId)

    Wherever a participant (either 'Alice' or 'Bob' in this example) needs to claim a locked asset using the secret text (pre-image of hash) s in your application, insert the following code snippet (Note: typically one would insert this in event callback functions or in functions that are polling the ledger to monitor whether the asset is locked in favor of a given recipient):

    const hash = HashFunctions.SHA512();    // Create Hash instance of one of the supported Hash Algorithm
    hash.setPreimage(s) // Set Pre-Image s
    const contract = <handle-to-fabric-application-chaincode>;
    const claimSuccess = await AssetManager.claimAssetInHTLCusingContractId(
    contract,
    contractId, // contractId obtained during lock
    hash
    )
    // return value claimSuccess is boolean indicating success or failure of claim

    Wherever the asset must be unlocked in your application (typically, an event callback function triggered upon the expiration of the time lock), insert the following code snippet:

    const contract = <handle-to-fabric-application-chaincode>;
    const reclaimSuccess = await AssetManager.reclaimAssetInHTLCusingContractId(
    contract,
    contractId // contractId obtained during lock
    )
    // return value 'reclaimSuccess' is a boolean indicating success or failure of reclaim

    For Asset Transfer

    TBD

    Pre-Configuration Phase

    Typically, pre-configuration in a Fabric network involves generating (after creating the channel specifications and policies):

    • Channel artifacts: orderer genesis block, channel transaction, and anchor peer configurations from a configtx.yaml file (using Fabric's configtxgen tool)
    • Crypto artifacts: keys and certificates for CAs, peers, orderers, and clients from a crypto-config.yaml file (using Fabric's cryptogen tool)
    • Connection profiles: one for every network organization, which will be used by the organization's Layer-2 applications to connect to the network's peers and CAs

    No changes are required in this process to support any of the three interoperation modes using Weaver. The connection profiles generated above will be used by certain Weaver modules, as we will see later. The only additional step required is to generate special wallet identities for the following:

    • Network administrator: one or more identities containing the network-admin attribute; only a user/application possessing this identity may record special (privileged) information regarding memberships and policies on the channel.
    • Fabric Driver: one or more identities (for each deployed driver) containing the relay attribute; only a relay-driver combination possessing this identity may run data sharing-related operations on the deployed Fabric Interoperation Chaincode.
    • IIN Agent: one or more identities (for each deployed agent) containing the iin-agent attribute: only an agent may submit foreign network membership records to the Fabric Interoperation Chaincode.

    Later we will see how the components possessing these identities are deployed.

    Startup and Bootstrap Phase

    After writing application code and creating the network configuration files, the components of a Fabric network (peers, CAs, and ordering service) are launched. In this section, we will list the additional tasks you, as a Fabric network administrator, must perform to make your network ready to interoperate.

    To launch a network using containerized components, you will typically use a Docker Compose or Kubernetes configuration file. No modifications are needed to the peers', orderers', and CAs' configurations. Sample instructions are given below for networks launched using Docker Compose; we leave it to the reader to adapt these to their custom launch processes.

    For Asset Exchange

    The asset exchange mode currently requires only the Fabric Interoperation Chaincode module from Weaver. Relays, drivers, and IIN agents, are not necessary. In the future, we expect to make the asset exchange protocol moe automated using these components; the instructions here will be updated appropriately.

    Install the Fabric Interoperation Chaincode

    Install the Fabric Interoperation Chaincode in the relevant channel(s), i.e., those that run chaincodes that will be involved in asset exchanges. This is a Go module that can be fetched from github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/contracts/interop. Following that, you an install it using the appropriate Fabric process: in Fabric v2, you will need to package, install, approve, and commit this module on the selected channels in your network.

    For Data Sharing or Asset Transfer

    Both the data sharing and asset transfer modes require the Fabric Interoperation Chaincode, relays, drivers, and IIN agents, to be deployed.

    Install the Fabric Interoperation Chaincode

    Install the Fabric Interoperation Chaincode in the relevant channel(s), i.e., those that run chaincodess that will be involved in data sharing (and asset transfers, which require multiple data shares). This is a Go module that can be fetched from github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/contracts/interop. Following that, you an install it using the appropriate Fabric process: in Fabric v2, you will need to package, install, approve, and commit this module on the selected channels in your network.

    Launch Relay

    You need to run one or more relays for network-to-network communication. Here we provide instructions to run one relay running in a Docker container, which is sufficient for data sharing. (Later, we will provide instructions to run multiple relays, which will be useful from a failover perspective.)

    Weaver provides a pre-built image for the relay. Before launching a container, you just need to customize its configuration for your Fabric network, which you can do by simply creating a folder (let's call it relay_config) and configuring the following files in it:

    • .env: This sets suitable environment variables within the relay container. Copy the .env.template file from the repository and customize it for your purposes, as indicated in the below sample:

      PATH_TO_CONFIG=./config.toml
      RELAY_NAME=<"name" in config.toml>
      RELAY_PORT=<relay-server-port/"port" in config.toml>
      EXTERNAL_NETWORK=<docker-bridge-network>
      DOCKER_REGISTRY=ghcr.io/hyperledger-labs
      DOCKER_IMAGE_NAME=weaver-relay
      DOCKER_TAG=1.5.4
      • The PATH_TO_CONFIG variable should point to the properties file typically named config.toml (you can name this whatever you wish). See further below for instructions to write this file.
      • The RELAY_NAME variable specifies a unique name for this relay. It should match what's specified in the config.toml (more on that below).
      • The RELAY_PORT variable specifies the port this relay server will listen on. It should match what's specified in the config.toml (more on that below).
      • The EXTERNAL_NETWORK variable should be set to the name of your Fabric network.
      • The DOCKER_* variables are used to specify the image on which the container will be built. Make sure you set DOCKER_TAG to the latest version you see on Github.

      For more details, see the Relay Docker README ("Relay Server Image" and "Running With Docker Compose" sections).

    • config.toml: This is the file specified in the PATH_TO_CONFIG variable in the .env. It specifies properties of this relay and the driver(s) it supports. A sample is given below:

      name=<relay-name>
      port=<relay-port>
      host="0.0.0.0"
      db_path="db/<relay-name>/requests"
      remote_db_path="db/<relay-name>/remote_request"

      # FOR TLS
      cert_path="credentials/fabric_cert.pem"
      key_path="credentials/fabric_key"
      tls=<true/false>

      [networks]
      [networks.<network-name>]
      network="<driver-name>"

      [relays]
      [relays.<foreign-relay-name>]
      hostname="<foreign-relay-hostname-or-ip-address>"
      port="<foreign-relay-port>"

      [drivers]
      [drivers.<driver-name>]
      hostname="<driver-hostname-or-ip-address>"
      port="<driver-port>"
      • <relay-name> should be a unique ID representing this relay; e.g., my_network_relay. It should match the RELAY_NAME value in .env.
      • <relay-port> is the port number the relay server will listen on. It should match the RELAY_PORT value in .env.
      • db_path and remote_db_path are used internally by the relay to store data. Replace <relay-name> with the same value set for the name parameter. (These can point to any filesystem paths in the relay's container.)
      • If you set tls to true, the relay will enforce TLS communication. The cert_path and key_path should point to a Fabric TLS certificate and key respectively, such as those created using the cryptogen tool.
      • <network-name> is a unique identifier for your local network. You can set it to whatever value you wish.
      • <driver-name> refers to the driver used by this relay to respond to requests. This also refers to one of the drivers's specifications in the drivers section further below. In this code snippet, we have defined one driver. (The names in lines 14 and 22 must match.) In lines 23 and 24 respectively, you should specify the hostname and port for the driver (whose configuration we will handle later).
      • The relays section specifies all foreign relays this relay can connect to. The <foreign-relay-name> value should be a unique ID for a given foreign relay, and this value will be used by your Layer-2 applications when constructing view addresses for data sharing requests. In lines 18 and 19, you should specify the hostname and port for the foreign relay.
      • Enabling TLS:
        • You can make your relay accept TLS connections by specifying a TLS certificate file path and private key file path in cert_path and key_path respectively, and set tls to true.
        • To communicate with a foreign relay using TLS, specify that relay's TLS CA certificate path in tlsca_cert_path (currently only one certificate can be configured) and set tls to true by extending that relay's section as follows (Note: this CA certificate should match the one specified in the cert_path property in the foreign relay's config.toml file):
          [relays]
          [relays.<foreign-relay-name>]
          hostname="<foreign-relay-hostname-or-ip-address>"
          port="<foreign-relay-port>"
          tls=<true|false>
          tlsca_cert_path="<relay-tls-ca-certificate-path>"
        • To communicate with a driver using TLS, specify the driver's TLS CA certificate in tlsca_cert_path (currently only one certificate can be configured) and set tls to true by extending that driver's section as follows (Note: this CA certificate must match the certificate used by the driver using the DRIVER_TLS_CERT_PATH property in its .env configuration file, which we will examine later):
          [drivers]
          [drivers.<driver-name>]
          hostname="<driver-hostname-or-ip-address>"
          port="<driver-port>"
          tls=<true|false>
          tlsca_cert_path="<driver-tls-ca-certificate-path>"
      Notes
      You can specify more than one foreign relay instance in the relays section.
      You can specify more than one driver instance in the drivers section.
    • docker-compose.yaml: This specifies the properties of the relay container. You can use the file in the repository verbatim.

    To start the relay server, navigate to the folder containing the above files and run the following:

    docker-compose up -d relay-server

    Launch Driver

    You need to run one or more drivers through which your relay can interact with your Fabric network. Here we provide instructions to run one Fabric driver running in a Docker container, which is sufficient for data sharing. (Later, we will provide instructions to run multiple drivers, which will be useful both from a failover perspective and to interact with different subsets of your Fabric network, like private data collections.)

    Weaver provides a pre-built image for the Fabric driver. Before launching a container, you just need to customize its configuration for your Fabric network, which you can do by simply creating a folder (let's call it driver_config) and configuring the following files in it:

    • .env: This sets suitable environment variables within the driver container. Copy the .env.template file from the repository and customize it for your purposes, as indicated in the below sample:

      CONNECTION_PROFILE=<path_to_connection_profile>
      DRIVER_CONFIG=./config.json
      RELAY_ENDPOINT=<relay-hostname>:<relay-port>
      NETWORK_NAME=<network-name>
      DRIVER_PORT=<driver-server-port>
      INTEROP_CHAINCODE=<interop-chaincode-name>
      EXTERNAL_NETWORK=<docker-bridge-network>
      TLS_CREDENTIALS_DIR=<dir-with-tls-cert-and-key>
      DOCKER_IMAGE_NAME=ghcr.io/hyperledger-labs/weaver-fabric-driver
      DOCKER_TAG=1.5.6
      DRIVER_TLS=<true|false>
      DRIVER_TLS_CERT_PATH=path_to_tls_cert_pem_for_driver
      DRIVER_TLS_KEY_PATH=path_to_tls_key_pem_for_driver
      RELAY_TLS=<true|false>
      RELAY_TLSCA_CERT_PATH=path_to_tls_ca_cert_pem_for_relay
      • <path_to_connection_profile> should point to the path of a connection profile you generated in the "Pre-Configuration" section. A Fabric driver obtains client credentials from one of the organizations in your network, so pick an organization and point to the right connection profile.
      • The DRIVER_CONFIG variable should point to the config.json (you can name this whatever you wish) specified below.
      • <relay-hostname> should be set to the hostname of the relay server machine and <relay-port> should match the port value in the relay's config.toml (see above).
      • The NETWORK_NAME variable should be a unique ID referring to the Fabric network. It will be used to distinguish container names and wallet paths. (This setting is relevant in situations where a driver is used to query multiple network channels.)
      • The DRIVER_PORT variable should be set to the port this driver will listen on.
      • The INTEROP_CHAINCODE variable should be set to the ID of the Fabric Interop Chaincode installed on your Fabric network channel.
      • The EXTERNAL_NETWORK variable should be set to the name of your Fabric network.
      • Enabling TLS:
        • You can make your driver accept TLS connections by specifying DRIVER_TLS as true and specifying a TLS certificate file path and private key file path in DRIVER_TLS_CERT_PATH and DRIVER_TLS_KEY_PATH respectively. The same certificate should be specified in this driver's definition in the drivers section in the config.toml file of your relay in the tlsca_cert_path property (see the earlier section on relay configuration).
        • To communicate with your network' relay using TLS (i.e., if the relay is TLS-enabled), specify that relay's TLS CA certificate path in RELAY_TLSCA_CERT_PATH (currently only one certificate can be configured) and set RELAY_TLS to true. This CA certificate should match the one specified in the cert_path property in the relay's config.toml file (see the earlier section on relay configuration):
        • You can point to the folder in your host system containing the certificate and key using the TLS_CREDENTIALS_DIR variable. (This folder will be synced to the /fabric-driver/credentials folder in the Fabric Driver container as specified in the docker-compose file.) Make sure you point to the right certificate and key file paths within the container using the DRIVER_TLS_CERT_PATH, DRIVER_TLS_KEY_PATH, and RELAY_TLSCA_CERT_PATH variables.
    • config.json: This contains settings used to connect to a CA of a Fabric network organization and enroll a client. A sample is given below:

      {
      "admin":{
      "name":"admin",
      "secret":"adminpw"
      },
      "relay": {
      "name":"relay",
      "affiliation":"<affiliation>",
      "role": "client",
      "attrs": [{ "name": "relay", "value": "true", "ecert": true }]
      },
      "mspId":"<msp-id>",
      "caUrl":"<ca-service-endpoint>"
      }
      • As in the .env configuration, you should pick an organization for the driver to associate with. The admin section specifies the registrar name and password (this should be familiar to any Fabric network administrator) used to enroll clients. Default values of admin and adminpw are specified above as examples, which you should replace with the right values configured in your network organization's CA.
      • <affiliation> should be what's specified in your organization's Fabric CA server configuration. The default is org1.department1, but you should look up the appropriate value from the CA server's configuration file.
      • <msp-id> should be set to the (or an) MSP ID of the selected organization.
      • <ca-service-endpoint> should be set to the CA server's endpoint. If you launched your CA server as a container from a docker-compose file, this should be set to the container's service name.
      Notes
      If your connection profile already contains specifications for a CA server, you can leave the <ca-service-endpoint> value as a blank.
    • docker-compose.yaml: This specifies the properties of the driver container. You can use the file in the repository verbatim.

    To start the driver, navigate to the folder containing the above files and run the following:

    docker-compose up -d

    Launch IIN Agents

    You need to run one IIN Agent for each organization in the Fabric network channel you are enabling Weaver in. This agent runs a protocol with other organizations' agents and with targeted foreign networks' agents to sync and record foreign networks' memberships to the channel ledger.

    Weaver provides a pre-built image for the IIN Agent. Before launching a container, you just need to customize its configuration for your Fabric network organization, which you can do by simply creating a folder (let's call it iin_agent_config_<orgname>) and configuring the following files in it:

    • config.json: This contains settings used to connect to a Fabric network organization and its CA (part of the organization's MSP). A sample is given below:

      {
      "admin":{
      "name":"admin",
      "secret":"adminpw"
      },
      "agent": {
      "name":"iin-agent",
      "affiliation":"<affiliation>",
      "role": "client",
      "attrs": [{ "name": "iin-agent", "value": "true", "ecert": true }]
      },
      "mspId":"<msp-id>",
      "ordererMspIds": [<list-of-orderer-msp-ids>],
      "ccpPath": "<path-to-connection-profile>",
      "walletPath": "",
      "caUrl": "<ca-service-endpoint>",
      "local": "false"
      }
    • dnsconfig.json: This specifies the list of known IIN agents of your network (i.e., belonging to other organizations) and of foreign networks. A sample DNS configuration file is given below:

      {
      "<securityDomainName1>": {
      "<iin-agent1-name>": {
      "endpoint": "<hostname:port>",
      "tls": <true/false>,
      "tlsCACertPath": "<cacert-path-or-empty-string>"
      },
      "<iin-agent2-name>": {
      "endpoint": "<hostname:port>",
      "tls": <true/false>,
      "tlsCACertPath": "<cacert-path-or-empty-string>"
      }
      },
      "<securityDomainName2>": {
      "<iin-agent1-name>": {
      "endpoint": "<hostname:port>",
      "tls": <true/false>,
      "tlsCACertPath": "<cacert-path-or-empty-string>"
      },
      "<iin-agent2-name>": {
      "endpoint": "<hostname:port>",
      "tls": <true/false>,
      "tlsCACertPath": "<cacert-path-or-empty-string>"
      }
      }
      }
      • Each security domain (i.e., unique ledger, like a Fabric channel) scopes a set of JSON objects, each containing specifications of an IIN Agent. The key (<iin-agent1-name> for example) in each is the IIN Agent's name, which can be the organization's MSP ID (for a Fabric network). The value is another JSON object, containing an endpoint with a hostname and port for the agent.
      • Enabling TLS: To communicate with a given IIN Agent using TLS (i.e., if that agent is TLS-enabled), specify tls as true and that agent's TLS CA certificate path in tlsCACertPath (currently only one certificate can be configured) within the JSON object corresponding to that agent. This CA certificate should match the one specified in that IIN Agent's .env file, whose configuration we will specify later.
    • security-domain-config.json: This config file contains list of security domain defined for the network and its members, i.e. it can be list of organizations or channel name. Sample security domain configuration file:

      {
      "<securityDomainName1>": "<channelName>",
      "<securityDomainName2>": [
      "<Org1MSPId>",
      "<Org2MSPId>"
      ]
      }
    • .env: This sets suitable environment variables within the driver container. Copy the .env.template file from the repository and customize it for your purposes, as indicated in the below sample:

      IIN_AGENT_PORT=<iin-agent-server-port>
      IIN_AGENT_TLS=<true/false>
      IIN_AGENT_TLS_CERT_PATH=<path_to_tls_cert_pem_for_iin_agent>
      IIN_AGENT_TLS_KEY_PATH=<path_to_tls_key_pem_for_iin_agent>
      MEMBER_ID=<org-msp-id>
      SECURITY_DOMAIN=network1
      DLT_TYPE=fabric
      CONFIG_PATH=./config.json
      DNS_CONFIG_PATH=./dnsconfig.json
      SECURITY_DOMAIN_CONFIG_PATH=./security-domain-config.json
      WEAVER_CONTRACT_ID=<name-of-weaver-interop-chaincode-installed>
      SYNC_PERIOD=<repeated_auto_sync_interval>
      AUTO_SYNC=<true/false>
      TLS_CREDENTIALS_DIR=<dir-with-tls-cert-and-key>
      DOCKER_IMAGE_NAME=ghcr.io/hyperledger-labs/weaver-iin-agent
      DOCKER_TAG=<iin-agent-docker-image-version>
      EXTERNAL_NETWORK=<docker-bridge-network>
      • IIN_AGENT_ENDPOINT: The endpoint at which IIN Agent server should listen. E.g.: 0.0.0.0:9500
      • IIN_AGENT_TLS: Set this to true to enable TLS on IIN Agent server
      • IIN_AGENT_TLS_CERT_PATH: Path to TLS certificate if TLS is enabled
      • IIN_AGENT_TLS_KEY_PATH: Path to TLS key if TLS is enabled
      • MEMBER_ID: Member Id for this IIN Agent. For fabric network, it should be the Organization's MSP ID
      • SECURITY_DOMAIN: Security domain to which this IIN Agent belongs
      • DLT_TYPE: To indicate the type of DLT for which this IIN Agent is running. E.g. fabric
      • CONFIG_PATH: Path to ledger specific config file (explained in next subsection)
      • DNS_CONFIG_PATH: Path to DNS config file explained in previous sub sections
      • SECURITY_DOMAIN_CONFIG_PATH: Path to security domain config file explained in previous sub sections
      • WEAVER_CONTRACT_ID: Contract ID for DLT specific Weaver interoperation module installed on network
      • SYNC_PERIOD: Period at which auto synchronization of memberships from other security domains should happen
      • AUTO_SYNC: Set this to true to enable auto synchronization of memberships from other security domains
      • DOCKER_TAG: Set this to the desired version of the Weaver IIN Agent docker image
      • EXTERNAL_NETWORK: Set to the network name of your Fabric network.
      • Enabling TLS:
        • Make your IIN Agent accept TLS connections by specifying IIN_AGENT_TLS as true and specifying a TLS certificate file path and private key file path in IIN_AGENT_TLS_CERT_PATH and IIN_AGENT_TLS_KEY_PATH respectively. The same certificate should be specified in this agent's JSON object in another agent's dnsconfig.json file under the appropriate security domain and IIN Agent ID scope.
        • You can point to the folder in your host system containing the certificate and key using the TLS_CREDENTIALS_DIR variable. (This folder will be synced to the /opt/iinagent/credentials folder in the IIN Agent container as specified in the docker-compose file.) Make sure you point to the right certificate and key file paths within the container using the IIN_AGENT_TLS_CERT_PATH and IIN_AGENT_TLS_KEY_PATH variables respectively.
    • docker-compose.yaml: This specifies the properties of the IIN agent container. You can use the file in the repository verbatim.

    Now to start the IIN agent, navigate to the folder containing the above files and run the following:

    docker-compose up -d

    Repeat the above steps to launch an IIN Agent for every other organization on your channnel, i.e., create similar configuration files in an organization-specific folder. Make sure you:

    • Update the organization names in every relevant location in the config.json.
    • Update IIN_AGENT_ENDPOINT and MEMBER_ID in the .env.

    Ledger Initialization

    To prepare your network for interoperation with a foreign network, you need to record the following to your network channel through the Fabric Interoperation Chaincode:

    • Access control policies: +Similarly lockInfoSerializedProto64 is a serialized protobuf in Base64 encoded string of AssetLock protobuf structure. Check the structure definition here.

    • LockFungibleAsset
      func (s *SmartContract) LockFungibleAsset(ctx contractapi.TransactionContextInterface, fungibleAssetExchangeAgreementSerializedProto64 string, lockInfoSerializedProto64 string) (string, error) {
      // Add some safety checks before calling LockFungibleAsset from library
      // Caller of this chaincode is supposed to be the Locker and the owner of the asset being locked.
      contractId, err := s.amc.LockFungibleAsset(ctx, "", fungibleAssetExchangeAgreementSerializedProto64, lockInfoSerializedProto64)
      if err != nil {
      return "", logThenErrorf(err.Error())
      }
      // Post proccessing of asset after LockFungibleAsset called like reduce the amount of tokens owned by the locker, or mark it locked so that it can't be spent.
      ...
      return contractId, nil
      }
      Here fungibleAssetExchangeAgreementSerializedProto64 is a serialized protobuf in Base64 encoded string of FungibleAssetExchangeAgreement protobuf structure, and can be used to extract details like asset quantity, type of asset and recipient. Check the structure definition here.
    • IsAssetLockedQueryUsingContractId
      func (s *SmartContract) IsAssetLockedQueryUsingContractId(ctx contractapi.TransactionContextInterface, contractId string) (bool, error) {
      return s.amc.IsAssetLockedQueryUsingContractId(ctx, contractId)
      }
    • ClaimAssetUsingContractId
      func (s *SmartContract) ClaimAssetUsingContractId(ctx contractapi.TransactionContextInterface, contractId, claimInfoSerializedProto64 string) (bool, error) {
      // Note recipient will be the caller for this function
      claimed := false
      err := s.amc.ClaimAssetUsingContractId(ctx, contractId, claimInfoSerializedProto64)
      if err != nil {
      return false, logThenErrorf(err.Error())
      }
      claimed = true
      // After the above function call, update the owner of the asset with recipeint/caller
      ...
      return claimed, nil
      }
    • UnlockAssetUsingContractId
      func (s *SmartContract) UnlockAssetUsingContractId(ctx contractapi.TransactionContextInterface, contractId string) (bool, error) {
      unlocked := false
      err := s.amc.UnlockAssetUsingContractId(ctx, contractId)
      if err != nil {
      return false, logThenErrorf(err.Error())
      }
      unlocked = true
      ...
      return true, nil
      }
      In addition, you should add the following extra utility functions to enable client applications to query and discover asset state:
    • func (s *SmartContract) GetHTLCHashByContractId(ctx contractapi.TransactionContextInterface, contractId string) (string, error) {
      return s.amc.GetHTLCHashByContractId(ctx, contractId)
      }
      func (s *SmartContract) GetHTLCHashPreImageByContractId(ctx contractapi.TransactionContextInterface, contractId string) (string, error) {
      return s.amc.GetHTLCHashPreImageByContractId(ctx, contractId)
      }

    For Asset Transfer

    TBD

    Client (or Layer-2) Applications

    Weaver provides an SDK to help you adapt your applications to exercise the various interoperability modes. These are called out as Interoperation Helpers in the network model illustrated earlier. Your Fabric network's Layer-2 applications have business logic embedded in them that, broadly speaking, accept data from users and other external agents and invoke smart contracts using library functions and APIs offered by the Fabric SDK. When you use Weaver for network interoperability, other options can be added, namely requesting and accepting data from foreign networks, and triggering locks and claims for atomic exchanges spanning two networks. Weaver's Fabric Interoperation SDK (currently implemented both in Node.js and Golang) offers a library to exercise these options, supplementing the Fabric SDK. But this will involve modification to the application's business logic.

    Notes
    The instructions here apply to applications implemented in Node.js (JavaScript and TypeScript), using the Weaver Node SDK for Fabric. We will add instructions later for Go applications using the Weaver Go SDK for Fabric.

    To import and use the Weaver SDK, you need to add the following dependency to the dependencies section of your Node.js application's package.json file:

    "@hyperledger-labs/weaver-fabric-interop-sdk": "latest",

    (Instead of latest, you can select a particular version from the package website.)

    Before you run npm install to fetch the dependencies, make sure you create a personal access token with read:packages access in GitHub. Create an .npmrc file in the same folder as the package.json with the following contents:

    registry=https://npm.pkg.github.com/hyperledger-labs
    //npm.pkg.github.com/:_authToken=<personal-access-token>

    Replace <personal-access-token> in this file with the token you created in GitHub.

    First, you must incorporate some code for Weaver's network administration, specifically identity management. Then, using the given sample code and examples, you can adapt your applications for each interoperability mode.

    For Identity Administration

    A Fabric network channel must share its security domain (or membership) configuration, i.e., its organizations' CA certificate chains, with a foreign network with which it seeks to interoperate. Each organization must run an IIN Agent for this purpose. The set of IIN Agents, a.k.a. the local membership must be recorded in the ledger before those agents can be operational. In your Fabric network application suite, one or more applications will exist for network administration; the following code snippet should be added in at least one of those applications to record local membership as a prerequisite for interoperability:

    import { MembershipManager } from '@hyperledger-labs/weaver-fabric-interop-sdk'

    const gateway = <get-fabric-network-gateway-instance>

    try {
    const response = await MembershipManager.createLocalMembership(
    gateway,
    members, // list of all organization MSPIDs that are part of the channel
    securityDomain, // name of the local network's security domain
    channelName, // Channel Name
    contractName // Fabric Interoperation Chaincode installation ID on the channel
    )
    } catch (e) {
    // On error try updating local membership
    const response = await MembershipManager.updateLocalMembership(gateway, members, securityDomain, channelName, contractName)
    }
    • <get-fabric-network-gateway-instance> should be replaced with standard (boilerplate) code to get a handle to your network's gateway. This requires a special wallet identity, namely one with a network-admin attribute indicating that the caller is a trusted network administrator who is authorized to record local memberships on the channelName channel.
    • members must consist of the list of organizational MSP IDs for the channelName channel.

    For Data Sharing

    Consider a scenario inspired by the global trade use case where a letter of credit (L/C) management business logic (chaincode letterofcreditcc) installed in the tradefinancechannel channel in the trade-finance-network network supports a transaction RecordBillOfLading, which validates and records a bill of lading (B/L) supplied by a user via a UI. Weaver will enable such a B/L to be fetched from a different network trade-logistics-network by querying the function GetBillOfLading exposed by the chaincode shipmentcc installed in the tradelogisticschannel channel.

    (In preparation, a suitable access control policy must be recorded on tradelogisticschannel in trade-logistics-network, and a suitable verification policy must be recorded on tradefinancechannel in trade-finance-network. We will see how to do this in the "Startup and Boostrap" section later.)

    You will need to insert some code in the Layer-2 application that accepts a B/L and submits a RecordBillOfLading transaction in trade-finance-network. (No code changes need to be made in any application in the other network.) The logic to accept a B/L should be replaced (or you can simply add an alternative) by a call to the interopFlow function offered by the weaver-fabric-interop-sdk library (there's an equivalent library in Golang too). The following code sample illustrates this (the Golang equivalent is left to the reader):

    const ihelper = require('@hyperledger-labs/weaver-fabric-interop-sdk').InteroperableHelper;
    const interopcc = <handle-to-fabric-interop-chaincode>; // Use Fabric SDK functions: (new Gateway()).getNetwork(...).getContract(<fabric-interop-chaincode-id>)
    const keyCert = await ihelper.getKeyAndCertForRemoteRequestbyUserName(<wallet>, <user-id>); // Read key and certificate for <user-id> from wallet (get handle using Fabric SDK Wallets API)
    // Collect view addresses for relay requests in the context of an interop flow
    interopJSONs.push({
    NetworkID: 'trade-logistics-network',
    RemoteEndpoint: <trade-logistics-relay-url[:<port>], // Replace with remote network's relay address and port
    ChannelID: 'tradelogisticschannel',
    ChaincodeID: 'shipmentcc',
    ChaincodeFunc: 'GetBillOfLading',
    ccArgs: [ <shipment-reference> ], // Replace <shipment-reference> with a value that can be used to look up the right B/L
    Sign: true
    });
    const indices = [ 1 ];
    // Trigger an end-to-end interoperation (data sharing) protocol
    // Send a request to a foreign network via your relay, receive the response and submit a transaction to a local chaincode
    const flowResponse = await ihelper.interopFlow(
    interopcc,
    'trade-finance-network',
    {
    channel: 'tradefinancechannel',
    contractName: 'letterofcreditcc',
    ccFunc: 'RecordBillOfLading',
    ccArgs: [ <shipment-reference> , '' ]
    },
    <org-msp-id>, // Replace with this Layer-2 application's organization's MSP ID
    <trade-finance-relay-url>[:<port>], // Replace with local network's relay address and port
    indices,
    interopJSONs,
    keyCert,
    <endorsingOrgs>, // List of orgs to submit transaction to local i.e. trade logistics network
    false, // Boolean flag to indicate whether return without submit transaction to local i.e. trade logistics network
    false, // Boolean flag indicating no TLS communication with relay
    [], // Keep it empty when TLS is disabled
    <confidential-flag>, // Boolean flag to indicate whether to use to end-to-end encryption
    );
    // List of errors to check for
    if (!flowResponse.views || flowResponse.views.length === 0 || !flowResponse.result || flowResponse.views.length !== argIndices.length) {
    throw <error>;
    }

    Let us understand this code snippet better. The structure in lines 20-25 specifies the local chaincode transaction that is to be triggered after remote data (view) has been requested and obtained via relays. The function RecordBillOfLading expects two arguments as specified in line 24: the first is the common shipment reference that is used by the letter of credit in trade-finance-network and the bill of lading in trade-logistics-network, and the second is the bill of lading contents. When the interopFlow function is called, this argument is left blank because it is supposed to be filled with contents obtained from a view request. The array list indices, which is passed as an argument to interopFlow therefore contains the index value 1 (line 14), indicating which argument ought to be substituted with view data. The interopJSONs array correspondingly contains a list of view addresses that are to be supplied to the relay. The <confidential-flag> if set to true will enable end-to-end confidentiality, i.e. payload will be encrypted from trade-finance-network's Weaver chaincode, and will be decrypted in SDK (i.e. Layer-2 client application) at trade-logistics-network, but relays and drivers in between will not be able to see the payload. By default this flag is set to false.

    Notes
    A local chaincode invocation may require multiple view requests to different networks, which is why indices and interopJSONs are arrays; they therefore must have the same lengths.

    The rest of the code ought to be self-explanatory. Values are hardcoded for explanation purposes, but you can refactor the above code by reading view addresses corresponding to chaincode invocations from a configuration file.

    Enabling TLS: +By default, the TLS is set to false in interopFlow, i.e. disabled. But if you want to enable TLS, can pass additional parameters to the interopFlow function as follows:

    const flowResponse = await ihelper.interopFlow(
    interopcc,
    'trade-finance-network',
    {
    channel: 'tradefinancechannel',
    contractName: 'letterofcreditcc',
    ccFunc: 'RecordBillOfLading',
    ccArgs: [ <shipment-reference> , '' ]
    },
    <org-msp-id>, // Replace with this Layer-2 application's organization's MSP ID
    <trade-finance-relay-url>[:<port>], // Replace with local network's relay address and port
    indices,
    interopJSONs,
    keyCert,
    <endorsingOrgs>, // List of orgs to submit transaction to in trade logistics network
    false, // Boolean flag to indicate whether return without submit transaction to local i.e. trade logistics network
    true, // Boolean indication TLS is enabled.
    <tlsCACertPathsForRelay>, // list of CA certificate file paths
    );

    For Asset Exchange

    Let's take an example of asset exchange between Alice and Bob, where Bob wants to purchase an asset of type Gold with id A123 from Alice in BondNetwork in exchange for 200 tokens of type CBDC01 in TokenNetwork.

    Alice needs to select a secret text (say s), and hash it (say H) using say SHA512, which will be used to lock her asset in BondNetwork. At the place in your application where an asset exchange is to be initiated, you need to add code to enable Alice to lock the non-fungible asset using hash H and timeout duration of 10 minutes:

    import { AssetManager, HashFunctions } from '@hyperledger-labs/weaver-fabric-interop-sdk'

    const hash = HashFunctions.SHA512(); // Create Hash instance of one of the supported Hash Algorithm
    hash.setSerializedHashBase64(H); // Set the Hash
    const timeout = Math.floor(Date.now()/1000) + 10 * 60;

    const bondContract = <handle-to-fabric-application-chaincode-in-bond-network>;

    const result = await AssetManager.createHTLC(
    bondContract,
    "Gold", // Asset ID
    "A123", // Asset Type
    bobCertificate, // Certificate of Bob in Bond Network
    hash, // Hash generated by Alice using her secret s
    timeout, // Timeout in epoch for 10 mins from current time
    null // Optional callback function to be called after the asset is locked
    );
    let bondContractId = result.result; // Unique ID for this asset exchange contract in BondNetwork
    Notes
    Note that 'Alice' and 'Bob' and the asset specifics can be parameterized in the above code, which can be reused for arbitrary asset exchange scenarios in your business workflow. The above code is only meant to be a sample.

    Now Bob will lock his tokens in TokenNetwork. To lock the fungible asset using same hash H and timeout of 5 minutes (half the timeout duration used by Alice in BondNetwork), add the following code snippet in your application:

    const hash = HashFunctions.SHA512();    // Create Hash instance of one of the supported Hash Algorithm
    hash.setSerializedHashBase64(H); // Set the Hash
    const timeout = Math.floor(Date.now()/1000) + 5 * 60;

    const tokenContract = <handle-to-fabric-application-chaincode-in-token-network>;
    const result = await AssetManager.createFungibleHTLC(
    tokenContract,
    "CBDC01", // Token ID
    200, // Token Quantity
    aliceCertificate, // Certificate of Alice in Token Network
    hash, // Hash H used by Alice in Bond Network
    timeout, // Timeout in epoch for 5 mins from current time
    null // Optional callback function to be called after the asset is locked
    )
    const tokenContractId = result.result // Unique ID for this asset exchange contract in TokenNetwork

    Wherever the lock status of the asset is required in your application, you should insert a query function call as follows:

    const contract = <handle-to-fabric-application-chaincode>;
    // Below contractId is the ID obtained during lock
    const isLocked = AssetManager.isAssetLockedInHTLCqueryUsingContractId(contract, contractId)

    Wherever a participant (either 'Alice' or 'Bob' in this example) needs to claim a locked asset using the secret text (pre-image of hash) s in your application, insert the following code snippet (Note: typically one would insert this in event callback functions or in functions that are polling the ledger to monitor whether the asset is locked in favor of a given recipient):

    const hash = HashFunctions.SHA512();    // Create Hash instance of one of the supported Hash Algorithm
    hash.setPreimage(s) // Set Pre-Image s
    const contract = <handle-to-fabric-application-chaincode>;
    const claimSuccess = await AssetManager.claimAssetInHTLCusingContractId(
    contract,
    contractId, // contractId obtained during lock
    hash
    )
    // return value claimSuccess is boolean indicating success or failure of claim

    Wherever the asset must be unlocked in your application (typically, an event callback function triggered upon the expiration of the time lock), insert the following code snippet:

    const contract = <handle-to-fabric-application-chaincode>;
    const reclaimSuccess = await AssetManager.reclaimAssetInHTLCusingContractId(
    contract,
    contractId // contractId obtained during lock
    )
    // return value 'reclaimSuccess' is a boolean indicating success or failure of reclaim

    For Asset Transfer

    TBD

    Pre-Configuration Phase

    Typically, pre-configuration in a Fabric network involves generating (after creating the channel specifications and policies):

    • Channel artifacts: orderer genesis block, channel transaction, and anchor peer configurations from a configtx.yaml file (using Fabric's configtxgen tool)
    • Crypto artifacts: keys and certificates for CAs, peers, orderers, and clients from a crypto-config.yaml file (using Fabric's cryptogen tool)
    • Connection profiles: one for every network organization, which will be used by the organization's Layer-2 applications to connect to the network's peers and CAs

    No changes are required in this process to support any of the three interoperation modes using Weaver. The connection profiles generated above will be used by certain Weaver modules, as we will see later. The only additional step required is to generate special wallet identities for the following:

    • Network administrator: one or more identities containing the network-admin attribute; only a user/application possessing this identity may record special (privileged) information regarding memberships and policies on the channel.
    • Fabric Driver: one or more identities (for each deployed driver) containing the relay attribute; only a relay-driver combination possessing this identity may run data sharing-related operations on the deployed Fabric Interoperation Chaincode.
    • IIN Agent: one or more identities (for each deployed agent) containing the iin-agent attribute: only an agent may submit foreign network membership records to the Fabric Interoperation Chaincode.

    Later we will see how the components possessing these identities are deployed.

    Startup and Bootstrap Phase

    After writing application code and creating the network configuration files, the components of a Fabric network (peers, CAs, and ordering service) are launched. In this section, we will list the additional tasks you, as a Fabric network administrator, must perform to make your network ready to interoperate.

    To launch a network using containerized components, you will typically use a Docker Compose or Kubernetes configuration file. No modifications are needed to the peers', orderers', and CAs' configurations. Sample instructions are given below for networks launched using Docker Compose; we leave it to the reader to adapt these to their custom launch processes.

    For Asset Exchange

    The asset exchange mode currently requires only the Fabric Interoperation Chaincode module from Weaver. Relays, drivers, and IIN agents, are not necessary. In the future, we expect to make the asset exchange protocol moe automated using these components; the instructions here will be updated appropriately.

    Install the Fabric Interoperation Chaincode

    Install the Fabric Interoperation Chaincode in the relevant channel(s), i.e., those that run chaincodes that will be involved in asset exchanges. This is a Go module that can be fetched from github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/contracts/interop. Following that, you an install it using the appropriate Fabric process: in Fabric v2, you will need to package, install, approve, and commit this module on the selected channels in your network.

    For Data Sharing or Asset Transfer

    Both the data sharing and asset transfer modes require the Fabric Interoperation Chaincode, relays, drivers, and IIN agents, to be deployed.

    Install the Fabric Interoperation Chaincode

    Install the Fabric Interoperation Chaincode in the relevant channel(s), i.e., those that run chaincodess that will be involved in data sharing (and asset transfers, which require multiple data shares). This is a Go module that can be fetched from github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/contracts/interop. Following that, you an install it using the appropriate Fabric process: in Fabric v2, you will need to package, install, approve, and commit this module on the selected channels in your network.

    Launch Relay

    You need to run one or more relays for network-to-network communication. Here we provide instructions to run one relay running in a Docker container, which is sufficient for data sharing. (Later, we will provide instructions to run multiple relays, which will be useful from a failover perspective.)

    Weaver provides a pre-built image for the relay. Before launching a container, you just need to customize its configuration for your Fabric network, which you can do by simply creating a folder (let's call it relay_config) and configuring the following files in it:

    • .env: This sets suitable environment variables within the relay container. Copy the .env.template file from the repository and customize it for your purposes, as indicated in the below sample:

      PATH_TO_CONFIG=./config.toml
      RELAY_NAME=<"name" in config.toml>
      RELAY_PORT=<relay-server-port/"port" in config.toml>
      EXTERNAL_NETWORK=<docker-bridge-network>
      DOCKER_REGISTRY=ghcr.io/hyperledger-labs
      DOCKER_IMAGE_NAME=weaver-relay
      DOCKER_TAG=1.5.4
      • The PATH_TO_CONFIG variable should point to the properties file typically named config.toml (you can name this whatever you wish). See further below for instructions to write this file.
      • The RELAY_NAME variable specifies a unique name for this relay. It should match what's specified in the config.toml (more on that below).
      • The RELAY_PORT variable specifies the port this relay server will listen on. It should match what's specified in the config.toml (more on that below).
      • The EXTERNAL_NETWORK variable should be set to the name of your Fabric network.
      • The DOCKER_* variables are used to specify the image on which the container will be built. Make sure you set DOCKER_TAG to the latest version you see on GitHub.

      For more details, see the Relay Docker README ("Relay Server Image" and "Running With Docker Compose" sections).

    • config.toml: This is the file specified in the PATH_TO_CONFIG variable in the .env. It specifies properties of this relay and the driver(s) it supports. A sample is given below:

      name=<relay-name>
      port=<relay-port>
      host="0.0.0.0"
      db_path="db/<relay-name>/requests"
      remote_db_path="db/<relay-name>/remote_request"

      # FOR TLS
      cert_path="credentials/fabric_cert.pem"
      key_path="credentials/fabric_key"
      tls=<true/false>

      [networks]
      [networks.<network-name>]
      network="<driver-name>"

      [relays]
      [relays.<foreign-relay-name>]
      hostname="<foreign-relay-hostname-or-ip-address>"
      port="<foreign-relay-port>"

      [drivers]
      [drivers.<driver-name>]
      hostname="<driver-hostname-or-ip-address>"
      port="<driver-port>"
      • <relay-name> should be a unique ID representing this relay; e.g., my_network_relay. It should match the RELAY_NAME value in .env.
      • <relay-port> is the port number the relay server will listen on. It should match the RELAY_PORT value in .env.
      • db_path and remote_db_path are used internally by the relay to store data. Replace <relay-name> with the same value set for the name parameter. (These can point to any filesystem paths in the relay's container.)
      • If you set tls to true, the relay will enforce TLS communication. The cert_path and key_path should point to a Fabric TLS certificate and key respectively, such as those created using the cryptogen tool.
      • <network-name> is a unique identifier for your local network. You can set it to whatever value you wish.
      • <driver-name> refers to the driver used by this relay to respond to requests. This also refers to one of the drivers's specifications in the drivers section further below. In this code snippet, we have defined one driver. (The names in lines 14 and 22 must match.) In lines 23 and 24 respectively, you should specify the hostname and port for the driver (whose configuration we will handle later).
      • The relays section specifies all foreign relays this relay can connect to. The <foreign-relay-name> value should be a unique ID for a given foreign relay, and this value will be used by your Layer-2 applications when constructing view addresses for data sharing requests. In lines 18 and 19, you should specify the hostname and port for the foreign relay.
      • Enabling TLS:
        • You can make your relay accept TLS connections by specifying a TLS certificate file path and private key file path in cert_path and key_path respectively, and set tls to true.
        • To communicate with a foreign relay using TLS, specify that relay's TLS CA certificate path in tlsca_cert_path (currently only one certificate can be configured) and set tls to true by extending that relay's section as follows (Note: this CA certificate should match the one specified in the cert_path property in the foreign relay's config.toml file):
          [relays]
          [relays.<foreign-relay-name>]
          hostname="<foreign-relay-hostname-or-ip-address>"
          port="<foreign-relay-port>"
          tls=<true|false>
          tlsca_cert_path="<relay-tls-ca-certificate-path>"
        • To communicate with a driver using TLS, specify the driver's TLS CA certificate in tlsca_cert_path (currently only one certificate can be configured) and set tls to true by extending that driver's section as follows (Note: this CA certificate must match the certificate used by the driver using the DRIVER_TLS_CERT_PATH property in its .env configuration file, which we will examine later):
          [drivers]
          [drivers.<driver-name>]
          hostname="<driver-hostname-or-ip-address>"
          port="<driver-port>"
          tls=<true|false>
          tlsca_cert_path="<driver-tls-ca-certificate-path>"
      Notes
      You can specify more than one foreign relay instance in the relays section.
      You can specify more than one driver instance in the drivers section.
    • docker-compose.yaml: This specifies the properties of the relay container. You can use the file in the repository verbatim.

    To start the relay server, navigate to the folder containing the above files and run the following:

    docker-compose up -d relay-server

    Launch Driver

    You need to run one or more drivers through which your relay can interact with your Fabric network. Here we provide instructions to run one Fabric driver running in a Docker container, which is sufficient for data sharing. (Later, we will provide instructions to run multiple drivers, which will be useful both from a failover perspective and to interact with different subsets of your Fabric network, like private data collections.)

    Weaver provides a pre-built image for the Fabric driver. Before launching a container, you just need to customize its configuration for your Fabric network, which you can do by simply creating a folder (let's call it driver_config) and configuring the following files in it:

    • .env: This sets suitable environment variables within the driver container. Copy the .env.docker.template file from the repository and customize it for your purposes, as indicated in the below sample:

      CONNECTION_PROFILE=<path_to_connection_profile>
      DRIVER_CONFIG=./config.json
      RELAY_ENDPOINT=<relay-hostname>:<relay-port>
      NETWORK_NAME=<network-name>
      DRIVER_PORT=<driver-server-port>
      INTEROP_CHAINCODE=<interop-chaincode-name>
      EXTERNAL_NETWORK=<docker-bridge-network>
      TLS_CREDENTIALS_DIR=<dir-with-tls-cert-and-key>
      DOCKER_IMAGE_NAME=ghcr.io/hyperledger-labs/weaver-fabric-driver
      DOCKER_TAG=1.5.6
      DRIVER_TLS=<true|false>
      DRIVER_TLS_CERT_PATH=path_to_tls_cert_pem_for_driver
      DRIVER_TLS_KEY_PATH=path_to_tls_key_pem_for_driver
      RELAY_TLS=<true|false>
      RELAY_TLSCA_CERT_PATH=path_to_tls_ca_cert_pem_for_relay
      • <path_to_connection_profile> should point to the path of a connection profile you generated in the "Pre-Configuration" section. A Fabric driver obtains client credentials from one of the organizations in your network, so pick an organization and point to the right connection profile.
      • The DRIVER_CONFIG variable should point to the config.json (you can name this whatever you wish) specified below.
      • <relay-hostname> should be set to the hostname of the relay server machine and <relay-port> should match the port value in the relay's config.toml (see above).
      • The NETWORK_NAME variable should be a unique ID referring to the Fabric network. It will be used to distinguish container names and wallet paths. (This setting is relevant in situations where a driver is used to query multiple network channels.)
      • The DRIVER_PORT variable should be set to the port this driver will listen on.
      • The INTEROP_CHAINCODE variable should be set to the ID of the Fabric Interop Chaincode installed on your Fabric network channel.
      • The EXTERNAL_NETWORK variable should be set to the name of your Fabric network.
      • Enabling TLS:
        • You can make your driver accept TLS connections by specifying DRIVER_TLS as true and specifying a TLS certificate file path and private key file path in DRIVER_TLS_CERT_PATH and DRIVER_TLS_KEY_PATH respectively. The same certificate should be specified in this driver's definition in the drivers section in the config.toml file of your relay in the tlsca_cert_path property (see the earlier section on relay configuration).
        • To communicate with your network' relay using TLS (i.e., if the relay is TLS-enabled), specify that relay's TLS CA certificate path in RELAY_TLSCA_CERT_PATH (currently only one certificate can be configured) and set RELAY_TLS to true. This CA certificate should match the one specified in the cert_path property in the relay's config.toml file (see the earlier section on relay configuration):
        • You can point to the folder in your host system containing the certificate and key using the TLS_CREDENTIALS_DIR variable. (This folder will be synced to the /fabric-driver/credentials folder in the Fabric Driver container as specified in the docker-compose file.) Make sure you point to the right certificate and key file paths within the container using the DRIVER_TLS_CERT_PATH, DRIVER_TLS_KEY_PATH, and RELAY_TLSCA_CERT_PATH variables.
    • config.json: This contains settings used to connect to a CA of a Fabric network organization and enroll a client. A sample is given below:

      {
      "admin":{
      "name":"admin",
      "secret":"adminpw"
      },
      "relay": {
      "name":"relay",
      "affiliation":"<affiliation>",
      "role": "client",
      "attrs": [{ "name": "relay", "value": "true", "ecert": true }]
      },
      "mspId":"<msp-id>",
      "caUrl":"<ca-service-endpoint>"
      }
      • As in the .env configuration, you should pick an organization for the driver to associate with. The admin section specifies the registrar name and password (this should be familiar to any Fabric network administrator) used to enroll clients. Default values of admin and adminpw are specified above as examples, which you should replace with the right values configured in your network organization's CA.
      • <affiliation> should be what's specified in your organization's Fabric CA server configuration. The default is org1.department1, but you should look up the appropriate value from the CA server's configuration file.
      • <msp-id> should be set to the (or an) MSP ID of the selected organization.
      • <ca-service-endpoint> should be set to the CA server's endpoint. If you launched your CA server as a container from a docker-compose file, this should be set to the container's service name.
      Notes
      If your connection profile already contains specifications for a CA server, you can leave the <ca-service-endpoint> value as a blank.
    • docker-compose.yaml: This specifies the properties of the driver container. You can use the file in the repository verbatim.

    To start the driver, navigate to the folder containing the above files and run the following:

    docker-compose up -d

    Launch IIN Agents

    You need to run one IIN Agent for each organization in the Fabric network channel you are enabling Weaver in. This agent runs a protocol with other organizations' agents and with targeted foreign networks' agents to sync and record foreign networks' memberships to the channel ledger.

    Weaver provides a pre-built image for the IIN Agent. Before launching a container, you just need to customize its configuration for your Fabric network organization, which you can do by simply creating a folder (let's call it iin_agent_config_<orgname>) and configuring the following files in it:

    • config.json: This contains settings used to connect to a Fabric network organization and its CA (part of the organization's MSP). A sample is given below:

      {
      "admin":{
      "name":"admin",
      "secret":"adminpw"
      },
      "agent": {
      "name":"iin-agent",
      "affiliation":"<affiliation>",
      "role": "client",
      "attrs": [{ "name": "iin-agent", "value": "true", "ecert": true }]
      },
      "mspId":"<msp-id>",
      "ordererMspIds": [<list-of-orderer-msp-ids>],
      "ccpPath": "<path-to-connection-profile>",
      "walletPath": "",
      "caUrl": "<ca-service-endpoint>",
      "local": "false"
      }
    • dnsconfig.json: This specifies the list of known IIN agents of your network (i.e., belonging to other organizations) and of foreign networks. A sample DNS configuration file is given below:

      {
      "<securityDomainName1>": {
      "<iin-agent1-name>": {
      "endpoint": "<hostname:port>",
      "tls": <true/false>,
      "tlsCACertPath": "<cacert-path-or-empty-string>"
      },
      "<iin-agent2-name>": {
      "endpoint": "<hostname:port>",
      "tls": <true/false>,
      "tlsCACertPath": "<cacert-path-or-empty-string>"
      }
      },
      "<securityDomainName2>": {
      "<iin-agent1-name>": {
      "endpoint": "<hostname:port>",
      "tls": <true/false>,
      "tlsCACertPath": "<cacert-path-or-empty-string>"
      },
      "<iin-agent2-name>": {
      "endpoint": "<hostname:port>",
      "tls": <true/false>,
      "tlsCACertPath": "<cacert-path-or-empty-string>"
      }
      }
      }
      • Each security domain (i.e., unique ledger, like a Fabric channel) scopes a set of JSON objects, each containing specifications of an IIN Agent. The key (<iin-agent1-name> for example) in each is the IIN Agent's name, which can be the organization's MSP ID (for a Fabric network). The value is another JSON object, containing an endpoint with a hostname and port for the agent.
      • Enabling TLS: To communicate with a given IIN Agent using TLS (i.e., if that agent is TLS-enabled), specify tls as true and that agent's TLS CA certificate path in tlsCACertPath (currently only one certificate can be configured) within the JSON object corresponding to that agent. This CA certificate should match the one specified in that IIN Agent's .env file, whose configuration we will specify later.
    • security-domain-config.json: This config file contains list of security domain defined for the network and its members, i.e. it can be list of organizations or channel name. Sample security domain configuration file:

      {
      "<securityDomainName1>": "<channelName>",
      "<securityDomainName2>": [
      "<Org1MSPId>",
      "<Org2MSPId>"
      ]
      }
    • .env: This sets suitable environment variables within the driver container. Copy the .env.template file from the repository and customize it for your purposes, as indicated in the below sample:

      IIN_AGENT_PORT=<iin-agent-server-port>
      IIN_AGENT_TLS=<true/false>
      IIN_AGENT_TLS_CERT_PATH=<path_to_tls_cert_pem_for_iin_agent>
      IIN_AGENT_TLS_KEY_PATH=<path_to_tls_key_pem_for_iin_agent>
      MEMBER_ID=<org-msp-id>
      SECURITY_DOMAIN=network1
      DLT_TYPE=fabric
      CONFIG_PATH=./config.json
      DNS_CONFIG_PATH=./dnsconfig.json
      SECURITY_DOMAIN_CONFIG_PATH=./security-domain-config.json
      WEAVER_CONTRACT_ID=<name-of-weaver-interop-chaincode-installed>
      SYNC_PERIOD=<repeated_auto_sync_interval>
      AUTO_SYNC=<true/false>
      TLS_CREDENTIALS_DIR=<dir-with-tls-cert-and-key>
      DOCKER_IMAGE_NAME=ghcr.io/hyperledger-labs/weaver-iin-agent
      DOCKER_TAG=<iin-agent-docker-image-version>
      EXTERNAL_NETWORK=<docker-bridge-network>
      • IIN_AGENT_ENDPOINT: The endpoint at which IIN Agent server should listen. E.g.: 0.0.0.0:9500
      • IIN_AGENT_TLS: Set this to true to enable TLS on IIN Agent server
      • IIN_AGENT_TLS_CERT_PATH: Path to TLS certificate if TLS is enabled
      • IIN_AGENT_TLS_KEY_PATH: Path to TLS key if TLS is enabled
      • MEMBER_ID: Member Id for this IIN Agent. For fabric network, it should be the Organization's MSP ID
      • SECURITY_DOMAIN: Security domain to which this IIN Agent belongs
      • DLT_TYPE: To indicate the type of DLT for which this IIN Agent is running. E.g. fabric
      • CONFIG_PATH: Path to ledger specific config file (explained in next subsection)
      • DNS_CONFIG_PATH: Path to DNS config file explained in previous sub sections
      • SECURITY_DOMAIN_CONFIG_PATH: Path to security domain config file explained in previous sub sections
      • WEAVER_CONTRACT_ID: Contract ID for DLT specific Weaver interoperation module installed on network
      • SYNC_PERIOD: Period at which auto synchronization of memberships from other security domains should happen
      • AUTO_SYNC: Set this to true to enable auto synchronization of memberships from other security domains
      • DOCKER_TAG: Set this to the desired version of the Weaver IIN Agent docker image
      • EXTERNAL_NETWORK: Set to the network name of your Fabric network.
      • Enabling TLS:
        • Make your IIN Agent accept TLS connections by specifying IIN_AGENT_TLS as true and specifying a TLS certificate file path and private key file path in IIN_AGENT_TLS_CERT_PATH and IIN_AGENT_TLS_KEY_PATH respectively. The same certificate should be specified in this agent's JSON object in another agent's dnsconfig.json file under the appropriate security domain and IIN Agent ID scope.
        • You can point to the folder in your host system containing the certificate and key using the TLS_CREDENTIALS_DIR variable. (This folder will be synced to the /opt/iinagent/credentials folder in the IIN Agent container as specified in the docker-compose file.) Make sure you point to the right certificate and key file paths within the container using the IIN_AGENT_TLS_CERT_PATH and IIN_AGENT_TLS_KEY_PATH variables respectively.
    • docker-compose.yaml: This specifies the properties of the IIN agent container. You can use the file in the repository verbatim.

    Now to start the IIN agent, navigate to the folder containing the above files and run the following:

    docker-compose up -d

    Repeat the above steps to launch an IIN Agent for every other organization on your channnel, i.e., create similar configuration files in an organization-specific folder. Make sure you:

    • Update the organization names in every relevant location in the config.json.
    • Update IIN_AGENT_ENDPOINT and MEMBER_ID in the .env.

    Ledger Initialization

    To prepare your network for interoperation with a foreign network, you need to record the following to your network channel through the Fabric Interoperation Chaincode:

    • Access control policies: Let's take the example of the request made from trade-finance-network to trade-logistics-network for a B/L earlier in this document. trade-logistics-network can have a policy of the following form permitting access to the GetBillOfLading function from a client belonging to the Exporter organization in trade-finance-network as follows:

      {
      "securityDomain":"trade-finance-network",
      "rules":
      [
      {
      "principal":"ExporterMSP",
      "principalType":"ca",
      "resource":"tradelogisticschannel:shipmentcc:GetBillOfLading:*",
      "read":true
      }
      ]
      }

      In this sample, a single rule is specified for requests coming from trade-finance-network: it states that a GetBillOfLading query made to the shipmentcc contract installed on the tradelogisticschannel channel is permitted for a requestor possessing credentials certified by an MSP with the ExporterMSP identity. The * at the end indicates that any arguments passed to the function will pass the access control check.

      You need to record this policy rule on your Fabric network's channel by invoking either the CreateAccessControlPolicy function or the UpdateAccessControlPolicy function on the Fabric Interoperation Chaincode that is already installed on that channel; use the former if you are recording a set of rules for the given securityDomain for the first time and the latter to overwrite a set of rules recorded earlier. In either case, the chaincode function will take a single argument, which is the policy in the form of a JSON string (make sure you escape the double quotes before sending the request to avoid parsing errors). You can do this in one of two ways: (1) writing a small piece of code in Layer-2 that invokes the contract using the Fabric SDK Gateway API, or (2) running a peer chaincode invoke command from within a Docker container built on the hyperledger/fabric-tools image. Either approach should be familiar to a Fabric practitioner.

    • Verification policies: Taking the same example as above, an example of a verification policy for a B/L requested by the trade-finance-network from the trade-logistics-network is as follows:

      {
      "securityDomain":"trade-logistics-network",
      "identifiers":
      [
      {
      "pattern":"tradelogisticschannel:shipmentcc:GetBillOfLading:*",
      "policy":
      {
      "type":"Signature",
      "criteria":
      [
      "ExporterMSP",
      "CarrierMSP"
      ]
      }
      }
      ]
      }

      In this sample, a single verification policy rule is specified for data views coming from trade-logistics-network: it states that the data returned by the GetBillOfLading query made to the shipmentcc chaincode on the tradelogisticschannel channel requires as proof two signatures, one from a peer in the organization whose MSP ID is ExporterMSP and another from a peer in the organization whose MSP ID is CarrierMSP.

      You need to record this policy rule on your Fabric network's channel by invoking either the CreateVerificationPolicy function or the UpdateVerificationPolicy function on the Fabric Interoperation Chaincode that is already installed on that channel; use the former if you are recording a set of rules for the given securityDomain for the first time and the latter to overwrite a set of rules recorded earlier. In either case, the chaincode function will take a single argument, which is the policy in the form of a JSON string (make sure you escape the double quotes before sending the request to avoid parsing errors). As with the access control policy, you can do this in one of two ways: (1) writing a small piece of code in Layer-2 that invokes the contract using the Fabric SDK Gateway API, or (2) running a peer chaincode invoke command from within a Docker container built on the hyperledger/fabric-tools image. Either approach should be familiar to a Fabric practitioner.

      Notes
      For any cross-network data request, make sure an access control policy is recorded in the source network (trade-logistics-network in the above example) and a corresponding verification policy is recorded in the destination network (trade-finance-network in the above example) before any relay request is triggered.
    • Local network security domain (membership) configuration: -Recall the code snippet added to your application in the "Identity Administration" section. Exercise that code snippet, exposed either through a function API or an HTTP endpoint, to record the initial local membership for the relevant network channels.

    Your Fabric network is now up and running with the necessary Weaver components, and your network's channel's ledger is bootstrapped with the initial configuration necessary for cross-network interactions!

    - - +Recall the code snippet added to your application in the "Identity Administration" section. Exercise that code snippet, exposed either through a function API or an HTTP endpoint, to record the initial local membership for the relevant network channels.

    Your Fabric network is now up and running with the necessary Weaver components, and your network's channel's ledger is bootstrapped with the initial configuration necessary for cross-network interactions!

    + + \ No newline at end of file diff --git a/docs/external/getting-started/enabling-weaver-network/overview/index.html b/docs/external/getting-started/enabling-weaver-network/overview/index.html index 8575027da..d6061583b 100644 --- a/docs/external/getting-started/enabling-weaver-network/overview/index.html +++ b/docs/external/getting-started/enabling-weaver-network/overview/index.html @@ -4,14 +4,14 @@ Enabling Weaver in Existing DLT Applications Overview | Weaver: DLT Interoperability Framework - - - + + +
    -

    Enabling Weaver in Existing DLT Applications Overview

    If you have an existing DLT network and application suite built on any of the following platforms, follow the appropriate link below to understand how to adapt it to use Weaver capabilities for cross-network interactions.

    - - +

    Enabling Weaver in Existing DLT Applications Overview

    If you have an existing DLT network and application suite built on any of the following platforms, follow the appropriate link below to understand how to adapt it to use Weaver capabilities for cross-network interactions.

    + + \ No newline at end of file diff --git a/docs/external/getting-started/guide/index.html b/docs/external/getting-started/guide/index.html index 21967228b..e92c6ffd9 100644 --- a/docs/external/getting-started/guide/index.html +++ b/docs/external/getting-started/guide/index.html @@ -4,14 +4,14 @@ Using Weaver | Weaver: DLT Interoperability Framework - - - + + +
    -

    Using Weaver

    The easiest way to understand how Weaver works is to run it at a small scale:

    • First, launch a set of basic test networks built on Fabric, Corda and Besu. These networks offer the most basic capabilities of their DLT platforms and run toy applications (contracts and Layer-2) that can easily be tracked and debugged. You can launch these networks in one of several different ways: building Weaver components and dependencies locally or importing pre-built ones from Github packages, running core components in the host or in Docker containers. The choice depends on whether you just want to get these networks up and running or if you wish to customize the setup by modifying source code and configurations.
    • Once the test networks are launched, you can test two distinct kinds of interoperation modes:
      • Data sharing: all combinations of Fabric and Corda networks supported
      • Asset exchange: all pairs of network types from {Fabric, Corda, Besu} are supported
      • Asset transfer: all combinations of Fabric and Corda networks supported
    • (To bring down the test networks, go back to the "Setup" pages and follow instructions in the respective "Teardown" sections.)
    • After you run these tests and get a flavor of how the system and protocols work, you will be ready to move on to "real" networks, enhancing them with interoperation capabilities by incorporating Weaver into them. Check out the guidelines and templates for Fabric, Corda, and Besu networks.

    If you wish to go further and understand Weaver specifics, dig into the code, or contribute to the open-source project, check out the project repository. For specific information about individual Weaver components, see:

    The Weaver RFCs contain detailed specifications of the models, data structures, protocols, and message formats.

    - - +

    Using Weaver

    The easiest way to understand how Weaver works is to run it at a small scale:

    • First, launch a set of basic test networks built on Fabric, Corda and Besu. These networks offer the most basic capabilities of their DLT platforms and run toy applications (contracts and Layer-2) that can easily be tracked and debugged. You can launch these networks in one of several different ways: building Weaver components and dependencies locally or importing pre-built ones from Github packages, running core components in the host or in Docker containers. The choice depends on whether you just want to get these networks up and running or if you wish to customize the setup by modifying source code and configurations.
    • Once the test networks are launched, you can test two distinct kinds of interoperation modes:
      • Data sharing: all combinations of Fabric and Corda networks supported
      • Asset exchange: all pairs of network types from {Fabric, Corda, Besu} are supported
      • Asset transfer: all combinations of Fabric and Corda networks supported
    • (To bring down the test networks, go back to the "Setup" pages and follow instructions in the respective "Teardown" sections.)
    • After you run these tests and get a flavor of how the system and protocols work, you will be ready to move on to "real" networks, enhancing them with interoperation capabilities by incorporating Weaver into them. Check out the guidelines and templates for Fabric, Corda, and Besu networks.

    If you wish to go further and understand Weaver specifics, dig into the code, or contribute to the open-source project, check out the project repository. For specific information about individual Weaver components, see:

    The Weaver RFCs contain detailed specifications of the models, data structures, protocols, and message formats.

    + + \ No newline at end of file diff --git a/docs/external/getting-started/interop/asset-exchange/besu-besu/index.html b/docs/external/getting-started/interop/asset-exchange/besu-besu/index.html index 1916a3aa6..2f972306f 100644 --- a/docs/external/getting-started/interop/asset-exchange/besu-besu/index.html +++ b/docs/external/getting-started/interop/asset-exchange/besu-besu/index.html @@ -4,16 +4,16 @@ Asset Exchange: Besu with Besu | Weaver: DLT Interoperability Framework - - - + + +

    Asset Exchange: Besu with Besu

    We divide this page into two sections, if you used default configuration in ledger initialization step, then go to section AliceERC721 with BobERC20, otherwise if you used hybrid tokens in network, then go to section AliceERC1155 with BobERC20

    Notes
    The hash used in following steps can be replaced by any valid SHA256 hash.

    AliceERC721 with BobERC20

    One Besu network transfers an non-fungible AliceERC721 token with id 0 from Alice to Bob in exchange for a transfer of 10 BobERC20 tokens from Bob to Alice in the other network. We will use account 1 for Alice and account 2 for Bob in both networks.

    Run the following steps:

    1. Navigate to the samples/besu/besu-cli folder in your clone of the Weaver repository.
    2. Run the following to verify the status of the assets owned by alice and bob in the two networks:
      ./bin/besu-cli asset get-balance --network=network1 --account=1
      ./bin/besu-cli asset get-balance --network=network1 --account=2
      ./bin/besu-cli asset get-balance --network=network2 --account=1
      ./bin/besu-cli asset get-balance --network=network2 --account=2
    3. Generate Secret-Hash Pair using following command (prints hash in base64):
      ./bin/besu-cli hash --hash_fn=SHA256 secrettext
    4. Run the following to trigger alice locking AliceERC721 token with id 0 for bob in network1 for 1 hour
      ./bin/besu-cli asset lock --network=network1 --sender_account=1 --recipient_account=2 --token_id=0 --asset_type=ERC721 --timeout=3600 --hash_base64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs=
      Value set to hash_base64 argument corresponds to what was generated in Step 3. Note the contract-id printed as output in above command. The output line containing contract-id (text in base64 after Lock contract ID:) would like this:
      Lock contract ID: 48f59da2ac632117bf79b4aa986f5ece8a2439dc143d576965c17bc8275b0925
    5. Run the following to verify alice's lock, replacing <contract-id> with actual contract-id:
      ./bin/besu-cli asset is-locked --network=network1 --lock_contract_id=<contract-id>
    6. Run the following to trigger bob locking 10 units of BobERC20 tokens for alice in network2 for 30 mins:
      ./bin/besu-cli asset lock --network=network2 --sender_account=2 --recipient_account=1 --amount=10 --timeout=1800 --hash_base64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs=
      Note the contract-id again for this lock printed as output in above command. Let's refer it <contract-id-2> for this demonstration.
    7. Run the following to verify bob's lock:
      ./bin/besu-cli asset is-locked --network=network2 --lock_contract_id=<contract-id-2>
    8. Run the following to trigger alice's claim for 10 units of BobERC20 tokens locked by bob in network2:
      ./bin/besu-cli asset claim --network=network2 --recipient_account=1 --preimage=secrettext --lock_contract_id=<contract-id-2>
    9. Run the following to trigger bob's claim for AliceERC721 NFT with id 0 locked by alice in network1:
      ./bin/besu-cli asset claim --network=network1 --recipient_account=2 --preimage=secrettext --token_id=0 --lock_contract_id=<contract-id>

    The above steps complete a successful asset exchange between two Besu networks. In addition to the above commands, following commands can be run if specified timeout has expired and the locked asset remains unclaimed.

    • If alice wants to unlock the asset, run the following to trigger alice's re-claim for AliceERC721 NFT with id 0 locked in network1:
      ./bin/besu-cli asset unlock --network=network1 --lock_contract_id=<contract-id> --sender_account=1 --token_id=0
    • If bob wants to unlock the token asset, run the following to trigger bob's re-claim for 10 BobERC20 tokens locked in network2:
      ./bin/besu-cli asset unlock --network=network2 --lock_contract_id=<contract-id-2> --sender_account=2

    AliceERC1155 with BobERC20

    One Besu network transfers an non-fungible 5 AliceERC1155 tokens with id 0 from Alice to Bob in exchange for a transfer of 50 BobERC20 tokens from Bob to Alice in the other network. We will use account 1 for Alice and account 2 for Bob in both networks.

    Run the following steps:

    1. Navigate to the samples/besu/besu-cli folder in your clone of the Weaver repository.
    2. Run the following to verify the status of the assets owned by alice and bob in the two networks:
      ./bin/besu-cli asset get-balance --network=network1 --account=1
      ./bin/besu-cli asset get-balance --network=network1 --account=2
      ./bin/besu-cli asset get-balance --network=network2 --account=1
      ./bin/besu-cli asset get-balance --network=network2 --account=2
    3. Generate Secret-Hash Pair using following command (prints hash in base64):
      ./bin/besu-cli hash --hash_fn=SHA256 secrettext
    4. Run the following to trigger alice locking 5 AliceERC1155 token with id 0 for bob in network1 for 1 hour
      ./bin/besu-cli asset lock --network=network1 --sender_account=1 --recipient_account=2 --amount=5 --token_id=0 --asset_type=ERC1155 --timeout=3600 --hash_base64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs=
      Value set to hash_base64 argument corresponds to what was generated in Step 3. Note the contract-id printed as output in above command. The output line containing contract-id (text in base64 after Lock contract ID:) would like this:
      Lock contract ID: 48f59da2ac632117bf79b4aa986f5ece8a2439dc143d576965c17bc8275b0925
    5. Run the following to verify alice's lock, replacing <contract-id> with actual contract-id:
      ./bin/besu-cli asset is-locked --network=network1 --lock_contract_id=<contract-id>
    6. Run the following to trigger bob locking 50 units of BobERC20 tokens for alice in network2:
      ./bin/besu-cli asset lock --network=network2 --sender_account=2 --recipient_account=1 --amount=50 --timeout=3600 --hash_base64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs=
      Note the contract-id again for this lock printed as output in above command. Let's refer it <contract-id-2> for this demonstration.
    7. Run the following to verify bob's lock:
      ./bin/besu-cli asset is-locked --network=network2 --lock_contract_id=<contract-id-2>
    8. Run the following to trigger alice's claim for 50 units of BobERC20 tokens locked by bob in network2:
      ./bin/besu-cli asset claim --network=network2 --recipient_account=1 --preimage=secrettext --lock_contract_id=<contract-id-2>
    9. Run the following to trigger bob's claim for 5 AliceERC1155 tokens with id 0 locked by alice in network1:
      ./bin/besu-cli asset claim --network=network1 --recipient_account=2 --preimage=secrettext --token_id=0 --lock_contract_id=<contract-id>

    The above steps complete a successful asset exchange between two Besu networks. -In addition to the above commands, following commands can be run if specified timeout has expired and the locked asset remains unclaimed.

    • If alice wants to unlock the asset, run the following to trigger alice's re-claim for 5 AliceERC1155 tokens with id 0 locked in network1:
      ./bin/besu-cli asset unlock --network=network1 --lock_contract_id=<contract-id> --sender_account=1 --token_id=0
    • If bob wants to unlock the token asset, run the following to trigger bob's re-claim for 50 BobERC20 tokens locked in network2:
      ./bin/besu-cli asset unlock --network=network2 --lock_contract_id=<contract-id-2> --sender_account=2

    Run the following to verify the status of the assets owned by alice and bob in the two networks:

    ./bin/besu-cli asset get-balance --network=network1 --account=1
    ./bin/besu-cli asset get-balance --network=network1 --account=2
    ./bin/besu-cli asset get-balance --network=network2 --account=1
    ./bin/besu-cli asset get-balance --network=network2 --account=2
    - - +In addition to the above commands, following commands can be run if specified timeout has expired and the locked asset remains unclaimed.

    • If alice wants to unlock the asset, run the following to trigger alice's re-claim for 5 AliceERC1155 tokens with id 0 locked in network1:
      ./bin/besu-cli asset unlock --network=network1 --lock_contract_id=<contract-id> --sender_account=1 --token_id=0
    • If bob wants to unlock the token asset, run the following to trigger bob's re-claim for 50 BobERC20 tokens locked in network2:
      ./bin/besu-cli asset unlock --network=network2 --lock_contract_id=<contract-id-2> --sender_account=2

    Run the following to verify the status of the assets owned by alice and bob in the two networks:

    ./bin/besu-cli asset get-balance --network=network1 --account=1
    ./bin/besu-cli asset get-balance --network=network1 --account=2
    ./bin/besu-cli asset get-balance --network=network2 --account=1
    ./bin/besu-cli asset get-balance --network=network2 --account=2
    + + \ No newline at end of file diff --git a/docs/external/getting-started/interop/asset-exchange/corda-besu/index.html b/docs/external/getting-started/interop/asset-exchange/corda-besu/index.html index 72d90403e..773df3cab 100644 --- a/docs/external/getting-started/interop/asset-exchange/corda-besu/index.html +++ b/docs/external/getting-started/interop/asset-exchange/corda-besu/index.html @@ -4,16 +4,16 @@ Asset Exchange: Corda with Besu | Weaver: DLT Interoperability Framework - - - + + +

    Asset Exchange: Corda with Besu

    We will demonstrate asset exchange of an AliceERC721 NFT in Besu network1 with 10 tokens on Corda_Network. For Besu commands, run from samples/besu/besu-cli folder, and for Corda commands, run from samples/corda/corda-simple-application folder. Here Alice with account 1 and Bob with account 2 in Besu network1 correspond to PartyA (CORDA_PORT=10006) and PartyB (CORDA_PORT=10009) in Corda_Network respectively. Following are the step-by-step asset exchange process:

    1. From corda client, generate secret-hash pair using following command (prints hash in base64):
      ./clients/build/install/clients/bin/clients utils hash --hash-fn=SHA256 -s secrettext
    2. Run the following to verify the status of the tokens owned by PartyA and PartyB in the Corda_Network and Corda_Network2:
      ./scripts/getAssetStatus.sh 2
    3. Run the following in besu-cli, to verify the status of the assets owned by Alice and Bob in the Besu networks:
      ./bin/besu-cli asset get-balance --network=network1 --account=1
      ./bin/besu-cli asset get-balance --network=network1 --account=2
    4. Complete the asset exchange using following steps:
    • Run the following to trigger alice locking AliceERC721 token with id 0 for bob in network1 for 1 hour
      ./bin/besu-cli asset lock --network=network1 --sender_account=1 --recipient_account=2 --token_id=0 --asset_type=ERC721 --timeout=3600 --hash_base64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs=
      Note the contract-id printed as output in above command. The output line containing contract-id (text in base64 after Lock contract ID:) would like this:
      Lock contract ID: 48f59da2ac632117bf79b4aa986f5ece8a2439dc143d576965c17bc8275b0925
    • Run the following to verify alice's lock, replacing <contract-id> with actual contract-id:
      ./bin/besu-cli asset is-locked --network=network1 --lock_contract_id=<contract-id>
    • Run the following to trigger PartyB locking 50 units of token type t1 for PartyA in Corda_Network for 30 mins:
      CORDA_PORT=10009 ./clients/build/install/clients/bin/clients lock-asset --fungible --hashBase64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs= --timeout=1800 --recipient="O=PartyA,L=London,C=GB" --param=t1:50
      Note the contract-id displayed after successful execution of the command, will be used in next steps. The output containing contract-id would like this:
      HTLC Lock State created with contract ID Right(b=10448674_80d2bee7-5a5d-45df-b14e-60bac4ba1bf3).
      contract-id is the alphanumeric text (with underscore and hyphens) after b= within parenthesis. Let's refer it <contract-id-2> for this demonstration.
    • Run the following to verify PartyB's lock (can be verified by both parties):
      CORDA_PORT=10006 ./clients/build/install/clients/bin/clients is-asset-locked --contract-id=<contract-id-2>
    • Run the following to trigger PartyA's claim for 50 units of token type t1 locked by PartyB in Corda_Network:
      CORDA_PORT=10006 ./clients/build/install/clients/bin/clients claim-asset --secret=secrettext --contract-id=<contract-id-2>
      PartyB can see its node's logs to get the revealed hash preimage, and use it to claim in the Besu network.
    • Run the following to trigger bob's claim for AliceERC721 NFT with id 0 locked by alice in network1:
      ./bin/besu-cli asset claim --network=network1 --recipient_account=2 --preimage=secrettext --token_id=0 --lock_contract_id=<contract-id>
      The above steps complete a successful asset exchange between two Besu networks. -In addition to the above commands, following commands can be run if specified timeout has expired and the locked asset remains unclaimed.
    • If alice wants to unlock the asset, run the following to trigger alice's re-claim for AliceERC721 NFT with id 0 locked in network1:
      ./bin/besu-cli asset unlock --network=network1 --lock_contract_id=<contract-id> --sender_account=1 --token_id=0
    • If PartyB wants to unlock the token asset, run the following to trigger unlock for t1:50 locked in Corda_Network:
      CORDA_PORT=10009 ./clients/build/install/clients/bin/clients unlock-asset --contract-id=<contract-id>
    1. Run the following to verify the status of the tokens owned by PartyA and PartyB in the Corda_Network and Corda_Network2:
      ./scripts/getAssetStatus.sh 2
    2. Run the following in besu-cli, to verify the status of the assets owned by Alice and Bob in the Besu networks:
      ./bin/besu-cli asset get-balance --network=network1 --account=1
      ./bin/besu-cli asset get-balance --network=network1 --account=2
    - - +In addition to the above commands, following commands can be run if specified timeout has expired and the locked asset remains unclaimed.
  • If alice wants to unlock the asset, run the following to trigger alice's re-claim for AliceERC721 NFT with id 0 locked in network1:
    ./bin/besu-cli asset unlock --network=network1 --lock_contract_id=<contract-id> --sender_account=1 --token_id=0
  • If PartyB wants to unlock the token asset, run the following to trigger unlock for t1:50 locked in Corda_Network:
    CORDA_PORT=10009 ./clients/build/install/clients/bin/clients unlock-asset --contract-id=<contract-id>
    1. Run the following to verify the status of the tokens owned by PartyA and PartyB in the Corda_Network and Corda_Network2:
      ./scripts/getAssetStatus.sh 2
    2. Run the following in besu-cli, to verify the status of the assets owned by Alice and Bob in the Besu networks:
      ./bin/besu-cli asset get-balance --network=network1 --account=1
      ./bin/besu-cli asset get-balance --network=network1 --account=2
    + + \ No newline at end of file diff --git a/docs/external/getting-started/interop/asset-exchange/corda-corda/index.html b/docs/external/getting-started/interop/asset-exchange/corda-corda/index.html index 3cc8d4b40..8e66379c1 100644 --- a/docs/external/getting-started/interop/asset-exchange/corda-corda/index.html +++ b/docs/external/getting-started/interop/asset-exchange/corda-corda/index.html @@ -4,15 +4,15 @@ Asset Exchange: Corda with Corda | Weaver: DLT Interoperability Framework - - - + + +
    -

    Asset Exchange: Corda with Corda

    We will demonstrate asset exchange of a tokens in Corda_Network with tokens on Corda_Network2. Here PartyA (CORDA_PORT=10006) and PartyB (CORDA_PORT=10009) in Corda_Network correspond to PartyA (CORDA_PORT=30006) and PartyB (CORDA_PORT=30009) in Corda_Network2 respectively. Following are the step-by-step asset exchange process:

    Notes
    The hash used in following steps can be replaced by any valid SHA256 hash.
    • Navigate to samples/corda/corda-simple-application folder.
    • Run the following to verify the status of the tokens owned by PartyA and PartyB in the Corda_Network and Corda_Network2:
      ./scripts/getAssetStatus.sh 2
    • Generate Secret-Hash Pair using following command (prints hash in base64):
      ./clients/build/install/clients/bin/clients utils hash --hash-fn=SHA256 -s secrettext
    • Run the following to trigger PartyA locking 30 units of token type t1 for PartyB in Corda_Network for 60 mins:
      CORDA_PORT=10006 ./clients/build/install/clients/bin/clients lock-asset --fungible --hashBase64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs= --timeout=3600 --recipient="O=PartyB,L=London,C=GB" --param=t1:30
      Note the contract-id displayed after successful execution of the command, will be used in next steps. The output containing contract-id would like this:
      HTLC Lock State created with contract ID Right(b=10448674_80d2bee7-5a5d-45df-b14e-60bac4ba1bf3).
      contract-id is the alphanumeric text (with underscore and hyphens) after b= within parenthesis. Let's denote it <contract-id-1>.
    • Run the following to verify PartyA's lock (can be verified by both parties):
      CORDA_PORT=10009 ./clients/build/install/clients/bin/clients is-asset-locked --contract-id=<contract-id-1>
    • Run the following to trigger PartyB locking 50 units of token type t2 for PartyA in Corda_Network2 for 30 mins:
      CORDA_PORT=30009 ./clients/build/install/clients/bin/clients lock-asset --fungible --hashBase64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs= --timeout=1800 --recipient="O=PartyA,L=London,C=GB" --param=t2:50
      Note the contract-id displayed after successful execution of the command, will be used in next steps. Let's denote it <contract-id-2>.
    • Run the following to verify PartyB's lock (can be verified by both parties):
      CORDA_PORT=30006 ./clients/build/install/clients/bin/clients is-asset-locked --contract-id=<contract-id-2>
    • Run the following to trigger PartyA's claim for 50 units of token type t2 locked by PartyB in Corda_Network2:
      CORDA_PORT=30006 ./clients/build/install/clients/bin/clients claim-asset --secret=secrettext --contract-id=<contract-id-2>
      PartyB can see its node's logs to get the revealed hash preimage, and use it to claim the bond in the Fabric network.
    • Run the following to trigger PartyB's claim for 30 units of token type t1 locked by PartyA in Corda_Network:
      CORDA_PORT=10009 ./clients/build/install/clients/bin/clients claim-asset --secret=secrettext --contract-id=<contract-id-1>
    • Run the following to verify the status of the tokens owned by PartyA and PartyB in the Corda_Network and Corda_Network2:
      ./scripts/getAssetStatus.sh 2

    The above steps complete a successful asset exchange between two Corda networks. -In addition to the above commands, following commands can be run if specified timeout has expired and the locked asset remains unclaimed.

    • If PartyA wants to unlock the token t1:30 asset, run the following to trigger PartyA's re-claim in Corda_Network:
      CORDA_PORT=10006 ./clients/build/install/clients/bin/clients unlock-asset --contract-id=<contract-id-1>
    • If PartyB wants to unlock the token t2:50 asset, run the following to trigger PartyB's re-claim in Corda_Network2:
      CORDA_PORT=30009 ./clients/build/install/clients/bin/clients unlock-asset --contract-id=<contract-id-2>
    - - +

    Asset Exchange: Corda with Corda

    We will demonstrate asset exchange of a tokens in Corda_Network with tokens on Corda_Network2. Here PartyA (CORDA_PORT=10006) and PartyB (CORDA_PORT=10009) in Corda_Network correspond to PartyA (CORDA_PORT=30006) and PartyB (CORDA_PORT=30009) in Corda_Network2 respectively. Following are the step-by-step asset exchange process:

    Notes
    The hash used in following steps can be replaced by any valid SHA256 hash.
    • Navigate to the samples/corda/corda-simple-application folder in your clone of the Weaver repository.
    • Run the following to verify the status of the tokens owned by PartyA and PartyB in the Corda_Network and Corda_Network2:
      ./scripts/getAssetStatus.sh 2
    • Generate Secret-Hash Pair using following command (prints hash in base64):
      ./clients/build/install/clients/bin/clients utils hash --hash-fn=SHA256 -s secrettext
    • Run the following to trigger PartyA locking 30 units of token type t1 for PartyB in Corda_Network for 60 mins:
      CORDA_PORT=10006 ./clients/build/install/clients/bin/clients lock-asset --fungible --hashBase64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs= --timeout=3600 --recipient="O=PartyB,L=London,C=GB" --param=t1:30
      Note the contract-id displayed after successful execution of the command, will be used in next steps. The output containing contract-id would like this:
      HTLC Lock State created with contract ID Right(b=10448674_80d2bee7-5a5d-45df-b14e-60bac4ba1bf3).
      contract-id is the alphanumeric text (with underscore and hyphens) after b= within parenthesis. Let's denote it <contract-id-1>.
    • Run the following to verify PartyA's lock (can be verified by both parties):
      CORDA_PORT=10009 ./clients/build/install/clients/bin/clients is-asset-locked --contract-id=<contract-id-1>
    • Run the following to trigger PartyB locking 50 units of token type t2 for PartyA in Corda_Network2 for 30 mins:
      CORDA_PORT=30009 ./clients/build/install/clients/bin/clients lock-asset --fungible --hashBase64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs= --timeout=1800 --recipient="O=PartyA,L=London,C=GB" --param=t2:50
      Note the contract-id displayed after successful execution of the command, will be used in next steps. Let's denote it <contract-id-2>.
    • Run the following to verify PartyB's lock (can be verified by both parties):
      CORDA_PORT=30006 ./clients/build/install/clients/bin/clients is-asset-locked --contract-id=<contract-id-2>
    • Run the following to trigger PartyA's claim for 50 units of token type t2 locked by PartyB in Corda_Network2:
      CORDA_PORT=30006 ./clients/build/install/clients/bin/clients claim-asset --secret=secrettext --contract-id=<contract-id-2>
      PartyB can see its node's logs to get the revealed hash preimage, and use it to claim the bond in the Fabric network.
    • Run the following to trigger PartyB's claim for 30 units of token type t1 locked by PartyA in Corda_Network:
      CORDA_PORT=10009 ./clients/build/install/clients/bin/clients claim-asset --secret=secrettext --contract-id=<contract-id-1>
    • Run the following to verify the status of the tokens owned by PartyA and PartyB in the Corda_Network and Corda_Network2:
      ./scripts/getAssetStatus.sh 2

    The above steps complete a successful asset exchange between two Corda networks. +In addition to the above commands, following commands can be run if specified timeout has expired and the locked asset remains unclaimed.

    • If PartyA wants to unlock the token t1:30 asset, run the following to trigger PartyA's re-claim in Corda_Network:
      CORDA_PORT=10006 ./clients/build/install/clients/bin/clients unlock-asset --contract-id=<contract-id-1>
    • If PartyB wants to unlock the token t2:50 asset, run the following to trigger PartyB's re-claim in Corda_Network2:
      CORDA_PORT=30009 ./clients/build/install/clients/bin/clients unlock-asset --contract-id=<contract-id-2>
    + + \ No newline at end of file diff --git a/docs/external/getting-started/interop/asset-exchange/fabric-besu/index.html b/docs/external/getting-started/interop/asset-exchange/fabric-besu/index.html index 6e7675b18..e22005bf5 100644 --- a/docs/external/getting-started/interop/asset-exchange/fabric-besu/index.html +++ b/docs/external/getting-started/interop/asset-exchange/fabric-besu/index.html @@ -4,16 +4,16 @@ Asset Exchange: Fabric with Besu | Weaver: DLT Interoperability Framework - - - + + +

    Asset Exchange: Fabric with Besu

    We will demonstrate asset exchange of a bond in Fabric network1 with 10 BobERC20 tokens on Besu network2. -For Fabric commands, run from samples/fabric/fabric-cli folder, and for Besu commands, run from ssamples/besu/besu-cli folder. Here Alice and Bob in Fabric network1 correspond to account 1 and account 2 in Besu network2 respectively. Following are the step-by-step asset exchange process:

    Notes
    The hash used in following steps can be replaced by any valid SHA256 hash.
    • From fabric-cli, generate secret-hash pair using following command (prints hash in base64):
      ./bin/fabric-cli hash --hash_fn=SHA256 secrettext
    • Run the following to verify the status of the bond assets owned by alice and bob in the Fabric network network1 from samples/fabric/fabric-cli folder:
      ./scripts/getAssetStatus.sh
    • Run the following in besu-cli, to verify the status of the assets owned by Alice and Bob in the Besu network network2:
      ./bin/besu-cli asset get-balance --network=network2 --account=1
      ./bin/besu-cli asset get-balance --network=network2 --account=2
    • Run the following to trigger alice locking bond01:a03 for bob in network1 for 60 mins:
      ./bin/fabric-cli asset exchange lock --timeout-duration=3600 --locker=alice --recipient=bob --hashBase64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs= --target-network=network1 --param=bond01:a03
    • Run the following to verify alice's lock:
      ./bin/fabric-cli asset exchange is-locked --locker=alice --recipient=bob --target-network=network1 --param=bond01:a03
    • Run the following to trigger bob locking 10 units of BobERC20 tokens for alice in network2 for 30 mins:
      ./bin/besu-cli asset lock --network=network2 --sender_account=2 --recipient_account=1 --amount=10 --timeout=1800 --hash_base64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs=
      Note the contract-id printed as output in above command. The output line containing contract-id (text in base64 after Lock contract ID:) would like this:
      Lock contract ID: 48f59da2ac632117bf79b4aa986f5ece8a2439dc143d576965c17bc8275b0925
      Let's refer it <contract-id-2> for this demonstration.
    • Run the following to verify bob's lock:
      ./bin/besu-cli asset is-locked --network=network2 --lock_contract_id=<contract-id-2>
    • Run the following to trigger alice's claim for 10 units of BobERC20 tokens locked by bob in network2:
      ./bin/besu-cli asset claim --network=network2 --recipient_account=1 --preimage=secrettext --lock_contract_id=<contract-id-2>
    • Run the following to trigger bob's claim for bond01:a03 locked by alice in network1:
      ./bin/fabric-cli asset exchange claim --recipient=bob --locker=alice --target-network=network1 --param=bond01:a03 --secret=secrettext
    • Run the following to verify the status of the bond assets owned by alice and bob in the Fabric network network1 from samples/fabric/fabric-cli folder:
      ./scripts/getAssetStatus.sh
    • Run the following in besu-cli, to verify the status of the assets owned by Alice and Bob in the Besu network network2:
      ./bin/besu-cli asset get-balance --network=network2 --account=1
      ./bin/besu-cli asset get-balance --network=network2 --account=2

    The above steps complete a successful asset exchange between Fabric and Corda networks. -In addition to the above commands, following commands can be run if specified timeout has expired and the locked asset remains unclaimed.

    • If alice wants to unlock the bond asset, run the following to trigger alice's re-claim for bond01:a03 locked in network1:
      ./bin/fabric-cli asset exchange unlock --locker=alice --recipient=bob --target-network=network1 --param=bond01:a03
    • If bob wants to unlock the token asset, run the following to trigger bob's re-claim for 50 BobERC20 tokens locked in network2:
      ./bin/besu-cli asset unlock --network=network2 --lock_contract_id=<contract-id-2> --sender_account=2
    - - +For Fabric commands, run from samples/fabric/fabric-cli folder, and for Besu commands, run from samples/besu/besu-cli folder, in your clone of the Weaver repository. Here Alice and Bob in Fabric network1 correspond to account 1 and account 2 in Besu network2 respectively. Following are the step-by-step asset exchange process:

    Notes
    The hash used in following steps can be replaced by any valid SHA256 hash.
    • From fabric-cli, generate secret-hash pair using following command (prints hash in base64):
      ./bin/fabric-cli hash --hash_fn=SHA256 secrettext
    • Run the following to verify the status of the bond assets owned by alice and bob in the Fabric network network1 from samples/fabric/fabric-cli folder:
      ./scripts/getAssetStatus.sh
    • Run the following in besu-cli, to verify the status of the assets owned by Alice and Bob in the Besu network network2:
      ./bin/besu-cli asset get-balance --network=network2 --account=1
      ./bin/besu-cli asset get-balance --network=network2 --account=2
    • Run the following to trigger alice locking bond01:a03 for bob in network1 for 60 mins:
      ./bin/fabric-cli asset exchange lock --timeout-duration=3600 --locker=alice --recipient=bob --hashBase64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs= --target-network=network1 --param=bond01:a03
    • Run the following to verify alice's lock:
      ./bin/fabric-cli asset exchange is-locked --locker=alice --recipient=bob --target-network=network1 --param=bond01:a03
    • Run the following to trigger bob locking 10 units of BobERC20 tokens for alice in network2 for 30 mins:
      ./bin/besu-cli asset lock --network=network2 --sender_account=2 --recipient_account=1 --amount=10 --timeout=1800 --hash_base64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs=
      Note the contract-id printed as output in above command. The output line containing contract-id (text in base64 after Lock contract ID:) would like this:
      Lock contract ID: 48f59da2ac632117bf79b4aa986f5ece8a2439dc143d576965c17bc8275b0925
      Let's refer it <contract-id-2> for this demonstration.
    • Run the following to verify bob's lock:
      ./bin/besu-cli asset is-locked --network=network2 --lock_contract_id=<contract-id-2>
    • Run the following to trigger alice's claim for 10 units of BobERC20 tokens locked by bob in network2:
      ./bin/besu-cli asset claim --network=network2 --recipient_account=1 --preimage=secrettext --lock_contract_id=<contract-id-2>
    • Run the following to trigger bob's claim for bond01:a03 locked by alice in network1:
      ./bin/fabric-cli asset exchange claim --recipient=bob --locker=alice --target-network=network1 --param=bond01:a03 --secret=secrettext
    • Run the following to verify the status of the bond assets owned by alice and bob in the Fabric network network1 from samples/fabric/fabric-cli folder:
      ./scripts/getAssetStatus.sh
    • Run the following in besu-cli, to verify the status of the assets owned by Alice and Bob in the Besu network network2:
      ./bin/besu-cli asset get-balance --network=network2 --account=1
      ./bin/besu-cli asset get-balance --network=network2 --account=2

    The above steps complete a successful asset exchange between Fabric and Corda networks. +In addition to the above commands, following commands can be run if specified timeout has expired and the locked asset remains unclaimed.

    • If alice wants to unlock the bond asset, run the following to trigger alice's re-claim for bond01:a03 locked in network1:
      ./bin/fabric-cli asset exchange unlock --locker=alice --recipient=bob --target-network=network1 --param=bond01:a03
    • If bob wants to unlock the token asset, run the following to trigger bob's re-claim for 50 BobERC20 tokens locked in network2:
      ./bin/besu-cli asset unlock --network=network2 --lock_contract_id=<contract-id-2> --sender_account=2
    + + \ No newline at end of file diff --git a/docs/external/getting-started/interop/asset-exchange/fabric-corda/index.html b/docs/external/getting-started/interop/asset-exchange/fabric-corda/index.html index e1b1b0a67..b31ab791a 100644 --- a/docs/external/getting-started/interop/asset-exchange/fabric-corda/index.html +++ b/docs/external/getting-started/interop/asset-exchange/fabric-corda/index.html @@ -4,16 +4,16 @@ Asset Exchange: Fabric with Corda | Weaver: DLT Interoperability Framework - - - + + +

    Asset Exchange: Fabric with Corda

    We will demonstrate asset exchange of a bond in Fabric network1 with tokens on Corda_Network. -For Fabric commands, run from samples/fabric/fabric-cli folder, and for Corda commands, run from samples/corda/corda-simple-application folder. Here Alice and Bob in Fabric network1 correspond to PartyA (CORDA_PORT=10006) and PartyB (CORDA_PORT=10009) in Corda_Network respectively. Following are the step-by-step asset exchange process:

    Notes
    The hash used in following steps can be replaced by any valid SHA256 hash.
    • Run the following to verify the status of the bond assets owned by alice and bob in the Fabric network network1 from samples/fabric/fabric-cli folder:
      ./scripts/getAssetStatus.sh
    • Run the following to verify the status of the assets owned by PartyA and PartyB in the Corda_Network from samples/corda/corda-simple-application folder:
      ./scripts/getAssetStatus.sh
    • Generate Secret-Hash Pair using following command (prints hash in base64):
      ./bin/fabric-cli hash --hash_fn=SHA256 secrettext
    • Run the following to trigger alice locking bond01:a03 for bob in network1 for 60 mins:
      ./bin/fabric-cli asset exchange lock --timeout-duration=3600 --locker=alice --recipient=bob --hashBase64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs= --target-network=network1 --param=bond01:a03
    • Run the following to verify alice's lock:
      ./bin/fabric-cli asset exchange is-locked --locker=alice --recipient=bob --target-network=network1 --param=bond01:a03
    • Run the following to trigger PartyB locking 50 units of token type t1 for PartyA in Corda_Network for 30 mins:
      CORDA_PORT=10009 ./clients/build/install/clients/bin/clients lock-asset --fungible --hashBase64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs= --timeout=1800 --recipient="O=PartyA,L=London,C=GB" --param=t1:50
      Note the contract-id displayed after successful execution of the command, will be used in next steps. The output containing contract-id would like this:
      HTLC Lock State created with contract ID Right(b=10448674_80d2bee7-5a5d-45df-b14e-60bac4ba1bf3).
      contract-id is the alphanumeric text (with underscore and hyphens) after b= within parenthesis.
    • Run the following to verify PartyB's lock (can be verified by both parties):
      CORDA_PORT=10006 ./clients/build/install/clients/bin/clients is-asset-locked --contract-id=<contract-id>
    • Run the following to trigger PartyA's claim for 50 units of token type t1 locked by PartyB in Corda_Network:
      CORDA_PORT=10006 ./clients/build/install/clients/bin/clients claim-asset --secret=secrettext --contract-id=<contract-id>
      PartyB can see its node's logs to get the revealed hash preimage, and use it to claim the bond in the Fabric network.
    • Run the following to trigger bob's claim for bond01:a03 locked by alice in network1:
      ./bin/fabric-cli asset exchange claim --recipient=bob --locker=alice --target-network=network1 --param=bond01:a03 --secret=secrettext
    • Run the following to verify the status of the bond assets owned by alice and bob in the Fabric network network1 from samples/fabric/fabric-cli folder:
      ./scripts/getAssetStatus.sh
    • Run the following to verify the status of the assets owned by PartyA and PartyB in the Corda_Network from samples/corda/corda-simple-application folder:
      ./scripts/getAssetStatus.sh

    The above steps complete a successful asset exchange between Fabric and Corda networks. -In addition to the above commands, following commands can be run if specified timeout has expired and the locked asset remains unclaimed.

    • If alice wants to unlock the bond asset, run the following to trigger alice's re-claim for bond01:a03 locked in network1:
      ./bin/fabric-cli asset exchange unlock --locker=alice --recipient=bob --target-network=network1 --param=bond01:a03
    • If PartyB wants to unlock the token asset, run the following to trigger unlock for t1:50 locked in Corda_Network:
      CORDA_PORT=10009 ./clients/build/install/clients/bin/clients unlock-asset --contract-id=<contract-id>
    - - +For Fabric commands, run from samples/fabric/fabric-cli folder, and for Corda commands, run from samples/corda/corda-simple-application folder, in your clone of the Weaver repository. Here Alice and Bob in Fabric network1 correspond to PartyA (CORDA_PORT=10006) and PartyB (CORDA_PORT=10009) in Corda_Network respectively. Following are the step-by-step asset exchange process:

    Notes
    The hash used in following steps can be replaced by any valid SHA256 hash.
    • Run the following to verify the status of the bond assets owned by alice and bob in the Fabric network network1 from samples/fabric/fabric-cli folder:
      ./scripts/getAssetStatus.sh
    • Run the following to verify the status of the assets owned by PartyA and PartyB in the Corda_Network from samples/corda/corda-simple-application folder:
      ./scripts/getAssetStatus.sh
    • Generate Secret-Hash Pair using following command (prints hash in base64):
      ./bin/fabric-cli hash --hash_fn=SHA256 secrettext
    • Run the following to trigger alice locking bond01:a03 for bob in network1 for 60 mins:
      ./bin/fabric-cli asset exchange lock --timeout-duration=3600 --locker=alice --recipient=bob --hashBase64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs= --target-network=network1 --param=bond01:a03
    • Run the following to verify alice's lock:
      ./bin/fabric-cli asset exchange is-locked --locker=alice --recipient=bob --target-network=network1 --param=bond01:a03
    • Run the following to trigger PartyB locking 50 units of token type t1 for PartyA in Corda_Network for 30 mins:
      CORDA_PORT=10009 ./clients/build/install/clients/bin/clients lock-asset --fungible --hashBase64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs= --timeout=1800 --recipient="O=PartyA,L=London,C=GB" --param=t1:50
      Note the contract-id displayed after successful execution of the command, will be used in next steps. The output containing contract-id would like this:
      HTLC Lock State created with contract ID Right(b=10448674_80d2bee7-5a5d-45df-b14e-60bac4ba1bf3).
      contract-id is the alphanumeric text (with underscore and hyphens) after b= within parenthesis.
    • Run the following to verify PartyB's lock (can be verified by both parties):
      CORDA_PORT=10006 ./clients/build/install/clients/bin/clients is-asset-locked --contract-id=<contract-id>
    • Run the following to trigger PartyA's claim for 50 units of token type t1 locked by PartyB in Corda_Network:
      CORDA_PORT=10006 ./clients/build/install/clients/bin/clients claim-asset --secret=secrettext --contract-id=<contract-id>
      PartyB can see its node's logs to get the revealed hash preimage, and use it to claim the bond in the Fabric network.
    • Run the following to trigger bob's claim for bond01:a03 locked by alice in network1:
      ./bin/fabric-cli asset exchange claim --recipient=bob --locker=alice --target-network=network1 --param=bond01:a03 --secret=secrettext
    • Run the following to verify the status of the bond assets owned by alice and bob in the Fabric network network1 from samples/fabric/fabric-cli folder:
      ./scripts/getAssetStatus.sh
    • Run the following to verify the status of the assets owned by PartyA and PartyB in the Corda_Network from samples/corda/corda-simple-application folder:
      ./scripts/getAssetStatus.sh

    The above steps complete a successful asset exchange between Fabric and Corda networks. +In addition to the above commands, following commands can be run if specified timeout has expired and the locked asset remains unclaimed.

    • If alice wants to unlock the bond asset, run the following to trigger alice's re-claim for bond01:a03 locked in network1:
      ./bin/fabric-cli asset exchange unlock --locker=alice --recipient=bob --target-network=network1 --param=bond01:a03
    • If PartyB wants to unlock the token asset, run the following to trigger unlock for t1:50 locked in Corda_Network:
      CORDA_PORT=10009 ./clients/build/install/clients/bin/clients unlock-asset --contract-id=<contract-id>
    + + \ No newline at end of file diff --git a/docs/external/getting-started/interop/asset-exchange/fabric-fabric/index.html b/docs/external/getting-started/interop/asset-exchange/fabric-fabric/index.html index 98bffb24b..1f31d6250 100644 --- a/docs/external/getting-started/interop/asset-exchange/fabric-fabric/index.html +++ b/docs/external/getting-started/interop/asset-exchange/fabric-fabric/index.html @@ -4,16 +4,16 @@ Asset Exchange: Fabric with Fabric | Weaver: DLT Interoperability Framework - - - + + +

    Asset Exchange: Fabric with Fabric

    One Fabric network transfers a bond from Alice to Bob in exchange for a transfer of tokens from Bob to Alice in the other network -Ensure that one of the following chaincodes have been deployed in both networks:

    • simpleasset
    • simpleassetandinterop
    • simpleassettransfer

    Run the following steps:

    Notes
    The hash used in following steps can be replaced by any valid SHA256 hash.
    1. Navigate to either the samples/fabric/fabric-cli folder or the samples/fabric/go-cli folder in your clone of the Weaver repository.
    2. Run the following to verify the status of the assets owned by alice and bob in the two networks:
      ./scripts/getAssetStatus.sh 2
    3. Complete the asset exchange in either of the two different ways:
      • Using a single command:
        • Run the following to trigger exchange of bond bond01:a03 owned by alice in network1 with 100 units of tokens token1 owned by bob in network2:
          ./bin/fabric-cli asset exchange-all --network1=network1 --network2=network2 --secret=secrettext --timeout-duration=100 alice:bond01:a03:bob:token1:100
        • To verify that bob now owns a bond in exchange for alice owning some tokens, run the following:
          ./scripts/getAssetStatus.sh 2
      • Using step-by-step commands:
        • Generate Secret-Hash Pair using following command (prints hash in base64):
          ./bin/fabric-cli hash --hash_fn=SHA256 secrettext
        • Run the following to trigger alice locking bond01:a03 for bob in network1
          ./bin/fabric-cli asset exchange lock --timeout-duration=3600 --locker=alice --recipient=bob --hashBase64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs= --target-network=network1 --param=bond01:a03
        • Run the following to verify alice's lock:
          ./bin/fabric-cli asset exchange is-locked --locker=alice --recipient=bob --target-network=network1 --param=bond01:a03
        • Run the following to trigger bob locking 100 units of token1 for alice in network2:
          ./bin/fabric-cli asset exchange lock --fungible --timeout-duration=1800 --locker=bob --recipient=alice --hashBase64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs= --target-network=network2 --param=token1:100
          Note the contract-id printed as output in above command. The output line containing contract-id (text in base64 after Contract Id:) would like this:
          ℹ Fungible Asset Locked with Contract Id: E0JZq8Z+eS//2Bt4WU0pU210MvNgDC2hdUT1RgszOq0=, preimage: null, hashvalue: ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs=
        • Run the following to verify bob's lock:
          ./bin/fabric-cli asset exchange is-locked --fungible --locker=bob --recipient=alice --target-network=network2 --contract-id=<contract-id>
        • Run the following to trigger alice's claim for 100 units of token1 locked by bob in network2:
          ./bin/fabric-cli asset exchange claim --fungible --recipient=alice --target-network=network2 --contract-id=<contract-id> --secret=<hash-pre-image>
        • Run the following to trigger bob's claim for bond01:a03 locked by alice in network1:
          ./bin/fabric-cli asset exchange claim --recipient=bob --locker=alice --target-network=network1 --param=bond01:a03 --secret=<hash-pre-image>
        The above steps complete a successful asset exchange between two Fabric networks. -In addition to the above commands, following commands can be run if specified timeout has expired and the locked asset remains unclaimed.
        • If alice wants to unlock the bond asset, run the following to trigger alice's re-claim for bond01:a03 locked in network1:
          ./bin/fabric-cli asset exchange unlock --locker=alice --recipient=bob --target-network=network1 --param=bond01:a03
        • If bob wants to unlock the token asset, run the following to trigger bob's re-claim for token1:100 locked in network2:
          ./bin/fabric-cli asset exchange unlock --fungible --locker=bob --target-network=network2 --contract-id=<contract-id>
    - - +Ensure that one of the following chaincodes have been deployed in both networks:

    • simpleasset
    • simpleassetandinterop
    • simpleassettransfer

    Run the following steps:

    Notes
    The hash used in following steps can be replaced by any valid SHA256 hash.
    1. Navigate to either the samples/fabric/fabric-cli folder (for the Node.js version) or the samples/fabric/go-cli folder (for the Golang version) in your clone of the Weaver repository.
    2. Run the following to verify the status of the assets owned by alice and bob in the two networks:
      ./scripts/getAssetStatus.sh 2
    3. Complete the asset exchange in either of the two different ways:
      • Using a single command:
        • Run the following to trigger exchange of bond bond01:a03 owned by alice in network1 with 100 units of tokens token1 owned by bob in network2:
          ./bin/fabric-cli asset exchange-all --network1=network1 --network2=network2 --secret=secrettext --timeout-duration=100 alice:bond01:a03:bob:token1:100
        • To verify that bob now owns a bond in exchange for alice owning some tokens, run the following:
          ./scripts/getAssetStatus.sh 2
      • Using step-by-step commands:
        • Generate Secret-Hash Pair using following command (prints hash in base64):
          ./bin/fabric-cli hash --hash_fn=SHA256 secrettext
        • Run the following to trigger alice locking bond01:a03 for bob in network1
          ./bin/fabric-cli asset exchange lock --timeout-duration=3600 --locker=alice --recipient=bob --hashBase64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs= --target-network=network1 --param=bond01:a03
        • Run the following to verify alice's lock:
          ./bin/fabric-cli asset exchange is-locked --locker=alice --recipient=bob --target-network=network1 --param=bond01:a03
        • Run the following to trigger bob locking 100 units of token1 for alice in network2:
          ./bin/fabric-cli asset exchange lock --fungible --timeout-duration=1800 --locker=bob --recipient=alice --hashBase64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs= --target-network=network2 --param=token1:100
          Note the contract-id printed as output in above command. The output line containing contract-id (text in base64 after Contract Id:) would like this:
          ℹ Fungible Asset Locked with Contract Id: E0JZq8Z+eS//2Bt4WU0pU210MvNgDC2hdUT1RgszOq0=, preimage: null, hashvalue: ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs=
        • Run the following to verify bob's lock:
          ./bin/fabric-cli asset exchange is-locked --fungible --locker=bob --recipient=alice --target-network=network2 --contract-id=<contract-id>
        • Run the following to trigger alice's claim for 100 units of token1 locked by bob in network2:
          ./bin/fabric-cli asset exchange claim --fungible --recipient=alice --target-network=network2 --contract-id=<contract-id> --secret=<hash-pre-image>
        • Run the following to trigger bob's claim for bond01:a03 locked by alice in network1:
          ./bin/fabric-cli asset exchange claim --recipient=bob --locker=alice --target-network=network1 --param=bond01:a03 --secret=<hash-pre-image>
        The above steps complete a successful asset exchange between two Fabric networks. +In addition to the above commands, following commands can be run if specified timeout has expired and the locked asset remains unclaimed.
        • If alice wants to unlock the bond asset, run the following to trigger alice's re-claim for bond01:a03 locked in network1:
          ./bin/fabric-cli asset exchange unlock --locker=alice --recipient=bob --target-network=network1 --param=bond01:a03
        • If bob wants to unlock the token asset, run the following to trigger bob's re-claim for token1:100 locked in network2:
          ./bin/fabric-cli asset exchange unlock --fungible --locker=bob --target-network=network2 --contract-id=<contract-id>
    + + \ No newline at end of file diff --git a/docs/external/getting-started/interop/asset-exchange/index.html b/docs/external/getting-started/interop/asset-exchange/index.html deleted file mode 100644 index 7347c93d7..000000000 --- a/docs/external/getting-started/interop/asset-exchange/index.html +++ /dev/null @@ -1,22 +0,0 @@ - - - - - -Asset Exchange | Weaver: DLT Interoperability Framework - - - - - -
    -

    Asset Exchange

    This document lists sample ways in which you can exercise the asset-exchange interoperation protocol on the test network launched earlier.

    For this scenario, you only need the networks to be running with the appropriate contracts deployed and the ledgers bootstrapped. You do not need to run relays and drivers. You can run the following combinations of exchanges (other combinations of DLTs will be supported soon).

    Fabric with Fabric

    One Fabric network transfers a bond from Alice to Bob in exchange for a transfer of tokens from Bob to Alice in the other network -Ensure that one of the following chaincodes have been deployed in both networks:

    • simpleasset
    • simpleassetandinterop
    • simpleassettransfer

    Run the following steps:

    Notes
    The hash used in following steps can be replaced by any valid SHA256 hash.
    1. Navigate to either the samples/fabric/fabric-cli folder or the samples/fabric/go-cli folder in your clone of the Weaver repository.
    2. Run the following to verify the status of the assets owned by alice and bob in the two networks:
      ./scripts/getAssetStatus.sh 2
    3. Complete the asset exchange in either of the two different ways:
      • Using a single command:
        • Run the following to trigger exchange of bond bond01:a03 owned by alice in network1 with 100 units of tokens token1 owned by bob in network2:
          ./bin/fabric-cli asset exchange-all --network1=network1 --network2=network2 --secret=secrettext --timeout-duration=100 alice:bond01:a03:bob:token1:100
        • To verify that bob now owns a bond in exchange for alice owning some tokens, run the following:
          ./scripts/getAssetStatus.sh 2
      • Using step-by-step commands:
        • Generate Secret-Hash Pair using following command (prints hash in base64):
          ./bin/fabric-cli hash --hash_fn=SHA256 secrettext
        • Run the following to trigger alice locking bond01:a03 for bob in network1
          ./bin/fabric-cli asset exchange lock --timeout-duration=3600 --locker=alice --recipient=bob --hashBase64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs= --target-network=network1 --param=bond01:a03
        • Run the following to verify alice's lock:
          ./bin/fabric-cli asset exchange is-locked --locker=alice --recipient=bob --target-network=network1 --param=bond01:a03
        • Run the following to trigger bob locking 100 units of token1 for alice in network2:
          ./bin/fabric-cli asset exchange lock --fungible --timeout-duration=1800 --locker=bob --recipient=alice --hashBase64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs= --target-network=network2 --param=token1:100
          Note the contract-id printed as output in above command. The output line containing contract-id (text in base64 after Contract Id:) would like this:
          ℹ Fungible Asset Locked with Contract Id: E0JZq8Z+eS//2Bt4WU0pU210MvNgDC2hdUT1RgszOq0=, preimage: null, hashvalue: ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs=
        • Run the following to verify bob's lock:
          ./bin/fabric-cli asset exchange is-locked --fungible --locker=bob --recipient=alice --target-network=network2 --contract-id=<contract-id>
        • Run the following to trigger alice's claim for 100 units of token1 locked by bob in network2:
          ./bin/fabric-cli asset exchange claim --fungible --recipient=alice --target-network=network2 --contract-id=<contract-id> --secret=<hash-pre-image>
        • Run the following to trigger bob's claim for bond01:a03 locked by alice in network1:
          ./bin/fabric-cli asset exchange claim --recipient=bob --locker=alice --target-network=network1 --param=bond01:a03 --secret=<hash-pre-image>
        The above steps complete a successful asset exchange between two Fabric networks. -In addition to the above commands, following commands can be run if specified timeout has expired and the locked asset remains unclaimed.
        • If alice wants to unlock the bond asset, run the following to trigger alice's re-claim for bond01:a03 locked in network1:
          ./bin/fabric-cli asset exchange unlock --locker=alice --recipient=bob --target-network=network1 --param=bond01:a03
        • If bob wants to unlock the token asset, run the following to trigger bob's re-claim for token1:100 locked in network2:
          ./bin/fabric-cli asset exchange unlock --fungible --locker=bob --target-network=network2 --contract-id=<contract-id>

    Fabric with Corda

    We will demonstrate asset exchange of a bond in Fabric network1 with tokens on Corda_Network. -For Fabric commands, run from samples/fabric/fabric-cli folder, and for Corda commands, run from samples/corda/corda-simple-application folder. Here Alice and Bob in Fabric network1 correspond to PartyA (CORDA_PORT=10006) and PartyB (CORDA_PORT=10009) in Corda_Network respectively. Following are the step-by-step asset exchange process:

    Notes
    The hash used in following steps can be replaced by any valid SHA256 hash.
    • Run the following to verify the status of the bond assets owned by alice and bob in the Fabric network network1 from samples/fabric/fabric-cli folder:
      ./scripts/getAssetStatus.sh
    • Run the following to verify the status of the assets owned by PartyA and PartyB in the Corda_Network from samples/corda/corda-simple-application folder:
    ./scripts/getAssetStatus.sh
    • Generate Secret-Hash Pair using following command (prints hash in base64):
      ./bin/fabric-cli hash --hash_fn=SHA256 secrettext
    • Run the following to trigger alice locking bond01:a03 for bob in network1 for 60 mins:
      ./bin/fabric-cli asset exchange lock --timeout-duration=3600 --locker=alice --recipient=bob --hashBase64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs= --target-network=network1 --param=bond01:a03
    • Run the following to verify alice's lock:
      ./bin/fabric-cli asset exchange is-locked --locker=alice --recipient=bob --target-network=network1 --param=bond01:a03
    • Run the following to trigger PartyB locking 50 units of token type t1 for PartyA in Corda_Network for 30 mins:
      CORDA_PORT=10009 ./clients/build/install/clients/bin/clients lock-asset --fungible --hashBase64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs= --timeout=1800 --recipient="O=PartyA,L=London,C=GB" --param=t1:50
      Note the contract-id displayed after successful execution of the command, will be used in next steps. The output containing contract-id would like this:
      HTLC Lock State created with contract ID Right(b=10448674_80d2bee7-5a5d-45df-b14e-60bac4ba1bf3).
      contract-id is the alphanumeric text (with underscore and hyphens) after b= within parenthesis.
    • Run the following to verify PartyB's lock (can be verified by both parties):
      CORDA_PORT=10006 ./clients/build/install/clients/bin/clients is-asset-locked --contract-id=<contract-id>
    • Run the following to trigger PartyA's claim for 50 units of token type t1 locked by PartyB in Corda_Network:
      CORDA_PORT=10006 ./clients/build/install/clients/bin/clients claim-asset --secret=secrettext --contract-id=<contract-id>
      PartyB can see its node's logs to get the revealed hash preimage, and use it to claim the bond in the Fabric network.
    • Run the following to trigger bob's claim for bond01:a03 locked by alice in network1:
      ./bin/fabric-cli asset exchange claim --recipient=bob --locker=alice --target-network=network1 --param=bond01:a03 --secret=secrettext
    • Run the following to verify the status of the bond assets owned by alice and bob in the Fabric network network1 from samples/fabric/fabric-cli folder:
      ./scripts/getAssetStatus.sh
    • Run the following to verify the status of the assets owned by PartyA and PartyB in the Corda_Network from samples/corda/corda-simple-application folder:
      ./scripts/getAssetStatus.sh

    The above steps complete a successful asset exchange between Fabric and Corda networks. -In addition to the above commands, following commands can be run if specified timeout has expired and the locked asset remains unclaimed.

    • If alice wants to unlock the bond asset, run the following to trigger alice's re-claim for bond01:a03 locked in network1:
      ./bin/fabric-cli asset exchange unlock --locker=alice --recipient=bob --target-network=network1 --param=bond01:a03
    • If PartyB wants to unlock the token asset, run the following to trigger unlock for t1:50 locked in Corda_Network:
      CORDA_PORT=10009 ./clients/build/install/clients/bin/clients unlock-asset --contract-id=<contract-id>

    Corda with Corda

    We will demonstrate asset exchange of a tokens in Corda_Network with tokens on Corda_Network2. Here PartyA (CORDA_PORT=10006) and PartyB (CORDA_PORT=10009) in Corda_Network correspond to PartyA (CORDA_PORT=30006) and PartyB (CORDA_PORT=30009) in Corda_Network2 respectively. Following are the step-by-step asset exchange process:

    Notes
    The hash used in following steps can be replaced by any valid SHA256 hash.
    • Navigate to samples/corda/corda-simple-application folder.
    • Run the following to verify the status of the tokens owned by PartyA and PartyB in the Corda_Network and Corda_Network2:
      ./scripts/getAssetStatus.sh 2
    • Generate Secret-Hash Pair using following command (prints hash in base64):
    ./clients/build/install/clients/bin/clients utils hash --hash-fn=SHA256 -s secrettext
    • Run the following to trigger PartyA locking 30 units of token type t1 for PartyB in Corda_Network for 60 mins:
      CORDA_PORT=10006 ./clients/build/install/clients/bin/clients lock-asset --fungible --hashBase64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs= --timeout=3600 --recipient="O=PartyB,L=London,C=GB" --param=t1:30
      Note the contract-id displayed after successful execution of the command, will be used in next steps. The output containing contract-id would like this:
      HTLC Lock State created with contract ID Right(b=10448674_80d2bee7-5a5d-45df-b14e-60bac4ba1bf3).
      contract-id is the alphanumeric text (with underscore and hyphens) after b= within parenthesis. Let's denote it <contract-id-1>.
    • Run the following to verify PartyA's lock (can be verified by both parties):
      CORDA_PORT=10009 ./clients/build/install/clients/bin/clients is-asset-locked --contract-id=<contract-id-1>
    • Run the following to trigger PartyB locking 50 units of token type t2 for PartyA in Corda_Network2 for 30 mins:
      CORDA_PORT=30009 ./clients/build/install/clients/bin/clients lock-asset --fungible --hashBase64=ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs= --timeout=1800 --recipient="O=PartyA,L=London,C=GB" --param=t2:50
      Note the contract-id displayed after successful execution of the command, will be used in next steps. Let's denote it <contract-id-2>.
    • Run the following to verify PartyB's lock (can be verified by both parties):
      CORDA_PORT=30006 ./clients/build/install/clients/bin/clients is-asset-locked --contract-id=<contract-id-2>
    • Run the following to trigger PartyA's claim for 50 units of token type t2 locked by PartyB in Corda_Network2:
      CORDA_PORT=30006 ./clients/build/install/clients/bin/clients claim-asset --secret=secrettext --contract-id=<contract-id-2>
      PartyB can see its node's logs to get the revealed hash preimage, and use it to claim the bond in the Fabric network.
    • Run the following to trigger PartyB's claim for 30 units of token type t1 locked by PartyA in Corda_Network:
      CORDA_PORT=10009 ./clients/build/install/clients/bin/clients claim-asset --secret=secrettext --contract-id=<contract-id-1>
    • Run the following to verify the status of the tokens owned by PartyA and PartyB in the Corda_Network and Corda_Network2:
      ./scripts/getAssetStatus.sh 2

    The above steps complete a successful asset exchange between two Corda networks. -In addition to the above commands, following commands can be run if specified timeout has expired and the locked asset remains unclaimed.

    • If PartyA wants to unlock the token t1:30 asset, run the following to trigger PartyA's re-claim in Corda_Network:
      CORDA_PORT=10006 ./clients/build/install/clients/bin/clients unlock-asset --contract-id=<contract-id-1>
    • If PartyB wants to unlock the token t2:50 asset, run the following to trigger PartyB's re-claim in Corda_Network2:
      CORDA_PORT=30009 ./clients/build/install/clients/bin/clients unlock-asset --contract-id=<contract-id-2>
    - - - - \ No newline at end of file diff --git a/docs/external/getting-started/interop/asset-exchange/overview/index.html b/docs/external/getting-started/interop/asset-exchange/overview/index.html index bcfb8dd8d..ae43bb658 100644 --- a/docs/external/getting-started/interop/asset-exchange/overview/index.html +++ b/docs/external/getting-started/interop/asset-exchange/overview/index.html @@ -4,14 +4,14 @@ Asset Exchange | Weaver: DLT Interoperability Framework - - - + + +
    -

    Asset Exchange

    This document lists sample ways in which you can exercise the asset-exchange interoperation protocol on the test network launched earlier.

    For this scenario, you only need the networks to be running with the appropriate contracts deployed and the ledgers bootstrapped. You do not need to run relays, drivers and IIN agents. You can run the following combinations of exchanges (other combinations of DLTs will be supported soon).

    - - +

    Asset Exchange

    This document lists sample ways in which you can exercise the asset-exchange interoperation protocol on the test network launched earlier.

    For this scenario, you only need the networks to be running with the appropriate contracts deployed and the ledgers bootstrapped. You do not need to run relays, drivers and IIN agents. You can run the following combinations of exchanges (other combinations of DLTs will be supported soon).

    + + \ No newline at end of file diff --git a/docs/external/getting-started/interop/asset-transfer/index.html b/docs/external/getting-started/interop/asset-transfer/index.html index d11e3df10..ef1abafdf 100644 --- a/docs/external/getting-started/interop/asset-transfer/index.html +++ b/docs/external/getting-started/interop/asset-transfer/index.html @@ -4,14 +4,14 @@ Asset Transfer | Weaver: DLT Interoperability Framework - - - + + +
    -

    Asset Transfer

    This document lists sample ways in which you can exercise the asset-transfer interoperation protocol on the test network launched earlier.

    Once the networks, relays, and drivers have been launched, and the ledgers bootstrapped, you can trigger the following interoperation flows corresponding to distinct asset-sharing combinations other combinations of DLTs will be supported soon):

    1. Fabric with Fabric

    One Fabric network transfers either a bond or some tokens owned by Alice to Bob in the other network

    Assuming that the simpleassettransfer chaincode has been deployed in both networks, run the following steps by navigating to the samples/fabric/fabric-cli folder (the Go CLI doesn't support asset transfer yet).

    Transfer or recover a bond (non-fungible) asset

    1. Verify that alice owns bonds with ids a03 and a04 as follows:
      ./bin/fabric-cli chaincode query --user=alice mychannel simpleassettransfer ReadAsset '["bond01","a03"]' --local-network=network1
      ./bin/fabric-cli chaincode query --user=alice mychannel simpleassettransfer ReadAsset '["bond01","a04"]' --local-network=network1
      You should see a JSON structure corresponding to the bond being logged on the console in each case.
    2. Get alice in network1 to pledge bond a03 to bob in network2 as follows (with a 1 hour timeout):
      ./bin/fabric-cli asset transfer pledge --source-network=network1 --dest-network=network2 --recipient=bob --expiry-secs=3600 --type=bond --ref=a03 --data-file=src/data/assetsForTransfer.json
      You should see a message containing the unique ID of this pledge on the console as Asset pledged with ID <pledge-id> (<pledge-id> is a hexadecimal string).
    3. Get bob in network2 to claim this bond asset as follows:
      ./bin/fabric-cli asset transfer claim --source-network=network1 --dest-network=network2 --user=bob --owner=alice --type='bond.fabric' --pledge-id=<pledge-id> --param=bond01:a03
    4. Verify that alice in network1 does not own this asset as follows:
      ./bin/fabric-cli chaincode query --user=alice mychannel simpleassettransfer ReadAsset '["bond01","a03"]' --local-network=network1
      You should see an error message like Error: the asset a03 does not exist.
    5. Verify that bob in network2 now owns this asset as follows:
      ./bin/fabric-cli chaincode query --user=bob mychannel simpleassettransfer ReadAsset '["bond01","a03"]' --local-network=network2
    6. Now get alice in network1 to pledge bond a04 to bob in network2 as follows (with a 1 minute timeout):
      ./bin/fabric-cli asset transfer pledge --source-network=network1 --dest-network=network2 --recipient=bob --expiry-secs=60 --type=bond --ref=a04 --data-file=src/data/assetsForTransfer.json
      Wait for a minute as follows:
      sleep 60
      You should see a message containing the unique ID of this pledge on the console as Asset pledged with ID <pledge-id> (<pledge-id> is a hexadecimal string).
    7. Now get bob in network2 to claim this bond asset as follows:
      ./bin/fabric-cli asset transfer claim --source-network=network1 --dest-network=network2 --user=bob --owner=alice --type='bond.fabric' --pledge-id=<pledge-id> --param=bond01:a04
      This should fail as the pledge has already expired.
    8. Now get alice in network1 to reclaim the asset as follows:
      ./bin/fabric-cli asset transfer reclaim --source-network=network1 --user=alice --type='bond.fabric' --pledge-id=<pledge-id> --param=bond01:a04
    9. Verify that alice in network1 owns this asset as follows:
      ./bin/fabric-cli chaincode query --user=alice mychannel simpleassettransfer ReadAsset '["bond01","a04"]' --local-network=network1
    10. Verify that bob in network2 does not own this asset as follows:
      ./bin/fabric-cli chaincode query --user=bob mychannel simpleassettransfer ReadAsset '["bond01","a04"]' --local-network=network2
      You should see an error message like Error: the asset a04 does not exist.

    Transfer or recover token (fungible) assets

    1. Verify that alice in network1 owns 10000 tokens as follows:
      ./scripts/getTokenBalance.sh network1 alice
    2. Verify that bob in network2 owns no tokens as follows:
      ./scripts/getTokenBalance.sh network2 bob
      You should see an error message like Error: owner does not have a wallet.
    3. Get alice in network1 to pledge 50 tokens to bob in network2 as follows (with a 1 hour timeout):
      ./bin/fabric-cli asset transfer pledge --source-network=network1 --dest-network=network2 --recipient=bob --expiry-secs=3600 --type=token --units=50 --owner=alice --data-file=src/data/tokensForTransfer.json
      You should see a message containing the unique ID of this pledge on the console as Asset pledged with ID <pledge-id> (<pledge-id> is a hexadecimal string).
    4. Get bob in network2 to claim these tokens as follows (replace <pledge-id> with the above hexadecimal value):
      ./bin/fabric-cli asset transfer claim --source-network=network1 --dest-network=network2 --user=bob --owner=alice --type='token.fabric' --pledge-id=<pledge-id> --param=token1:50
    5. Verify that alice in network1 owns 9950 tokens (after losing 50) as follows:
      ./scripts/getTokenBalance.sh network1 alice
    6. Verify that bob in network2 now owns 50 tokens as follows:
      ./scripts/getTokenBalance.sh network2 bob
    7. Now get alice in network1 to pledge 100 tokens to bob in network2 as follows (with a 1 minute timeout):
      ./bin/fabric-cli asset transfer pledge --source-network=network1 --dest-network=network2 --recipient=bob --expiry-secs=60 --type=token --units=100 --owner=alice --data-file=src/data/tokensForTransfer.json
      Wait for a minute as follows:
      sleep 60
      You should see a message containing the unique ID of this pledge on the console as Asset pledged with ID <pledge-id> (<pledge-id> is a hexadecimal string).
    8. Now get bob in network2 to claim these tokens as follows (replace <pledge-id> with the above hexadecimal value):
      ./bin/fabric-cli asset transfer claim --source-network=network1 --dest-network=network2 --user=bob --owner=alice --type='token.fabric' --pledge-id=<pledge-id> --param=token1:100
      This should fail as the pledge has already expired.
    9. Now get alice in network1 to reclaim these tokens as follows:
      ./bin/fabric-cli asset transfer reclaim --source-network=network1 --user=alice --type='token.fabric' --pledge-id=<pledge-id> --param=token1:100
    10. Verify that alice in network1 still owns 9950 tokens (after losing 50) as follows:
      ./scripts/getTokenBalance.sh network1 alice
    11. Verify that bob in network2 still owns only 50 tokens as follows:
      ./scripts/getTokenBalance.sh network2 bob

    2. Corda with Corda

    One Corda network transfers either a bond or some tokens owned by the party PartyA (CORDA_PORT=10006) to the party PartyA (CORDA_PORT=30006) in the other network.

    Transfer or recover token (fungible) assets

    Assume that the CorDapp cordaSimpleApplication has been deployed in both networks.

    • Navigate to samples/corda/corda-simple-application folder.
    • Add 5 tokens of type t1 to PartyA in Corda_Network:
      NETWORK_NAME='Corda_Network' CORDA_PORT=10006 ./clients/build/install/clients/bin/clients issue-asset-state 5 t1
      (check token balance for PartyA by running the command CORDA_PORT=10006 ./clients/build/install/clients/bin/clients get-asset-states-by-type t1)
    • Let PartyA pledge these tokens in Corda_Network to be transferred to PartyA of Corda_Network2 (pledge burns the tokens in the source/exporting network):
      NETWORK_NAME='Corda_Network' CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer pledge-asset --fungible --timeout="3600" --import-network-id='Corda_Network2' --recipient='O=PartyA, L=London, C=GB' --param='t1:5'
      Note the pledge-id displayed after successful execution of the command, which will be used in next steps. Let's denote it <pledge-id> which is a hexadecimal string (pledge details can be cross checked using the commands CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer is-asset-pledged -pid <pledge-id> and CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer get-pledge-state -pid <pledge-id>).
    • Check the token asset balance for PartyA in Corda_Network by running the below command, and the output should not include the asset t1:5 issued earlier.
      CORDA_PORT=10006 ./clients/build/install/clients/bin/clients get-asset-states-by-type t1
    • Let PartyA claim in Corda_Network2 the tokens which are pledged in the Corda network Corda_Network by replacing <pledge-id> with the above hexadecimal value (claim issues the tokens in the destination/importing network):
      NETWORK_NAME='Corda_Network2' CORDA_PORT=30006 ./clients/build/install/clients/bin/clients transfer claim-remote-asset --pledge-id='<pledge-id>' --locker='O=PartyA, L=London, C=GB' --transfer-category='token.corda' --export-network-id='Corda_Network' --param='t1:5' --import-relay-address='localhost:9082'
      (the linear-id, which is displayed after successful execution of the above command, can be used to check the newly issued tokens for PartyA in Corda_Network2 by running CORDA_PORT=30006 ./clients/build/install/clients/bin/clients get-state-using-linear-id <linear-id>; or simply check the token balance for PartyA by running the command CORDA_PORT=30006 ./clients/build/install/clients/bin/clients get-asset-states-by-type t1 which should output 5 tokens of type t1)

    The above steps complete a successful asset transfer from the Corda network Corda_Network to the Corda network Corda_Network2. In addition to the above commands, following is an extra option.

    • Let PartyA in Corda_Network try re-claim the token t1:5 asset, which will succeed only if the asset was not claimed by PartyA in Corda_Network2 and the pledge has expired:
      NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer reclaim-pledged-asset --pledge-id=<pledge-id> --export-relay-address='localhost:9081' --transfer-category='token.corda' --import-network-id='Corda_Network2' --param='t1:5'

    Transfer or recover bond (non-fungible) assets

    Assume that the CorDapp cordaSimpleApplication has been deployed in both networks.

    • Navigate to samples/corda/corda-simple-application folder.
    • Add a bond asset with id a10 and type bond01 to PartyA in Corda_Network:
      NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients bond issue-asset 'a10' 'bond01'
      (check token balance for PartyA by running the command CORDA_PORT=10006 ./clients/build/install/clients/bin/clients bond get-assets-by-type 'bond01')
    • Let PartyA pledge these tokens in Corda_Network to be transferred to PartyA of Corda_Network2 (pledge burns the tokens in the source/exporting network):
      NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer pledge-asset --timeout="3600" --import-network-id='Corda_Network2' --recipient='O=PartyA, L=London, C=GB' --param='bond01:a10'
      Note the pledge-id displayed after successful execution of the command, which will be used in next steps. Let's denote it <pledge-id> which is a hexadecimal string (pledge details can be cross checked using the commands CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer is-asset-pledged -pid <pledge-id> and CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer get-pledge-state -pid <pledge-id>).
    • Check the bond asset balance for PartyA in Corda_Network by running the below command, and the output should not include the asset bond01:a10 issued earlier.
      CORDA_PORT=10006 ./clients/build/install/clients/bin/clients bond get-assets-by-type 'bond01'`
    • Let PartyA in Corda_Network2 claim the bond asset which is pledged in the Corda network Corda_Network by replacing <pledge-id> with the above hexadecimal value (claim issues the bond asset in the destination/importing network):
      NETWORK_NAME=Corda_Network2 CORDA_PORT=30006 ./clients/build/install/clients/bin/clients transfer claim-remote-asset --pledge-id='<pledge-id>' --locker='O=PartyA, L=London, C=GB' --transfer-category='bond.corda' --export-network-id='Corda_Network' --param='bond01:a10' --import-relay-address='localhost:9082'
      (the linear-id, which is displayed after successful execution of the above command, can be used to check the newly issued bond asset for PartyA in Corda_Network2 by running CORDA_PORT=30006 ./clients/build/install/clients/bin/clients bond get-asset-by-linear-id <linear-id>; or simply check the bond asset balance for PartyA by running the command CORDA_PORT=30006 ./clients/build/install/clients/bin/clients bond get-assets-by-type 'bond01' which should output asset with id a10 and type bond01)

    The above steps complete a successful asset transfer from the Corda network Corda_Network to the Corda network Corda_Network2. In addition to the above commands, following is an extra option.

    • Let PartyA in Corda_Network try re-claim the bond asset bond01:a10, which will succeed only if the asset was not claimed by PartyA and the pledge has expired:
      NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer reclaim-pledged-asset --pledge-id=<pledge-id> --export-relay-address='localhost:9081' --transfer-category='bond.corda' --import-network-id='Corda_Network2' --param='bond01:a10'

    3. Fabric with Corda

    A Fabric network transfers some tokens owned by Alice to PartyA (CORDA_PORT=10006) in a Corda network.

    Transfer or recover token (fungible) assets

    Assuming that the simpleassettransfer chaincode has been deployed in Fabric network network1, run the following steps related to Fabric by navigating to the samples/fabric/fabric-cli folder (the Go CLI doesn't support asset transfer yet).

    Similarly, assuming that the CorDapp cordaSimpleApplication has been deployed in the Corda network Corda_Network, run the following steps related to Corda by navigating to the samples/corda/corda-simple-application folder.

    • Verify that alice in network1 owns 10000 tokens as follows:

      ./scripts/getTokenBalance.sh network1 alice
    • Get alice in network1 to pledge 50 tokens to PartyA in Corda_Network as follows (with a 1 hour timeout):

      ./bin/fabric-cli asset transfer pledge --source-network='network1' --dest-network='Corda_Network' --recipient='O=PartyA, L=London, C=GB' --expiry-secs=3600 --type='token' --units=50 --owner=alice --data-file=src/data/tokensForTransfer.json

      You should see a message containing the unique ID of this pledge on the console as Asset pledged with ID <pledge-id> (<pledge-id> is a hexadecimal string).

    • Verify that alice in network1 owns 9950 tokens (after losing 50) as follows:

      ./scripts/getTokenBalance.sh network1 alice
    • Let PartyA claim in Corda_Network the tokens which are pledged in the Fabric network network1 by replacing <pledge-id> with the above hexadecimal value (claim issues the tokens in the destination/importing network):

      NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer claim-remote-asset --pledge-id='<pledge-id>' --locker='alice' --transfer-category='token.fabric' --export-network-id='network1' --param='token1:50' --import-relay-address='localhost:9081'

      (the linear-id, which is displayed after successful execution of the above command, can be used to check the newly issued tokens for PartyA in Corda_Network by running CORDA_PORT=10006 ./clients/build/install/clients/bin/clients get-state-using-linear-id <linear-id>; or simply check the token balance for PartyA by running the command CORDA_PORT=10006 ./clients/build/install/clients/bin/clients get-asset-states-by-type token1 which should output 50 tokens of type token1)

    The above steps complete a successful asset transfer from the Fabric network network1 to the Corda network Corda_Network. Below demostrates re-claim of the tokens pledged in the Fabric network after the pledge expiry.

    • Now get alice in network1 to pledge 100 tokens to PartyA in Corda_Network as follows (with a 1 minute timeout):

      ./bin/fabric-cli asset transfer pledge --source-network='network1' --dest-network='Corda_Network' --recipient='O=PartyA, L=London, C=GB' --expiry-secs=60 --type=token --units=100 --owner=alice --data-file=src/data/tokensForTransfer.json

      You should see a message containing the unique ID of this pledge on the console as Asset pledged with ID <pledge-id> (<pledge-id> is a hexadecimal string).

      Wait for a minute as follows:

      sleep 60
    • Let PartyA in Corda_Network claim the tokens which are pledged in the Fabric network network1 by replacing <pledge-id> with the above hexadecimal value (claim issues the tokens in the destination/importing network):

      NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer claim-remote-asset --pledge-id='<pledge-id>' --locker='alice' --transfer-category='token.fabric' --export-network-id='network1' --param='token1:100' --import-relay-address='localhost:9080'

      This should fail as the pledge has already expired.

      (check the token balance for PartyA by running the command CORDA_PORT=10006 ./clients/build/install/clients/bin/clients get-asset-states-by-type token1 which should still show 50 tokens of type token1 but not 150)

    • Now get alice in network1 to reclaim these tokens as follows:

      ./bin/fabric-cli asset transfer reclaim --source-network='network1' --user='alice' --type='token.corda' --pledge-id=<pledge-id> --param=token1:100
    • Verify that alice in network1 still owns 9950 tokens (after losing 50) as follows:

      ./scripts/getTokenBalance.sh network1 alice

    4. Corda with Fabric

    A Corda network transfers some tokens owned by PartyA (CORDA_PORT=10006) to Alice in a Fabric network.

    Transfer or recover token (fungible) assets

    Assuming that the CorDapp cordaSimpleApplication has been deployed in the Corda network Corda_Network, run the following steps related to Corda by navigating to the samples/corda/corda-simple-application folder.

    Similarly, assume that the simpleassettransfer chaincode has been deployed in Fabric network network1, run the following steps related to Fabric by navigating to the samples/fabric/fabric-cli folder (the Go CLI doesn't support asset transfer yet).

    • Add 5 tokens of type token1 to PartyA in Corda_Network:
      CORDA_PORT=10006 ./clients/build/install/clients/bin/clients issue-asset-state 5 token1
      (check token balance for PartyA by running the command CORDA_PORT=10006 ./clients/build/install/clients/bin/clients get-asset-states-by-type token1)
    • Let PartyA pledge (with a 1 hour timeout) these tokens in Corda_Network to be transferred to Alice of Fabric network network1 (pledge burns the tokens in the source/exporting network):
      CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer pledge-asset --fungible --timeout="3600" --import-network-id='network1' --recipient='alice' --param='token1:5'
      Note the pledge-id displayed after successful execution of the command, which will be used in next steps. Let's denote it <pledge-id> which is a hexadecimal string (pledge details can be cross checked using the commands CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer is-asset-pledged -pid <pledge-id> and CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer get-pledge-state -pid <pledge-id>).
    • Check the token asset balance for PartyA in Corda_Network by running the below command, and the output should not include the asset token1:5 issued earlier.
      CORDA_PORT=10006 ./clients/build/install/clients/bin/clients get-asset-states-by-type token1`
    • Verify that alice in network1 owns 10000 tokens as follows:
      ./scripts/getTokenBalance.sh network1 alice
    • Get alice in network to claim these tokens as follows (replace <pledge-id> with the above hexadecimal value):
      ./bin/fabric-cli asset transfer claim --source-network='Corda_Network' --dest-network=network1 --user='alice' --owner='O=PartyA, L=London, C=GB' --type='token.corda' --pledge-id=<pledge-id> --param=token1:5
    • Verify that alice in network now owns 1050 tokens as follows:
      ./scripts/getTokenBalance.sh network1 alice

    The above steps complete a successful asset transfer from the Corda network Corda_Network to the Fabric network network1. In addition to the above commands, following is an extra option.

    • Let PartyA in Corda_Network try re-claim the token token1:5 asset, which will succeed only if the asset was not claimed by alice in Fabric network and the pledge has expired (replace <pledge-id> with the above hexadecimal value):
      NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer reclaim-pledged-asset --pledge-id=<pledge-id> --export-relay-address='localhost:9081' --transfer-category='token.fabric' --import-network-id='network1' --param='token1:5'
    - - +

    Asset Transfer

    This document lists sample ways in which you can exercise the asset-transfer interoperation protocol on the test network launched earlier.

    Once the networks, relays, and drivers have been launched, and the ledgers bootstrapped, you can trigger the following interoperation flows corresponding to distinct asset-sharing combinations other combinations of DLTs will be supported soon):

    1. Fabric with Fabric

    One Fabric network transfers either a bond or some tokens owned by Alice to Bob in the other network

    Assuming that the simpleassettransfer chaincode has been deployed in both networks, run the following steps by navigating to the samples/fabric/fabric-cli folder (the Go CLI doesn't support asset transfer yet).

    Transfer or recover a bond (non-fungible) asset

    1. Verify that alice owns bonds with ids a03 and a04 as follows:
      ./bin/fabric-cli chaincode query --user=alice mychannel simpleassettransfer ReadAsset '["bond01","a03"]' --local-network=network1
      ./bin/fabric-cli chaincode query --user=alice mychannel simpleassettransfer ReadAsset '["bond01","a04"]' --local-network=network1
      You should see a JSON structure corresponding to the bond being logged on the console in each case.
    2. Get alice in network1 to pledge bond a03 to bob in network2 as follows (with a 1 hour timeout):
      ./bin/fabric-cli asset transfer pledge --source-network=network1 --dest-network=network2 --recipient=bob --expiry-secs=3600 --type=bond --ref=a03 --data-file=src/data/assetsForTransfer.json
      You should see a message containing the unique ID of this pledge on the console as Asset pledged with ID <pledge-id> (<pledge-id> is a hexadecimal string).
    3. Get bob in network2 to claim this bond asset as follows:
      ./bin/fabric-cli asset transfer claim --source-network=network1 --dest-network=network2 --user=bob --owner=alice --type='bond.fabric' --pledge-id=<pledge-id> --param=bond01:a03
    4. Verify that alice in network1 does not own this asset as follows:
      ./bin/fabric-cli chaincode query --user=alice mychannel simpleassettransfer ReadAsset '["bond01","a03"]' --local-network=network1
      You should see an error message like Error: the asset a03 does not exist.
    5. Verify that bob in network2 now owns this asset as follows:
      ./bin/fabric-cli chaincode query --user=bob mychannel simpleassettransfer ReadAsset '["bond01","a03"]' --local-network=network2
    6. Now get alice in network1 to pledge bond a04 to bob in network2 as follows (with a 1 minute timeout):
      ./bin/fabric-cli asset transfer pledge --source-network=network1 --dest-network=network2 --recipient=bob --expiry-secs=60 --type=bond --ref=a04 --data-file=src/data/assetsForTransfer.json
      Wait for a minute as follows:
      sleep 60
      You should see a message containing the unique ID of this pledge on the console as Asset pledged with ID <pledge-id> (<pledge-id> is a hexadecimal string).
    7. Now get bob in network2 to claim this bond asset as follows:
      ./bin/fabric-cli asset transfer claim --source-network=network1 --dest-network=network2 --user=bob --owner=alice --type='bond.fabric' --pledge-id=<pledge-id> --param=bond01:a04
      This should fail as the pledge has already expired.
    8. Now get alice in network1 to reclaim the asset as follows:
      ./bin/fabric-cli asset transfer reclaim --source-network=network1 --user=alice --type='bond.fabric' --pledge-id=<pledge-id> --param=bond01:a04
    9. Verify that alice in network1 owns this asset as follows:
      ./bin/fabric-cli chaincode query --user=alice mychannel simpleassettransfer ReadAsset '["bond01","a04"]' --local-network=network1
    10. Verify that bob in network2 does not own this asset as follows:
      ./bin/fabric-cli chaincode query --user=bob mychannel simpleassettransfer ReadAsset '["bond01","a04"]' --local-network=network2
      You should see an error message like Error: the asset a04 does not exist.

    Transfer or recover token (fungible) assets

    1. Verify that alice in network1 owns 10000 tokens as follows:
      ./scripts/getTokenBalance.sh network1 alice
    2. Verify that bob in network2 owns no tokens as follows:
      ./scripts/getTokenBalance.sh network2 bob
      You should see an error message like Error: owner does not have a wallet.
    3. Get alice in network1 to pledge 50 tokens to bob in network2 as follows (with a 1 hour timeout):
      ./bin/fabric-cli asset transfer pledge --source-network=network1 --dest-network=network2 --recipient=bob --expiry-secs=3600 --type=token --units=50 --owner=alice --data-file=src/data/tokensForTransfer.json
      You should see a message containing the unique ID of this pledge on the console as Asset pledged with ID <pledge-id> (<pledge-id> is a hexadecimal string).
    4. Get bob in network2 to claim these tokens as follows (replace <pledge-id> with the above hexadecimal value):
      ./bin/fabric-cli asset transfer claim --source-network=network1 --dest-network=network2 --user=bob --owner=alice --type='token.fabric' --pledge-id=<pledge-id> --param=token1:50
    5. Verify that alice in network1 owns 9950 tokens (after losing 50) as follows:
      ./scripts/getTokenBalance.sh network1 alice
    6. Verify that bob in network2 now owns 50 tokens as follows:
      ./scripts/getTokenBalance.sh network2 bob
    7. Now get alice in network1 to pledge 100 tokens to bob in network2 as follows (with a 1 minute timeout):
      ./bin/fabric-cli asset transfer pledge --source-network=network1 --dest-network=network2 --recipient=bob --expiry-secs=60 --type=token --units=100 --owner=alice --data-file=src/data/tokensForTransfer.json
      Wait for a minute as follows:
      sleep 60
      You should see a message containing the unique ID of this pledge on the console as Asset pledged with ID <pledge-id> (<pledge-id> is a hexadecimal string).
    8. Now get bob in network2 to claim these tokens as follows (replace <pledge-id> with the above hexadecimal value):
      ./bin/fabric-cli asset transfer claim --source-network=network1 --dest-network=network2 --user=bob --owner=alice --type='token.fabric' --pledge-id=<pledge-id> --param=token1:100
      This should fail as the pledge has already expired.
    9. Now get alice in network1 to reclaim these tokens as follows:
      ./bin/fabric-cli asset transfer reclaim --source-network=network1 --user=alice --type='token.fabric' --pledge-id=<pledge-id> --param=token1:100
    10. Verify that alice in network1 still owns 9950 tokens (after losing 50) as follows:
      ./scripts/getTokenBalance.sh network1 alice
    11. Verify that bob in network2 still owns only 50 tokens as follows:
      ./scripts/getTokenBalance.sh network2 bob

    2. Corda with Corda

    One Corda network transfers either a bond or some tokens owned by the party PartyA (CORDA_PORT=10006) to the party PartyA (CORDA_PORT=30006) in the other network.

    Transfer or recover token (fungible) assets

    Assume that the CorDapp cordaSimpleApplication has been deployed in both networks.

    • Navigate to the samples/corda/corda-simple-application folder in your clone of the Weaver repository.
    • Add 5 tokens of type t1 to PartyA in Corda_Network:
      NETWORK_NAME='Corda_Network' CORDA_PORT=10006 ./clients/build/install/clients/bin/clients issue-asset-state 5 t1
      (check token balance for PartyA by running the command CORDA_PORT=10006 ./clients/build/install/clients/bin/clients get-asset-states-by-type t1)
    • Let PartyA pledge these tokens in Corda_Network to be transferred to PartyA of Corda_Network2 (pledge burns the tokens in the source/exporting network):
      NETWORK_NAME='Corda_Network' CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer pledge-asset --fungible --timeout="3600" --import-network-id='Corda_Network2' --recipient='O=PartyA, L=London, C=GB' --param='t1:5'
      Note the pledge-id displayed after successful execution of the command, which will be used in next steps. Let's denote it <pledge-id> which is a hexadecimal string (pledge details can be cross checked using the commands CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer is-asset-pledged -pid <pledge-id> and CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer get-pledge-state -pid <pledge-id>).
    • Check the token asset balance for PartyA in Corda_Network by running the below command, and the output should not include the asset t1:5 issued earlier.
      CORDA_PORT=10006 ./clients/build/install/clients/bin/clients get-asset-states-by-type t1
    • Let PartyA claim in Corda_Network2 the tokens which are pledged in the Corda network Corda_Network by replacing <pledge-id> with the above hexadecimal value (claim issues the tokens in the destination/importing network):
      NETWORK_NAME='Corda_Network2' CORDA_PORT=30006 ./clients/build/install/clients/bin/clients transfer claim-remote-asset --pledge-id='<pledge-id>' --locker='O=PartyA, L=London, C=GB' --transfer-category='token.corda' --export-network-id='Corda_Network' --param='t1:5' --import-relay-address='localhost:9082'
      (the linear-id, which is displayed after successful execution of the above command, can be used to check the newly issued tokens for PartyA in Corda_Network2 by running CORDA_PORT=30006 ./clients/build/install/clients/bin/clients get-state-using-linear-id <linear-id>; or simply check the token balance for PartyA by running the command CORDA_PORT=30006 ./clients/build/install/clients/bin/clients get-asset-states-by-type t1 which should output 5 tokens of type t1)

    The above steps complete a successful asset transfer from the Corda network Corda_Network to the Corda network Corda_Network2. In addition to the above commands, following is an extra option.

    • Let PartyA in Corda_Network try re-claim the token t1:5 asset, which will succeed only if the asset was not claimed by PartyA in Corda_Network2 and the pledge has expired:
      NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer reclaim-pledged-asset --pledge-id=<pledge-id> --export-relay-address='localhost:9081' --transfer-category='token.corda' --import-network-id='Corda_Network2' --param='t1:5'

    Transfer or recover bond (non-fungible) assets

    Assume that the CorDapp cordaSimpleApplication has been deployed in both networks.

    • Navigate to the samples/corda/corda-simple-application folder in your clone of the Weaver repository.
    • Add a bond asset with id a10 and type bond01 to PartyA in Corda_Network:
      NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients bond issue-asset 'a10' 'bond01'
      (check token balance for PartyA by running the command CORDA_PORT=10006 ./clients/build/install/clients/bin/clients bond get-assets-by-type 'bond01')
    • Let PartyA pledge these tokens in Corda_Network to be transferred to PartyA of Corda_Network2 (pledge burns the tokens in the source/exporting network):
      NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer pledge-asset --timeout="3600" --import-network-id='Corda_Network2' --recipient='O=PartyA, L=London, C=GB' --param='bond01:a10'
      Note the pledge-id displayed after successful execution of the command, which will be used in next steps. Let's denote it <pledge-id> which is a hexadecimal string (pledge details can be cross checked using the commands CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer is-asset-pledged -pid <pledge-id> and CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer get-pledge-state -pid <pledge-id>).
    • Check the bond asset balance for PartyA in Corda_Network by running the below command, and the output should not include the asset bond01:a10 issued earlier.
      CORDA_PORT=10006 ./clients/build/install/clients/bin/clients bond get-assets-by-type 'bond01'`
    • Let PartyA in Corda_Network2 claim the bond asset which is pledged in the Corda network Corda_Network by replacing <pledge-id> with the above hexadecimal value (claim issues the bond asset in the destination/importing network):
      NETWORK_NAME=Corda_Network2 CORDA_PORT=30006 ./clients/build/install/clients/bin/clients transfer claim-remote-asset --pledge-id='<pledge-id>' --locker='O=PartyA, L=London, C=GB' --transfer-category='bond.corda' --export-network-id='Corda_Network' --param='bond01:a10' --import-relay-address='localhost:9082'
      (the linear-id, which is displayed after successful execution of the above command, can be used to check the newly issued bond asset for PartyA in Corda_Network2 by running CORDA_PORT=30006 ./clients/build/install/clients/bin/clients bond get-asset-by-linear-id <linear-id>; or simply check the bond asset balance for PartyA by running the command CORDA_PORT=30006 ./clients/build/install/clients/bin/clients bond get-assets-by-type 'bond01' which should output asset with id a10 and type bond01)

    The above steps complete a successful asset transfer from the Corda network Corda_Network to the Corda network Corda_Network2. In addition to the above commands, following is an extra option.

    • Let PartyA in Corda_Network try re-claim the bond asset bond01:a10, which will succeed only if the asset was not claimed by PartyA and the pledge has expired:
      NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer reclaim-pledged-asset --pledge-id=<pledge-id> --export-relay-address='localhost:9081' --transfer-category='bond.corda' --import-network-id='Corda_Network2' --param='bond01:a10'

    3. Fabric with Corda

    A Fabric network transfers some tokens owned by Alice to PartyA (CORDA_PORT=10006) in a Corda network.

    Transfer or recover token (fungible) assets

    Assuming that the simpleassettransfer chaincode has been deployed in Fabric network network1, run the following steps related to Fabric by navigating to the samples/fabric/fabric-cli folder (the Go CLI doesn't support asset transfer yet).

    Similarly, assuming that the CorDapp cordaSimpleApplication has been deployed in the Corda network Corda_Network, run the following steps related to Corda by navigating to the samples/corda/corda-simple-application folder.

    • Verify that alice in network1 owns 10000 tokens as follows:

      ./scripts/getTokenBalance.sh network1 alice
    • Get alice in network1 to pledge 50 tokens to PartyA in Corda_Network as follows (with a 1 hour timeout):

      ./bin/fabric-cli asset transfer pledge --source-network='network1' --dest-network='Corda_Network' --recipient='O=PartyA, L=London, C=GB' --expiry-secs=3600 --type='token' --units=50 --owner=alice --data-file=src/data/tokensForTransfer.json

      You should see a message containing the unique ID of this pledge on the console as Asset pledged with ID <pledge-id> (<pledge-id> is a hexadecimal string).

    • Verify that alice in network1 owns 9950 tokens (after losing 50) as follows:

      ./scripts/getTokenBalance.sh network1 alice
    • Let PartyA claim in Corda_Network the tokens which are pledged in the Fabric network network1 by replacing <pledge-id> with the above hexadecimal value (claim issues the tokens in the destination/importing network):

      NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer claim-remote-asset --pledge-id='<pledge-id>' --locker='alice' --transfer-category='token.fabric' --export-network-id='network1' --param='token1:50' --import-relay-address='localhost:9081'

      (the linear-id, which is displayed after successful execution of the above command, can be used to check the newly issued tokens for PartyA in Corda_Network by running CORDA_PORT=10006 ./clients/build/install/clients/bin/clients get-state-using-linear-id <linear-id>; or simply check the token balance for PartyA by running the command CORDA_PORT=10006 ./clients/build/install/clients/bin/clients get-asset-states-by-type token1 which should output 50 tokens of type token1)

    The above steps complete a successful asset transfer from the Fabric network network1 to the Corda network Corda_Network. Below demostrates re-claim of the tokens pledged in the Fabric network after the pledge expiry.

    • Now get alice in network1 to pledge 100 tokens to PartyA in Corda_Network as follows (with a 1 minute timeout):

      ./bin/fabric-cli asset transfer pledge --source-network='network1' --dest-network='Corda_Network' --recipient='O=PartyA, L=London, C=GB' --expiry-secs=60 --type=token --units=100 --owner=alice --data-file=src/data/tokensForTransfer.json

      You should see a message containing the unique ID of this pledge on the console as Asset pledged with ID <pledge-id> (<pledge-id> is a hexadecimal string).

      Wait for a minute as follows:

      sleep 60
    • Let PartyA in Corda_Network claim the tokens which are pledged in the Fabric network network1 by replacing <pledge-id> with the above hexadecimal value (claim issues the tokens in the destination/importing network):

      NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer claim-remote-asset --pledge-id='<pledge-id>' --locker='alice' --transfer-category='token.fabric' --export-network-id='network1' --param='token1:100' --import-relay-address='localhost:9080'

      This should fail as the pledge has already expired.

      (check the token balance for PartyA by running the command CORDA_PORT=10006 ./clients/build/install/clients/bin/clients get-asset-states-by-type token1 which should still show 50 tokens of type token1 but not 150)

    • Now get alice in network1 to reclaim these tokens as follows:

      ./bin/fabric-cli asset transfer reclaim --source-network='network1' --user='alice' --type='token.corda' --pledge-id=<pledge-id> --param=token1:100
    • Verify that alice in network1 still owns 9950 tokens (after losing 50) as follows:

      ./scripts/getTokenBalance.sh network1 alice

    4. Corda with Fabric

    A Corda network transfers some tokens owned by PartyA (CORDA_PORT=10006) to Alice in a Fabric network.

    Transfer or recover token (fungible) assets

    Assuming that the CorDapp cordaSimpleApplication has been deployed in the Corda network Corda_Network, run the following steps related to Corda by navigating to the samples/corda/corda-simple-application folder.

    Similarly, assume that the simpleassettransfer chaincode has been deployed in Fabric network network1, run the following steps related to Fabric by navigating to the samples/fabric/fabric-cli folder (the Go CLI doesn't support asset transfer yet).

    • Add 5 tokens of type token1 to PartyA in Corda_Network:
      CORDA_PORT=10006 ./clients/build/install/clients/bin/clients issue-asset-state 5 token1
      (check token balance for PartyA by running the command CORDA_PORT=10006 ./clients/build/install/clients/bin/clients get-asset-states-by-type token1)
    • Let PartyA pledge (with a 1 hour timeout) these tokens in Corda_Network to be transferred to Alice of Fabric network network1 (pledge burns the tokens in the source/exporting network):
      CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer pledge-asset --fungible --timeout="3600" --import-network-id='network1' --recipient='alice' --param='token1:5'
      Note the pledge-id displayed after successful execution of the command, which will be used in next steps. Let's denote it <pledge-id> which is a hexadecimal string (pledge details can be cross checked using the commands CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer is-asset-pledged -pid <pledge-id> and CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer get-pledge-state -pid <pledge-id>).
    • Check the token asset balance for PartyA in Corda_Network by running the below command, and the output should not include the asset token1:5 issued earlier.
      CORDA_PORT=10006 ./clients/build/install/clients/bin/clients get-asset-states-by-type token1`
    • Verify that alice in network1 owns 10000 tokens as follows:
      ./scripts/getTokenBalance.sh network1 alice
    • Get alice in network to claim these tokens as follows (replace <pledge-id> with the above hexadecimal value):
      ./bin/fabric-cli asset transfer claim --source-network='Corda_Network' --dest-network=network1 --user='alice' --owner='O=PartyA, L=London, C=GB' --type='token.corda' --pledge-id=<pledge-id> --param=token1:5
    • Verify that alice in network now owns 1050 tokens as follows:
      ./scripts/getTokenBalance.sh network1 alice

    The above steps complete a successful asset transfer from the Corda network Corda_Network to the Fabric network network1. In addition to the above commands, following is an extra option.

    • Let PartyA in Corda_Network try re-claim the token token1:5 asset, which will succeed only if the asset was not claimed by alice in Fabric network and the pledge has expired (replace <pledge-id> with the above hexadecimal value):
      NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients transfer reclaim-pledged-asset --pledge-id=<pledge-id> --export-relay-address='localhost:9081' --transfer-category='token.fabric' --import-network-id='network1' --param='token1:5'
    + + \ No newline at end of file diff --git a/docs/external/getting-started/interop/data-sharing/index.html b/docs/external/getting-started/interop/data-sharing/index.html index 4607e5c6f..904250c94 100644 --- a/docs/external/getting-started/interop/data-sharing/index.html +++ b/docs/external/getting-started/interop/data-sharing/index.html @@ -4,14 +4,14 @@ Data Sharing | Weaver: DLT Interoperability Framework - - - + + +
    -

    Data Sharing

    This document lists sample ways in which you can exercise the data-sharing interoperation protocol on the test network launched earlier.

    Once the networks, relays, and drivers have been launched, and the ledgers bootstrapped, you can trigger four different interoperation flows corresponding to distinct data-sharing combinations as follows:

    1. Corda to Corda: Either Corda network requests state and proof from another Corda network
    2. Corda to Fabric: The Corda network requests state and proof from either Fabric network
    3. Fabric to Corda: Either Fabric network requests state and proof from the Corda network
    4. Fabric to Fabric: One Fabric network requests state and proof from another Fabric network

    We assume that one of the following chaincodes have been deployed in either Fabric network you are testing with:

    • simplestate
    • simplestatewithacl

    Corda to Corda

    To test the scenario where Corda_Network requests the value of the state (key) H from Corda_Network2, do the following:

    • (Make sure the following are running: Corda_Network, relay, and driver; Corda_Network2, relay, and driver)
    • Navigate to the samples/corda/corda-simple-application folder.
    • Run the following:
      • If Relays and Drivers are deployed in the host machine:
        • Without TLS:
          NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients request-state localhost:9081 localhost:9082/Corda_Network2/localhost:30006#com.cordaSimpleApplication.flow.GetStateByKey:H
        • With TLS:
          RELAY_TLS=true RELAY_TLSCA_CERT_PATHS=../../../core/relay/credentials/fabric_ca_cert.pem NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients request-state localhost:9081 localhost:9082/Corda_Network2/localhost:30006#com.cordaSimpleApplication.flow.GetStateByKey:H
      • If Relays and Drivers are deployed in Docker containers:
        • Without TLS:
          NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients request-state localhost:9081 relay-corda2:9082/Corda_Network2/corda_network2_partya_1:10003#com.cordaSimpleApplication.flow.GetStateByKey:H
        • With TLS:
          RELAY_TLS=true RELAY_TLSCA_CERT_PATHS=../../../core/relay/credentials/docker/ca-cert.pem NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients request-state localhost:9081 relay-corda2:9082/Corda_Network2/corda_network2_partya_1:10003#com.cordaSimpleApplication.flow.GetStateByKey:H
    • Query the value of the requested state using key H in Corda_Network by running the following command:
      NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients get-state H

    To test the scenario where Corda_Network2 requests the value of the state (key) C from Corda_Network, do the following:

    • (Make sure the following are running: Corda_Network, relay, and driver; Corda_Network2, relay, and driver)
    • Navigate to the samples/corda/corda-simple-application folder.
    • Run the following:
      • If Relays and Drivers are deployed in the host machine:
        • Without TLS:
          NETWORK_NAME=Corda_Network2 CORDA_PORT=30006 ./clients/build/install/clients/bin/clients request-state localhost:9082 localhost:9081/Corda_Network/localhost:10006#com.cordaSimpleApplication.flow.GetStateByKey:C
        • With TLS:
          RELAY_TLS=true RELAY_TLSCA_CERT_PATHS=../../../core/relay/credentials/fabric_ca_cert.pem NETWORK_NAME=Corda_Network2 CORDA_PORT=30006 ./clients/build/install/clients/bin/clients request-state localhost:9082 localhost:9081/Corda_Network/localhost:10006#com.cordaSimpleApplication.flow.GetStateByKey:C
      • If Relays and Drivers are deployed in Docker containers:
        • Without TLS:
          NETWORK_NAME=Corda_Network2 CORDA_PORT=30006 ./clients/build/install/clients/bin/clients request-state localhost:9082 relay-corda:9081/Corda_Network/corda_partya_1:10003#com.cordaSimpleApplication.flow.GetStateByKey:C
        • With TLS:
          RELAY_TLS=true RELAY_TLSCA_CERT_PATHS=../../../core/relay/credentials/docker/ca-cert.pem NETWORK_NAME=Corda_Network2 CORDA_PORT=30006 ./clients/build/install/clients/bin/clients request-state localhost:9082 relay-corda:9081/Corda_Network/corda_partya_1:10003#com.cordaSimpleApplication.flow.GetStateByKey:C
    • Query the value of the requested state, using the key C in Corda_Network by running the following command:
      NETWORK_NAME=Corda_Network2 CORDA_PORT=30006 ./clients/build/install/clients/bin/clients get-state C

    Corda to Fabric

    To test the scenario where Corda_Network requests the value of the state (key) a from network1, do the following:

    • (Make sure the following are running: Corda network, relay, and driver; Fabric network1, relay, and driver)
    • Navigate to the samples/corda/corda-simple-application folder.
    • Run the following:
      • If Relays and Drivers are deployed in the host machine:
        • Without TLS:
          NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients request-state localhost:9081 localhost:9080/network1/mychannel:simplestate:Read:a
        • With TLS:
          RELAY_TLS=true RELAY_TLSCA_CERT_PATHS=../../../core/relay/credentials/fabric_ca_cert.pem NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients request-state localhost:9081 localhost:9080/network1/mychannel:simplestate:Read:a
      • If Relays and Drivers are deployed in Docker containers:
        • Without TLS:
          NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients request-state localhost:9081 relay-network1:9080/network1/mychannel:simplestate:Read:a
        • With TLS:
          RELAY_TLS=true RELAY_TLSCA_CERT_PATHS=../../../core/relay/credentials/docker/ca-cert.pem NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients request-state localhost:9081 relay-network1:9080/network1/mychannel:simplestate:Read:a
    • Query the value of the requested state (key) a in Corda_Network using the following:
      NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients get-state a

    To test the scenario where Corda_Network requests the value of the state (key) Arcturus from network2, do the following:

    • (Make sure the following are running: Corda network, relay, and driver; Fabric network2, relay, and driver)
    • Navigate to the samples/corda/corda-simple-application folder.
    • Run the following:
      • If Relays and Drivers are deployed in the host machine:
        • Without TLS:
          NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients request-state localhost:9081 localhost:9083/network2/mychannel:simplestate:Read:Arcturus
        • With TLS:
          RELAY_TLS=true RELAY_TLSCA_CERT_PATHS=../../../core/relay/credentials/fabric_ca_cert.pem NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients request-state localhost:9081 localhost:9083/network2/mychannel:simplestate:Read:Arcturus
      • If Relays and Drivers are deployed in Docker containers:
        • Without TLS:
          NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients request-state localhost:9081 relay-network2:9083/network2/mychannel:simplestate:Read:Arcturus
        • With TLS:
          RELAY_TLS=true RELAY_TLSCA_CERT_PATHS=../../../core/relay/credentials/docker/ca-cert.pem NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients request-state localhost:9081 relay-network2:9083/network2/mychannel:simplestate:Read:Arcturus
    • Query the value of the requested state (key) Arcturus in Corda_Network using the following:
      NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients get-state Arcturus
    Notes
    You can test the above data transfer scenario with Corda_Network2 instead of Corda_Network by changing the following in the request-state or get-state command:
    • Network name environment variable:
      • NETWORK_NAME=Corda_Network to NETWORK_NAME=Corda_Network2
    • Corda node's RPC endpoint port environment variable:
      • CORDA_PORT=10006 to CORDA_PORT=30006
    • Local relay address
      • localhost:9081 to localhost:9082 (host deployment of relays and drivers)
      • relay-corda2:9081 to relay-corda2:9082 (Docker container deployment of relays and drivers)

    Fabric to Corda

    To test the scenario where network1 requests the value of the state (key) H from Corda_Network, do the following:

    • (Make sure the following are running: Corda network, relay, and driver; Fabric network1, relay, and driver)
    • Navigate to the samples/fabric/fabric-cli (for the Node.js version) or the samples/fabric/go-cli (for the Golang version) folder.
    • (Make sure you have configured fabric-cli as per earlier instructions)
    • Edit chaincode.json: in the simplestate:Create:args attribute, replace the argument "a" with "H" (this specifies the key to which the data from the remote view is to be written into); i.e.,:
      "args": ["a", ""]
      with
      "args": ["H", ""]
    • Run the following:
      • If Relays and Drivers are deployed in the host machine:
        • Without TLS:
          ./bin/fabric-cli interop --local-network=network1 --sign=true --requesting-org=Org1MSP localhost:9081/Corda_Network/localhost:10006#com.cordaSimpleApplication.flow.GetStateByKey:H --debug=true
        • With TLS:
          ./bin/fabric-cli interop --local-network=network1 --sign=true --requesting-org=Org1MSP --relay-tls=true --relay-tls-ca-files=../../../core/relay/credentials/fabric_ca_cert.pem localhost:9081/Corda_Network/localhost:10006#com.cordaSimpleApplication.flow.GetStateByKey:H --debug=true
      • If Relays and Drivers are deployed in Docker containers:
        • Without TLS:
          ./bin/fabric-cli interop --local-network=network1 --sign=true --requesting-org=Org1MSP relay-corda:9081/Corda_Network/corda_partya_1:10003#com.cordaSimpleApplication.flow.GetStateByKey:H --debug=true
        • With TLS:
          ./bin/fabric-cli interop --local-network=network1 --sign=true --requesting-org=Org1MSP --relay-tls=true --relay-tls-ca-files=../../../core/relay/credentials/docker/ca-cert.pem relay-corda:9081/Corda_Network/corda_partya_1:10003#com.cordaSimpleApplication.flow.GetStateByKey:H --debug=true
    • Query the value of the requested state (key) H in network1 using the following:
      ./bin/fabric-cli chaincode query mychannel simplestate read '["H"]' --local-network=network1

    To test the scenario where network2 requests the value of the state (key) H from Corda_Network, do the following:

    • (Make sure the following are running: Corda network, relay, and driver; Fabric network2, relay, and driver)
    • Navigate to the samples/fabric/fabric-cli (for the Node.js version) or the samples/fabric/go-cli (for the Golang version) folder.
    • (Make sure you have configured fabric-cli as per earlier instructions)
    • Edit chaincode.json: in the simplestate:Create:args attribute, replace the argument "a" with "H" (this specifies the key to which the data from the remote view is to be written into); i.e.,:
      "args": ["a", ""]
      with
      "args": ["H", ""]
    • Run the following:
      • If Relays and Drivers are deployed in the host machine:
        • Without TLS:
          ./bin/fabric-cli interop --local-network=network2 --sign=true --requesting-org=Org1MSP localhost:9081/Corda_Network/localhost:10006#com.cordaSimpleApplication.flow.GetStateByKey:H --debug=true
        • With TLS:
          ./bin/fabric-cli interop --local-network=network2 --sign=true --requesting-org=Org1MSP --relay-tls=true --relay-tls-ca-files=../../../core/relay/credentials/fabric_ca_cert.pem localhost:9081/Corda_Network/localhost:10006#com.cordaSimpleApplication.flow.GetStateByKey:H --debug=true
      • If Relays and Drivers are deployed in Docker containers:
        • Without TLS:
          ./bin/fabric-cli interop --local-network=network2 --sign=true --requesting-org=Org1MSP relay-corda:9081/Corda_Network/corda_partya_1:10003#com.cordaSimpleApplication.flow.GetStateByKey:H --debug=true
        • With TLS:
          ./bin/fabric-cli interop --local-network=network2 --sign=true --requesting-org=Org1MSP --relay-tls=true --relay-tls-ca-files=../../../core/relay/credentials/docker/ca-cert.pem relay-corda:9081/Corda_Network/corda_partya_1:10003#com.cordaSimpleApplication.flow.GetStateByKey:H --debug=true
    • Query the value of the requested state (key) H in network2 using the following:
      ./bin/fabric-cli chaincode query mychannel simplestate read '["H"]' --local-network=network2
    Notes
    You can test the above data transfer scenario with Corda_Network2 instead of Corda_Network by changing the following in the view address (last parameter in the interop command):
    • Local relay address (prefix):
      • localhost:9081 to localhost:9082 (host deployment of relays and drivers)
      • relay-corda2:9081 to relay-corda2:9082 (Docker container deployment of relays and drivers)
    • Network name:
      • Corda_Network to Corda_Network2
    • Corda node's RPC endpoint:
      • localhost:10006 to localhost:30006 (host deployment of relays and drivers)
      • corda_partya_1:10003 to corda_network2_partya_1:10003 (Docker container deployment of relays and drivers)

    Fabric to Fabric

    To test the scenario where network1 requests the value of the state (key) Arcturus from network2, do the following:

    • (Make sure the following are running: Fabric network1, relay, and driver; Fabric network2, relay, and driver)
    • Navigate to the samples/fabric/fabric-cli (for the Node.js version) or the samples/fabric/go-cli (for the Golang version) folder.
    • (Make sure you have configured fabric-cli as per earlier instructions)
    • Edit chaincode.json: in the simplestate:Create:args attribute, replace the argument "a" with "Arcturus" (this specifies the key to which the data from the remote view is to be written into); i.e.,:
      "args": ["a", ""]
      with
      "args": ["Arcturus", ""]
    • Run the following:
      • If Relays and Drivers are deployed in the host machine:
        • Without TLS:
          ./bin/fabric-cli interop --local-network=network1 --requesting-org=Org1MSP localhost:9083/network2/mychannel:simplestate:Read:Arcturus
        • With TLS:
          ./bin/fabric-cli interop --local-network=network1 --requesting-org=Org1MSP --relay-tls=true --relay-tls-ca-files=../../../core/relay/credentials/fabric_ca_cert.pem localhost:9083/network2/mychannel:simplestate:Read:Arcturus
      • If Relays and Drivers are deployed in Docker containers:
        • Without TLS:
          ./bin/fabric-cli interop --local-network=network1 --requesting-org=Org1MSP relay-network2:9083/network2/mychannel:simplestate:Read:Arcturus
        • With TLS:
          ./bin/fabric-cli interop --local-network=network1 --requesting-org=Org1MSP --relay-tls=true --relay-tls-ca-files=../../../core/relay/credentials/docker/ca-cert.pem relay-network2:9083/network2/mychannel:simplestate:Read:Arcturus
    Notes
    If you wish to enable end-to-end confidentiality for this data sharing session, add the --e2e-confidentiality=true switch to any of the above commands. For example: ./bin/fabric-cli interop --local-network=network1 --requesting-org=Org1MSP --e2e-confidentiality=true localhost:9083/network2/mychannel:simplestate:Read:Arcturus
    • Query the value of the requested state (key) Arcturus in network1 using the following:
      ./bin/fabric-cli chaincode query mychannel simplestate read '["Arcturus"]' --local-network=network1

    To test the scenario where network2 requests the value of the state (key) a from network1, do the following:

    • (Make sure the following are running: Fabric network1, relay, and driver; Fabric network2, relay, and driver)
    • Navigate to the samples/fabric/fabric-cli (for the Node.js version) or the samples/fabric/go-cli (for the Golang version) folder.
    • (Make sure you have configured fabric-cli as per earlier instructions)
    • (There is no need to edit chaincode.json to change the key as the default argument "a" is what we intend to use in this data sharing use scenario.)
    • Run the following:
      • If Relays and Drivers are deployed in the host machine:
        • Without TLS:
          ./bin/fabric-cli interop --local-network=network2 --requesting-org=Org1MSP localhost:9080/network1/mychannel:simplestate:Read:a
        • With TLS:
          ./bin/fabric-cli interop --local-network=network2 --requesting-org=Org1MSP --relay-tls=true --relay-tls-ca-files=../../../core/relay/credentials/fabric_ca_cert.pem localhost:9080/network1/mychannel:simplestate:Read:a
      • If Relays and Drivers are deployed in Docker containers:
        • Without TLS:
          ./bin/fabric-cli interop --local-network=network2 --requesting-org=Org1MSP relay-network1:9080/network1/mychannel:simplestate:Read:a
        • With TLS:
          ./bin/fabric-cli interop --local-network=network2 --requesting-org=Org1MSP --relay-tls=true --relay-tls-ca-files=../../../core/relay/credentials/docker/ca-cert.pem relay-network1:9080/network1/mychannel:simplestate:Read:a:173
    Notes
    If you wish to enable end-to-end confidentiality for this data sharing session, add the --e2e-confidentiality=true switch to any of the above commands. For example: ./bin/fabric-cli interop --local-network=network2 --requesting-org=Org1MSP --e2e-confidentiality=true localhost:9080/network1/mychannel:simplestate:Read:a
    • Query the value of the requested state (key) a in network2 using the following:
      ./bin/fabric-cli chaincode query mychannel simplestate read '["a"]' --local-network=network2
    - - +

    Data Sharing

    This document lists sample ways in which you can exercise the data-sharing interoperation protocol on the test network launched earlier.

    Once the networks, relays, and drivers have been launched, and the ledgers bootstrapped, you can trigger four different interoperation flows corresponding to distinct data-sharing combinations as follows:

    1. Corda to Corda: Either Corda network requests state and proof from another Corda network
    2. Corda to Fabric: The Corda network requests state and proof from either Fabric network
    3. Fabric to Corda: Either Fabric network requests state and proof from the Corda network
    4. Fabric to Fabric: One Fabric network requests state and proof from another Fabric network

    We assume that one of the following chaincodes have been deployed in either Fabric network you are testing with:

    • simplestate
    • simplestatewithacl

    Corda to Corda

    To test the scenario where Corda_Network requests the value of the state (key) H from Corda_Network2 and writes the value to a key H in its local state, do the following:

    • (Make sure the following are running: Corda_Network, relay, and driver; Corda_Network2, relay, and driver)
    • Navigate to the samples/corda/corda-simple-application folder in your clone of the Weaver repository.
    • Run the following:
      • If Relays and Drivers are deployed in the host machine:
        • Without TLS:
          NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients request-state localhost:9081 localhost:9082/Corda_Network2/localhost:30006#com.cordaSimpleApplication.flow.GetStateByKey:H
        • With TLS:
          RELAY_TLS=true RELAY_TLSCA_CERT_PATHS=../../../core/relay/credentials/fabric_ca_cert.pem NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients request-state localhost:9081 localhost:9082/Corda_Network2/localhost:30006#com.cordaSimpleApplication.flow.GetStateByKey:H
      • If Relays and Drivers are deployed in Docker containers:
        • Without TLS:
          NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients request-state localhost:9081 relay-corda2:9082/Corda_Network2/corda_network2_partya_1:10003#com.cordaSimpleApplication.flow.GetStateByKey:H
        • With TLS:
          RELAY_TLS=true RELAY_TLSCA_CERT_PATHS=../../../core/relay/credentials/docker/ca-cert.pem NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients request-state localhost:9081 relay-corda2:9082/Corda_Network2/corda_network2_partya_1:10003#com.cordaSimpleApplication.flow.GetStateByKey:H
    • Query the value of the requested state using key H in Corda_Network by running the following command:
      NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients get-state H

    To test the scenario where Corda_Network2 requests the value of the state (key) C from Corda_Network and writes the value to a key C in its local state, do the following:

    • (Make sure the following are running: Corda_Network, relay, and driver; Corda_Network2, relay, and driver)
    • Navigate to the samples/corda/corda-simple-application folder in your clone of the Weaver repository.
    • Run the following:
      • If Relays and Drivers are deployed in the host machine:
        • Without TLS:
          NETWORK_NAME=Corda_Network2 CORDA_PORT=30006 ./clients/build/install/clients/bin/clients request-state localhost:9082 localhost:9081/Corda_Network/localhost:10006#com.cordaSimpleApplication.flow.GetStateByKey:C
        • With TLS:
          RELAY_TLS=true RELAY_TLSCA_CERT_PATHS=../../../core/relay/credentials/fabric_ca_cert.pem NETWORK_NAME=Corda_Network2 CORDA_PORT=30006 ./clients/build/install/clients/bin/clients request-state localhost:9082 localhost:9081/Corda_Network/localhost:10006#com.cordaSimpleApplication.flow.GetStateByKey:C
      • If Relays and Drivers are deployed in Docker containers:
        • Without TLS:
          NETWORK_NAME=Corda_Network2 CORDA_PORT=30006 ./clients/build/install/clients/bin/clients request-state localhost:9082 relay-corda:9081/Corda_Network/corda_partya_1:10003#com.cordaSimpleApplication.flow.GetStateByKey:C
        • With TLS:
          RELAY_TLS=true RELAY_TLSCA_CERT_PATHS=../../../core/relay/credentials/docker/ca-cert.pem NETWORK_NAME=Corda_Network2 CORDA_PORT=30006 ./clients/build/install/clients/bin/clients request-state localhost:9082 relay-corda:9081/Corda_Network/corda_partya_1:10003#com.cordaSimpleApplication.flow.GetStateByKey:C
    • Query the value of the requested state, using the key C in Corda_Network by running the following command:
      NETWORK_NAME=Corda_Network2 CORDA_PORT=30006 ./clients/build/install/clients/bin/clients get-state C

    Corda to Fabric

    To test the scenario where Corda_Network requests the value of the state (key) a from network1 and writes the value to a key a in its local state, do the following:

    • (Make sure the following are running: Corda network, relay, and driver; Fabric network1, relay, and driver)
    • Navigate to the samples/corda/corda-simple-application folder in your clone of the Weaver repository.
    • Run the following:
      • If Relays and Drivers are deployed in the host machine:
        • Without TLS:
          NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients request-state localhost:9081 localhost:9080/network1/mychannel:simplestate:Read:a
        • With TLS:
          RELAY_TLS=true RELAY_TLSCA_CERT_PATHS=../../../core/relay/credentials/fabric_ca_cert.pem NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients request-state localhost:9081 localhost:9080/network1/mychannel:simplestate:Read:a
      • If Relays and Drivers are deployed in Docker containers:
        • Without TLS:
          NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients request-state localhost:9081 relay-network1:9080/network1/mychannel:simplestate:Read:a
        • With TLS:
          RELAY_TLS=true RELAY_TLSCA_CERT_PATHS=../../../core/relay/credentials/docker/ca-cert.pem NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients request-state localhost:9081 relay-network1:9080/network1/mychannel:simplestate:Read:a
    • Query the value of the requested state (key) a in Corda_Network using the following:
      NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients get-state a

    To test the scenario where Corda_Network requests the value of the state (key) Arcturus from network2 and writes the value to a key Arcturus in its local state, do the following:

    • (Make sure the following are running: Corda network, relay, and driver; Fabric network2, relay, and driver)
    • Navigate to the samples/corda/corda-simple-application folder in your clone of the Weaver repository.
    • Run the following:
      • If Relays and Drivers are deployed in the host machine:
        • Without TLS:
          NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients request-state localhost:9081 localhost:9083/network2/mychannel:simplestate:Read:Arcturus
        • With TLS:
          RELAY_TLS=true RELAY_TLSCA_CERT_PATHS=../../../core/relay/credentials/fabric_ca_cert.pem NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients request-state localhost:9081 localhost:9083/network2/mychannel:simplestate:Read:Arcturus
      • If Relays and Drivers are deployed in Docker containers:
        • Without TLS:
          NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients request-state localhost:9081 relay-network2:9083/network2/mychannel:simplestate:Read:Arcturus
        • With TLS:
          RELAY_TLS=true RELAY_TLSCA_CERT_PATHS=../../../core/relay/credentials/docker/ca-cert.pem NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients request-state localhost:9081 relay-network2:9083/network2/mychannel:simplestate:Read:Arcturus
    • Query the value of the requested state (key) Arcturus in Corda_Network using the following:
      NETWORK_NAME=Corda_Network CORDA_PORT=10006 ./clients/build/install/clients/bin/clients get-state Arcturus
    Notes
    You can test the above data transfer scenario with Corda_Network2 instead of Corda_Network by changing the following in the request-state or get-state command:
    • Network name environment variable:
      • NETWORK_NAME=Corda_Network to NETWORK_NAME=Corda_Network2
    • Corda node's RPC endpoint port environment variable:
      • CORDA_PORT=10006 to CORDA_PORT=30006
    • Local relay address
      • localhost:9081 to localhost:9082 (host deployment of relays and drivers)
      • relay-corda2:9081 to relay-corda2:9082 (Docker container deployment of relays and drivers)

    Fabric to Corda

    To test the scenario where network1 requests the value of the state (key) H from Corda_Network and writes the value to a key H in its local state, do the following:

    • (Make sure the following are running: Corda network, relay, and driver; Fabric network1, relay, and driver)
    • Navigate to the samples/fabric/fabric-cli (for the Node.js version) or the samples/fabric/go-cli (for the Golang version) folder in your clone of the Weaver repository.
    • (Make sure you have configured fabric-cli as per earlier instructions)
    • Edit chaincode.json: in the simplestate:Create:args attribute, replace the argument "a" with "H" (this specifies the key to which the data from the remote view is to be written into); i.e.,:
      "args": ["a", ""]
      with
      "args": ["H", ""]
    • Run the following:
      • If Relays and Drivers are deployed in the host machine:
        • Without TLS:
          ./bin/fabric-cli interop --local-network=network1 --sign=true --requesting-org=Org1MSP localhost:9081/Corda_Network/localhost:10006#com.cordaSimpleApplication.flow.GetStateByKey:H --debug=true
        • With TLS:
          ./bin/fabric-cli interop --local-network=network1 --sign=true --requesting-org=Org1MSP --relay-tls=true --relay-tls-ca-files=../../../core/relay/credentials/fabric_ca_cert.pem localhost:9081/Corda_Network/localhost:10006#com.cordaSimpleApplication.flow.GetStateByKey:H --debug=true
      • If Relays and Drivers are deployed in Docker containers:
        • Without TLS:
          ./bin/fabric-cli interop --local-network=network1 --sign=true --requesting-org=Org1MSP relay-corda:9081/Corda_Network/corda_partya_1:10003#com.cordaSimpleApplication.flow.GetStateByKey:H --debug=true
        • With TLS:
          ./bin/fabric-cli interop --local-network=network1 --sign=true --requesting-org=Org1MSP --relay-tls=true --relay-tls-ca-files=../../../core/relay/credentials/docker/ca-cert.pem relay-corda:9081/Corda_Network/corda_partya_1:10003#com.cordaSimpleApplication.flow.GetStateByKey:H --debug=true
    • Query the value of the requested state (key) H in network1 using the following:
      ./bin/fabric-cli chaincode query mychannel simplestate read '["H"]' --local-network=network1

    To test the scenario where network2 requests the value of the state (key) H from Corda_Network and writes the value to a key H in its local state, do the following:

    • (Make sure the following are running: Corda network, relay, and driver; Fabric network2, relay, and driver)
    • Navigate to the samples/fabric/fabric-cli (for the Node.js version) or the samples/fabric/go-cli (for the Golang version) folder in your clone of the Weaver repository.
    • (Make sure you have configured fabric-cli as per earlier instructions)
    • Edit chaincode.json: in the simplestate:Create:args attribute, replace the argument "a" with "H" (this specifies the key to which the data from the remote view is to be written into); i.e.,:
      "args": ["a", ""]
      with
      "args": ["H", ""]
    • Run the following:
      • If Relays and Drivers are deployed in the host machine:
        • Without TLS:
          ./bin/fabric-cli interop --local-network=network2 --sign=true --requesting-org=Org1MSP localhost:9081/Corda_Network/localhost:10006#com.cordaSimpleApplication.flow.GetStateByKey:H --debug=true
        • With TLS:
          ./bin/fabric-cli interop --local-network=network2 --sign=true --requesting-org=Org1MSP --relay-tls=true --relay-tls-ca-files=../../../core/relay/credentials/fabric_ca_cert.pem localhost:9081/Corda_Network/localhost:10006#com.cordaSimpleApplication.flow.GetStateByKey:H --debug=true
      • If Relays and Drivers are deployed in Docker containers:
        • Without TLS:
          ./bin/fabric-cli interop --local-network=network2 --sign=true --requesting-org=Org1MSP relay-corda:9081/Corda_Network/corda_partya_1:10003#com.cordaSimpleApplication.flow.GetStateByKey:H --debug=true
        • With TLS:
          ./bin/fabric-cli interop --local-network=network2 --sign=true --requesting-org=Org1MSP --relay-tls=true --relay-tls-ca-files=../../../core/relay/credentials/docker/ca-cert.pem relay-corda:9081/Corda_Network/corda_partya_1:10003#com.cordaSimpleApplication.flow.GetStateByKey:H --debug=true
    • Query the value of the requested state (key) H in network2 using the following:
      ./bin/fabric-cli chaincode query mychannel simplestate read '["H"]' --local-network=network2
    Notes
    You can test the above data transfer scenario with Corda_Network2 instead of Corda_Network by changing the following in the view address (last parameter in the interop command):
    • Local relay address (prefix):
      • localhost:9081 to localhost:9082 (host deployment of relays and drivers)
      • relay-corda2:9081 to relay-corda2:9082 (Docker container deployment of relays and drivers)
    • Network name:
      • Corda_Network to Corda_Network2
    • Corda node's RPC endpoint:
      • localhost:10006 to localhost:30006 (host deployment of relays and drivers)
      • corda_partya_1:10003 to corda_network2_partya_1:10003 (Docker container deployment of relays and drivers)

    Fabric to Fabric

    To test the scenario where network1 requests the value of the state (key) Arcturus from network2 and writes the value to a key Arcturus in its local state, do the following:

    • (Make sure the following are running: Fabric network1, relay, and driver; Fabric network2, relay, and driver)
    • Navigate to the samples/fabric/fabric-cli (for the Node.js version) or the samples/fabric/go-cli (for the Golang version) folder in your clone of the Weaver repository.
    • (Make sure you have configured fabric-cli as per earlier instructions)
    • Edit chaincode.json: in the simplestate:Create:args attribute, replace the argument "a" with "Arcturus" (this specifies the key to which the data from the remote view is to be written into); i.e.,:
      "args": ["a", ""]
      with
      "args": ["Arcturus", ""]
    • Run the following:
      • If Relays and Drivers are deployed in the host machine:
        • Without TLS:
          ./bin/fabric-cli interop --local-network=network1 --requesting-org=Org1MSP localhost:9083/network2/mychannel:simplestate:Read:Arcturus
        • With TLS:
          ./bin/fabric-cli interop --local-network=network1 --requesting-org=Org1MSP --relay-tls=true --relay-tls-ca-files=../../../core/relay/credentials/fabric_ca_cert.pem localhost:9083/network2/mychannel:simplestate:Read:Arcturus
      • If Relays and Drivers are deployed in Docker containers:
        • Without TLS:
          ./bin/fabric-cli interop --local-network=network1 --requesting-org=Org1MSP relay-network2:9083/network2/mychannel:simplestate:Read:Arcturus
        • With TLS:
          ./bin/fabric-cli interop --local-network=network1 --requesting-org=Org1MSP --relay-tls=true --relay-tls-ca-files=../../../core/relay/credentials/docker/ca-cert.pem relay-network2:9083/network2/mychannel:simplestate:Read:Arcturus
    Notes
    If you wish to enable end-to-end confidentiality for this data sharing session, add the --e2e-confidentiality=true switch to any of the above commands. For example: ./bin/fabric-cli interop --local-network=network1 --requesting-org=Org1MSP --e2e-confidentiality=true localhost:9083/network2/mychannel:simplestate:Read:Arcturus
    • Query the value of the requested state (key) Arcturus in network1 using the following:
      ./bin/fabric-cli chaincode query mychannel simplestate read '["Arcturus"]' --local-network=network1

    To test the scenario where network2 requests the value of the state (key) a from network1 and writes the value to a key a in its local state, do the following:

    • (Make sure the following are running: Fabric network1, relay, and driver; Fabric network2, relay, and driver)
    • Navigate to the samples/fabric/fabric-cli (for the Node.js version) or the samples/fabric/go-cli (for the Golang version) folder in your clone of the Weaver repository.
    • (Make sure you have configured fabric-cli as per earlier instructions)
    • (There is no need to edit chaincode.json to change the key as the default argument "a" is what we intend to use in this data sharing use scenario.)
    • Run the following:
      • If Relays and Drivers are deployed in the host machine:
        • Without TLS:
          ./bin/fabric-cli interop --local-network=network2 --requesting-org=Org1MSP localhost:9080/network1/mychannel:simplestate:Read:a
        • With TLS:
          ./bin/fabric-cli interop --local-network=network2 --requesting-org=Org1MSP --relay-tls=true --relay-tls-ca-files=../../../core/relay/credentials/fabric_ca_cert.pem localhost:9080/network1/mychannel:simplestate:Read:a
      • If Relays and Drivers are deployed in Docker containers:
        • Without TLS:
          ./bin/fabric-cli interop --local-network=network2 --requesting-org=Org1MSP relay-network1:9080/network1/mychannel:simplestate:Read:a
        • With TLS:
          ./bin/fabric-cli interop --local-network=network2 --requesting-org=Org1MSP --relay-tls=true --relay-tls-ca-files=../../../core/relay/credentials/docker/ca-cert.pem relay-network1:9080/network1/mychannel:simplestate:Read:a:173
    Notes
    If you wish to enable end-to-end confidentiality for this data sharing session, add the --e2e-confidentiality=true switch to any of the above commands. For example: ./bin/fabric-cli interop --local-network=network2 --requesting-org=Org1MSP --e2e-confidentiality=true localhost:9080/network1/mychannel:simplestate:Read:a
    • Query the value of the requested state (key) a in network2 using the following:
      ./bin/fabric-cli chaincode query mychannel simplestate read '["a"]' --local-network=network2
    + + \ No newline at end of file diff --git a/docs/external/getting-started/interop/overview/index.html b/docs/external/getting-started/interop/overview/index.html index 9c8a0a88f..c1b26c27a 100644 --- a/docs/external/getting-started/interop/overview/index.html +++ b/docs/external/getting-started/interop/overview/index.html @@ -4,14 +4,14 @@ Testing Interoperation Modes Overview | Weaver: DLT Interoperability Framework - - - + + + - - +
    + + \ No newline at end of file diff --git a/docs/external/getting-started/test-network/advanced-configuration/index.html b/docs/external/getting-started/test-network/advanced-configuration/index.html index d78df0868..06c2aa4c2 100644 --- a/docs/external/getting-started/test-network/advanced-configuration/index.html +++ b/docs/external/getting-started/test-network/advanced-configuration/index.html @@ -4,15 +4,15 @@ Advanced Configuration | Weaver: DLT Interoperability Framework - - - + + +
    -

    Advanced Configuration

    You can configure the different components of the test network to use non-default parameter values for various settings (such as host names or port numbers). Here is a list of configurations you can tweak, classified by the DLT type.

    Corda

    Relay

    To run the relay on a different port from the default (9081), do the following:

    • Navigate to the core/relay folder.
    • Update the port field in config/Corda_Relay.toml.
    • To ensure that the relay of network1 can communicate with this relay, update the port field in the relays.Corda_Relay section in config/Fabric_Relay.toml with the same value.
    • To ensure that the relay of network2 can communicate with this relay, update the port field in the relays.Corda_Relay section in config/Fabric_Relay2.toml with the same value.
    • (You can update host names in similar locations, by adjusting the hostname field.)
    • When you attempt a Fabric to Corda interoperation flow, use the new host name or port (instead of localhost:9081).

    Driver

    To run the driver on a different port from the default (9099), do the following:

    • Navigate to the core/drivers/corda-driver folder.
    • Set the environment variable DRIVER_PORT appropriately while running the executable as follows:
      DRIVER_PORT=<port> ./build/install/corda-driver/bin/corda-driver

    To ensure that the relay can connect to this driver:

    • Navigate to the core/relay folder.
    • Update the port field in the drivers.Corda section in config/Corda_Relay.toml with the same value.

    Network

    Notes
    In our sample setup, all the Corda nodes must be running on the same machine (localhost or some other) for seamless communication.

    To change the ports the Corda nodes are listening on, do the following:

    • Navigate to the tests/network-setups/corda folder.
    • Update the exposed ports in docker-compose.yml (defaults are 10003 for the notary container and 10006 for the partya container).
    • Navigate to the samples/corda/corda-simple-application folder.
    • Update the CORDA_HOST (default is localhost) and CORDA_PORT (default is 10006) environment variables on your host machine to reflect the above update, or run the client bootstrapping script as follows:
      CORDA_HOST=<hostname> CORDA_PORT=<port> make initialise-vault
    • When you attempt a Fabric to Corda interoperation flow, use the new host name and port values as in the following example (network1 requesting Corda_Network):
      ./bin/fabric-cli interop --local-network=network1 --requesting-org=org1.network1.com localhost:9081/Corda_Network/<CORDA_HOST>:<CORDA_PORT>#com.cordaSimpleApplication.flow.GetStateByKey:H`

    Client Application

    The config files used to initialise the network's verification policies, access control policies, and security group info, contain the address (host name and port) of the Corda node. -To update the address of the Corda node, do the following:

    • Navigate to the samples/corda/corda-simple-application folder.
    • Edit the rules --> resource field in line 7 in clients/src/main/resources/config/FabricNetworkAccessControlPolicy.json by replacing localhost:10006 with <CORDA_HOST>:<CORDA_PORT> as specified in the previous section.

    Fabric

    Relay

    To run the relay on a different port from the default (9080 for network1 and 9083 for network2), do the following:

    • Navigate to the core/relay folder.
    • Update the port field in config/Fabric_Relay.toml (for network1) or config/Fabric_Relay2.toml (for network2).
    • To ensure Fabric-Fabric relay communication, update the foreign relay port in the port field in the relays.Fabric_Relay section in either of the above files.
    • To ensure that the Corda network's relay can communicate with this relay, update the port field in the relays.Fabric_Relay section in config/Corda_Relay.toml.
    • (You can update host names in similar locations, by adjusting the hostname field.)
    • When you attempt a Fabric to Fabric or Corda to Fabric interoperation flow, use the new host name or port (instead of localhost:9081 or localhost:9083).
    • Navigate to the core/drivers/fabric-driver folder.
    • Update the RELAY_ENDPOINT variable in .env or specify RELAY_ENDPOINT=<hostname>:<port> in the command line while running the driver using npm run dev.
    • Navigate to the samples/fabric/fabric-cli folder.
    • Update the relayEndpoint variables appropriately.

    Driver

    The fabric-driver configuration can be controlled by environment variables either set in .env in the core/drivers/fabric-driver folder (or a copy if you created one) or passed in the command line when you run npm run dev to start the driver. The relevant variables you can control when you make any change to the setup are:

    • CONNECTION_PROFILE: this is the path to the connection profile. If you make changes to the network or use a different one, create a new connection profile and point to it using this variable.
    • RELAY_ENDPOINT: this is the endpoint of the relay (hostname and port), and you can adjust it as described in the previous section; this is where the relay will be listening for incoming requests and from where the relay will channel foreign requests as well.
    • DRIVER_ENDPOINT: this is the hostname and port the driver itself will bind to, and you can change it from the default (localhost:9090 for network1 and localhost:9095 for network2) as per your need

    Fabric CLI

    You can adjust settings for fabric-cli in the .env and config.json (in the samples/fabric/fabric-cli folder) as described earlier.

    Important environment variables (in .env) are:

    • DEFAULT_CHANNEL: this is the name of the channel the CLI will interact with. If you build a new channel or network, update the channel name here.
    • DEFAULT_CHAINCODE: this is the name of the interoperaton chaincode the CLI will submit transactions and queries to for policy and security group bootstrapping. If you wish to test with a modified interoperation chaincode with a different name, update this value.
    • MEMBER_CREDENTIAL_FOLDER: as described earlier, this is an absolute path that points to policies and security group info associated with foreign networks. You can adjust this info for the existing three networks or add credentials for another network you wish to test interoperation flows with.
    • LOCAL: this is a boolean, indicating whether the network to connect to is running on (and as) localhost
    • DEFAULT_APPLICATION_CHAINCODE: this is the name of the application chaincode which maintains information that can be shared (with proof) with other networks upon request using interoperation. You may write and deploy your own chaincode and use its name here instead of the default simplestate.
    • CONFIG_PATH: this points to the JSON file containing the configurations of all the Fabric networks that need to be configured using the fabric-cli.

    The config.json (which can have a different name as long as you add the right reference to .env and configure fabric-cli suitably) has the following structure (it can have any number of networks specified):

    {
    "network1": {
    "connProfilePath": "",
    "relayEndpoint": ""
    },
    "network2": {
    "connProfilePath": "",
    "relayEndpoint": ""
    }
    }

    • connProfilePath: absolute path of the network's connection profile
    • relayEndpoint: hostname and port of the particular network's relay (make sure you sync this with any changes made to that relay's configuration)
    - - +

    Advanced Configuration

    You can configure the different components of the test network to use non-default parameter values for various settings (such as host names or port numbers). Here is a list of configurations you can tweak, classified by the DLT type.

    Corda

    Relay

    To run the relay on a different port from the default (9081), do the following:

    • Navigate to the core/relay folder in your clone of the Weaver repository.
    • Update the port field in config/Corda_Relay.toml.
    • To ensure that the relay of network1 can communicate with this relay, update the port field in the relays.Corda_Relay section in config/Fabric_Relay.toml with the same value.
    • To ensure that the relay of network2 can communicate with this relay, update the port field in the relays.Corda_Relay section in config/Fabric_Relay2.toml with the same value.
    • (You can update host names in similar locations, by adjusting the hostname field.)
    • When you attempt a Fabric to Corda interoperation flow, use the new host name or port (instead of localhost:9081).

    Driver

    To run the driver on a different port from the default (9099), do the following:

    • Navigate to the core/drivers/corda-driver folder in your clone of the Weaver repository.
    • Set the environment variable DRIVER_PORT appropriately while running the executable as follows:
      DRIVER_PORT=<port> ./build/install/corda-driver/bin/corda-driver

    To ensure that the relay can connect to this driver:

    • Navigate to the core/relay folder in your clone of the Weaver repository.
    • Update the port field in the drivers.Corda section in config/Corda_Relay.toml with the same value.

    Network

    Notes
    In our sample setup, all the Corda nodes must be running on the same machine (localhost or some other) for seamless communication.

    To change the ports the Corda nodes are listening on, do the following:

    • Navigate to the tests/network-setups/corda folder in your clone of the Weaver repository.
    • Update the exposed ports in docker-compose.yml (defaults are 10003 for the notary container and 10006 for the partya container).
    • Navigate to the samples/corda/corda-simple-application folder in your clone of the Weaver repository.
    • Update the CORDA_HOST (default is localhost) and CORDA_PORT (default is 10006) environment variables on your host machine to reflect the above update, or run the client bootstrapping script as follows:
      CORDA_HOST=<hostname> CORDA_PORT=<port> make initialise-vault
    • When you attempt a Fabric to Corda interoperation flow, use the new host name and port values as in the following example (network1 requesting Corda_Network):
      ./bin/fabric-cli interop --local-network=network1 --requesting-org=org1.network1.com localhost:9081/Corda_Network/<CORDA_HOST>:<CORDA_PORT>#com.cordaSimpleApplication.flow.GetStateByKey:H`

    Client Application

    The config files used to initialise the network's verification policies, access control policies, and security group info, contain the address (host name and port) of the Corda node. +To update the address of the Corda node, do the following:

    • Navigate to the samples/corda/corda-simple-application folder in your clone of the Weaver repository.
    • Edit the rules --> resource field in line 7 in clients/src/main/resources/config/FabricNetworkAccessControlPolicy.json by replacing localhost:10006 with <CORDA_HOST>:<CORDA_PORT> as specified in the previous section.

    Fabric

    Relay

    To run the relay on a different port from the default (9080 for network1 and 9083 for network2), do the following:

    • Navigate to the core/relay folder in your clone of the Weaver repository.
    • Update the port field in config/Fabric_Relay.toml (for network1) or config/Fabric_Relay2.toml (for network2).
    • To ensure Fabric-Fabric relay communication, update the foreign relay port in the port field in the relays.Fabric_Relay section in either of the above files.
    • To ensure that the Corda network's relay can communicate with this relay, update the port field in the relays.Fabric_Relay section in config/Corda_Relay.toml.
    • (You can update host names in similar locations, by adjusting the hostname field.)
    • When you attempt a Fabric to Fabric or Corda to Fabric interoperation flow, use the new host name or port (instead of localhost:9081 or localhost:9083).
    • Navigate to the core/drivers/fabric-driver folder in your clone of the Weaver repository.
    • Update the RELAY_ENDPOINT variable in .env or specify RELAY_ENDPOINT=<hostname>:<port> in the command line while running the driver using npm run dev.
    • Navigate to the samples/fabric/fabric-cli folder in your clone of the Weaver repository.
    • Update the relayEndpoint variables appropriately.

    Driver

    The fabric-driver configuration can be controlled by environment variables either set in .env in the core/drivers/fabric-driver folder (or a copy if you created one) in your clone of the Weaver repository or passed in the command line when you run npm run dev to start the driver. The relevant variables you can control when you make any change to the setup are:

    • CONNECTION_PROFILE: this is the path to the connection profile. If you make changes to the network or use a different one, create a new connection profile and point to it using this variable.
    • RELAY_ENDPOINT: this is the endpoint of the relay (hostname and port), and you can adjust it as described in the previous section; this is where the relay will be listening for incoming requests and from where the relay will channel foreign requests as well.
    • DRIVER_ENDPOINT: this is the hostname and port the driver itself will bind to, and you can change it from the default (localhost:9090 for network1 and localhost:9095 for network2) as per your need

    Fabric CLI

    You can adjust settings for fabric-cli in the .env and config.json (in the samples/fabric/fabric-cli folder in your clone of the Weaver repository) as described earlier.

    Important environment variables (in .env) are:

    • DEFAULT_CHANNEL: this is the name of the channel the CLI will interact with. If you build a new channel or network, update the channel name here.
    • DEFAULT_CHAINCODE: this is the name of the interoperaton chaincode the CLI will submit transactions and queries to for policy and security group bootstrapping. If you wish to test with a modified interoperation chaincode with a different name, update this value.
    • MEMBER_CREDENTIAL_FOLDER: as described earlier, this is an absolute path that points to policies and security group info associated with foreign networks. You can adjust this info for the existing three networks or add credentials for another network you wish to test interoperation flows with.
    • LOCAL: this is a boolean, indicating whether the network to connect to is running on (and as) localhost
    • DEFAULT_APPLICATION_CHAINCODE: this is the name of the application chaincode which maintains information that can be shared (with proof) with other networks upon request using interoperation. You may write and deploy your own chaincode and use its name here instead of the default simplestate.
    • CONFIG_PATH: this points to the JSON file containing the configurations of all the Fabric networks that need to be configured using the fabric-cli.

    The config.json (which can have a different name as long as you add the right reference to .env and configure fabric-cli suitably) has the following structure (it can have any number of networks specified):

    {
    "network1": {
    "connProfilePath": "",
    "relayEndpoint": ""
    },
    "network2": {
    "connProfilePath": "",
    "relayEndpoint": ""
    }
    }

    • connProfilePath: absolute path of the network's connection profile
    • relayEndpoint: hostname and port of the particular network's relay (make sure you sync this with any changes made to that relay's configuration)
    + + \ No newline at end of file diff --git a/docs/external/getting-started/test-network/ledger-initialization/index.html b/docs/external/getting-started/test-network/ledger-initialization/index.html index eb1f2221b..f1eb5902b 100644 --- a/docs/external/getting-started/test-network/ledger-initialization/index.html +++ b/docs/external/getting-started/test-network/ledger-initialization/index.html @@ -4,22 +4,22 @@ Ledger Initialization | Weaver: DLT Interoperability Framework - - - + + +
    -

    Ledger Initialization

    Once the two Fabric networks and the Corda network are up and running along with their associated relays and drivers, we must initialize states in those networks to prepare them for interoperation. For the Fabric networks, this involves recording state in the channel ledgers, and for the Corda network, in the nodes' vaults. The configuration and bootstrapping takes different form depending on what interoperability mode you wish to test.

    Preparation for Data Sharing

    Follow the below instructions to prepare your networks for data sharing tests.

    Initializing the Fabric Networks

    We use the Fabric CLI (fabric-cli) built earlier (in samples/fabric/fabric-cli and samples/fabric/go-cli) for this purpose.

    Configuring the Fabric CLI

    During bootstrap, the ledgers in both network1 and network2 must be populated with the following information scoped by the interoperation chaincode:

    • Access control policies governing requests from foreign networks
    • Security group info for foreign networks (i.e., identities of network units and their membership providers' certificate chains)
    • Verification policies for proofs supplied by foreign networks +

      Ledger Initialization

      Once the two Fabric networks and the Corda network are up and running along with their associated relays and drivers, we must initialize states in those networks to prepare them for interoperation. For the Fabric networks, this involves recording state in the channel ledgers, and for the Corda network, in the nodes' vaults. The configuration and bootstrapping takes different form depending on what interoperability mode you wish to test.

      Preparation for Data Sharing

      Follow the below instructions to prepare your networks for data sharing tests.

      Initializing the Fabric Networks

      We use the Fabric CLI (fabric-cli) built earlier (in samples/fabric/fabric-cli for the Node.js version and samples/fabric/go-cli for the Golang version) for this purpose.

      Configuring the Fabric CLI

      During bootstrap, the ledgers in both network1 and network2 must be populated with the following information scoped by the interoperation chaincode:

      • Access control policies governing requests from foreign networks
      • Security group info for foreign networks (i.e., identities of network units and their membership providers' certificate chains)
      • Verification policies for proofs supplied by foreign networks Knowledge of foreign networks that must be configured in this stage is as follows:
      • network1 has policies and security group info for network2 and Corda_Network
      • network2 has policies and security group info for network1 and Corda_Network (Corda_Network will be launched later.) -The ledgers must also be populated with sample key-value pairs for testing interoperation flows, scoped by the sample application chaincode.

      Prepare fabric-cli for configuration suitably as follows.

      • Navigate to the samples/fabric/fabric-cli (for the Node.js version) or the samples/fabric/go-cli (for the Golang version) folder.
      • Create a config.json file by copying the config.template.json and setting (or adding or removing) suitable values:
        • For each network, the relay port and connection profile paths are specified using the keys relayPort and connProfilePath respectively.
          • Replace <PATH-TO-WEAVER> with the absolute path location of the weaver-dlt-interoperability clone folder.
          • Otherwise, leave the default values unchanged.
      • Create a chaincode.json file by copying the chaincode.json.template and leaving the default values unchanged. This file specified the arguments of the transaction to be locally invoked after fetching a remote view.
      • Create a .env file by copying .env.template and setting the following parameter values:
        • If Relays and Drivers are deployed in the host machine:
          MEMBER_CREDENTIAL_FOLDER=<PATH-TO-WEAVER>/samples/fabric/fabric-cli/src/data/credentials
          DEFAULT_APPLICATION_CHAINCODE=<chaincode-name>
          DEFAULT_APPLICATION_FUNC=<function-name>
          CONFIG_PATH=./config.json
          CHAINCODE_PATH=./chaincode.json
        • If Relays and Drivers are deployed in the Docker containers:
          MEMBER_CREDENTIAL_FOLDER=<PATH-TO-WEAVER>/samples/fabric/fabric-cli/src/data/credentials_docker
          DEFAULT_APPLICATION_CHAINCODE=<chaincode-name>
          DEFAULT_APPLICATION_FUNC=<function-name>
          CONFIG_PATH=./config.json
          CHAINCODE_PATH=./chaincode.json
        • In each case, replace <PATH-TO-WEAVER> with the location of your clone of Weaver and <chaincode-name> with the name of the deployed chaincode, either simplestate or simplestatewithacl.
        • If simplestate is deployed, set <function-name> to Create, and if simplestatewithacl if deployed, set <function-name> to CreateFromRemote.
        • Leave the default values unchanged for the other parameters.
      • Run the following command:
        ./bin/fabric-cli env set-file ./.env
        Notes
        If the CONFIG_PATH environment variable is omitted from .env, then you must also run:
        ./bin/fabric-cli config set-file ./config.json

      Bootstrapping Network and Application State

      Finally, to prepare both network1 and network2 for interoperation, run:

      ./bin/fabric-cli configure all network1 network2

      If Fabric networks were launched with 2 organizations, run:

      ./bin/fabric-cli configure all network1 network2 --num-orgs=2

      Instead, if you launched only one of the two Fabric networks, run the following after replacing <network-id> with either network1 or network2, and <1/2> with number of organizations in the network:

      ./bin/fabric-cli configure all <network-id> --num-orgs=<1/2>

      Wait for at least 5 minutes before moving on to the next step (testing interoperability modes) to allow the networks' IIN Agents to sync their respective memberships (which occur after every 5 minutes by default).

      Optionally, fabric-cli can be used to trigger sync manually by running following command:

      ./bin/fabric-cli configure membership --local-network=network1 --target-network=network2 --iin-agent-endpoint=localhost:9500

      This command syncs network2's membership (target-network) in network1 (local-network) using IIN Agent of Org1MSP as initiator. Similarly network1's membership can be synced to network2's ledger by running:

      ./bin/fabric-cli configure membership --local-network=network2 --target-network=network1 --iin-agent-endpoint=localhost:9501

      Wait for 20-30 seconds after above commands to allow IIN Agents to finish the sync.

      Initializing the Corda Networks

      Once the Corda networks are launched, the client applications (built earlier) needs to be exercised to generate network (ledger) state in preparation to test interoperation flows.

      Bootstrapping Networks and Application States

      Just as we did for either Fabric network, the Corda network ledger (or vault on each node) must be initialized with access control policies, verification policies, and security group information for the two Fabric networks. Further, sample key-value pairs need to be recorded so we can later share them with a Fabric network via an interoperation flow.

      Bootstrap the Corda networks and application states as follows (the following instructions will initialize either or both Corda networks, depending on which of those are up and running):

      • Navigate to the samples/corda/corda-simple-application folder.
      • Run the following:
        • If Relays and Drivers are deployed in the host machine:
          make initialise-vault
        • If Relays and Drivers are deployed in the Docker containers:
          make initialise-vault-docker

      Next Steps

      The test networks are now configured and their ledgers are initialized. You can now run the data sharing flows.

      Preparation for Asset Exchange

      Follow the below instructions to prepare your networks for asset exchange tests.

      Initializing the Fabric Networks

      We use the Fabric CLI (fabric-cli) built earlier (in samples/fabric/fabric-cli and samples/fabric/go-cli) for this purpose.

      Configuring the Fabric CLI

      The ledgers must be populated with sample key-value pairs for testing interoperation flows, scoped by the sample application chaincode.

      Prepare fabric-cli for configuration suitably as follows.

      • Navigate to the samples/fabric/fabric-cli (for the Node.js version) or the samples/fabric/go-cli (for the Golang version) folder.
      • Create a config.json file by copying the config.template.json and setting (or adding or removing) suitable values:
        • For each network, the relay port and connection profile paths are specified using the keys relayPort and connProfilePath respectively.
          • Replace <PATH-TO-WEAVER> with the absolute path location of the weaver-dlt-interoperability clone folder.
          • Set the chaincode attribute in each network to the deployed chaincode name (simpleasset or simpleassetandinterop or simpleassettransfer).
          • Otherwise, leave the default values unchanged.
      • Create a .env file by copying .env.template and setting following parameter values:
        • If Relays and Drivers are deployed in the host machine:
          MEMBER_CREDENTIAL_FOLDER=<PATH-TO-WEAVER>/samples/fabric/fabric-cli/src/data/credentials
          CONFIG_PATH=./config.json
        • If Relays and Drivers are deployed in the Docker containers:
          MEMBER_CREDENTIAL_FOLDER=<PATH-TO-WEAVER>/samples/fabric/fabric-cli/src/data/credentials_docker
          CONFIG_PATH=./config.json
        • In each case, replace <PATH-TO-WEAVER> with the location of your clone of Weaver.
        • Leave the default values unchanged for the other parameters.
      • Run the following command:
        ./bin/fabric-cli env set-file ./.env
        Notes
        If the CONFIG_PATH environment variable is omitted from .env, then you must also run:
        ./bin/fabric-cli config set-file ./config.json

      Bootstrapping Network and Application State

      Finally, to prepare both network1 and network2 for interoperation, run:

      ./scripts/initAsset.sh

      Initializing the Corda Networks

      Corda Network needs to be initialized with assets for asset-exchange to be performed: +The ledgers must also be populated with sample key-value pairs for testing interoperation flows, scoped by the sample application chaincode.

    Prepare fabric-cli for configuration suitably as follows.

    • Navigate to the samples/fabric/fabric-cli (for the Node.js version) or the samples/fabric/go-cli (for the Golang version) folder.
    • Create a config.json file by copying the config.template.json and setting (or adding or removing) suitable values:
      • For each network, the relay port and connection profile paths are specified using the keys relayPort and connProfilePath respectively.
        • Replace <PATH-TO-WEAVER> with the absolute path location of the weaver-dlt-interoperability clone folder.
        • Otherwise, leave the default values unchanged.
    • Create a chaincode.json file by copying the chaincode.json.template and leaving the default values unchanged. This file specified the arguments of the transaction to be locally invoked after fetching a remote view.
    • Create a .env file by copying .env.template and setting the following parameter values:
      • If Relays and Drivers are deployed in the host machine:
        MEMBER_CREDENTIAL_FOLDER=<PATH-TO-WEAVER>/samples/fabric/fabric-cli/src/data/credentials
        DEFAULT_APPLICATION_CHAINCODE=<chaincode-name>
        DEFAULT_APPLICATION_FUNC=<function-name>
        CONFIG_PATH=./config.json
        CHAINCODE_PATH=./chaincode.json
      • If Relays and Drivers are deployed in the Docker containers:
        MEMBER_CREDENTIAL_FOLDER=<PATH-TO-WEAVER>/samples/fabric/fabric-cli/src/data/credentials_docker
        DEFAULT_APPLICATION_CHAINCODE=<chaincode-name>
        DEFAULT_APPLICATION_FUNC=<function-name>
        CONFIG_PATH=./config.json
        CHAINCODE_PATH=./chaincode.json
      • In each case, replace <PATH-TO-WEAVER> with the absolute path location of your clone of Weaver and <chaincode-name> with the name of the deployed chaincode, either simplestate or simplestatewithacl.
      • If simplestate is deployed, set <function-name> to Create, and if simplestatewithacl if deployed, set <function-name> to CreateFromRemote.
      • Leave the default values unchanged for the other parameters.
    • Run the following command:
      ./bin/fabric-cli env set-file ./.env
    Notes
    If the CONFIG_PATH environment variable is omitted from .env, then you must also run:
    ./bin/fabric-cli config set-file ./config.json

    Bootstrapping Network and Application State

    Finally, to prepare both network1 and network2 for interoperation, run:

    ./bin/fabric-cli configure all network1 network2

    If Fabric networks were launched with 2 organizations, run:

    ./bin/fabric-cli configure all network1 network2 --num-orgs=2

    Instead, if you launched only one of the two Fabric networks, run the following after replacing <network-id> with either network1 or network2, and <1/2> with number of organizations in the network:

    ./bin/fabric-cli configure all <network-id> --num-orgs=<1/2>

    Wait for at least 5 minutes before moving on to the next step (testing interoperability modes) to allow the networks' IIN Agents to sync their respective memberships (which occur after every 5 minutes by default).

    Optionally, fabric-cli can be used to trigger sync manually by running following command:

    ./bin/fabric-cli configure membership --local-network=network1 --target-network=network2 --iin-agent-endpoint=localhost:9500

    This command syncs network2's membership (target-network) in network1 (local-network) using IIN Agent of Org1MSP as initiator. Similarly network1's membership can be synced to network2's ledger by running:

    ./bin/fabric-cli configure membership --local-network=network2 --target-network=network1 --iin-agent-endpoint=localhost:9501

    Wait for 20-30 seconds after above commands to allow IIN Agents to finish the sync.

    Initializing the Corda Networks

    Once the Corda networks are launched, the client applications (built earlier) needs to be exercised to generate network (ledger) state in preparation to test interoperation flows.

    Bootstrapping Networks and Application States

    Just as we did for either Fabric network, the Corda network ledger (or vault on each node) must be initialized with access control policies, verification policies, and security group information for the two Fabric networks. Further, sample key-value pairs need to be recorded so we can later share them with a Fabric network via an interoperation flow.

    Bootstrap the Corda networks and application states as follows (the following instructions will initialize either or both Corda networks, depending on which of those are up and running):

    • Navigate to the samples/corda/corda-simple-application folder.
    • Run the following:
      • If Relays and Drivers are deployed in the host machine:
        make initialise-vault
      • If Relays and Drivers are deployed in the Docker containers:
        make initialise-vault-docker
        Even upon successful execution (as indicated by the console output), you may see errors of the following form:
      [ERROR] 07:51:17.206 [epollEventLoopGroup-19-1] client.exceptionCaught - AMQ214015: Failed to execute connection life cycle listener
      java.util.concurrent.RejectedExecutionException: Task org.apache.activemq.artemis.utils.actors.ProcessorBase$$Lambda$34/681158875@666df796 rejected from java.util.concurrent.ThreadPoolExecutor@236f653f[Terminated, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 6]
      at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063) ~[?:1.8.0_402]
      ..........
      You can ignore these as they are transient errors that don't impact the operations.

    Next Steps

    The test networks are now configured and their ledgers are initialized. You can now run the data sharing flows.

    Preparation for Asset Exchange

    Follow the below instructions to prepare your networks for asset exchange tests.

    Initializing the Fabric Networks

    We use the Fabric CLI (fabric-cli) built earlier (in samples/fabric/fabric-cli for the Node.js version and samples/fabric/go-cli for the Golang version) for this purpose.

    Configuring the Fabric CLI

    The ledgers must be populated with sample key-value pairs for testing interoperation flows, scoped by the sample application chaincode.

    Prepare fabric-cli for configuration suitably as follows.

    • Navigate to the samples/fabric/fabric-cli (for the Node.js version) or the samples/fabric/go-cli (for the Golang version) folder.
    • Create a config.json file by copying the config.template.json and setting (or adding or removing) suitable values:
      • For each network, the relay port and connection profile paths are specified using the keys relayPort and connProfilePath respectively.
        • Replace <PATH-TO-WEAVER> with the absolute path location of the weaver-dlt-interoperability clone folder.
        • Set the chaincode attribute in each network to the deployed chaincode name (simpleasset or simpleassetandinterop or simpleassettransfer).
        • Otherwise, leave the default values unchanged.
    • Create a .env file by copying .env.template and setting following parameter values:
      • If Relays and Drivers are deployed in the host machine:
        MEMBER_CREDENTIAL_FOLDER=<PATH-TO-WEAVER>/samples/fabric/fabric-cli/src/data/credentials
        CONFIG_PATH=./config.json
      • If Relays and Drivers are deployed in the Docker containers:
        MEMBER_CREDENTIAL_FOLDER=<PATH-TO-WEAVER>/samples/fabric/fabric-cli/src/data/credentials_docker
        CONFIG_PATH=./config.json
      • In each case, replace <PATH-TO-WEAVER> with the absolute path location of your clone of Weaver.
      • Leave the default values unchanged for the other parameters.
    • Run the following command:
      ./bin/fabric-cli env set-file ./.env
    Notes
    If the CONFIG_PATH environment variable is omitted from .env, then you must also run:
    ./bin/fabric-cli config set-file ./config.json

    Bootstrapping Network and Application State

    Finally, to prepare both network1 and network2 for interoperation, run:

    ./scripts/initAsset.sh

    Initializing the Corda Networks

    Corda Network needs to be initialized with assets for asset-exchange to be performed: Bootstrap the Corda network and application states as follows:

    • Navigate to the samples/corda/corda-simple-application folder.
    • Run the following:
      • For cordaSimpleApplication app, run:
        ./scripts/initAsset.sh

    Initializing the Besu Networks

    Let's assume that network1 can either manage NFT AliceERC721 or Hybrid AliceERC1155 tokens, while network2 manages fungible BobERC20 tokens. Here we use account 1 for Alice and account 2 for Bob in both neworks. To prepare Besu networks for asset exchange, navigate to the samples/besu/besu-cli and then follow the steps in next subsections.

    Configuring the Besu-CLI

    Create a config.json file by copying the config.template.json, keep the default values for managing AliceERC721 tokens in network1 and BobERC20 tokens in network2. -If you want to change the token type used in the network1 to Hybrid AliceERC1155 tokens, in config.json update tokenContract field with value "../simpleasset/build/contracts/AliceERC1155.json".

    Bootstrapping Network and Application State

    Finally, to prepare both network1 and network2 for interoperation, run:

    • If you wish to test the default exchange (ERC-20 tokens for ERC-721 tokens), run::
      ./scripts/initAsset.sh
      This will issue 100 BobERC20 tokens to each account in network2 and AliceERC721 token with id 0 to Alice and id 1 to Bob in network1.
    • Instead, if you wish to test Alice's exchange of ERC-1155 tokens for Bob's ERC-20 tokens, run:
      ./scripts/initAsset.sh hybrid
      This will issue 100 BobERC20 tokens to each account in network2 and 100 AliceERC1155 tokens with id 0 to Alice and id 1 to Bob in network1.

    Next Steps

    The test networks are now configured and their ledgers are initialized. You can now run the asset exchange flows.

    Preparation for Asset Transfer

    Follow the below instructions to prepare your networks for asset transfer tests.

    Initializing the Fabric Networks

    We use the Fabric CLI (fabric-cli) built earlier (in samples/fabric/fabric-cli and samples/fabric/go-cli) for this purpose.

    Configuring the Fabric CLI

    During bootstrap, the ledgers in both network1 and network2 must be populated with the following information scoped by the interoperation chaincode:

    • Access control policies governing requests from foreign networks
    • Security group info for foreign networks (i.e., identities of network units and their membership providers' certificate chains)
    • Verification policies for proofs supplied by foreign networks +If you want to change the token type used in the network1 to Hybrid AliceERC1155 tokens, in config.json update tokenContract field with value "../simpleasset/build/contracts/AliceERC1155.json".

      Bootstrapping Network and Application State

      Finally, to prepare both network1 and network2 for interoperation, run:

      • If you wish to test the default exchange (ERC-20 tokens for ERC-721 tokens), run::
        ./scripts/initAsset.sh
        This will issue 100 BobERC20 tokens to each account in network2 and AliceERC721 token with id 0 to Alice and id 1 to Bob in network1.
      • Instead, if you wish to test Alice's exchange of ERC-1155 tokens for Bob's ERC-20 tokens, run:
        ./scripts/initAsset.sh hybrid
        This will issue 100 BobERC20 tokens to each account in network2 and 100 AliceERC1155 tokens with id 0 to Alice and id 1 to Bob in network1.

      Next Steps

      The test networks are now configured and their ledgers are initialized. You can now run the asset exchange flows.

      Preparation for Asset Transfer

      Follow the below instructions to prepare your networks for asset transfer tests.

      Initializing the Fabric Networks

      We use the Fabric CLI (fabric-cli) built earlier (in samples/fabric/fabric-cli for the Node.js version and samples/fabric/go-cli for the Golang version) for this purpose.

      Configuring the Fabric CLI

      During bootstrap, the ledgers in both network1 and network2 must be populated with the following information scoped by the interoperation chaincode:

      • Access control policies governing requests from foreign networks
      • Security group info for foreign networks (i.e., identities of network units and their membership providers' certificate chains)
      • Verification policies for proofs supplied by foreign networks Knowledge of foreign networks that must be configured in this stage is as follows:
      • network1 has policies and security group info for network2 and Corda_Network
      • network2 has policies and security group info for network1 and Corda_Network (The Corda sample application doesn't support asset transfer yet, but there is no harm in including it above.) -The ledgers must also be populated with sample key-value pairs for testing interoperation flows, scoped by the sample application chaincode.

      Prepare fabric-cli for configuration suitably as follows.

      • Navigate to the samples/fabric/fabric-cli folder (the Go CLI doesn't support asset transfer yet).
      • Create a config.json file by copying the config.template.json and setting (or adding or removing) suitable values:
        • For each network, the relay port and connection profile paths are specified using the keys relayPort and connProfilePath respectively.
          • Replace <PATH-TO-WEAVER> with the absolute path location of the weaver-dlt-interoperability clone folder.
          • Set the chaincode attribute in each network to simpleassettransfer.
          • Set the aclPolicyPrincipalType attribute in network2 to ca.
          • Otherwise, leave the default values unchanged.
      • Create remote-network-config.json file by copying remote-network-config.json.template. Use default values if relays and drivers are deployed in the host machine; else if they are deployed in Docker, update as follows:
        • Update value for relayEndpoint for network1 as relay-network1:9080.
        • Update value for relayEndpoint for network2 as relay-network2:9083.
        • Update value for relayEndpoint for Corda_Network as relay-corda:9081.
        • Update value for relayEndpoint for Corda_Network2 as relay-corda2:9082.
        • Update value for partyEndPoint for Corda_Network as corda_partya_1:10003.
        • Update value for partyEndPoint for Corda_Network2 as corda_network2_partya_1:10003.
      • Create chaincode.json file by copying chaincode.json.template. Keep the default values unchanged.
      • Create a .env file by copying .env.template and setting the following parameter values:
        • If Relays and Drivers are deployed in the host machine:
          MEMBER_CREDENTIAL_FOLDER=<PATH-TO-WEAVER>/samples/fabric/fabric-cli/src/data/credentials
          DEFAULT_APPLICATION_CHAINCODE=simpleassettransfer
          CONFIG_PATH=./config.json
          REMOTE_CONFIG_PATH=./remote-network-config.json
          CHAINCODE_PATH=./chaincode.json
        • If Relays and Drivers are deployed in the Docker containers:
          MEMBER_CREDENTIAL_FOLDER=<PATH-TO-WEAVER>/samples/fabric/fabric-cli/src/data/credentials_docker
          DEFAULT_APPLICATION_CHAINCODE=simpleassettransfer
          CONFIG_PATH=./config.json
          REMOTE_CONFIG_PATH=./remote-network-config.json
          CHAINCODE_PATH=./chaincode.json
        • In each case, replace <PATH-TO-WEAVER> with the location of your clone of Weaver.
        • Leave the default values unchanged for the other parameters.
      • Run the following command:
        ./bin/fabric-cli env set-file ./.env
        Notes
        If the CONFIG_PATH environment variable is omitted from .env, then you must also run:
        ./bin/fabric-cli config set-file ./config.json

      Bootstrapping Network and Application State

      Create appropriate access control and verification policies for network1 and network2 by running:

      ./bin/fabric-cli configure create all --local-network=network1
      ./bin/fabric-cli configure create all --local-network=network2

      Load access control and verification policies onto the ledgers of network1 and network2 by running (replace <1/2> with number of organizations in the network):

      ./bin/fabric-cli configure network --local-network=network1 --num-orgs=<1/2>
      ./bin/fabric-cli configure network --local-network=network2 --num-orgs=<1/2>

      Wait for at least 5 minutes before moving on to the next step (testing interoperability modes) to allow the networks' IIN Agents to sync their respective memberships (which occur after every 5 minutes by default).

      Optionally, fabric-cli can be used to trigger sync manually by running following command:

      ./bin/fabric-cli configure membership --local-network=network1 --target-network=network2 --iin-agent-endpoint=localhost:9500

      This command syncs network2's membership (target-network) in network1 (local-network) using IIN Agent of Org1MSP as initiator. Similarly network1's membership can be synced to network2's ledger by running:

      ./bin/fabric-cli configure membership --local-network=network2 --target-network=network1 --iin-agent-endpoint=localhost:9501

      Wait for 20-30 seconds after above commands to allow IIN Agents to finish the sync.

      Initialize bond and token asset states and ownerships on the network1 ledger by running the following (this step will also create a user alice in network1 and a user bob in network2):

      ./scripts/initAssetsForTransfer.sh

      Initializing the Corda Networks

      Once the Corda networks (Corda_Network and Corda_Network2) are launched, the client applications (built earlier) needs to be exercised to generate ledger state in both exporting/source and importing/destination networks in preparation to test asset transfer interoperation flows.

      Bootstrapping Networks and Application States

      The Corda network ledger (or vault on each node) must be initialized with access control policies, verification policies, and security group information for the other networks (two Fabric networks and other Corda network).

      Bootstrap the Corda networks and application states as follows (the following instructions will initialize either or both Corda networks, depending on which of those are up and running):

      • Navigate to the samples/corda/corda-simple-application folder.
      • Run the following:
        cp clients/src/main/resources/config/remote-network-config.json.template clients/src/main/resources/config/remote-network-config.json
        Use default values in remote-network-config.json if relays and drivers are deployed in the host machine; else if they are deployed in Docker, update as follows:
        • Update value for relayEndpoint for network1 as relay-network1:9080.
        • Update value for relayEndpoint for network2 as relay-network2:9083.
        • Update value for relayEndpoint for Corda_Network as relay-corda:9081.
        • Update value for relayEndpoint for Corda_Network2 as relay-corda2:9082.
        • Update value for partyEndPoint for Corda_Network as corda_partya_1:10003.
        • Update value for partyEndPoint for Corda_Network2 as corda_network2_partya_1:10003.
      • Run the following:
        • If Relays and Drivers are deployed in the host machine:
          make initialise-vault-asset-transfer
        • If Relays and Drivers are deployed in the Docker containers:
          make initialise-vault-asset-transfer-docker

      Next Steps

      The test networks are now configured and their ledgers are initialized. You can now run the asset transfer flows.

    - - +The ledgers must also be populated with sample key-value pairs for testing interoperation flows, scoped by the sample application chaincode.

    Prepare fabric-cli for configuration suitably as follows.

    • Navigate to the samples/fabric/fabric-cli folder (the Go CLI doesn't support asset transfer yet).
    • Create a config.json file by copying the config.template.json and setting (or adding or removing) suitable values:
      • For each network, the relay port and connection profile paths are specified using the keys relayPort and connProfilePath respectively.
        • Replace <PATH-TO-WEAVER> with the absolute path location of the weaver-dlt-interoperability clone folder.
        • Set the chaincode attribute in each network to simpleassettransfer.
        • Set the aclPolicyPrincipalType attribute in network2 to ca.
        • Otherwise, leave the default values unchanged.
    • Create remote-network-config.json file by copying remote-network-config.json.template. Use default values if relays and drivers are deployed in the host machine; else if they are deployed in Docker, update as follows:
      • Update value for relayEndpoint for network1 as relay-network1:9080.
      • Update value for relayEndpoint for network2 as relay-network2:9083.
      • Update value for relayEndpoint for Corda_Network as relay-corda:9081.
      • Update value for relayEndpoint for Corda_Network2 as relay-corda2:9082.
      • Update value for partyEndPoint for Corda_Network as corda_partya_1:10003.
      • Update value for partyEndPoint for Corda_Network2 as corda_network2_partya_1:10003.
    • Create chaincode.json file by copying chaincode.json.template. Keep the default values unchanged.
    • Create a .env file by copying .env.template and setting the following parameter values:
      • If Relays and Drivers are deployed in the host machine:
        MEMBER_CREDENTIAL_FOLDER=<PATH-TO-WEAVER>/samples/fabric/fabric-cli/src/data/credentials
        DEFAULT_APPLICATION_CHAINCODE=simpleassettransfer
        CONFIG_PATH=./config.json
        REMOTE_CONFIG_PATH=./remote-network-config.json
        CHAINCODE_PATH=./chaincode.json
      • If Relays and Drivers are deployed in the Docker containers:
        MEMBER_CREDENTIAL_FOLDER=<PATH-TO-WEAVER>/samples/fabric/fabric-cli/src/data/credentials_docker
        DEFAULT_APPLICATION_CHAINCODE=simpleassettransfer
        CONFIG_PATH=./config.json
        REMOTE_CONFIG_PATH=./remote-network-config.json
        CHAINCODE_PATH=./chaincode.json
      • In each case, replace <PATH-TO-WEAVER> with the absolute path location of your clone of Weaver.
      • Leave the default values unchanged for the other parameters.
    • Run the following command:
      ./bin/fabric-cli env set-file ./.env
    Notes
    If the CONFIG_PATH environment variable is omitted from .env, then you must also run:
    ./bin/fabric-cli config set-file ./config.json

    Bootstrapping Network and Application State

    Create appropriate access control and verification policies for network1 and network2 by running:

    ./bin/fabric-cli configure create all --local-network=network1
    ./bin/fabric-cli configure create all --local-network=network2

    Load access control and verification policies onto the ledgers of network1 and network2 by running (replace <1/2> with number of organizations in the network):

    ./bin/fabric-cli configure network --local-network=network1 --num-orgs=<1/2>
    ./bin/fabric-cli configure network --local-network=network2 --num-orgs=<1/2>

    Wait for at least 5 minutes before moving on to the next step (testing interoperability modes) to allow the networks' IIN Agents to sync their respective memberships (which occur after every 5 minutes by default).

    Optionally, fabric-cli can be used to trigger sync manually by running following command:

    ./bin/fabric-cli configure membership --local-network=network1 --target-network=network2 --iin-agent-endpoint=localhost:9500

    This command syncs network2's membership (target-network) in network1 (local-network) using IIN Agent of Org1MSP as initiator. Similarly network1's membership can be synced to network2's ledger by running:

    ./bin/fabric-cli configure membership --local-network=network2 --target-network=network1 --iin-agent-endpoint=localhost:9501

    Wait for 20-30 seconds after above commands to allow IIN Agents to finish the sync.

    Initialize bond and token asset states and ownerships on the network1 ledger by running the following (this step will also create a user alice in network1 and a user bob in network2):

    ./scripts/initAssetsForTransfer.sh

    Initializing the Corda Networks

    Once the Corda networks (Corda_Network and Corda_Network2) are launched, the client applications (built earlier) needs to be exercised to generate ledger state in both exporting/source and importing/destination networks in preparation to test asset transfer interoperation flows.

    Bootstrapping Networks and Application States

    The Corda network ledger (or vault on each node) must be initialized with access control policies, verification policies, and security group information for the other networks (two Fabric networks and other Corda network).

    Bootstrap the Corda networks and application states as follows (the following instructions will initialize either or both Corda networks, depending on which of those are up and running):

    • Navigate to the samples/corda/corda-simple-application folder.
    • Run the following:
      cp clients/src/main/resources/config/remote-network-config.json.template clients/src/main/resources/config/remote-network-config.json
      Use default values in remote-network-config.json if relays and drivers are deployed in the host machine; else if they are deployed in Docker, update as follows:
      • Update value for relayEndpoint for network1 as relay-network1:9080.
      • Update value for relayEndpoint for network2 as relay-network2:9083.
      • Update value for relayEndpoint for Corda_Network as relay-corda:9081.
      • Update value for relayEndpoint for Corda_Network2 as relay-corda2:9082.
      • Update value for partyEndPoint for Corda_Network as corda_partya_1:10003.
      • Update value for partyEndPoint for Corda_Network2 as corda_network2_partya_1:10003.
    • Run the following:
      • If Relays and Drivers are deployed in the host machine:
        make initialise-vault-asset-transfer
      • If Relays and Drivers are deployed in the Docker containers:
        make initialise-vault-asset-transfer-docker
        Even upon successful execution (as indicated by the console output), you may see errors of the following form:
      [ERROR] 07:51:17.206 [epollEventLoopGroup-19-1] client.exceptionCaught - AMQ214015: Failed to execute connection life cycle listener
      java.util.concurrent.RejectedExecutionException: Task org.apache.activemq.artemis.utils.actors.ProcessorBase$$Lambda$34/681158875@666df796 rejected from java.util.concurrent.ThreadPoolExecutor@236f653f[Terminated, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 6]
      at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063) ~[?:1.8.0_402]
      ..........
      You can ignore these as they are transient errors that don't impact the operations.

    Next Steps

    The test networks are now configured and their ledgers are initialized. You can now run the asset transfer flows.

    + + \ No newline at end of file diff --git a/docs/external/getting-started/test-network/overview/index.html b/docs/external/getting-started/test-network/overview/index.html index cc0aefb33..f7d1191df 100644 --- a/docs/external/getting-started/test-network/overview/index.html +++ b/docs/external/getting-started/test-network/overview/index.html @@ -4,15 +4,15 @@ Component Overview | Weaver: DLT Interoperability Framework - - - + + +
    -

    Component Overview

    Weaver offers a basic test network launching capability, both to demonstrate interoperation modes and to serve as a testbed for development and prototyping. Different modes (or scenarios) require different sets of components, but collectively you will need to run the following:

    • Fabric testnet - A pair of basic Fabric networks for testing interop flows
    • Corda testnet - A pair of basic Corda networks for testing interop flows
    • Besu testnet - A pair of basic Besu networks for testing interop flows
    • Relay - The server module and protocol for cross-DLT interoperability. An instance of this is needed for every Fabric and Corda network
    • Fabric driver - Driver used by the Fabric networks relay to communicate with the Fabric testnet
    • Corda driver - Driver used by the Corda networks relay to communicate with the Corda testnet
    • Fabric Interop chaincode - The Fabric interoperability contracts handle the dual process of servicing requests for views from external networks, and verifying requested views for integrity
    • Corda interop app CorDapp used to handle interop duties between the relay and the application
    • Besu interop contract Solidity smart contract(s) used to handle interop duties for a Besu network
    • Fabric client - Fabric client used to trigger interop flows initiated from the Fabric side and to manage Fabric state
    • Corda client app - CorDapp and client used to trigger interop flows initiated from the Corda side and to manage Corda state
    • Besu sample application - A sample application for asset exchange across two besu networks using HTLC
    • Besu client app - Besu client used to interact with the contracts deployed on the Besu testnet

    You can launch these components in one of several different ways:

    • Setup with Locally Built Weaver Components:
      • Deployed on Host Machine: Build the above components purely from your local clone of the Weaver code repository. If you wish to experiment with source code modifications, this is the right option to choose.
      • Deployed in Docker containers: This is similar to the above option, except with relays and drivers launched in Docker containers rather than in the host.
    • Setup with Imported Weaver Components:
      • Deployed on Host Machine: Import pre-built Weaver components from Github Packages instead of building them locally. If you wish to see how Weaver works using pre-tested components and without, choose this option.
      • Deployed in Docker containers: This is similar to the above option, except with relays and drivers launched in Docker containers rather than in the host.

    After setting up and launching the components, you must initialize the network by following steps in Ledger Initialization. -Then you can test the following interoperation modes:

    - - +

    Component Overview

    Weaver offers a basic test network launching capability, both to demonstrate interoperation modes and to serve as a testbed for development and prototyping. Different modes (or scenarios) require different sets of components, but collectively you will need to run the following:

    • Fabric testnet - A pair of basic Fabric networks for testing interop flows
    • Corda testnet - A pair of basic Corda networks for testing interop flows
    • Besu testnet - A pair of basic Besu networks for testing interop flows
    • Relay - The server module and protocol for cross-DLT interoperability. An instance of this is needed for every Fabric and Corda network
    • Fabric driver - Driver used by the Fabric networks relay to communicate with the Fabric testnet
    • Corda driver - Driver used by the Corda networks relay to communicate with the Corda testnet
    • Fabric Interop chaincode - The Fabric interoperability contracts handle the dual process of servicing requests for views from external networks, and verifying requested views for integrity
    • Corda interop app CorDapp used to handle interop duties between the relay and the application
    • Besu interop contract Solidity smart contract(s) used to handle interop duties for a Besu network
    • Fabric client - Fabric client used to trigger interop flows initiated from the Fabric side and to manage Fabric state
    • Corda client app - CorDapp and client used to trigger interop flows initiated from the Corda side and to manage Corda state
    • Besu sample application - A sample application for asset exchange across two besu networks using HTLC
    • Besu client app - Besu client used to interact with the contracts deployed on the Besu testnet

    You can launch these components in one of several different ways:

    • Setup with Locally Built Weaver Components:
      • Deployed on Host Machine: Build the above components purely from your local clone of the Weaver code repository. If you wish to experiment with source code modifications, this is the right option to choose.
      • Deployed in Docker containers: This is similar to the above option, except with relays and drivers launched in Docker containers rather than in the host.
    • Setup with Imported Weaver Components:
      • Deployed on Host Machine: Import pre-built Weaver components from GitHub Packages instead of building them locally. If you wish to see how Weaver works using pre-tested components and without, choose this option.
      • Deployed in Docker containers: This is similar to the above option, except with relays and drivers launched in Docker containers rather than in the host.

    After setting up and launching the components, you must initialize the network by following steps in Ledger Initialization. +Then you can test the following interoperation modes:

    + + \ No newline at end of file diff --git a/docs/external/getting-started/test-network/setup-local-docker/index.html b/docs/external/getting-started/test-network/setup-local-docker/index.html index 3438a7079..46d287184 100644 --- a/docs/external/getting-started/test-network/setup-local-docker/index.html +++ b/docs/external/getting-started/test-network/setup-local-docker/index.html @@ -4,17 +4,17 @@ Setup with Locally Built Dockerized Weaver Components | Weaver: DLT Interoperability Framework - - - + + +
    -

    Setup with Locally Built Dockerized Weaver Components

    In this document, we detail the steps using which you can bring up networks using the default configuration settings and by fetching pre-built Weaver interoperation modules, SDK libraries, and relay docker image, drivers docker images from Github Package repositories. To customize these settings (e.g., hostnames, ports), refer to the Advanced Configuration page.

    Notes
    All components are run within Docker containers, except client applications.

    Follow the instructions below to build and run components followed by interoperation flows. These instructions have been tested on Ubuntu Linux (bash shell) and Mac OS. In general, they should work on any system and shell as long as the various dependencies have been installed and configured.

    Prerequisites

    Software

    Before starting, make sure you have the following software installed on your host machine:

    • Curl: install using package manager, like apt on Debian/Ubuntu Linux
    • Git: sample instructions
    • Docker: sample instructions (Latest version)
    • Docker-Compose: sample instructions (Version 1.28.2 or higher, but lower than version V2)
    • Golang: sample instructions (Version 1.16 or higher)
    • Java (JDK and JRE): sample instructions (Version 8)
    • Node.js and NPM: sample instructions (Version 16 Supported)
    • Yarn: sample instructions
    • Protoc (Protobuf compiler): Golang should already be installed and configured.
      • Default method: Run the following with sudo if necessary. This will install both the protobuf compiler and the Go code generator plugins.
        apt-get install protobuf-compiler
        go install google.golang.org/protobuf/cmd/protoc-gen-go
        go install google.golang.org/grpc/cmd/protoc-gen-go-grpc
      • If the above method installs an older version of protoc (check using protoc --version), say below 3.12.x, you should download pre-compiled binaries instead. (With an older version, you may see errors while attempting to launch and setup the Fabric networks).
        sudo apt-get remove protobuf-compiler
        curl -LO https://github.com/protocolbuffers/protobuf/releases/download/v3.15.6/protoc-3.15.6-linux-x86_64.zip
        sudo apt-get install unzip
        unzip protoc-3.15.6-linux-x86_64.zip -d <some-folder-path>
        export PATH="$PATH:<some-folder-path>/bin"
        go install google.golang.org/protobuf/cmd/protoc-gen-go
        go install google.golang.org/grpc/cmd/protoc-gen-go-grpc
        Notes
        The latest version at present is 3.15.6, but you should check the above link to find the most current version before running the above steps.

    Credentials

    Make sure you have an SSH or GPG key registered in https://github.com to allow seamless cloning of repositories (at present, various setup scripts clone repositories using the https:// prefix but this may change to git@ in the future).

    Getting the Code and Documentation

    Clone the weaver-dlt-interoperability repository. The code to get a basic test network up and running and test data-sharing interoperation flows lies in the subfolder tests/network-setups, which should be your starting point, though the setups will rely on other parts of the repository, as you will find out in the instructions given on this page.

    Common Structures

    The common/protos folder contains structure definitions in the protobuf format that are used by all the different components. The various common/protos-* folders are meant to contain compiled protobufs (in different languages).

    To compile the protobufs for JavaScript, do the following:

    • Navigate to the common/protos-js folder.
    • Run the following command:
      make build

    To compile the protobufs for Golang, do the following:

    • Navigate to the common/protos-go folder.
    • Run the following command:
      make build

    To compile the protobufs for Java, do the following:

    • Navigate to the common/protos-java-kt folder.
    • Run the following command:
      make build

    Securing Components

    Notes
    The relays and drivers corresponding to the different test networks you will encounter below can be run with or without TLS enabled. But the default files used in the demonstrations assume that either all relays and drivers are TLS-enabled or none are. Therefore, you should determine at the outset whether or not you wish to run the entire set of components in TLS-enabled mode, and select appropriate commands in the provided instructions.

    Hyperledger Fabric Components

    Using the sequence of instructions below, you can start two separate Fabric networks, each with a single channel and application contract (chaincode). You can also start an interoperation contract, a relay and a driver acting on behalf of each network. You can build a Fabric CLI tool with which you can initialize both networks' ledgers with access control policies, foreign networks' security groups (i.e., membership providers' certificate chains), and some sample key-value pairs that can be shared during subsequent interoperation flows.

    Fabric Interoperation Node SDK

    A client-layer library (companion to hyperledger/fabric-sdk-node) is defined in the sdks/fabric/interoperation-node-sdk folder. This contains functions for Fabric Gateway-based applications to exercise interoperation capabilities via relays and also several utility/helper functions. The Fabric-CLI tool, which we will use later, depends on this library.

    To build the library, do the following:

    • Navigate to the sdks/fabric/interoperation-node-sdk folder.
    • Run the following command:
      make build-local

    Fabric Network

    The code for this lies in the tests/network-setups folder.

    This folder contains code to create and launch networks network1 and network2 of identical specifications:

    • Network: 1 peer, 1 peer CA, 1 ordering service node, 1 ordering service CA
    • Single channel named mychannel
    • One of the following contracts deployed on mychannel, the choice depending on the interoperability mode you wish to test:
      • simplestate (Data Sharing): supports simple transactions (Create, Read, Update, Delete) involving storage and lookup of <key, value> pairs.
      • simplestatewithacl (Data Sharing): identical to simplestate but with extra security features to ensure that the Weaver infrastructure cannot be bypassed by a malicious client of the network.
      • simpleasset (Asset Exchange): supports creation, modification, transfer, and deletion, as well as locking, unlocking, and claiming, of simple bonds and tokens (examples of non-fungible and fungible assets respectively).
      • simpleassetandinterop (Asset Exchange): identical to simpleasset but where the locking, unlocking, and claiming logic is imported as a library in the chaincode rather than available in the common Fabric Interoperation Chaincode (a Weaver component).
      • simpleassettransfer (Asset Exchange or Asset Transfer): augmentation of simpleasset with asset pledging, claiming, and reclaiming features for cross-network transfers.
    Notes
    For new users, we recommend testing the Data Sharing feature first with the simplestate contract. To test the other modes, you can simply tear down the Fabric networks and restart them with the appropriate chaincodes installed.

    Follow the instructions below to build and launch the networks:

    • Navigate to the tests/network-setups/fabric/dev folder.
    • To spin up both network1 and network2 with the interoperation chaincode and the default simplestate chaincode installed, run:
      make start-interop-local
    • To launch the networks with a different application chaincode from the above list, run:
      make start-interop-local CHAINCODE_NAME=<chaincode-name>
    • To launch the networks with 2 organizations, each with a peer (this will enable more variation and experimentation, which you can attempt after testing interoperation protocols across basic network configurations), run:
      make start-interop-local PROFILE="2-nodes"
    Notes
    If you do not wish to test Fabric-Fabric interoperation, you can choose to launch only one of the two networks along with its interoperation chaincode. For network1, run make start-interop-network1-local, and for network2, run make start-interop-network2-local
    If you wish to enable end-to-end confidentiality by default in the interoperation modules that are deployed during network launch, set the environment variable E2E_CONFIDENTIALITY to true in the command line as follows: E2E_CONFIDENTIALITY=true make start-interop-local

    For more information, refer to the associated README.

    Troubleshooting Tips:

    • If you see any errors during the launches, re-check the prerequisites (software installations and credentials). Ensure your network connection is working. As a safe bet, you can retry after cleanup: kill and remove all Docker containers and associated volumes.
    • If protoc or protoc-gen-go throws an error, reinstall protoc and protoc-gen-go using suggestions made in the Prerequisites section above.

    Fabric Relay

    The relay is a module acting on behalf of a network, enabling interoperation flows with other networks by communicating with their relays. +

    Setup with Locally Built Dockerized Weaver Components

    In this document, we detail the steps using which you can bring up networks using the default configuration settings and by fetching pre-built Weaver interoperation modules, SDK libraries, and relay docker image, drivers docker images from GitHub Package repositories. To customize these settings (e.g., hostnames, ports), refer to the Advanced Configuration page.

    Notes
    All components are run within Docker containers, except client applications.

    Follow the instructions below to build and run components followed by interoperation flows. These instructions have been tested on Ubuntu Linux (bash shell) and Mac OS. In general, they should work on any system and shell as long as the various dependencies have been installed and configured.

    Prerequisites

    Software

    Before starting, make sure you have the following software installed on your host machine:

    • Curl: install using package manager, like apt on Debian/Ubuntu Linux

    • Git: sample instructions

    • Docker: sample instructions (Latest version)

    • Docker-Compose: sample instructions (Version 1.28.2 or higher, but lower than version V2)

    • Golang: sample instructions (Version 1.16 or higher)

    • Java (JDK and JRE): sample instructions (Version 8)

    • Node.js and NPM: sample instructions (Version 16 Supported)

    • Yarn: sample instructions

    • Protoc (Protobuf compiler): Golang should already be installed and configured.

      • Default method: Run the following with sudo if necessary. This will install both the protobuf compiler and the Go code generator plugins.

        apt-get install protobuf-compiler
        go install google.golang.org/protobuf/cmd/protoc-gen-go
        go install google.golang.org/grpc/cmd/protoc-gen-go-grpc
      • If the above method installs an older version of protoc (check using protoc --version), say below 3.12.x, you should download pre-compiled binaries instead. (With an older version, you may see errors while attempting to launch and setup the Fabric networks).

        sudo apt-get remove protobuf-compiler
        curl -LO https://github.com/protocolbuffers/protobuf/releases/download/v3.15.6/protoc-3.15.6-linux-x86_64.zip
        sudo apt-get install unzip
        unzip protoc-3.15.6-linux-x86_64.zip -d <some-folder-path>
        export PATH="$PATH:<some-folder-path>/bin"
        go install google.golang.org/protobuf/cmd/protoc-gen-go
        go install google.golang.org/grpc/cmd/protoc-gen-go-grpc
        Notes
        The latest version at present is 3.15.6, but you should check the above link to find the most current version before running the above steps.

    Credentials

    Make sure you have an SSH or GPG key registered in https://github.com to allow seamless cloning of repositories (at present, various setup scripts clone repositories using the https:// prefix but this may change to git@ in the future).

    Getting the Code and Documentation

    Clone the weaver-dlt-interoperability repository. The code to get a basic test network up and running and test data-sharing interoperation flows lies in the subfolder tests/network-setups, which should be your starting point, though the setups will rely on other parts of the repository, as you will find out in the instructions given on this page.

    Common Structures

    The common/protos folder contains structure definitions in the protobuf format that are used by all the different components. The various common/protos-* folders are meant to contain compiled protobufs (in different languages).

    To compile the protobufs for JavaScript, do the following:

    • Navigate to the common/protos-js folder.
    • Run the following command:
      make build

    To compile the protobufs for Golang, do the following:

    • Navigate to the common/protos-go folder.
    • Run the following command:
      make build

    To compile the protobufs for Java, do the following:

    • Navigate to the common/protos-java-kt folder.
    • Run the following command:
      make build

    To compile the protobufs for Solidity, do the following:

    • Navigate to the common/protos-sol folder.
    • Run the following command:
      make build

    To compile the protobufs for Rust, do the following:

    • Navigate to the common/protos-rs folder.
    • Run the following command:
      make build

    Securing Components

    Notes
    The relays and drivers corresponding to the different test networks you will encounter below can be run with or without TLS enabled. But the default files used in the demonstrations assume that either all relays and drivers are TLS-enabled or none are. Therefore, you should determine at the outset whether or not you wish to run the entire set of components in TLS-enabled mode, and select appropriate commands in the provided instructions.

    Hyperledger Fabric Components

    Using the sequence of instructions below, you can start two separate Fabric networks, each with a single channel and application contract (chaincode). You can also start an interoperation contract, a relay and a driver acting on behalf of each network. You can build a Fabric CLI tool with which you can initialize both networks' ledgers with access control policies, foreign networks' security groups (i.e., membership providers' certificate chains), and some sample key-value pairs that can be shared during subsequent interoperation flows.

    Fabric Interoperation Node SDK

    A client-layer library (companion to hyperledger/fabric-sdk-node) is defined in the sdks/fabric/interoperation-node-sdk folder. This contains functions for Fabric Gateway-based applications to exercise interoperation capabilities via relays and also several utility/helper functions. The Fabric-CLI tool, which we will use later, depends on this library.

    To build the library, do the following:

    • Navigate to the sdks/fabric/interoperation-node-sdk folder.
    • Run the following command:
      make build-local

    Fabric Network

    The code for this lies in the tests/network-setups folder.

    This folder contains code to create and launch networks network1 and network2 of identical specifications:

    • Network: 1 peer, 1 peer CA, 1 ordering service node, 1 ordering service CA
    • Single channel named mychannel
    • One of the following contracts deployed on mychannel, the choice depending on the interoperability mode you wish to test:
      • simplestate (Data Sharing): supports simple transactions (Create, Read, Update, Delete) involving storage and lookup of <key, value> pairs.
      • simplestatewithacl (Data Sharing): identical to simplestate but with extra security features to ensure that the Weaver infrastructure cannot be bypassed by a malicious client of the network.
      • simpleasset (Asset Exchange): supports creation, modification, transfer, and deletion, as well as locking, unlocking, and claiming, of simple bonds and tokens (examples of non-fungible and fungible assets respectively).
      • simpleassetandinterop (Asset Exchange): identical to simpleasset but where the locking, unlocking, and claiming logic is imported as a library in the chaincode rather than available in the common Fabric Interoperation Chaincode (a Weaver component).
      • simpleassettransfer (Asset Exchange or Asset Transfer): augmentation of simpleasset with asset pledging, claiming, and reclaiming features for cross-network transfers.
    Notes
    For new users, we recommend testing the Data Sharing feature first with the simplestate contract. To test the other modes, you can simply tear down the Fabric networks and restart them with the appropriate chaincodes installed.

    Follow the instructions below to build and launch the networks:

    • Navigate to the tests/network-setups/fabric/dev folder.
    • To spin up both network1 and network2 with the interoperation chaincode and the default simplestate chaincode installed, run:
      make start-interop-local
    • To launch the networks with a different application chaincode from the above list, run:
      make start-interop-local CHAINCODE_NAME=<chaincode-name>
    • To launch the networks with 2 organizations, each with a peer (this will enable more variation and experimentation, which you can attempt after testing interoperation protocols across basic network configurations), run:
      make start-interop-local PROFILE="2-nodes"
    Notes
    If you do not wish to test Fabric-Fabric interoperation, you can choose to launch only one of the two networks along with its interoperation chaincode. For network1, run make start-interop-network1-local, and for network2, run make start-interop-network2-local
    If you wish to enable end-to-end confidentiality by default in the interoperation modules that are deployed during network launch, set the environment variable E2E_CONFIDENTIALITY to true in the command line as follows: E2E_CONFIDENTIALITY=true make start-interop-local

    For more information, refer to the associated README.

    Troubleshooting Tips:

    • If you see any errors during the launches, re-check the prerequisites (software installations and credentials). Ensure your network connection is working. As a safe bet, you can retry after cleanup: kill and remove all Docker containers and associated volumes.
    • If protoc or protoc-gen-go throws an error, reinstall protoc and protoc-gen-go using suggestions made in the Prerequisites section above.

    Fabric Relay

    The relay is a module acting on behalf of a network, enabling interoperation flows with other networks by communicating with their relays. The code for this lies in the core/relay folder. Navigate to the core/relay folder.

    Building Relay Image

    To build the docker image for relay, run:

    make build-server-local

    Deployment

    • The docker-compose.yaml in this folder is minimally configured with default values. To modify it for use with the Fabric testnets, run:
      make convert-compose-method2
    • The .env.n1 and .env.n1.tls files in the docker/testnet-envs directory contain environment variables used by the network1 relay at startup and runtime. Edit either of these files (depending on whether you wish to start the relay with or without TLS), and update the following value:
      DOCKER_IMAGE_NAME=weaver-relay-server
    • Repeat the above step for .env.n2 or .env.n2.tls in docker/testnet-envs directory, which contain environment variables for the network2 relay.
    • To deploy the relay server for network1 without TLS, run:
      make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.n1'
      Instead, to deploy the relay server with TLS, run:
      make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.n1.tls'
    • To deploy the relay server for network2 without TLS, run:
      make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.n2'
      Instead, to deploy the relay server with TLS, run:
      make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.n2.tls'
    • After launching the relay(s), you can revert the docker-compose.yaml changes by running:
      make convert-compose-method1

    For more information, see the relay-docker README.

    Fabric Driver

    A driver is a DLT-specific plugin invoked by the relay while channelling external data queries to the local peer network and collecting a response with proofs. The Fabric driver is built as a Fabric client application on the fabric-network NPM package. -The code for this lies in the core/drivers/fabric-driver folder. Navigate to the core/drivers/fabric-driver folder.

    Building

    To build the fabric-driver image, run:

    make build-image-local

    Deployment

    Use the following steps to run Fabric drivers in Docker containers:

    • The .env.n1 and .env.n1.tls files in the docker-testnet-envs directory contain environment variables used by the network1 driver at startup and runtime. Edit either of these files (depending on whether you wish to start the relay with or without TLS) as follows:
      • Replace <PATH-TO-WEAVER> with the absolute path of the weaver-dlt-interoperability clone folder.
      • Update the following value:
        DOCKER_IMAGE_NAME=weaver-fabric-driver
    • Repeat the above steps for .env.n2 or .env.n2.tls in docker-testnet-envs directory, which contain environment variables for the network2 driver.
    • To deploy the Fabric driver for network1 without TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.n1' NETWORK_NAME=$(grep NETWORK_NAME docker-testnet-envs/.env.n1 | cut -d '=' -f 2)
      Instead, to deploy the driver with TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.n1.tls' NETWORK_NAME=$(grep NETWORK_NAME docker-testnet-envs/.env.n1.tls | cut -d '=' -f 2)
    • To deploy the Fabric driver for network2 without TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.n2' NETWORK_NAME=$(grep NETWORK_NAME docker-testnet-envs/.env.n2 | cut -d '=' -f 2)
      Instead, to deploy the driver with TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.n2.tls' NETWORK_NAME=$(grep NETWORK_NAME docker-testnet-envs/.env.n2.tls | cut -d '=' -f 2)

    Fabric IIN Agent

    IIN Agent is a client of a member of a DLT network or security domain with special permissions to update security domain identities and configurations on the ledger via the network's interoperation module. The code for this lies in the core/identity-management/iin-agent folder. Navigate to the core/identity-management/iin-agent folder.

    Building

    To build the IIN Agent image, run:

    make build-image-local

    Deployment

    Use the following steps to run Fabric IIN Agents in Docker containers:

    • The .env.n1.org1 and .env.n1.org1.tls files in the docker-testnet/envs directory contain environment variables used by the iin-agent of org1 of network1 at startup and runtime. Edit either of these files (depending on whether you wish to start the relay with or without TLS) as follows:
      • Replace <PATH-TO-WEAVER> with the absolute path of the weaver-dlt-interoperability clone folder.
      • Update the following value:
        DOCKER_IMAGE_NAME=weaver-iin-agent
      • If Fabric network was started with 1 org, and IIN Agents are to be started with TLS enabled, update the DNS_CONFIG_PATH variable as:
        DNS_CONFIG_PATH=./docker-testnet/configs/dnsconfig-tls.json
      • If Fabric network was started with 2 orgs, and IIN Agents are to be started without TLS, update the DNS_CONFIG_PATH variable as
        DNS_CONFIG_PATH=./docker-testnet/configs/dnsconfig-2-nodes.json
      • If Fabric network was started with 2 orgs and IIN Agents are to be started with TLS enabled, update the DNS_CONFIG_PATH variable as:
        DNS_CONFIG_PATH=./docker-testnet/configs/dnsconfig-tls-2-nodes.json
    • Repeat the above steps for all other environment variable files (depending upon whether tls is enabled) in docker-testnet/envs directory.
    • To deploy the Fabric IIN Agent for org1 of network1 without TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n1.org1' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n1.org1 | cut -d '=' -f 2)
      Instead, to deploy the IIN Agent with TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n1.org1.tls' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n1.org1.tls | cut -d '=' -f 2)
    • To deploy the Fabric IIN Agent for org2 of network1 without TLS (only required if Fabric network was started with 2 orgs), run:
      make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n1.org2' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n1.org2 | cut -d '=' -f 2)
      Instead, to deploy the IIN Agent with TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n1.org2.tls' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n1.org2.tls | cut -d '=' -f 2)
    • To deploy the Fabric IIN Agent for org1 of network2 without TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n2.org1' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n2.org1 | cut -d '=' -f 2)
      Instead, to deploy the IIN Agent with TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n2.org1.tls' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n2.org1.tls | cut -d '=' -f 2)
    • To deploy the Fabric IIN Agent for org2 of network2 without TLS (only required if Fabric network was started with 2 orgs), run:
      make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n2.org2' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n2.org2 | cut -d '=' -f 2)
      Instead, to deploy the IIN Agent with TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n2.org2.tls' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n2.org2.tls | cut -d '=' -f 2)

    Fabric Client (Application)

    The CLI is used to interact with a Fabric network, configure it and run chaincode transactions to record data on the channel ledger or query data. It is also used to interact with remote networks through the relay in order to trigger an interoperation flow for data request and acceptance.

    The fabric-cli Node.js source code is located in the samples/fabric/fabric-cli folder and the Golang source code in the samples/fabric/go-cli folder.

    Prerequisites

    If you are using a Linux system, make sure that lib64 is installed.

    Notes
    For the Node.js version of the fabric-cli, the setup and running instructions below were tested with all Node.js versions from v11.14.0 to v14.17.3.

    Installation

    You can install fabric-cli as follows (for both the Node.js and Golang versions):

    • Navigate to the samples/fabric/fabric-cli folder or the samples/fabric/go-cli folder.
    • Run the following to install dependencies (for the Node.js version) or the executable (for the Golang version):
      make build-local
    • Use the fabric-cli executable in the bin folder for subsequent actions.

    Corda Components

    Using the sequence of instructions below, you can start a Corda network and run an application CorDapp on it. You can also run an interoperation CorDapp, a relay and a driver acting on behalf of the network. You can initialize the network's vault with access control policies, foreign networks' security groups (i.e., membership providers' certificate chains), and some sample state values that can be shared during subsequent interoperation flows.

    Interoperation CorDapp

    The interoperation CorDapp is deployed to run as part of any Corda application flow that involves cross-network interoperation.

    Build the interoperation CorDapp as follows:

    • Navigate to the core/network/corda-interop-app folder.
    • Run the following to create the JAR files on which other Corda network components will depend on:
      make build-local

    Corda Interoperation SDK

    A client-layer library is defined in the sdks/corda folder. This contains functions for Corda based client applications to exercise interoperation capabilities via relays and also several utility/helper functions. The Corda Client tool, which we will use later, depends on this library.

    To build the library, do the following:

    • Navigate to the sdks/corda folder.
    • Run the following command (make sure there is no github.properties file present in the directory):
      make build

    Corda Simple Application and Client (Application)

    This is a simple CorDapp that maintains a state of type SimpleState, which is a set of key-value pairs (of strings). -The code for this lies in the samples/corda/corda-simple-application folder.

    Build the corda-simple-application CorDapp as follows:

    • Navigate to the samples/corda/corda-simple-application folder.
    • Run the following:
      make build-local

    Corda Network

    The Corda networks' code lies in the tests/network-setups/corda folder. You can launch two separate Corda networks, namely Corda_Network and Corda_Network2. Each network runs the samples/corda/corda-simple-application CorDapp by default, which maintains a state named SimpleState containing a set of key-value pairs (of strings).

    Follow the instructions below to build and launch both networks:

    • Navigate to the tests/network-setups/corda folder.
    • To spin up the Corda networks with the Interoperation CorDapps:
      • Each consisting of 1 node and a notary (for data-transfer), run:
        make start-local
      • Each consisting of 2 nodes and a notary (for asset-exchange/transfer), run:
        make start-local PROFILE="2-nodes"
      • Each consisting of 3 nodes and a notary (for asset-exchange/transfer), run:
        make start-local PROFILE="3-nodes"
    Notes
    If you do not wish to test Corda-Corda interoperation, you can choose to launch only one of the two networks along with its interoperation CorDapp. For Corda_Network, run make start-network1-local, and for Corda_Network2, run make start-network2-local.

    You should see the following message in the terminal:

    Waiting for network node services to start

    The Corda nodes and notary may take a while (several minutes on memory-constrained systems) to start. If they start up successfully, you should something like the following for each network, though the number of node entries will depend on the profile you used to start the network with (replace <network-name> with Corda_Network or Corda_Network2):

    PartyA node services started for network <network-name>
    PartyB node services started for network <network-name>
    PartyC node services started for network <network-name>
    Notary node services started for network <network-name>

    Corda Relay

    Navigate to the core/relay folder. Refer here to build the relay image if not already built. Now run a relay for Corda_Network and/or Corda_Network2 in Docker container as follows:

    • The docker-compose.yaml in this folder is minimally configured with default values. To modify it for use with the Fabric testnets, run:
      make convert-compose-method2
    • The .env.corda and .env.corda.tls files in the docker/testnet-envs directory contain environment variables used by the Corda_Network relay at startup and runtime. Edit either of these files (depending on whether you wish to start the relay with or without TLS), and update the following value:
      DOCKER_IMAGE_NAME=weaver-relay-server
    • Repeat the above step for .env.corda2 or .env.corda2.tls in docker/testnet-envs directory, which contain environment variables for the Corda_Network2 relay.
    • To deploy the relay server for Corda_Network without TLS, run:
      make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.corda'
      Instead, to deploy the relay server with TLS, run:
      make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.corda.tls'
    • To deploy the relay server for Corda_Network2 without TLS, run:
      make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.corda2'
      Instead, to deploy the relay server with TLS, run:
      make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.corda2.tls'
    • After launching the relay(s), you can revert the docker-compose.yaml changes by running:
      make convert-compose-method1

    Corda Driver

    Navigate to the core/drivers/corda-driver folder.

    Building

    To build the corda driver docker image, run:

    make image-local

    Deployment

    Use the following steps to run Corda drivers in Docker containers:

    • The .env.corda and .env.corda.tls files in the docker-testnet-envs directory contain environment variables used by the Corda_Network driver at startup and runtime. Edit either of these files (depending on whether you wish to start the relay with or without TLS) to update the following value:
      DOCKER_IMAGE_NAME=weaver-corda-driver
    • Repeat the above steps for .env.corda2 or .env.corda2.tls in docker-testnet-envs directory, which contain environment variables for the Corda_Network2 driver.
    • To deploy the Corda driver for Corda_Network without TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.corda'
      Instead, to deploy the driver with TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.corda.tls'
      If the driver starts successfully, it should log the following message when you run docker logs corda-driver-Corda_Network:
      Corda driver gRPC server started. Listening on port 9099
    • To deploy the Corda driver for Corda_Network2 without TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.corda2'
      Instead, to deploy the driver with TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.corda2.tls'
      If the driver starts successfully, it should log the following message when you run docker logs corda-driver-Corda_Network2:
      Corda driver gRPC server started. Listening on port 9098

    Tear Down the Setup

    Bring down the various components as follows (Navigate to the root folder of your clone of the Weaver repository):

    Relay

    To bring down the relays (for all 3 networks), run:

    cd core/relay
    make convert-compose-method2
    make stop COMPOSE_ARG='--env-file .env.n1'
    make stop COMPOSE_ARG='--env-file .env.n2'
    make stop COMPOSE_ARG='--env-file .env.corda'
    make stop COMPOSE_ARG='--env-file .env.corda2'
    make convert-compose-method1
    cd -

    Fabric Driver

    To bring down the fabric drivers (for both networks), run:

    cd core/drivers/fabric-driver
    make stop COMPOSE_ARG='--env-file .env.n1'
    make stop COMPOSE_ARG='--env-file .env.n2'
    cd -

    Corda Driver

    To bring down the corda driver, run:

    cd core/drivers/corda-driver
    make stop COMPOSE_ARG='--env-file docker-testnet-envs/.env.corda'
    make stop COMPOSE_ARG='--env-file docker-testnet-envs/.env.corda2'
    cd -

    Corda Network

    To bring down the Corda network:

    cd tests/network-setups/corda
    make clean
    cd -

    Fabric Network

    To bring down both of the Fabric networks along with weaver components:

    cd tests/network-setups/fabric/dev
    make clean
    cd -
    - - +The code for this lies in the core/drivers/fabric-driver folder. Navigate to the core/drivers/fabric-driver folder.

    Building

    To build the fabric-driver image, run:

    make build-image-local

    Deployment

    Use the following steps to run Fabric drivers in Docker containers:

    • The .env.n1 and .env.n1.tls files in the docker-testnet-envs directory contain environment variables used by the network1 driver at startup and runtime. Edit either of these files (depending on whether you wish to start the relay with or without TLS) as follows:
      • Replace <PATH-TO-WEAVER> with the absolute path of the weaver-dlt-interoperability clone folder.
      • Update the following value:
        DOCKER_IMAGE_NAME=weaver-fabric-driver
    • Repeat the above steps for .env.n2 or .env.n2.tls in docker-testnet-envs directory, which contain environment variables for the network2 driver.
    • To deploy the Fabric driver for network1 without TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.n1' NETWORK_NAME=$(grep NETWORK_NAME docker-testnet-envs/.env.n1 | cut -d '=' -f 2)
      Instead, to deploy the driver with TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.n1.tls' NETWORK_NAME=$(grep NETWORK_NAME docker-testnet-envs/.env.n1.tls | cut -d '=' -f 2)
    • To deploy the Fabric driver for network2 without TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.n2' NETWORK_NAME=$(grep NETWORK_NAME docker-testnet-envs/.env.n2 | cut -d '=' -f 2)
      Instead, to deploy the driver with TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.n2.tls' NETWORK_NAME=$(grep NETWORK_NAME docker-testnet-envs/.env.n2.tls | cut -d '=' -f 2)

    Fabric IIN Agent

    IIN Agent is a client of a member of a DLT network or security domain with special permissions to update security domain identities and configurations on the ledger via the network's interoperation module. The code for this lies in the core/identity-management/iin-agent folder. Navigate to the core/identity-management/iin-agent folder.

    Building

    To build the IIN Agent image, run:

    make build-image-local

    Deployment

    Use the following steps to run Fabric IIN Agents in Docker containers:

    • The .env.n1.org1 and .env.n1.org1.tls files in the docker-testnet/envs directory contain environment variables used by the iin-agent of org1 of network1 at startup and runtime. Edit either of these files (depending on whether you wish to start the relay with or without TLS) as follows:
      • Replace <PATH-TO-WEAVER> with the absolute path of the weaver-dlt-interoperability clone folder.
      • Update the following value:
        DOCKER_IMAGE_NAME=weaver-iin-agent
      • If Fabric network was started with 1 org, and IIN Agents are to be started with TLS enabled, update the DNS_CONFIG_PATH variable as:
        DNS_CONFIG_PATH=./docker-testnet/configs/dnsconfig-tls.json
      • If Fabric network was started with 2 orgs, and IIN Agents are to be started without TLS, update the DNS_CONFIG_PATH variable as
        DNS_CONFIG_PATH=./docker-testnet/configs/dnsconfig-2-nodes.json
      • If Fabric network was started with 2 orgs and IIN Agents are to be started with TLS enabled, update the DNS_CONFIG_PATH variable as:
        DNS_CONFIG_PATH=./docker-testnet/configs/dnsconfig-tls-2-nodes.json
    • Repeat the above steps for all other environment variable files (depending upon whether tls is enabled) in docker-testnet/envs directory.
    • To deploy the Fabric IIN Agent for org1 of network1 without TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n1.org1' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n1.org1 | cut -d '=' -f 2)
      Instead, to deploy the IIN Agent with TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n1.org1.tls' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n1.org1.tls | cut -d '=' -f 2)
    • To deploy the Fabric IIN Agent for org2 of network1 without TLS (only required if Fabric network was started with 2 orgs), run:
      make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n1.org2' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n1.org2 | cut -d '=' -f 2)
      Instead, to deploy the IIN Agent with TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n1.org2.tls' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n1.org2.tls | cut -d '=' -f 2)
    • To deploy the Fabric IIN Agent for org1 of network2 without TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n2.org1' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n2.org1 | cut -d '=' -f 2)
      Instead, to deploy the IIN Agent with TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n2.org1.tls' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n2.org1.tls | cut -d '=' -f 2)
    • To deploy the Fabric IIN Agent for org2 of network2 without TLS (only required if Fabric network was started with 2 orgs), run:
      make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n2.org2' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n2.org2 | cut -d '=' -f 2)
      Instead, to deploy the IIN Agent with TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n2.org2.tls' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n2.org2.tls | cut -d '=' -f 2)

    Fabric Client (Application)

    The CLI is used to interact with a Fabric network, configure it and run chaincode transactions to record data on the channel ledger or query data. It is also used to interact with remote networks through the relay in order to trigger an interoperation flow for data request and acceptance.

    The fabric-cli Node.js source code is located in the samples/fabric/fabric-cli folder and the Golang source code in the samples/fabric/go-cli folder.

    Prerequisites

    If you are using a Linux system, make sure that lib64 is installed.

    Notes
    For the Node.js version of the fabric-cli, the setup and running instructions below were tested with all Node.js versions from v11.14.0 to v14.17.3.

    Installation

    You can install fabric-cli as follows (for both the Node.js and Golang versions):

    • Navigate to the samples/fabric/fabric-cli folder (for the Node.js version) or the samples/fabric/go-cli folder (for the Golang version).
    • Run the following to install dependencies (for the Node.js version) or the executable (for the Golang version):
      make build-local
    • Use the fabric-cli executable in the bin folder for subsequent actions.

    Corda Components

    Using the sequence of instructions below, you can start a Corda network and run an application CorDapp on it. You can also run an interoperation CorDapp, a relay and a driver acting on behalf of the network. You can initialize the network's vault with access control policies, foreign networks' security groups (i.e., membership providers' certificate chains), and some sample state values that can be shared during subsequent interoperation flows.

    Interoperation CorDapp

    The interoperation CorDapp is deployed to run as part of any Corda application flow that involves cross-network interoperation.

    Build the interoperation CorDapp as follows:

    • Navigate to the core/network/corda-interop-app folder.
    • Run the following to create the JAR files on which other Corda network components will depend on:
      make build-local

    Corda Interoperation SDK

    A client-layer library is defined in the sdks/corda folder. This contains functions for Corda based client applications to exercise interoperation capabilities via relays and also several utility/helper functions. The Corda Client tool, which we will use later, depends on this library.

    To build the library, do the following:

    • Navigate to the sdks/corda folder.
    • Run the following command (make sure there is no github.properties file present in the directory):
      make build

    Corda Simple Application and Client (Application)

    This is a simple CorDapp that maintains a state of type SimpleState, which is a set of key-value pairs (of strings). +The code for this lies in the samples/corda/corda-simple-application folder.

    Build the corda-simple-application CorDapp as follows:

    • Navigate to the samples/corda/corda-simple-application folder.
    • Run the following:
      make build-local

    Corda Network

    The Corda networks' code lies in the tests/network-setups/corda folder. You can launch two separate Corda networks, namely Corda_Network and Corda_Network2. Each network runs the samples/corda/corda-simple-application CorDapp by default, which maintains a state named SimpleState containing a set of key-value pairs (of strings).

    Follow the instructions below to build and launch both networks:

    • Navigate to the tests/network-setups/corda folder.
    • To spin up the Corda networks with the Interoperation CorDapps:
      • Each consisting of 1 node and a notary (for data-transfer), run:
        make start-local
      • Each consisting of 2 nodes and a notary (for asset-exchange/transfer), run:
        make start-local PROFILE="2-nodes"
      • Each consisting of 3 nodes and a notary (for asset-exchange/transfer), run:
        make start-local PROFILE="3-nodes"
    Notes
    If you do not wish to test Corda-Corda interoperation, you can choose to launch only one of the two networks along with its interoperation CorDapp. For Corda_Network, run make start-network1-local, and for Corda_Network2, run make start-network2-local.

    You should see the following message in the terminal:

    Waiting for network node services to start

    The Corda nodes and notary may take a while (several minutes on memory-constrained systems) to start. If they start up successfully, you should something like the following for each network, though the number of node entries will depend on the profile you used to start the network with (replace <network-name> with Corda_Network or Corda_Network2):

    PartyA node services started for network <network-name>
    PartyB node services started for network <network-name>
    PartyC node services started for network <network-name>
    Notary node services started for network <network-name>

    Corda Relay

    Navigate to the core/relay folder. Refer here to build the relay image if not already built. Now run a relay for Corda_Network and/or Corda_Network2 in Docker container as follows:

    • The docker-compose.yaml in this folder is minimally configured with default values. To modify it for use with the Fabric testnets, run:
      make convert-compose-method2
    • The .env.corda and .env.corda.tls files in the docker/testnet-envs directory contain environment variables used by the Corda_Network relay at startup and runtime. Edit either of these files (depending on whether you wish to start the relay with or without TLS), and update the following value:
      DOCKER_IMAGE_NAME=weaver-relay-server
    • Repeat the above step for .env.corda2 or .env.corda2.tls in docker/testnet-envs directory, which contain environment variables for the Corda_Network2 relay.
    • To deploy the relay server for Corda_Network without TLS, run:
      make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.corda'
      Instead, to deploy the relay server with TLS, run:
      make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.corda.tls'
    • To deploy the relay server for Corda_Network2 without TLS, run:
      make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.corda2'
      Instead, to deploy the relay server with TLS, run:
      make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.corda2.tls'
    • After launching the relay(s), you can revert the docker-compose.yaml changes by running:
      make convert-compose-method1

    Corda Driver

    Navigate to the core/drivers/corda-driver folder.

    Building

    To build the corda driver docker image, run:

    make image-local

    Deployment

    Use the following steps to run Corda drivers in Docker containers:

    • The .env.corda and .env.corda.tls files in the docker-testnet-envs directory contain environment variables used by the Corda_Network driver at startup and runtime. Edit either of these files (depending on whether you wish to start the relay with or without TLS) to update the following value:
      DOCKER_IMAGE_NAME=weaver-corda-driver
    • Repeat the above steps for .env.corda2 or .env.corda2.tls in docker-testnet-envs directory, which contain environment variables for the Corda_Network2 driver.
    • To deploy the Corda driver for Corda_Network without TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.corda'
      Instead, to deploy the driver with TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.corda.tls'
      If the driver starts successfully, it should log the following message when you run docker logs corda-driver-Corda_Network:
      Corda driver gRPC server started. Listening on port 9099
    • To deploy the Corda driver for Corda_Network2 without TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.corda2'
      Instead, to deploy the driver with TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.corda2.tls'
      If the driver starts successfully, it should log the following message when you run docker logs corda-driver-Corda_Network2:
      Corda driver gRPC server started. Listening on port 9098

    Tear Down the Setup

    Bring down the various components as follows (Navigate to the root folder of your clone of the Weaver repository):

    Relay

    To bring down the relays (for all 3 networks), run:

    cd core/relay
    make convert-compose-method2
    make stop COMPOSE_ARG='--env-file .env.n1'
    make stop COMPOSE_ARG='--env-file .env.n2'
    make stop COMPOSE_ARG='--env-file .env.corda'
    make stop COMPOSE_ARG='--env-file .env.corda2'
    make convert-compose-method1
    cd -

    Fabric Driver

    To bring down the fabric drivers (for both networks), run:

    cd core/drivers/fabric-driver
    make stop COMPOSE_ARG='--env-file .env.n1'
    make stop COMPOSE_ARG='--env-file .env.n2'
    cd -

    Corda Driver

    To bring down the corda driver, run:

    cd core/drivers/corda-driver
    make stop COMPOSE_ARG='--env-file docker-testnet-envs/.env.corda'
    make stop COMPOSE_ARG='--env-file docker-testnet-envs/.env.corda2'
    cd -

    Corda Network

    To bring down the Corda network:

    cd tests/network-setups/corda
    make clean
    cd -

    Fabric Network

    To bring down both of the Fabric networks along with weaver components:

    cd tests/network-setups/fabric/dev
    make clean
    cd -
    + + \ No newline at end of file diff --git a/docs/external/getting-started/test-network/setup-local/index.html b/docs/external/getting-started/test-network/setup-local/index.html index 287b4bc82..fa02aad46 100644 --- a/docs/external/getting-started/test-network/setup-local/index.html +++ b/docs/external/getting-started/test-network/setup-local/index.html @@ -4,18 +4,18 @@ Setup with Locally Built Weaver Components | Weaver: DLT Interoperability Framework - - - + + +
    -

    Setup with Locally Built Weaver Components

    In this document, we detail the steps using which you can bring up networks using the default configuration settings and by building Weaver interoperation modules, SDK libraries, and relay drivers locally from your Weaver clone. To customize these settings (e.g., hostnames, ports), refer to the Advanced Configuration page.

    Notes
    The default configuration is for a development setup, therefore all components are run on localhost, many within Docker containers.

    Follow the instructions below to build and run components followed by interoperation flows. These instructions have been tested on Ubuntu Linux (bash shell) and Mac OS. In general, they should work on any system and shell as long as the various dependenices have been installed and configured.

    Prerequisites

    Software

    Before starting, make sure you have the following software installed on your host machine:

    • Curl: install using package manager, like apt on Debian/Ubuntu Linux
    • Git: sample instructions
    • Docker: sample instructions (Latest version)
    • Docker-Compose: sample instructions (Version 1.28.2 or higher, but lower than version V2)
    • Golang: sample instructions (Version 1.16 or higher)
    • Java (JDK and JRE): sample instructions (Version 8)
    • Node.js and NPM: sample instructions (Version 16 Supported)
    • Yarn: sample instructions
    • Rust: sample instructions
    • Protoc (Protobuf compiler): Golang should already be installed and configured.
      • Default method: Run the following with sudo if necessary. This will install both the protobuf compiler and the Go code generator plugins.
        apt-get install protobuf-compiler
        go install google.golang.org/protobuf/cmd/protoc-gen-go
        go install google.golang.org/grpc/cmd/protoc-gen-go-grpc
      • If the above method installs an older version of protoc (check using protoc --version), say below 3.12.x, you should download pre-compiled binaries instead. (With an older version, you may see errors while attempting to launch and setup the Fabric networks).
        sudo apt-get remove protobuf-compiler
        curl -LO https://github.com/protocolbuffers/protobuf/releases/download/v3.15.6/protoc-3.15.6-linux-x86_64.zip
        sudo apt-get install unzip
        unzip protoc-3.15.6-linux-x86_64.zip -d <some-folder-path>
        export PATH="$PATH:<some-folder-path>/bin"
        go install google.golang.org/protobuf/cmd/protoc-gen-go
        go install google.golang.org/grpc/cmd/protoc-gen-go-grpc
        Notes
        The latest version at present is 3.15.6, but you should check the above link to find the most current version before running the above steps.

    Credentials

    Make sure you have an SSH or GPG key registered in https://github.com to allow seamless cloning of repositories (at present, various setup scripts clone repositories using the https:// prefix but this may change to git@ in the future).

    Getting the Code and Documentation

    Clone the weaver-dlt-interoperability repository. The code to get a basic test network up and running and test data-sharing interoperation flows lies in the subfolder tests/network-setups, which should be your starting point, though the setups will rely on other parts of the repository, as you will find out in the instructions given on this page.

    Common Structures

    The common/protos folder contains structure definitions in the protobuf format that are used by all the different components. The various common/protos-* folders are meant to contain compiled protobufs (in different languages).

    To compile the protobufs for JavaScript, do the following:

    • Navigate to the common/protos-js folder.
    • Run the following command:
      make build

    To compile the protobufs for Golang, do the following:

    • Navigate to the common/protos-go folder.
    • Run the following command:
      make build

    To compile the protobufs for Java, do the following:

    • Navigate to the common/protos-java-kt folder.
    • Run the following command:
      make build

    To compile the protobufs for Solidity, do the following:

    • Navigate to the common/protos-sol folder.
    • Run the following command:
      make build

    Securing Components

    Notes
    The relays and drivers corresponding to the different test networks you will encounter below can be run with or without TLS enabled. But the default files used in the demonstrations assume that either all relays and drivers are TLS-enabled or none are. Therefore, you should determine at the outset whether or not you wish to run the entire set of components in TLS-enabled mode, and select appropriate commands in the provided instructions.

    Hyperledger Fabric Components

    Using the sequence of instructions below, you can start two separate Fabric networks, each with a single channel and application contract (chaincode). You can also start an interoperation contract, a relay, and a driver acting on behalf of each network. You can build a Fabric CLI tool with which you can initialize both networks' ledgers with access control policies, foreign networks' security groups (i.e., membership providers' certificate chains), and some sample key-value pairs that can be shared during subsequent interoperation flows.

    Fabric Interoperation Node SDK

    A client-layer library (companion to hyperledger/fabric-sdk-node) is defined in the sdks/fabric/interoperation-node-sdk folder. This contains functions for Fabric Gateway-based applications to exercise interoperation capabilities via relays and also several utility/helper functions. The Fabric-CLI tool, which we will use later, depends on this library.

    To build the library, do the following:

    • Navigate to the sdks/fabric/interoperation-node-sdk folder.
    • Run the following command:
      make build-local

    Fabric Network

    The code for this lies in the tests/network-setups folder.

    This folder contains code to create and launch networks network1 and network2 of identical specifications:

    • Network: 1 peer, 1 peer CA, 1 ordering service node, 1 ordering service CA
    • Single channel named mychannel
    • One of the following contracts deployed on mychannel, the choice depending on the interoperability mode you wish to test:
      • simplestate (Data Sharing): supports simple transactions (Create, Read, Update, Delete) involving storage and lookup of <key, value> pairs.
      • simplestatewithacl (Data Sharing): identical to simplestate but with extra security features to ensure that the Weaver infrastructure cannot be bypassed by a malicious client of the network.
      • simpleasset (Asset Exchange): supports creation, modification, transfer, and deletion, as well as locking, unlocking, and claiming, of simple bonds and tokens (examples of non-fungible and fungible assets respectively).
      • simpleassetandinterop (Asset Exchange): identical to simpleasset but where the locking, unlocking, and claiming logic is imported as a library in the chaincode rather than available in the common Fabric Interoperation Chaincode (a Weaver component).
      • simpleassettransfer (Asset Exchange or Asset Transfer): augmentation of simpleasset with asset pledging, claiming, and reclaiming features for cross-network transfers.
    Notes
    For new users, we recommend testing the Data Sharing feature first with the simplestate contract. To test the other modes, you can simply tear down the Fabric networks and restart them with the appropriate chaincodes installed.

    Follow the instructions below to build and launch the networks:

    • Navigate to the tests/network-setups/fabric/dev folder.
    • To spin up both network1 and network2 with the interoperation chaincode and the default simplestate chaincode installed, run:
      make start-interop-local
    • To launch the networks with a different application chaincode from the above list, run:
      make start-interop-local CHAINCODE_NAME=<chaincode-name>
    • To launch the networks with 2 organizations, each with a peer (this will enable more variation and experimentation, which you can attempt after testing interoperation protocols across basic network configurations), run:
      make start-interop-local PROFILE="2-nodes"
    Notes
    If you do not wish to test Fabric-Fabric interoperation, you can choose to launch only one of the two networks along with its interoperation chaincode. For network1, run make start-interop-network1-local, and for network2, run make start-interop-network2-local
    If you wish to enable end-to-end confidentiality by default in the interoperation modules that are deployed during network launch, set the environment variable E2E_CONFIDENTIALITY to true in the command line as follows: E2E_CONFIDENTIALITY=true make start-interop-local

    For more information, refer to the associated README.

    Troubleshooting Tips:

    • If you see any errors during the launches, re-check the prerequisites (software installations and credentials). Ensure your network connection is working. As a safe bet, you can retry after cleanup: kill and remove all Docker containers and associated volumes.
    • If protoc or protoc-gen-go throws an error, reinstall protoc and protoc-gen-go using suggestions made in the Prerequisites section above.

    Fabric Client (fabric-cli)

    The CLI is used to interact with a Fabric network, configure it and run chaincode transactions to record data on the channel ledger or query data. It is also used to interact with remote networks through the relay to trigger an interoperation flow for data request and acceptance.

    The fabric-cli Node.js source code is located in the samples/fabric/fabric-cli folder and the Golang source code in the samples/fabric/go-cli folder.

    Prerequisites

    If you are using a Linux system, make sure that lib64 is installed.

    Notes
    For the Node.js version of the fabric-cli, the setup and running instructions below were tested with all Node.js versions from v11.14.0 to v14.17.3.

    Installation

    You can install fabric-cli as follows (for both the Node.js and Golang versions):

    • Navigate to the samples/fabric/fabric-cli folder or the samples/fabric/go-cli folder.
    • Run the following to install dependencies (for the Node.js version) or the executable (for the Golang version):
      make build-local
    • Use the fabric-cli executable in the bin folder for subsequent actions.

    Fabric Relay

    The relay is a module acting on behalf of a network, enabling interoperation flows with other networks by communicating with their relays. -The code for this lies in the core/relay folder.

    Building

    Prerequisite: make sure Rust is already installed and that the cargo executable is in your system path (after installation of Rust, this should be available in $HOME/.cargo/bin); you can also ensure this by running source "$HOME/.cargo/env".

    Build the generic (i.e., common to all DLTs) relay module as follows:

    • Navigate to the core/relay folder.
    • Run the following:
      make
    • To avoid errors during Weaver Relay compilation, update certain packages (on which the Weaver Relay is dependent) to their latest versions as follows:
      make update-pkgs

    Deployment

    An instance or a relay can be run using a suitable configuration file. Samples are available in the core/relay/config folder.

    Run a relay for network1 as follows:

    • Navigate to the core/relay folder.
    • To launch the server without TLS, leave the configuration file config/Fabric_Relay.toml in its default state. Otherwise, edit it to set TLS flags for this relay and the other relays and drivers it will connect to in this demonstration as follows:
      .
      .
      cert_path="credentials/fabric_cert.pem"
      key_path="credentials/fabric_key"
      tls=true
      .
      .
      [relays]
      [relays.Corda_Relay]
      hostname="localhost"
      port="9081"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      [relays.Corda_Relay2]
      hostname="localhost"
      port="9082"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      [relays.Fabric_Relay2]
      hostname="localhost"
      port="9083"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      .
      .
      [drivers]
      [drivers.Fabric]
      hostname="localhost"
      port="9090"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      .
      .
    • To launch the server, simply run the following:
      RELAY_CONFIG=config/Fabric_Relay.toml cargo run --bin server

    Run a relay for network2 as follows (do this only if you have launched both Fabric networks network1 and network2 and wish to test interoperation between them)

    • Navigate to the core/relay folder.
    • To launch the server without TLS, leave the configuration file config/Fabric_Relay2.toml in its default state. Otherwise, edit it to set TLS flags for this relay and the other relays and drivers it will connect to in this demonstration as follows:
      .
      .
      cert_path="credentials/fabric_cert.pem"
      key_path="credentials/fabric_key"
      tls=true
      .
      .
      [relays]
      [relays.Corda_Relay]
      hostname="localhost"
      port="9081"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      [relays.Corda_Relay2]
      hostname="localhost"
      port="9082"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      [relays.Fabric_Relay]
      hostname="localhost"
      port="9080"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      .
      .
      [drivers]
      [drivers.Fabric]
      hostname="localhost"
      port="9095"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      .
      .
    • To launch the server, simply run the following:
      RELAY_CONFIG=config/Fabric_Relay2.toml cargo run --bin server

    For more information, see the relay README.

    Fabric Driver

    A driver is a DLT-specific plugin invoked by the relay while conveying external data queries to the local peer network and collecting a response with proofs. The Fabric driver is built as a Fabric client application on the fabric-network NPM package. -The code for this lies in the core/drivers/fabric-driver folder.

    Configuring

    In the core/drivers/fabric-driver folder, copy .env.template to .env and update CONNECTION_PROFILE to point to the connection profile of the Fabric network (e.g. <PATH-TO-WEAVER>/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json)

    Configure fabric-driver for network1 as follows:

    • Navigate to the core/drivers/fabric-driver folder.
    • Create a .env file by copying .env.template and setting suitable parameter values:
      • The CONNECTION_PROFILE should point to the absolute path of the connection profile for network1.
        • For this exercise, specify the path <PATH-TO-WEAVER>/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json (you must specify the full absolute path here).
        • <PATH-TO-WEAVER> here is the absolute path of the weaver-dlt-interoperability clone folder.
      • If you wish to start the driver without TLS, set the following parameter values:
        RELAY_TLS=false
        RELAY_TLSCA_CERT_PATH=
        DRIVER_TLS=false
        DRIVER_TLS_CERT_PATH=
        DRIVER_TLS_KEY_PATH=
        Otherwise, if you wish to start the driver with TLS enabled, set the following parameter values (replace <PATH-TO-WEAVER> with the absolute path of the weaver-dlt-interoperability clone folder):
        RELAY_TLS=true
        RELAY_TLSCA_CERT_PATH=<PATH-TO-WEAVER>/core/relay/credentials/fabric_ca_cert.pem
        DRIVER_TLS=true
        DRIVER_TLS_CERT_PATH=<PATH-TO-WEAVER>/core/relay/credentials/fabric_cert.pem
        DRIVER_TLS_KEY_PATH=<PATH-TO-WEAVER>/core/relay/credentials/fabric_key
      • Leave the default values unchanged for the other parameters. The relay and driver endpoints as well as the network name are already specified in the template.

    Building

    Build the Fabric driver module as follows:

    • Navigate to the core/drivers/fabric-driver folder.
    • Run the following:
      make build-local

    Running

    Run a Fabric driver for network1 as follows:

    • Navigate to the core/drivers/fabric-driver folder.
    • Run the following:
      npm run dev

    Run a Fabric driver for network2 as follows (do this only if you wish to test interoperation between the two Fabric networks network1 and network2)

    • Navigate to the core/drivers/fabric-driver folder.
    • Run the following:
      CONNECTION_PROFILE=<PATH-TO-WEAVER>/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/connection-org1.json NETWORK_NAME=network2 RELAY_ENDPOINT=localhost:9083 DRIVER_ENDPOINT=localhost:9095 npm run dev
    Notes
    The variables we specified earlier in the .env for network1 are now passed in the command line. Alternatively, you can make a copy of the fabric-driver folder with a different name and create a separate .env file within it that contains links to the connection profile, relay, and driver for network2.

    Fabric IIN Agent

    IIN Agent is a client of a member of a DLT network or security domain with special permissions to update security domain identities and configurations on the ledger via the network's interoperation module. The code for this lies in the core/identity-management/iin-agent folder. Navigate to the core/identity-management/iin-agent folder.

    Building

    To build the IIN Agent, run:

    make build-local

    Configuration

    Ledger config file specifies ledger specific IIN Agent details such as identity and which network and organization to connect to.

    1. To create config file for Org1MSP's Fabric IIN Agent of network1, follow the steps:

      • Create copy of template config file for Fabric IIN Agent: src/fabric-ledger/config.json.template, say to location src/fabric-ledger/config-n1-org1.json.
      • Replace <path-to-connection-profile> with <PATH-TO-WEAVER>/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json, where replace <PATH-TO-WEAVER> with the location of your clone of Weaver.
      • Set mspId as Org1MSP.
      • Set agent.affiliation as org1.department1.
    2. To create config file for Org2MSP's Fabric IIN Agent of network1, repeat Step 1 with different name for config file, say src/fabric-ledger/config-n1-org2.json, and replace org1 with org2 and Org1MSP with Org2MSP.

    3. To create config file for Org1MSP's Fabric IIN Agent of network2, repeat Step 1 with different name for config file, say src/fabric-ledger/config-n2-org1.json, and replace network1 with network2.

    4. To create config file for Org2MSP's Fabric IIN Agent of network2, repeat Step 1 with different name for config file, say src/fabric-ledger/config-n2-org2.json, and replace network1 with network2, org1 with org2 and Org1MSP with Org2MSP.

    Security Domain Configuration

    Security Domain config file specifies the scope of security domain, which can be a channel in Fabric networks or list of nodes. File docker-testnet/configs/security-domain-config.json can be used for Weaver testnets.

    DNS Configuration

    To allow an IIN Agent's to be able to discover other IIN Agents, a config file for DNS is required. Create one dnsconfig.json by creating a copy of template dnsconfig.json.template, and replace the values with:

    • If Fabric networks are started with 1 org, and IIN Agent are to be started without TLS, use following values:
    {
    "network1": {
    "Org1MSP": {
    "endpoint": "localhost:9500",
    "tls": false,
    "tlsCACertPath": ""
    }
    },
    "network2": {
    "Org1MSP": {
    "endpoint": "localhost:9501",
    "tls": false,
    "tlsCACertPath": ""
    }
    }
    }
    • If Fabric networks are started with 1 org, and IIN Agent are to be started with TLS, use following values:
    {
    "network1": {
    "Org1MSP": {
    "endpoint": "localhost:9500",
    "tls": true,
    "tlsCACertPath": "../../relay/credentials/fabric_ca_cert.pem"
    }
    },
    "network2": {
    "Org1MSP": {
    "endpoint": "localhost:9501",
    "tls": true,
    "tlsCACertPath": "../../relay/credentials/fabric_ca_cert.pem"
    }
    }
    }
    • If Fabric networks are started with 2 orgs, and IIN Agent are to be started without TLS, use following values:
    {
    "network1": {
    "Org1MSP": {
    "endpoint": "localhost:9500",
    "tls": false,
    "tlsCACertPath": ""
    },
    "Org2MSP": {
    "endpoint": "localhost:9510",
    "tls": false,
    "tlsCACertPath": ""
    }
    },
    "network2": {
    "Org1MSP": {
    "endpoint": "localhost:9501",
    "tls": false,
    "tlsCACertPath": ""
    },
    "Org2MSP": {
    "endpoint": "localhost:9511",
    "tls": false,
    "tlsCACertPath": ""
    }
    }
    }
    • If Fabric networks are started with 2 orgs, and IIN Agent are to be started with TLS, use following values:
    {
    "network1": {
    "Org1MSP": {
    "endpoint": "localhost:9500",
    "tls": true,
    "tlsCACertPath": "../../relay/credentials/fabric_ca_cert.pem"
    },
    "Org2MSP": {
    "endpoint": "localhost:9510",
    "tls": true,
    "tlsCACertPath": "../../relay/credentials/fabric_ca_cert.pem"
    }
    },
    "network2": {
    "Org1MSP": {
    "endpoint": "localhost:9501",
    "tls": true,
    "tlsCACertPath": "../../relay/credentials/fabric_ca_cert.pem"
    },
    "Org2MSP": {
    "endpoint": "localhost:9511",
    "tls": true,
    "tlsCACertPath": "../../relay/credentials/fabric_ca_cert.pem"
    }
    }
    }

    Environment Variables

    To configure environment variables for Org1MSP's Fabric IIN Agent of network1, follow the steps:

    1. Create a copy of .env.template as .env, and update following values based on previous configuration file paths:
    IIN_AGENT_ENDPOINT=localhost:9500
    MEMBER_ID=Org1MSP
    SECURITY_DOMAIN=network1
    DLT_TYPE=fabric
    CONFIG_PATH=./src/fabric-ledger/config-n1-org1.json
    DNS_CONFIG_PATH=./dnsconfig.json
    SECURITY_DOMAIN_CONFIG_PATH=./docker-testnet/configs/security-domain-config.json
    WEAVER_CONTRACT_ID=interop
    AUTO_SYNC=true
    1. If IIN Agent has to be started with TLS enabled, also update following values:
    IIN_AGENT_TLS=false
    IIN_AGENT_TLS_CERT_PATH=../../relay/credentials/fabric_cert.pem
    IIN_AGENT_TLS_KEY_PATH=../../relay/credentials/fabric_key

    Deployment

    Use the following steps to run Fabric IIN Agents in host machine:

    • To start IIN Agent for Org1MSP of network1, run:
    npm run dev
    • To start IIN Agent for Org2MSP of network1 (only required if Fabric network was started with 2 orgs), run:
    IIN_AGENT_ENDPOINT=localhost:9510 MEMBER_ID=Org2MSP CONFIG_PATH=./src/fabric-ledger/config-n1-org2.json npm run dev
    • To start IIN Agent for Org1MSP of network2, run:
    IIN_AGENT_ENDPOINT=localhost:9501 SECURITY_DOMAIN=network2 CONFIG_PATH=./src/fabric-ledger/config-n2-org1.json npm run dev
    • To start IIN Agent for Org2MSP of network2 (only required if Fabric network was started with 2 orgs), run:
    IIN_AGENT_ENDPOINT=localhost:9511 MEMBER_ID=Org2MSP SECURITY_DOMAIN=network2 CONFIG_PATH=./src/fabric-ledger/config-n2-org2.json npm run dev
    Notes
    The variables we specified earlier in the .env for network1 are now passed in the command line. Alternatively, you can make a copy of the fabric-driver folder with a different name and create a separate .env file within it that contains links to the connection profile, relay, and driver for network2.

    Corda Components

    Using the sequence of instructions below, you can start a Corda network and run an application CorDapp on it. You can also run an interoperation CorDapp, a relay and a driver acting on behalf of the network. You can initialize the network's vault with access control policies, foreign networks' security groups (i.e., membership providers' certificate chains), and some sample state values that can be shared during subsequent interoperation flows.

    Interoperation CorDapp

    The interoperation CorDapp is deployed to run as part of any Corda application flow that involves cross-network interoperation.

    Build the interoperation CorDapp as follows:

    • Navigate to the core/network/corda-interop-app folder.
    • Run the following to create the JAR files on which other Corda network components will depend on:
      make build-local

    Corda Interoperation SDK

    A client-layer library is defined in the sdks/corda folder. This contains functions for Corda based client applications to exercise interoperation capabilities via relays and also several utility/helper functions. The Corda Client tool, which we will use later, depends on this library.

    To build the library, do the following:

    • Navigate to the sdks/corda folder.
    • Run the following command (make sure there is no github.properties file present in the directory):
      make build

    Corda Simple Application and Client (Application)

    This is a simple CorDapp that maintains a state of type SimpleState, which is a set of key-value pairs (of strings). +

    Setup with Locally Built Weaver Components

    In this document, we detail the steps using which you can bring up networks using the default configuration settings and by building Weaver interoperation modules, SDK libraries, and relay drivers locally from your Weaver clone. To customize these settings (e.g., hostnames, ports), refer to the Advanced Configuration page.

    Notes
    The default configuration is for a development setup, therefore all components are run on localhost, many within Docker containers.

    Follow the instructions below to build and run components followed by interoperation flows. These instructions have been tested on Ubuntu Linux (bash shell) and Mac OS. In general, they should work on any system and shell as long as the various dependenices have been installed and configured.

    Prerequisites

    Software

    Before starting, make sure you have the following software installed on your host machine:

    • OpenSSL: install using package manager, like apt on Debian/Ubuntu Linux (specifically packages openssl and libssl-dev)

    • Curl: install using package manager, like apt on Debian/Ubuntu Linux

    • Git: sample instructions

    • Docker: sample instructions (Latest version)

    • Docker-Compose: sample instructions (Version 1.28.2 or higher, but lower than version V2)

    • Golang: sample instructions (Version 1.16 or higher)

    • Java (JDK and JRE): sample instructions (Version 8)

    • Node.js and NPM: sample instructions (Version 16 Supported)

    • Yarn: sample instructions

    • Rust: sample instructions

    • Protoc (Protobuf compiler): Golang should already be installed and configured.

      • Default method: Run the following with sudo if necessary. This will install both the protobuf compiler and the Go code generator plugins.

        apt-get install protobuf-compiler
        go install google.golang.org/protobuf/cmd/protoc-gen-go
        go install google.golang.org/grpc/cmd/protoc-gen-go-grpc
      • If the above method installs an older version of protoc (check using protoc --version), say below 3.12.x, you should download pre-compiled binaries instead. (With an older version, you may see errors while attempting to launch and setup the Fabric networks).

        sudo apt-get remove protobuf-compiler
        curl -LO https://github.com/protocolbuffers/protobuf/releases/download/v3.15.6/protoc-3.15.6-linux-x86_64.zip
        sudo apt-get install unzip
        unzip protoc-3.15.6-linux-x86_64.zip -d <some-folder-path>
        export PATH="$PATH:<some-folder-path>/bin"
        go install google.golang.org/protobuf/cmd/protoc-gen-go
        go install google.golang.org/grpc/cmd/protoc-gen-go-grpc
        Notes
        The latest version at present is 3.15.6, but you should check the above link to find the most current version before running the above steps.

    Credentials

    Make sure you have an SSH or GPG key registered in https://github.com to allow seamless cloning of repositories (at present, various setup scripts clone repositories using the https:// prefix but this may change to git@ in the future).

    Getting the Code and Documentation

    Clone the weaver-dlt-interoperability repository. The code to get a basic test network up and running and test data-sharing interoperation flows lies in the subfolder tests/network-setups, which should be your starting point, though the setups will rely on other parts of the repository, as you will find out in the instructions given on this page.

    Common Structures

    The common/protos folder contains structure definitions in the protobuf format that are used by all the different components. The various common/protos-* folders are meant to contain compiled protobufs (in different languages).

    To compile the protobufs for JavaScript, do the following:

    • Navigate to the common/protos-js folder.
    • Run the following command:
      make build

    To compile the protobufs for Golang, do the following:

    • Navigate to the common/protos-go folder.
    • Run the following command:
      make build

    To compile the protobufs for Java, do the following:

    • Navigate to the common/protos-java-kt folder.
    • Run the following command:
      make build

    To compile the protobufs for Solidity, do the following:

    • Navigate to the common/protos-sol folder.
    • Run the following command:
      make build

    To compile the protobufs for Rust, do the following:

    • Navigate to the common/protos-rs folder.
    • Run the following command:
      make build

    Securing Components

    Notes
    The relays and drivers corresponding to the different test networks you will encounter below can be run with or without TLS enabled. But the default files used in the demonstrations assume that either all relays and drivers are TLS-enabled or none are. Therefore, you should determine at the outset whether or not you wish to run the entire set of components in TLS-enabled mode, and select appropriate commands in the provided instructions.

    Hyperledger Fabric Components

    Using the sequence of instructions below, you can start two separate Fabric networks, each with a single channel and application contract (chaincode). You can also start an interoperation contract, a relay, and a driver acting on behalf of each network. You can build a Fabric CLI tool with which you can initialize both networks' ledgers with access control policies, foreign networks' security groups (i.e., membership providers' certificate chains), and some sample key-value pairs that can be shared during subsequent interoperation flows.

    Fabric Interoperation Node SDK

    A client-layer library (companion to hyperledger/fabric-sdk-node) is defined in the sdks/fabric/interoperation-node-sdk folder. This contains functions for Fabric Gateway-based applications to exercise interoperation capabilities via relays and also several utility/helper functions. The Fabric-CLI tool, which we will use later, depends on this library.

    To build the library, do the following:

    • Navigate to the sdks/fabric/interoperation-node-sdk folder.
    • Run the following command:
      make build-local

    Fabric Network

    The code for this lies in the tests/network-setups folder.

    This folder contains code to create and launch networks network1 and network2 of identical specifications:

    • Network: 1 peer, 1 peer CA, 1 ordering service node, 1 ordering service CA
    • Single channel named mychannel
    • One of the following contracts deployed on mychannel, the choice depending on the interoperability mode you wish to test:
      • simplestate (Data Sharing): supports simple transactions (Create, Read, Update, Delete) involving storage and lookup of <key, value> pairs.
      • simplestatewithacl (Data Sharing): identical to simplestate but with extra security features to ensure that the Weaver infrastructure cannot be bypassed by a malicious client of the network.
      • simpleasset (Asset Exchange): supports creation, modification, transfer, and deletion, as well as locking, unlocking, and claiming, of simple bonds and tokens (examples of non-fungible and fungible assets respectively).
      • simpleassetandinterop (Asset Exchange): identical to simpleasset but where the locking, unlocking, and claiming logic is imported as a library in the chaincode rather than available in the common Fabric Interoperation Chaincode (a Weaver component).
      • simpleassettransfer (Asset Exchange or Asset Transfer): augmentation of simpleasset with asset pledging, claiming, and reclaiming features for cross-network transfers.
    Notes
    For new users, we recommend testing the Data Sharing feature first with the simplestate contract. To test the other modes, you can simply tear down the Fabric networks and restart them with the appropriate chaincodes installed.

    Follow the instructions below to build and launch the networks:

    • Navigate to the tests/network-setups/fabric/dev folder.
    • To spin up both network1 and network2 with the interoperation chaincode and the default simplestate chaincode installed, run:
      make start-interop-local
    • To launch the networks with a different application chaincode from the above list, run:
      make start-interop-local CHAINCODE_NAME=<chaincode-name>
    • To launch the networks with 2 organizations, each with a peer (this will enable more variation and experimentation, which you can attempt after testing interoperation protocols across basic network configurations), run:
      make start-interop-local PROFILE="2-nodes"
    Notes
    If you do not wish to test Fabric-Fabric interoperation, you can choose to launch only one of the two networks along with its interoperation chaincode. For network1, run make start-interop-network1-local, and for network2, run make start-interop-network2-local
    If you wish to enable end-to-end confidentiality by default in the interoperation modules that are deployed during network launch, set the environment variable E2E_CONFIDENTIALITY to true in the command line as follows: E2E_CONFIDENTIALITY=true make start-interop-local

    For more information, refer to the associated README.

    Troubleshooting Tips:

    • If you see any errors during the launches, re-check the prerequisites (software installations and credentials). Ensure your network connection is working. As a safe bet, you can retry after cleanup: kill and remove all Docker containers and associated volumes.
    • If protoc or protoc-gen-go throws an error, reinstall protoc and protoc-gen-go using suggestions made in the Prerequisites section above.

    Fabric Client (fabric-cli)

    The CLI is used to interact with a Fabric network, configure it and run chaincode transactions to record data on the channel ledger or query data. It is also used to interact with remote networks through the relay to trigger an interoperation flow for data request and acceptance.

    The fabric-cli Node.js source code is located in the samples/fabric/fabric-cli folder and the Golang source code in the samples/fabric/go-cli folder.

    Prerequisites

    If you are using a Linux system, make sure that lib64 is installed.

    Notes
    For the Node.js version of the fabric-cli, the setup and running instructions below were tested with all Node.js versions from v11.14.0 to v14.17.3.

    Installation

    You can install fabric-cli as follows (for both the Node.js and Golang versions):

    • Navigate to the samples/fabric/fabric-cli folder (for the Node.js version) or the samples/fabric/go-cli folder (for the Golang version).
    • Run the following to install dependencies (for the Node.js version) or the executable (for the Golang version):
      make build-local
    • Use the fabric-cli executable in the bin folder for subsequent actions.

    Fabric Relay

    The relay is a module acting on behalf of a network, enabling interoperation flows with other networks by communicating with their relays. +The code for this lies in the core/relay folder.

    Building

    Prerequisite: make sure Rust is already installed and that the cargo executable is in your system path (after installation of Rust, this should be available in $HOME/.cargo/bin); you can also ensure this by running source "$HOME/.cargo/env".

    Build the generic (i.e., common to all DLTs) relay module as follows:

    • Navigate to the core/relay folder.
    • Run the following:
      make
    • If you observe errors during the above compilation, update certain packages (on which the Weaver Relay is dependent) to their latest versions and recompile as follows:
      make update-pkgs
      make

    Deployment

    An instance or a relay can be run using a suitable configuration file. Samples are available in the core/relay/config folder.

    Run a relay for network1 as follows:

    • Navigate to the core/relay folder.
    • To launch the server without TLS, leave the configuration file config/Fabric_Relay.toml in its default state. Otherwise, edit it to set TLS flags for this relay and the other relays and drivers it will connect to in this demonstration as follows:
      .
      .
      cert_path="credentials/fabric_cert.pem"
      key_path="credentials/fabric_key"
      tls=true
      .
      .
      [relays]
      [relays.Corda_Relay]
      hostname="localhost"
      port="9081"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      [relays.Corda_Relay2]
      hostname="localhost"
      port="9082"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      [relays.Fabric_Relay2]
      hostname="localhost"
      port="9083"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      .
      .
      [drivers]
      [drivers.Fabric]
      hostname="localhost"
      port="9090"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      .
      .
    • To launch the server, simply run the following:
      RELAY_CONFIG=config/Fabric_Relay.toml cargo run --bin server

    Run a relay for network2 as follows (do this only if you have launched both Fabric networks network1 and network2 and wish to test interoperation between them)

    • Navigate to the core/relay folder.
    • To launch the server without TLS, leave the configuration file config/Fabric_Relay2.toml in its default state. Otherwise, edit it to set TLS flags for this relay and the other relays and drivers it will connect to in this demonstration as follows:
      .
      .
      cert_path="credentials/fabric_cert.pem"
      key_path="credentials/fabric_key"
      tls=true
      .
      .
      [relays]
      [relays.Corda_Relay]
      hostname="localhost"
      port="9081"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      [relays.Corda_Relay2]
      hostname="localhost"
      port="9082"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      [relays.Fabric_Relay]
      hostname="localhost"
      port="9080"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      .
      .
      [drivers]
      [drivers.Fabric]
      hostname="localhost"
      port="9095"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      .
      .
    • To launch the server, simply run the following:
      RELAY_CONFIG=config/Fabric_Relay2.toml cargo run --bin server

    For more information, see the relay README.

    Fabric Driver

    A driver is a DLT-specific plugin invoked by the relay while conveying external data queries to the local peer network and collecting a response with proofs. The Fabric driver is built as a Fabric client application on the fabric-network NPM package. +The code for this lies in the core/drivers/fabric-driver folder.

    Configuring

    In the core/drivers/fabric-driver folder, copy .env.template to .env and update CONNECTION_PROFILE to point to the connection profile of the Fabric network (e.g. <PATH-TO-WEAVER>/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json)

    Configure fabric-driver for network1 as follows:

    • Navigate to the core/drivers/fabric-driver folder.
    • Create a .env file by copying .env.template and setting suitable parameter values:
      • The CONNECTION_PROFILE should point to the absolute path of the connection profile for network1.
        • For this exercise, specify the path <PATH-TO-WEAVER>/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json (you must specify the full absolute path here).
        • <PATH-TO-WEAVER> here is the absolute path of the weaver-dlt-interoperability clone folder.
      • If you wish to start the driver without TLS, set the following parameter values:
        RELAY_TLS=false
        RELAY_TLSCA_CERT_PATH=
        DRIVER_TLS=false
        DRIVER_TLS_CERT_PATH=
        DRIVER_TLS_KEY_PATH=
        Otherwise, if you wish to start the driver with TLS enabled, set the following parameter values (replace <PATH-TO-WEAVER> with the absolute path of the weaver-dlt-interoperability clone folder):
        RELAY_TLS=true
        RELAY_TLSCA_CERT_PATH=<PATH-TO-WEAVER>/core/relay/credentials/fabric_ca_cert.pem
        DRIVER_TLS=true
        DRIVER_TLS_CERT_PATH=<PATH-TO-WEAVER>/core/relay/credentials/fabric_cert.pem
        DRIVER_TLS_KEY_PATH=<PATH-TO-WEAVER>/core/relay/credentials/fabric_key
      • Leave the default values unchanged for the other parameters. The relay and driver endpoints as well as the network name are already specified in the template.

    Building

    Build the Fabric driver module as follows:

    • Navigate to the core/drivers/fabric-driver folder.
    • Run the following:
      make build-local

    Running

    Run a Fabric driver for network1 as follows:

    • Navigate to the core/drivers/fabric-driver folder.
    • Run the following:
      npm run dev

    Run a Fabric driver for network2 as follows (do this only if you wish to test interoperation between the two Fabric networks network1 and network2)

    • Navigate to the core/drivers/fabric-driver folder.
    • Run the following (replace <PATH-TO-WEAVER> with the absolute path of the weaver-dlt-interoperability clone folder):
      CONNECTION_PROFILE=<PATH-TO-WEAVER>/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/connection-org1.json NETWORK_NAME=network2 RELAY_ENDPOINT=localhost:9083 DRIVER_ENDPOINT=localhost:9095 npm run dev
    Notes
    The variables we specified earlier in the .env for network1 are now passed in the command line. Alternatively, you can make a copy of the fabric-driver folder with a different name and create a separate .env file within it that contains links to the connection profile, relay, and driver for network2.

    Fabric IIN Agent

    IIN Agent is a client of a member of a DLT network or security domain with special permissions to update security domain identities and configurations on the ledger via the network's interoperation module. The code for this lies in the core/identity-management/iin-agent folder. Navigate to the core/identity-management/iin-agent folder.

    Building

    To build the IIN Agent, run:

    make build-local

    Configuration

    Ledger config file specifies ledger specific IIN Agent details such as identity and which network and organization to connect to.

    1. To create config file for Org1MSP's Fabric IIN Agent of network1, follow the steps:

      • Create copy of template config file for Fabric IIN Agent: src/fabric-ledger/config.json.template, say to location src/fabric-ledger/config-n1-org1.json.
      • Replace <path-to-connection-profile> with <PATH-TO-WEAVER>/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json, where <PATH-TO-WEAVER> should be substituted with the absolute path location of your clone of Weaver.
      • Set mspId as Org1MSP.
      • Set agent.affiliation as org1.department1.
    2. To create config file for Org2MSP's Fabric IIN Agent of network1, repeat Step 1 with different name for config file, say src/fabric-ledger/config-n1-org2.json, and replace org1 with org2 and Org1MSP with Org2MSP.

    3. To create config file for Org1MSP's Fabric IIN Agent of network2, repeat Step 1 with different name for config file, say src/fabric-ledger/config-n2-org1.json, and replace network1 with network2.

    4. To create config file for Org2MSP's Fabric IIN Agent of network2, repeat Step 1 with different name for config file, say src/fabric-ledger/config-n2-org2.json, and replace network1 with network2, org1 with org2 and Org1MSP with Org2MSP.

    Security Domain Configuration

    Security Domain config file specifies the scope of security domain, which can be a channel in Fabric networks or list of nodes. File docker-testnet/configs/security-domain-config.json can be used for Weaver testnets.

    DNS Configuration

    To allow an IIN Agent's to be able to discover other IIN Agents, a config file for DNS is required. Create one dnsconfig.json by creating a copy of template dnsconfig.json.template, and replace the values with:

    • If Fabric networks are started with 1 org, and IIN Agent are to be started without TLS, use following values:
    {
    "network1": {
    "Org1MSP": {
    "endpoint": "localhost:9500",
    "tls": false,
    "tlsCACertPath": ""
    }
    },
    "network2": {
    "Org1MSP": {
    "endpoint": "localhost:9501",
    "tls": false,
    "tlsCACertPath": ""
    }
    }
    }
    • If Fabric networks are started with 1 org, and IIN Agent are to be started with TLS, use following values:
    {
    "network1": {
    "Org1MSP": {
    "endpoint": "localhost:9500",
    "tls": true,
    "tlsCACertPath": "../../relay/credentials/fabric_ca_cert.pem"
    }
    },
    "network2": {
    "Org1MSP": {
    "endpoint": "localhost:9501",
    "tls": true,
    "tlsCACertPath": "../../relay/credentials/fabric_ca_cert.pem"
    }
    }
    }
    • If Fabric networks are started with 2 orgs, and IIN Agent are to be started without TLS, use following values:
    {
    "network1": {
    "Org1MSP": {
    "endpoint": "localhost:9500",
    "tls": false,
    "tlsCACertPath": ""
    },
    "Org2MSP": {
    "endpoint": "localhost:9510",
    "tls": false,
    "tlsCACertPath": ""
    }
    },
    "network2": {
    "Org1MSP": {
    "endpoint": "localhost:9501",
    "tls": false,
    "tlsCACertPath": ""
    },
    "Org2MSP": {
    "endpoint": "localhost:9511",
    "tls": false,
    "tlsCACertPath": ""
    }
    }
    }
    • If Fabric networks are started with 2 orgs, and IIN Agent are to be started with TLS, use following values:
    {
    "network1": {
    "Org1MSP": {
    "endpoint": "localhost:9500",
    "tls": true,
    "tlsCACertPath": "../../relay/credentials/fabric_ca_cert.pem"
    },
    "Org2MSP": {
    "endpoint": "localhost:9510",
    "tls": true,
    "tlsCACertPath": "../../relay/credentials/fabric_ca_cert.pem"
    }
    },
    "network2": {
    "Org1MSP": {
    "endpoint": "localhost:9501",
    "tls": true,
    "tlsCACertPath": "../../relay/credentials/fabric_ca_cert.pem"
    },
    "Org2MSP": {
    "endpoint": "localhost:9511",
    "tls": true,
    "tlsCACertPath": "../../relay/credentials/fabric_ca_cert.pem"
    }
    }
    }

    Environment Variables

    To configure environment variables for Org1MSP's Fabric IIN Agent of network1, follow the steps:

    1. Create a copy of .env.template as .env, and update following values based on previous configuration file paths:
    IIN_AGENT_ENDPOINT=localhost:9500
    MEMBER_ID=Org1MSP
    SECURITY_DOMAIN=network1
    DLT_TYPE=fabric
    CONFIG_PATH=./src/fabric-ledger/config-n1-org1.json
    DNS_CONFIG_PATH=./dnsconfig.json
    SECURITY_DOMAIN_CONFIG_PATH=./docker-testnet/configs/security-domain-config.json
    WEAVER_CONTRACT_ID=interop
    AUTO_SYNC=true
    1. If IIN Agent has to be started with TLS enabled, also update following values:
    IIN_AGENT_TLS=true
    IIN_AGENT_TLS_CERT_PATH=../../relay/credentials/fabric_cert.pem
    IIN_AGENT_TLS_KEY_PATH=../../relay/credentials/fabric_key

    Deployment

    Use the following steps to run Fabric IIN Agents in host machine:

    • To start IIN Agent for Org1MSP of network1, run:
    npm run dev
    • To start IIN Agent for Org2MSP of network1 (only required if Fabric network was started with 2 orgs), run:
    IIN_AGENT_ENDPOINT=localhost:9510 MEMBER_ID=Org2MSP CONFIG_PATH=./src/fabric-ledger/config-n1-org2.json npm run dev
    • To start IIN Agent for Org1MSP of network2, run:
    IIN_AGENT_ENDPOINT=localhost:9501 SECURITY_DOMAIN=network2 CONFIG_PATH=./src/fabric-ledger/config-n2-org1.json npm run dev
    • To start IIN Agent for Org2MSP of network2 (only required if Fabric network was started with 2 orgs), run:
    IIN_AGENT_ENDPOINT=localhost:9511 MEMBER_ID=Org2MSP SECURITY_DOMAIN=network2 CONFIG_PATH=./src/fabric-ledger/config-n2-org2.json npm run dev
    Notes
    The variables we specified earlier in the .env for network1 are now passed in the command line. Alternatively, you can make a copy of the fabric-driver folder with a different name and create a separate .env file within it that contains links to the connection profile, relay, and driver for network2.

    Corda Components

    Using the sequence of instructions below, you can start a Corda network and run an application CorDapp on it. You can also run an interoperation CorDapp, a relay and a driver acting on behalf of the network. You can initialize the network's vault with access control policies, foreign networks' security groups (i.e., membership providers' certificate chains), and some sample state values that can be shared during subsequent interoperation flows.

    Interoperation CorDapp

    The interoperation CorDapp is deployed to run as part of any Corda application flow that involves cross-network interoperation.

    Build the interoperation CorDapp as follows:

    • Navigate to the core/network/corda-interop-app folder.
    • Run the following to create the JAR files on which other Corda network components will depend on:
      make build-local

    Corda Interoperation SDK

    A client-layer library is defined in the sdks/corda folder. This contains functions for Corda based client applications to exercise interoperation capabilities via relays and also several utility/helper functions. The Corda Client tool, which we will use later, depends on this library.

    To build the library, do the following:

    • Navigate to the sdks/corda folder.
    • Run the following command (make sure there is no github.properties file present in the directory):
      make build

    Corda Simple Application and Client (Application)

    This is a simple CorDapp that maintains a state of type SimpleState, which is a set of key-value pairs (of strings). The code for this lies in the samples/corda/corda-simple-application folder.

    Build the corda-simple-application CorDapp as follows:

    • Navigate to the samples/corda/corda-simple-application folder.
    • Run the following:
      make build-local

    Corda Network

    The Corda networks' code lies in the tests/network-setups/corda folder. You can launch two separate Corda networks, namely Corda_Network and Corda_Network2. Each network runs the samples/corda/corda-simple-application CorDapp by default, which maintains a state named SimpleState containing a set of key-value pairs (of strings).

    Follow the instructions below to build and launch both networks:

    • Navigate to the tests/network-setups/corda folder.
    • To spin up the Corda networks with the Interoperation CorDapps:
      • Each consisting of 1 node and a notary (for data-transfer), run:
        make start-local
      • Each consisting of 2 nodes and a notary (for asset-exchange/transfer), run:
        make start-local PROFILE="2-nodes"
      • Each consisting of 3 nodes and a notary (for asset-exchange/transfer), run:
        make start-local PROFILE="3-nodes"
    Notes
    If you do not wish to test Corda-Corda interoperation, you can choose to launch only one of the two networks along with its interoperation CorDapp. For Corda_Network, run make start-network1-local, and for Corda_Network2, run make start-network2-local.

    You should see the following message in the terminal:

    Waiting for network node services to start

    The Corda nodes and notary may take a while (several minutes on memory-constrained systems) to start. If they start up successfully, you should something like the following for each network, though the number of node entries will depend on the profile you used to start the network with (replace <network-name> with Corda_Network or Corda_Network2):

    PartyA node services started for network <network-name>
    PartyB node services started for network <network-name>
    PartyC node services started for network <network-name>
    Notary node services started for network <network-name>

    Corda Relay

    The relay was built earlier, so you just need to use a different configuration file to start a relay for the Corda network.

    Run a relay for Corda_Network as follows:

    • Navigate to the core/relay folder.

    • (Make sure you've already built the relay by running make.)

    • To launch the server without TLS, leave the configuration file config/Corda_Relay.toml in its default state. Otherwise, edit it to set TLS flags for this relay and the other relays and drivers it will connect to in this demonstration as follows:

      .
      .
      cert_path="credentials/fabric_cert.pem"
      key_path="credentials/fabric_key"
      tls=true
      .
      .
      [relays]
      [relays.Fabric_Relay]
      hostname="localhost"
      port="9080"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      [relays.Fabric_Relay2]
      hostname="localhost"
      port="9083"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      [relays.Corda_Relay2]
      hostname="localhost"
      port="9082"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      .
      .
      [drivers]
      [drivers.Corda]
      hostname="localhost"
      port="9099"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      .
      .
    • To launch the server, simply run the following:

      RELAY_CONFIG=config/Corda_Relay.toml cargo run --bin server

      If the relay starts up successfully, the following will be logged on your terminal:

      Relay Name: "Corda_Relay"
      RelayServer listening on [::1]:9081

    Run a relay for Corda_Network2 as follows (do this only if you have launched both Corda networks Corda_Network and Corda_Network2 and wish to test interoperation between them)

    • Navigate to the core/relay folder.

    • To launch the server without TLS, leave the configuration file config/Corda_Relay2.toml in its default state. Otherwise, edit it to set TLS flags for this relay and the other relays and drivers it will connect to in this demonstration as follows:

      .
      .
      cert_path="credentials/fabric_cert.pem"
      key_path="credentials/fabric_key"
      tls=true
      .
      .
      [relays]
      [relays.Fabric_Relay]
      hostname="localhost"
      port="9080"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      [relays.Fabric_Relay2]
      hostname="localhost"
      port="9083"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      [relays.Corda_Relay]
      hostname="localhost"
      port="9081"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      .
      .
      [drivers]
      [drivers.Corda]
      hostname="localhost"
      port="9098"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      .
      .
    • To launch the server, simply run the following:

      RELAY_CONFIG=config/Corda_Relay2.toml cargo run --bin server

      If the relay starts up successfully, the following will be logged on your terminal:

      Relay Name: "Corda2_Relay"
      RelayServer listening on [::1]:9082

    Corda Driver

    The code for this lies in the core/drivers/corda-driver folder.

    Building Corda Driver

    Build the Corda driver module as follows:

    • Navigate to the core/drivers/corda-driver folder.
    • Run the following:
      make build-local

    Configuring

    Configure the drivers as follows (you can skip this if you wish to run the drivers without TLS):

    • Navigate to the core/drivers/corda-driver folder and create a .env file.
    • To run the drivers without TLS, set the following default values:
      RELAY_TLS=false
      RELAY_TLSCA_TRUST_STORE=
      RELAY_TLSCA_TRUST_STORE_PASSWORD=
      RELAY_TLSCA_CERT_PATHS=
    • To run the drivers with TLS, set the following values (replace <PATH-TO-WEAVER> with the absolute path of the weaver-dlt-interoperability clone folder):
      RELAY_TLS=true
      RELAY_TLSCA_TRUST_STORE=<PATH-TO-WEAVER>/core/relay/credentials/fabric_trust_store.jks
      RELAY_TLSCA_TRUST_STORE_PASSWORD=trelay
      RELAY_TLSCA_CERT_PATHS=<PATH-TO-WEAVER>/core/relay/credentials/fabric_ca_cert.pem

    Running

    Run a Corda driver as follows:

    • Navigate to the core/drivers/corda-driver folder.
    • Run the following to start Corda driver for Corda_Network:
      ./build/install/corda-driver/bin/corda-driver
      If the driver starts successfully, it should log the following message on your terminal:
      Corda driver gRPC server started. Listening on port 9099
    • Run the following to start Corda driver for Corda_Network2:
      DRIVER_PORT=9098 ./build/install/corda-driver/bin/corda-driver
      If the driver starts successfully, it should log the following message on your terminal:
      Corda driver gRPC server started. Listening on port 9098

    Hyperledger Besu Components

    Using the sequence of instructions below, you can start two separate Besu networks, each with 4 validator nodes, and EthSigner and application contract. You can also install an interoperation contract in the network. You can build a Besu CLI tool with which you can initialize both networks' ledgers.

    Prerequisites

    Besu Interoperation Node SDK

    A client-layer library is defined in the sdks/besu/interoperation-node-sdk folder. This contains functions for Besu web3JS based applications to exercise interoperation capabilities via several utility/helper functions. The Besu-CLI tool, which we will use later, depends on this library.

    To build the library, do the following:

    • Navigate to the sdks/besu/interoperation-node-sdk folder.
    • Run the following command:
      make build-local

    Besu Network

    The code for this lies in the tests/network-setups/besu folder.

    This folder contains code to create and launch networks Network1 and Network2 of identical specifications:

    • Network: 4 validator nodes, 1 EthSigner node.
    • Network1 uses 8545 port for EthSigner while Network2 uses 9544 port for EthSigner.

    Follow the instructions below to build and launch the networks:

    • Navigate to the tests/network-setups/besu folder.
    • To spin up both Network1 and Network2, run:
      make start
    Notes
    If you do not wish to test Besu-Besu interoperation, you can choose to launch only one of the two networks. For Network1, run make start-network1, and for Network2, run make start-network2

    For more information, refer to the associated README.

    Contracts

    • AssetExchangeContract must be deployed which is present in core/network/besu/contracts/interop/manageAssetAny.sol. This contract is deployed along with application contract.
    • Application contract simpleasset, located in samples/besu/simpleasset directory (for Asset Exchange), which supports creation, modification, transfer, and deletion, as well as locking, unlocking, and claiming, of simple AliceERC20 and BobERC20 tokens (examples of fungible assets), or AliceERC721 and BobERC721 tokens (example of non-fungible assets), or AliceERC1155 and BobERC1155 tokens (example of hybrid assets).

    To deploy simpleasset with AssetExchangeContract on both Besu networks, navigate to samples/besu/simpleasset folder, and run:

    make deploy-contracts
    Notes
    If you chose to launch only one of the two networks, then for Network1, run make deploy-contract-network1, and for Network2, run deploy-contract-network2

    Besu Client (besu-cli)

    The CLI is used to interact with a Besu network, configure it and run contract transactions to record data on the ledger or query data.

    The besu-cli Node.js source code is located in the samples/besu/besu-cli folder.

    Prerequisites

    If you are using a Linux system, make sure that lib64 is installed.

    Notes
    For the Node.js version of the besu-cli, the setup and running instructions below were tested with all Node.js versions from v11.14.0 to v14.17.3.

    Installation

    You can install besu-cli as follows:

    • Navigate to the samples/besu/besu-cli folder.
    • Run the following to install dependencies:
      make build-local
    • Use the besu-cli executable in the bin folder for subsequent actions.

    Tear Down the Setup

    Bring down the test network's components as follows:

    • Simply terminate the various relays and drivers, which are running in the foreground in different terminals
    • To bring down the running Corda network:
      • Navigate to the tests/network-setups/corda folder.
      • Run the following:
        make clean
    • To bring down all the running Fabric networks:
      • Navigate to the tests/network-setups/fabric/dev folder.
      • Run the following:
        make clean
    • To bring down all the running Besu networks:
      • Navigate to the tests/network-setups/besu folder.
      • Run the following:
        make clean
    - - +You need to run Besu instructions in a separate environment (separate terminal or machine) than Corda, as Corda requires Java 8. You can also use update-alternatives to switch between java versions.
  • tmux: sudo apt install tmux
  • Besu:
  • EthSigner:
  • Besu Interoperation Node SDK

    A client-layer library is defined in the sdks/besu/interoperation-node-sdk folder. This contains functions for Besu web3JS based applications to exercise interoperation capabilities via several utility/helper functions. The Besu-CLI tool, which we will use later, depends on this library.

    To build the library, do the following:

    • Navigate to the sdks/besu/interoperation-node-sdk folder.
    • Run the following command:
      make build-local

    Besu Network

    The code for this lies in the tests/network-setups/besu folder.

    This folder contains code to create and launch networks Network1 and Network2 of identical specifications:

    • Network: 4 validator nodes, 1 EthSigner node.
    • Network1 uses 8545 port for EthSigner while Network2 uses 9544 port for EthSigner.

    Follow the instructions below to build and launch the networks:

    • Navigate to the tests/network-setups/besu folder.
    • To spin up both Network1 and Network2, run:
      make start
    Notes
    If you do not wish to test Besu-Besu interoperation, you can choose to launch only one of the two networks. For Network1, run make start-network1, and for Network2, run make start-network2

    For more information, refer to the associated README.

    Contracts

    • AssetExchangeContract must be deployed which is present in core/network/besu/contracts/interop/manageAssetAny.sol. This contract is deployed along with application contract.
    • Application contract simpleasset, located in samples/besu/simpleasset directory (for Asset Exchange), which supports creation, modification, transfer, and deletion, as well as locking, unlocking, and claiming, of simple AliceERC20 and BobERC20 tokens (examples of fungible assets), or AliceERC721 and BobERC721 tokens (example of non-fungible assets), or AliceERC1155 and BobERC1155 tokens (example of hybrid assets).

    To deploy simpleasset with AssetExchangeContract on both Besu networks, navigate to samples/besu/simpleasset folder, and run:

    make deploy-contracts
    Notes
    If you chose to launch only one of the two networks, then for Network1, run make deploy-contract-network1, and for Network2, run deploy-contract-network2

    Besu Client (besu-cli)

    The CLI is used to interact with a Besu network, configure it and run contract transactions to record data on the ledger or query data.

    The besu-cli Node.js source code is located in the samples/besu/besu-cli folder.

    Prerequisites

    If you are using a Linux system, make sure that lib64 is installed.

    Notes
    For the Node.js version of the besu-cli, the setup and running instructions below were tested with all Node.js versions from v11.14.0 to v14.17.3.

    Installation

    You can install besu-cli as follows:

    • Navigate to the samples/besu/besu-cli folder.
    • Run the following to install dependencies:
      make build-local
    • Use the besu-cli executable in the bin folder for subsequent actions.

    Tear Down the Setup

    Bring down the test network's components as follows:

    • Simply terminate the various relays and drivers, which are running in the foreground in different terminals
    • To bring down the running Corda network:
      • Navigate to the tests/network-setups/corda folder.
      • Run the following:
        make clean
    • To bring down all the running Fabric networks:
      • Navigate to the tests/network-setups/fabric/dev folder.
      • Run the following:
        make clean
    • To bring down all the running Besu networks:
      • Navigate to the tests/network-setups/besu folder.
      • Run the following:
        make clean
    + + \ No newline at end of file diff --git a/docs/external/getting-started/test-network/setup-packages-docker/index.html b/docs/external/getting-started/test-network/setup-packages-docker/index.html index 436bd331b..ca811b5ae 100644 --- a/docs/external/getting-started/test-network/setup-packages-docker/index.html +++ b/docs/external/getting-started/test-network/setup-packages-docker/index.html @@ -4,16 +4,16 @@ Setup with Imported Dockerized Weaver Components | Weaver: DLT Interoperability Framework - - - + + +
    -

    Setup with Imported Dockerized Weaver Components

    In this document, we detail the steps using which you can bring up networks using the default configuration settings and by fetching pre-built Weaver interoperation modules, SDK libraries, and relay docker image, drivers docker images from Github Package repositories. To customize these settings (e.g., hostnames, ports), refer to the Advanced Configuration page.

    Notes
    All components are run within Docker containers, except client applications.

    Follow the instructions below to build and run components followed by interoperation flows. These instructions have been tested on Ubuntu Linux (bash shell) and Mac OS. In general, they should work on any system and shell as long as the various dependencies have been installed and configured.

    Prerequisites

    Software

    Before starting, make sure you have the following software installed on your host machine:

    Credentials

    Make sure you have an SSH or GPG key registered in https://github.com to allow seamless cloning of repositories (at present, various setup scripts clone repositories using the https:// prefix but this may change to git@ in the future).

    Package Access Token:

    Create a personal access token with read:packages access in github in order to use modules published in github packages. Refer Creating a Personal Access Token for help.

    Run docker login ghcr.io, and provide github email id as username and personal access token created above as password. This will allow the docker to fetch images of relay, fabric-driver and corda-driver from hyperledger-labs/weaver-dlt-interoperability.

    Getting the Code and Documentation

    Clone the weaver-dlt-interoperability repository. The code to get a basic test network up and running and test data-sharing interoperation flows lies in the subfolder tests/network-setups, which should be your starting point, though the setups will rely on other parts of the repository, as you will find out in the instructions given on this page.

    Securing Components

    Notes
    The relays and drivers corresponding to the different test networks you will encounter below can be run with or without TLS enabled. But the default files used in the demonstrations assume that either all relays and drivers are TLS-enabled or none are. Therefore, you should determine at the outset whether or not you wish to run the entire set of components in TLS-enabled mode, and select appropriate commands in the provided instructions.

    Hyperledger Fabric Components

    Using the sequence of instructions below, you can start two separate Fabric networks, each with a single channel and application contract (chaincode). You can also start an interoperation contract, a relay and a driver acting on behalf of each network. You can build a Fabric CLI tool with which you can initialize both networks' ledgers with access control policies, foreign networks' security groups (i.e., membership providers' certificate chains), and some sample key-value pairs that can be shared during subsequent interoperation flows.

    Fabric Network

    The code for this lies in the tests/network-setups folder.

    This folder contains code to create and launch networks network1 and network2 of identical specifications:

    • Network: 1 peer, 1 peer CA, 1 ordering service node, 1 ordering service CA
    • Single channel named mychannel
    • One of the following contracts deployed on mychannel, the choice depending on the interoperability mode you wish to test:
      • simplestate (Data Sharing): supports simple transactions (Create, Read, Update, Delete) involving storage and lookup of <key, value> pairs.
      • simplestatewithacl (Data Sharing): identical to simplestate but with extra security features to ensure that the Weaver infrastructure cannot be bypassed by a malicious client of the network.
      • simpleasset (Asset Exchange): supports creation, modification, transfer, and deletion, as well as locking, unlocking, and claiming, of simple bonds and tokens (examples of non-fungible and fungible assets respectively).
      • simpleassetandinterop (Asset Exchange): identical to simpleasset but where the locking, unlocking, and claiming logic is imported as a library in the chaincode rather than available in the common Fabric Interoperation Chaincode (a Weaver component).
      • simpleassettransfer (Asset Exchange or Asset Transfer): augmentation of simpleasset with asset pledging, claiming, and reclaiming features for cross-network transfers.
    Notes
    For new users, we recommend testing the Data Sharing feature first with the simplestate contract. To test the other modes, you can simply tear down the Fabric networks and restart them with the appropriate chaincodes installed.

    Follow the instructions below to build and launch the networks:

    • Navigate to the tests/network-setups/fabric/dev folder.
    • To spin up both network1 and network2 with the interoperation chaincode and the default simplestate chaincode installed, run:
      make start-interop
    • To launch the networks with a different application chaincode from the above list, run:
      make start-interop CHAINCODE_NAME=<chaincode-name>
    • To launch the networks with 2 organizations, each with a peer (this will enable more variation and experimentation, which you can attempt after testing interoperation protocols across basic network configurations), run:
      make start-interop-local PROFILE="2-nodes"
    Notes
    If you do not wish to test Fabric-Fabric interoperation, you can choose to launch only one of the two networks along with its interoperation chaincode. For network1, run make start-interop-network1, and for network2, run make start-interop-network2
    If you wish to enable end-to-end confidentiality by default in the interoperation modules that are deployed during network launch, set the environment variable E2E_CONFIDENTIALITY to true in the command line as follows: E2E_CONFIDENTIALITY=true make start-interop

    For more information, refer to the associated README.

    Troubleshooting Tips:

    • If you see any errors during the launches, re-check the prerequisites (software installations and credentials). Ensure your network connection is working. As a safe bet, you can retry after cleanup: kill and remove all Docker containers and associated volumes.

    Fabric Relay

    The relay is a module acting on behalf of a network, enabling interoperation flows with other networks by communicating with their relays. +

    Setup with Imported Dockerized Weaver Components

    In this document, we detail the steps using which you can bring up networks using the default configuration settings and by fetching pre-built Weaver interoperation modules, SDK libraries, and relay docker image, drivers docker images from GitHub Package repositories. To customize these settings (e.g., hostnames, ports), refer to the Advanced Configuration page.

    Notes
    All components are run within Docker containers, except client applications.

    Follow the instructions below to build and run components followed by interoperation flows. These instructions have been tested on Ubuntu Linux (bash shell) and Mac OS. In general, they should work on any system and shell as long as the various dependencies have been installed and configured.

    Prerequisites

    Software

    Before starting, make sure you have the following software installed on your host machine:

    Credentials

    Make sure you have an SSH or GPG key registered in https://github.com to allow seamless cloning of repositories (at present, various setup scripts clone repositories using the https:// prefix but this may change to git@ in the future).

    Package Access Token:

    Create a personal access token with read:packages access in GitHub in order to use modules published in GitHub packages. Refer Creating a Personal Access Token for help.

    Run docker login ghcr.io, and provide GitHub email id as username and personal access token created above as password. This will allow the docker to fetch images of relay, fabric-driver and corda-driver from hyperledger-labs/weaver-dlt-interoperability.

    Getting the Code and Documentation

    Clone the weaver-dlt-interoperability repository. The code to get a basic test network up and running and test data-sharing interoperation flows lies in the subfolder tests/network-setups, which should be your starting point, though the setups will rely on other parts of the repository, as you will find out in the instructions given on this page.

    Securing Components

    Notes
    The relays and drivers corresponding to the different test networks you will encounter below can be run with or without TLS enabled. But the default files used in the demonstrations assume that either all relays and drivers are TLS-enabled or none are. Therefore, you should determine at the outset whether or not you wish to run the entire set of components in TLS-enabled mode, and select appropriate commands in the provided instructions.

    Hyperledger Fabric Components

    Using the sequence of instructions below, you can start two separate Fabric networks, each with a single channel and application contract (chaincode). You can also start an interoperation contract, a relay and a driver acting on behalf of each network. You can build a Fabric CLI tool with which you can initialize both networks' ledgers with access control policies, foreign networks' security groups (i.e., membership providers' certificate chains), and some sample key-value pairs that can be shared during subsequent interoperation flows.

    Fabric Network

    The code for this lies in the tests/network-setups folder.

    This folder contains code to create and launch networks network1 and network2 of identical specifications:

    • Network: 1 peer, 1 peer CA, 1 ordering service node, 1 ordering service CA
    • Single channel named mychannel
    • One of the following contracts deployed on mychannel, the choice depending on the interoperability mode you wish to test:
      • simplestate (Data Sharing): supports simple transactions (Create, Read, Update, Delete) involving storage and lookup of <key, value> pairs.
      • simplestatewithacl (Data Sharing): identical to simplestate but with extra security features to ensure that the Weaver infrastructure cannot be bypassed by a malicious client of the network.
      • simpleasset (Asset Exchange): supports creation, modification, transfer, and deletion, as well as locking, unlocking, and claiming, of simple bonds and tokens (examples of non-fungible and fungible assets respectively).
      • simpleassetandinterop (Asset Exchange): identical to simpleasset but where the locking, unlocking, and claiming logic is imported as a library in the chaincode rather than available in the common Fabric Interoperation Chaincode (a Weaver component).
      • simpleassettransfer (Asset Exchange or Asset Transfer): augmentation of simpleasset with asset pledging, claiming, and reclaiming features for cross-network transfers.
    Notes
    For new users, we recommend testing the Data Sharing feature first with the simplestate contract. To test the other modes, you can simply tear down the Fabric networks and restart them with the appropriate chaincodes installed.

    Follow the instructions below to build and launch the networks:

    • Navigate to the tests/network-setups/fabric/dev folder.
    • To spin up both network1 and network2 with the interoperation chaincode and the default simplestate chaincode installed, run:
      make start-interop
    • To launch the networks with a different application chaincode from the above list, run:
      make start-interop CHAINCODE_NAME=<chaincode-name>
    • To launch the networks with 2 organizations, each with a peer (this will enable more variation and experimentation, which you can attempt after testing interoperation protocols across basic network configurations), run:
      make start-interop-local PROFILE="2-nodes"
    Notes
    If you do not wish to test Fabric-Fabric interoperation, you can choose to launch only one of the two networks along with its interoperation chaincode. For network1, run make start-interop-network1, and for network2, run make start-interop-network2
    If you wish to enable end-to-end confidentiality by default in the interoperation modules that are deployed during network launch, set the environment variable E2E_CONFIDENTIALITY to true in the command line as follows: E2E_CONFIDENTIALITY=true make start-interop

    For more information, refer to the associated README.

    Troubleshooting Tips:

    • If you see any errors during the launches, re-check the prerequisites (software installations and credentials). Ensure your network connection is working. As a safe bet, you can retry after cleanup: kill and remove all Docker containers and associated volumes.

    Fabric Relay

    The relay is a module acting on behalf of a network, enabling interoperation flows with other networks by communicating with their relays. The code for this lies in the core/relay folder.

    Navigate to the core/relay folder and run a relay as follows:

    • The docker-compose.yaml in this folder is minimally configured with default values. To modify it for use with the Fabric testnets, run:
      make convert-compose-method2
    • (The .env.n1 and .env.n1.tls files in the docker/testnet-envs directory contain environment variables used by the network1 relay at startup and runtime.)
    • (The .env.n2 and .env.n2.tls files in the docker/testnet-envs directory contain environment variables used by the network2 relay at startup and runtime.)
    • To deploy the relay server for network1 without TLS, run:
      make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.n1'
      Instead, to deploy the relay server with TLS, run:
      make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.n1.tls'
    • To deploy the relay server for network2 without TLS, run:
      make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.n2'
      Instead, to deploy the relay server with TLS, run:
      make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.n2.tls'
    • After launching the relay(s), you can revert the docker-compose.yaml changes by running:
      make convert-compose-method1

    For more information, see the relay-docker README.

    Fabric Driver

    A driver is a DLT-specific plugin invoked by the relay while channelling external data queries to the local peer network and collecting a response with proofs. The Fabric driver is built as a Fabric client application on the fabric-network NPM package. -The code for this lies in the core/drivers/fabric-driver folder.

    Use the following steps to run Fabric drivers in Docker containers:

    • Navigate to the core/drivers/fabric-driver folder.
    • The .env.n1 and .env.n1.tls files in the docker-testnet-envs directory contain environment variables used by the network1 driver at startup and runtime. Edit either of these files (depending on whether you wish to start the relay with or without TLS) as follows:
      • Replace <PATH-TO-WEAVER> with the absolute path of the weaver-dlt-interoperability clone folder.
    • Repeat the above step for .env.n2 or .env.n2.tls in docker-testnet-envs directory, which contain environment variables for the network2 driver.
    • To deploy the Fabric driver for network1 without TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.n1' NETWORK_NAME=$(grep NETWORK_NAME docker-testnet-envs/.env.n1 | cut -d '=' -f 2)
      Instead, to deploy the driver with TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.n1.tls' NETWORK_NAME=$(grep NETWORK_NAME docker-testnet-envs/.env.n1.tls | cut -d '=' -f 2)
    • To deploy the Fabric driver for network2 without TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.n2' NETWORK_NAME=$(grep NETWORK_NAME docker-testnet-envs/.env.n2 | cut -d '=' -f 2)
      Instead, to deploy the driver with TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.n2.tls' NETWORK_NAME=$(grep NETWORK_NAME docker-testnet-envs/.env.n2.tls | cut -d '=' -f 2)

    Fabric IIN Agent

    IIN Agent is a client of a member of a DLT network or security domain with special permissions to update security domain identities and configurations on the ledger via the network's interoperation module. The code for this lies in the core/identity-management/iin-agent folder. Navigate to the core/identity-management/iin-agent folder.

    Deployment

    Use the following steps to run Fabric IIN Agents in Docker containers:

    • The .env.n1.org1 and .env.n1.org1.tls files in the docker-testnet/envs directory contain environment variables used by the iin-agent of org1 of network1 at startup and runtime. Edit either of these files (depending on whether you wish to start the relay with or without TLS) as follows:
      • Replace <PATH-TO-WEAVER> with the absolute path of the weaver-dlt-interoperability clone folder.
      • If Fabric network was started with 1 org, and IIN Agents are to be started with TLS enabled, update the DNS_CONFIG_PATH variable as:
        DNS_CONFIG_PATH=./docker-testnet/configs/dnsconfig-tls.json
      • If Fabric network was started with 2 orgs, and IIN Agents are to be started without TLS, update the DNS_CONFIG_PATH variable as
        DNS_CONFIG_PATH=./docker-testnet/configs/dnsconfig-2-nodes.json
      • If Fabric network was started with 2 orgs and IIN Agents are to be started with TLS enabled, update the DNS_CONFIG_PATH variable as:
        DNS_CONFIG_PATH=./docker-testnet/configs/dnsconfig-tls-2-nodes.json
    • Repeat the above steps for all other environment variable files (depending upon whether tls is enabled) in docker-testnet/envs directory.
    • To deploy the Fabric IIN Agent for org1 of network1 without TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n1.org1' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n1.org1 | cut -d '=' -f 2)
      Instead, to deploy the IIN Agent with TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n1.org1.tls' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n1.org1.tls | cut -d '=' -f 2)
    • To deploy the Fabric IIN Agent for org2 of network1 without TLS (only required if Fabric network was started with 2 orgs), run:
      make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n1.org2' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n1.org2 | cut -d '=' -f 2)
      Instead, to deploy the IIN Agent with TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n1.org2.tls' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n1.org2.tls | cut -d '=' -f 2)
    • To deploy the Fabric IIN Agent for org1 of network2 without TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n2.org1' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n2.org1 | cut -d '=' -f 2)
      Instead, to deploy the IIN Agent with TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n2.org1.tls' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n2.org1.tls | cut -d '=' -f 2)
    • To deploy the Fabric IIN Agent for org2 of network2 without TLS (only required if Fabric network was started with 2 orgs), run:
      make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n2.org2' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n2.org2 | cut -d '=' -f 2)
      Instead, to deploy the IIN Agent with TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n2.org2.tls' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n2.org2.tls | cut -d '=' -f 2)

    Fabric Client (Application)

    The CLI is used to interact with a Fabric network, configure it and run chaincode transactions to record data on the channel ledger or query data. It is also used to interact with remote networks through the relay in order to trigger an interoperation flow for data request and acceptance.

    The fabric-cli Node.js source code is located in the samples/fabric/fabric-cli folder and the Golang source code in the samples/fabric/go-cli folder.

    Prerequisites

    If you are using a Linux system, make sure that lib64 is installed.

    Notes
    For the Node.js version of the fabric-cli, the setup and running instructions below were tested with all Node.js versions from v11.14.0 to v14.17.3.

    Installation

    You can install fabric-cli as follows (for both the Node.js and Golang versions):

    • Navigate to the samples/fabric/fabric-cli folder or the samples/fabric/go-cli folder.
    • Create .npmrc from template .npmrc.template, by replacing <personal-access-token> with yours created above..
    • Run the following to install dependencies (for the Node.js version) or the executable (for the Golang version):
      make build
    • Use the fabric-cli executable in the bin folder for subsequent actions.

    Corda Components

    Using the sequence of instructions below, you can start a Corda network and run an application CorDapp on it. You can also run an interoperation CorDapp, a relay and a driver acting on behalf of the network. You can initialize the network's vault with access control policies, foreign networks' security groups (i.e., membership providers' certificate chains), and some sample state values that can be shared during subsequent interoperation flows.

    Corda Network

    The Corda networks' code lies in the tests/network-setups/corda folder. You can launch two separate Corda networks, namely Corda_Network and Corda_Network2. Each network runs the samples/corda/corda-simple-application CorDapp by default, which maintains a state named SimpleState containing a set of key-value pairs (of strings).

    The following steps will, in addition to launching the network, build the CorDapp and a Corda client in samples/corda/corda-simple-application/client.

    Running with Interoperation CorDapp from Github Packages

    Follow the instructions below to build and launch the network:

    • Navigate to the tests/network-setups/corda folder.
    • Create copy of github.properties.template as github.properties.
    • Replace <GITHUB email> with your github email, and <GITHUB Personal Access Token> with the access token created above.
    • To spin up the Corda networks with the Interoperation CorDapps:
      • Each consisting of 1 node and a notary (for data-transfer), run:
        make start
      • Each consisting of 2 nodes and a notary (for asset-exchange/transfer), run:
        make start PROFILE="2-nodes"
      • Each consisting of 3 nodes and a notary (for asset-exchange/transfer), run:
        make start PROFILE="3-nodes"

    You should see the following message in the terminal:

    Waiting for network node services to start

    The Corda nodes and notary may take a while (several minutes on memory-constrained systems) to start. If they start up successfully, you should something like the following for each network, though the number of node entries will depend on the profile you used to start the network with (replace <network-name> with Corda_Network or Corda_Network2):

    PartyA node services started for network <network-name>
    PartyB node services started for network <network-name>
    PartyC node services started for network <network-name>
    Notary node services started for network <network-name>

    Corda Relay

    Navigate to the core/relay folder and run a relay for Corda_Network and/or Corda_Network2 in Docker container as follows:

    • The docker-compose.yaml in this folder is minimally configured with default values. To modify it for use with the Fabric testnets, run:

      make convert-compose-method2
    • (The .env.corda and .env.corda.tls files in the docker/testnet-envs directory contain environment variables used by the Corda_Network relay at startup and runtime.)

    • (The .env.corda2 and .env.corda2.tls files in the docker/testnet-envs directory contain environment variables used by the Corda_Network2 relay at startup and runtime.)

    • To deploy the relay server for Corda_Network without TLS, run:

      make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.corda'

      Instead, to deploy the relay server with TLS, run:

      make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.corda.tls'
    • To deploy the relay server for Corda_Network2 without TLS, run:

      make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.corda2'

      Instead, to deploy the relay server with TLS, run:

      make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.corda2.tls'
    • After launching the relay(s), you can revert the docker-compose.yaml changes by running:

      make convert-compose-method1

    Corda Driver

    Use the following steps to run Corda drivers in Docker containers:

    • Navigate to the core/drivers/corda-driver folder.
    • (The .env.corda and .env.corda.tls files in the docker-testnet-envs contain environment variables used by the Corda_Network driver at startup and runtime.)
    • (The .env.corda2 and .env.corda2.tls files in the docker-testnet-envs contain environment variables used by the Corda_Network2 driver at startup and runtime.)
    • To deploy the Corda driver for Corda_Network without TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.corda'
      Instead, to deploy the driver with TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.corda.tls'
      If the driver starts successfully, it should log the following message when you run docker logs corda-driver-Corda_Network:
      Corda driver gRPC server started. Listening on port 9099
    • To deploy the Corda driver for Corda_Network2 without TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.corda2'
      Instead, to deploy the driver with TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.corda2.tls'
      If the driver starts successfully, it should log the following message when you run docker logs corda-driver-Corda_Network2:
      Corda driver gRPC server started. Listening on port 9098

    Tear Down the Setup

    Bring down the various components as follows (Navigate to the root folder of your clone of the Weaver repository):

    Relay

    To bring down the relays (for all 3 networks), run:

    cd core/relay
    make convert-compose-method2
    make stop COMPOSE_ARG='--env-file docker/testnet-envs/.env.n1'
    make stop COMPOSE_ARG='--env-file docker/testnet-envs/.env.n2'
    make stop COMPOSE_ARG='--env-file docker/testnet-envs/.env.corda'
    make stop COMPOSE_ARG='--env-file docker/testnet-envs/.env.corda2'
    make convert-compose-method1
    cd -

    Fabric Driver

    To bring down the fabric drivers (for both networks), run:

    cd core/drivers/fabric-driver
    make stop COMPOSE_ARG='--env-file docker-testnet-envs/.env.n1'
    make stop COMPOSE_ARG='--env-file docker-testnet-envs/.env.n2'
    cd -

    Corda Driver

    To bring down the corda driver, run:

    cd core/drivers/corda-driver
    make stop COMPOSE_ARG='--env-file docker-testnet-envs/.env.corda'
    make stop COMPOSE_ARG='--env-file docker-testnet-envs/.env.corda2'
    cd -

    Corda Network

    To bring down the Corda network:

    cd tests/network-setups/corda
    make clean
    cd -

    Fabric Network

    To bring down both of the Fabric networks along with weaver components:

    cd tests/network-setups/fabric/dev
    make clean
    cd -
    - - +The code for this lies in the core/drivers/fabric-driver folder.

    Use the following steps to run Fabric drivers in Docker containers:

    • Navigate to the core/drivers/fabric-driver folder.
    • The .env.n1 and .env.n1.tls files in the docker-testnet-envs directory contain environment variables used by the network1 driver at startup and runtime. Edit either of these files (depending on whether you wish to start the relay with or without TLS) as follows:
      • Replace <PATH-TO-WEAVER> with the absolute path of the weaver-dlt-interoperability clone folder.
    • Repeat the above step for .env.n2 or .env.n2.tls in docker-testnet-envs directory, which contain environment variables for the network2 driver.
    • To deploy the Fabric driver for network1 without TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.n1' NETWORK_NAME=$(grep NETWORK_NAME docker-testnet-envs/.env.n1 | cut -d '=' -f 2)
      Instead, to deploy the driver with TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.n1.tls' NETWORK_NAME=$(grep NETWORK_NAME docker-testnet-envs/.env.n1.tls | cut -d '=' -f 2)
    • To deploy the Fabric driver for network2 without TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.n2' NETWORK_NAME=$(grep NETWORK_NAME docker-testnet-envs/.env.n2 | cut -d '=' -f 2)
      Instead, to deploy the driver with TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.n2.tls' NETWORK_NAME=$(grep NETWORK_NAME docker-testnet-envs/.env.n2.tls | cut -d '=' -f 2)

    Fabric IIN Agent

    IIN Agent is a client of a member of a DLT network or security domain with special permissions to update security domain identities and configurations on the ledger via the network's interoperation module. The code for this lies in the core/identity-management/iin-agent folder. Navigate to the core/identity-management/iin-agent folder.

    Deployment

    Use the following steps to run Fabric IIN Agents in Docker containers:

    • The .env.n1.org1 and .env.n1.org1.tls files in the docker-testnet/envs directory contain environment variables used by the iin-agent of org1 of network1 at startup and runtime. Edit either of these files (depending on whether you wish to start the relay with or without TLS) as follows:
      • Replace <PATH-TO-WEAVER> with the absolute path of the weaver-dlt-interoperability clone folder.
      • If Fabric network was started with 1 org, and IIN Agents are to be started with TLS enabled, update the DNS_CONFIG_PATH variable as:
        DNS_CONFIG_PATH=./docker-testnet/configs/dnsconfig-tls.json
      • If Fabric network was started with 2 orgs, and IIN Agents are to be started without TLS, update the DNS_CONFIG_PATH variable as
        DNS_CONFIG_PATH=./docker-testnet/configs/dnsconfig-2-nodes.json
      • If Fabric network was started with 2 orgs and IIN Agents are to be started with TLS enabled, update the DNS_CONFIG_PATH variable as:
        DNS_CONFIG_PATH=./docker-testnet/configs/dnsconfig-tls-2-nodes.json
    • Repeat the above steps for all other environment variable files (depending upon whether tls is enabled) in docker-testnet/envs directory.
    • To deploy the Fabric IIN Agent for org1 of network1 without TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n1.org1' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n1.org1 | cut -d '=' -f 2)
      Instead, to deploy the IIN Agent with TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n1.org1.tls' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n1.org1.tls | cut -d '=' -f 2)
    • To deploy the Fabric IIN Agent for org2 of network1 without TLS (only required if Fabric network was started with 2 orgs), run:
      make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n1.org2' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n1.org2 | cut -d '=' -f 2)
      Instead, to deploy the IIN Agent with TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n1.org2.tls' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n1.org2.tls | cut -d '=' -f 2)
    • To deploy the Fabric IIN Agent for org1 of network2 without TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n2.org1' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n2.org1 | cut -d '=' -f 2)
      Instead, to deploy the IIN Agent with TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n2.org1.tls' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n2.org1.tls | cut -d '=' -f 2)
    • To deploy the Fabric IIN Agent for org2 of network2 without TLS (only required if Fabric network was started with 2 orgs), run:
      make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n2.org2' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n2.org2 | cut -d '=' -f 2)
      Instead, to deploy the IIN Agent with TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n2.org2.tls' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n2.org2.tls | cut -d '=' -f 2)

    Fabric Client (Application)

    The CLI is used to interact with a Fabric network, configure it and run chaincode transactions to record data on the channel ledger or query data. It is also used to interact with remote networks through the relay in order to trigger an interoperation flow for data request and acceptance.

    The fabric-cli Node.js source code is located in the samples/fabric/fabric-cli folder and the Golang source code in the samples/fabric/go-cli folder.

    Prerequisites

    If you are using a Linux system, make sure that lib64 is installed.

    Notes
    For the Node.js version of the fabric-cli, the setup and running instructions below were tested with all Node.js versions from v11.14.0 to v14.17.3.

    Installation

    You can install fabric-cli as follows (for both the Node.js and Golang versions):

    • Navigate to the samples/fabric/fabric-cli folder (for the Node.js version) or the samples/fabric/go-cli folder (for the Golang version).
    • Create .npmrc from template .npmrc.template, by replacing <personal-access-token> with yours created above..
    • Run the following to install dependencies (for the Node.js version) or the executable (for the Golang version):
      make build
    • Use the fabric-cli executable in the bin folder for subsequent actions.

    Corda Components

    Using the sequence of instructions below, you can start a Corda network and run an application CorDapp on it. You can also run an interoperation CorDapp, a relay and a driver acting on behalf of the network. You can initialize the network's vault with access control policies, foreign networks' security groups (i.e., membership providers' certificate chains), and some sample state values that can be shared during subsequent interoperation flows.

    Corda Network

    The Corda networks' code lies in the tests/network-setups/corda folder. You can launch two separate Corda networks, namely Corda_Network and Corda_Network2. Each network runs the samples/corda/corda-simple-application CorDapp by default, which maintains a state named SimpleState containing a set of key-value pairs (of strings).

    The following steps will, in addition to launching the network, build the CorDapp and a Corda client in samples/corda/corda-simple-application/client.

    Running with Interoperation CorDapp from GitHub Packages

    Follow the instructions below to build and launch the network:

    • Navigate to the tests/network-setups/corda folder.
    • Create copy of github.properties.template as github.properties.
    • Replace <GITHUB email> with your GitHub email, and <GITHUB Personal Access Token> with the access token created above.
    • To spin up the Corda networks with the Interoperation CorDapps:
      • Each consisting of 1 node and a notary (for data-transfer), run:
        make start
      • Each consisting of 2 nodes and a notary (for asset-exchange/transfer), run:
        make start PROFILE="2-nodes"
      • Each consisting of 3 nodes and a notary (for asset-exchange/transfer), run:
        make start PROFILE="3-nodes"

    You should see the following message in the terminal:

    Waiting for network node services to start

    The Corda nodes and notary may take a while (several minutes on memory-constrained systems) to start. If they start up successfully, you should something like the following for each network, though the number of node entries will depend on the profile you used to start the network with (replace <network-name> with Corda_Network or Corda_Network2):

    PartyA node services started for network <network-name>
    PartyB node services started for network <network-name>
    PartyC node services started for network <network-name>
    Notary node services started for network <network-name>

    Corda Relay

    Navigate to the core/relay folder and run a relay for Corda_Network and/or Corda_Network2 in Docker container as follows:

    • The docker-compose.yaml in this folder is minimally configured with default values. To modify it for use with the Fabric testnets, run:

      make convert-compose-method2
    • (The .env.corda and .env.corda.tls files in the docker/testnet-envs directory contain environment variables used by the Corda_Network relay at startup and runtime.)

    • (The .env.corda2 and .env.corda2.tls files in the docker/testnet-envs directory contain environment variables used by the Corda_Network2 relay at startup and runtime.)

    • To deploy the relay server for Corda_Network without TLS, run:

      make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.corda'

      Instead, to deploy the relay server with TLS, run:

      make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.corda.tls'
    • To deploy the relay server for Corda_Network2 without TLS, run:

      make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.corda2'

      Instead, to deploy the relay server with TLS, run:

      make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.corda2.tls'
    • After launching the relay(s), you can revert the docker-compose.yaml changes by running:

      make convert-compose-method1

    Corda Driver

    Use the following steps to run Corda drivers in Docker containers:

    • Navigate to the core/drivers/corda-driver folder.
    • (The .env.corda and .env.corda.tls files in the docker-testnet-envs contain environment variables used by the Corda_Network driver at startup and runtime.)
    • (The .env.corda2 and .env.corda2.tls files in the docker-testnet-envs contain environment variables used by the Corda_Network2 driver at startup and runtime.)
    • To deploy the Corda driver for Corda_Network without TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.corda'
      Instead, to deploy the driver with TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.corda.tls'
      If the driver starts successfully, it should log the following message when you run docker logs corda-driver-Corda_Network:
      Corda driver gRPC server started. Listening on port 9099
    • To deploy the Corda driver for Corda_Network2 without TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.corda2'
      Instead, to deploy the driver with TLS, run:
      make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.corda2.tls'
      If the driver starts successfully, it should log the following message when you run docker logs corda-driver-Corda_Network2:
      Corda driver gRPC server started. Listening on port 9098

    Tear Down the Setup

    Bring down the various components as follows (Navigate to the root folder of your clone of the Weaver repository):

    Relay

    To bring down the relays (for all 3 networks), run:

    cd core/relay
    make convert-compose-method2
    make stop COMPOSE_ARG='--env-file docker/testnet-envs/.env.n1'
    make stop COMPOSE_ARG='--env-file docker/testnet-envs/.env.n2'
    make stop COMPOSE_ARG='--env-file docker/testnet-envs/.env.corda'
    make stop COMPOSE_ARG='--env-file docker/testnet-envs/.env.corda2'
    make convert-compose-method1
    cd -

    Fabric Driver

    To bring down the fabric drivers (for both networks), run:

    cd core/drivers/fabric-driver
    make stop COMPOSE_ARG='--env-file docker-testnet-envs/.env.n1'
    make stop COMPOSE_ARG='--env-file docker-testnet-envs/.env.n2'
    cd -

    Corda Driver

    To bring down the corda driver, run:

    cd core/drivers/corda-driver
    make stop COMPOSE_ARG='--env-file docker-testnet-envs/.env.corda'
    make stop COMPOSE_ARG='--env-file docker-testnet-envs/.env.corda2'
    cd -

    Corda Network

    To bring down the Corda network:

    cd tests/network-setups/corda
    make clean
    cd -

    Fabric Network

    To bring down both of the Fabric networks along with weaver components:

    cd tests/network-setups/fabric/dev
    make clean
    cd -
    + + \ No newline at end of file diff --git a/docs/external/getting-started/test-network/setup-packages/index.html b/docs/external/getting-started/test-network/setup-packages/index.html index d726a7d52..fb3fec99e 100644 --- a/docs/external/getting-started/test-network/setup-packages/index.html +++ b/docs/external/getting-started/test-network/setup-packages/index.html @@ -4,16 +4,16 @@ Setup with Imported Weaver Components | Weaver: DLT Interoperability Framework - - - + + +
    -

    Setup with Imported Weaver Components

    In this document, we detail the steps using which you can bring up networks using the default configuration settings and by fetching pre-built Weaver interoperation modules, SDK libraries, and relay drivers from Github Package repositories. To customize these settings (e.g., hostnames, ports), refer to the Advanced Configuration page.

    Notes
    The default configuration is for a development setup, therefore all components are run on localhost, many within Docker containers.

    Follow the instructions below to build and run components followed by interoperation flows. These instructions have been tested on Ubuntu Linux (bash shell) and Mac OS. In general, they should work on any system and shell as long as the various dependencies have been installed and configured.

    Prerequisites

    Software

    Before starting, make sure you have the following software installed on your host machine:

    Credentials

    Make sure you have an SSH or GPG key registered in https://github.com to allow seamless cloning of repositories (at present, various setup scripts clone repositories using the https:// prefix but this may change to git@ in the future).

    Create a personal access token with read:packages access in github in order to use modules published in github packages. Refer Creating a Personal Access Token for help.

    Getting the Code and Documentation

    Clone the weaver-dlt-interoperability repository. The code to get a basic test network up and running and test data-sharing interoperation flows lies in the subfolder tests/network-setups, which should be your starting point, though the setups will rely on other parts of the repository, as you will find out in the instructions given on this page.

    Securing Components

    Notes
    The relays and drivers corresponding to the different test networks you will encounter below can be run with or without TLS enabled. But the default files used in the demonstrations assume that either all relays and drivers are TLS-enabled or none are. Therefore, you should determine at the outset whether or not you wish to run the entire set of components in TLS-enabled mode, and select appropriate commands in the provided instructions.

    Hyperledger Fabric Components

    Using the sequence of instructions below, you can start two separate Fabric networks, each with a single channel and application contract (chaincode). You can also start an interoperation contract, a relay, and a driver acting on behalf of each network. You can build a Fabric CLI tool with which you can initialize both networks' ledgers with access control policies, foreign networks' security groups (i.e., membership providers' certificate chains), and some sample key-value pairs that can be shared during subsequent interoperation flows.

    Fabric Network

    The code for this lies in the tests/network-setups folder.

    This folder contains code to create and launch networks network1 and network2 of identical specifications:

    • Network: 1 peer, 1 peer CA, 1 ordering service node, 1 ordering service CA
    • Single channel named mychannel
    • One of the following contracts deployed on mychannel, the choice depending on the interoperability mode you wish to test:
      • simplestate (Data Sharing): supports simple transactions (Create, Read, Update, Delete) involving storage and lookup of <key, value> pairs.
      • simplestatewithacl (Data Sharing): identical to simplestate but with extra security features to ensure that the Weaver infrastructure cannot be bypassed by a malicious client of the network.
      • simpleasset (Asset Exchange): supports creation, modification, transfer, and deletion, as well as locking, unlocking, and claiming, of simple bonds and tokens (examples of non-fungible and fungible assets respectively).
      • simpleassetandinterop (Asset Exchange): identical to simpleasset but where the locking, unlocking, and claiming logic is imported as a library in the chaincode rather than available in the common Fabric Interoperation Chaincode (a Weaver component).
      • simpleassettransfer (Asset Exchange or Asset Transfer): augmentation of simpleasset with asset pledging, claiming, and reclaiming features for cross-network transfers.
    Notes
    For new users, we recommend testing the Data Sharing feature first with the simplestate contract. To test the other modes, you can simply tear down the Fabric networks and restart them with the appropriate chaincodes installed.

    Follow the instructions below to build and launch the networks:

    • Navigate to the tests/network-setups/fabric/dev folder.
    • To spin up both network1 and network2 with the interoperation chaincode and the default simplestate chaincode installed, run:
      make start-interop
    • To launch the networks with a different application chaincode from the above list, run:
      make start-interop CHAINCODE_NAME=<chaincode-name>
    • To launch the networks with 2 organizations, each with a peer (this will enable more variation and experimentation, which you can attempt after testing interoperation protocols across basic network configurations), run:
      make start-interop-local PROFILE="2-nodes"
    Notes
    If you do not wish to test Fabric-Fabric interoperation, you can choose to launch only one of the two networks along with its interoperation chaincode. For network1, run make start-interop-network1, and for network2, run make start-interop-network2
    If you wish to enable end-to-end confidentiality by default in the interoperation modules that are deployed during network launch, set the environment variable E2E_CONFIDENTIALITY to true in the command line as follows: E2E_CONFIDENTIALITY=true make start-interop

    For more information, refer to the associated README.

    Troubleshooting Tips:

    • If you see any errors during the launches, re-check the prerequisites (software installations and credentials). Ensure your network connection is working. As a safe bet, you can retry after cleanup: kill and remove all Docker containers and associated volumes.

    Fabric Client (fabric-cli)

    The CLI is used to interact with a Fabric network, configure it and run chaincode transactions to record data on the channel ledger or query data. It is also used to interact with remote networks through the relay to trigger an interoperation flow for data request and acceptance.

    The fabric-cli Node.js source code is located in the samples/fabric/fabric-cli folder and the Golang source code in the samples/fabric/go-cli folder.

    Prerequisites

    If you are using a Linux system, make sure that lib64 is installed.

    Notes
    For the Node.js version of the fabric-cli, the setup and running instructions below were tested with all Node.js versions from v11.14.0 to v14.17.3.

    Installation

    You can install fabric-cli as follows (for both the Node.js and Golang versions):

    • Navigate to the samples/fabric/fabric-cli folder or the samples/fabric/go-cli folder.
    • Create .npmrc from template .npmrc.template, by replacing <personal-access-token> with yours created above..
    • Run the following to install dependencies (for the Node.js version) or the executable (for the Golang version):
      make build
    • Use the fabric-cli executable in the bin folder for subsequent actions.

    Fabric Relay

    The relay is a module acting on behalf of a network, enabling interoperation flows with other networks by communicating with their relays. -The code for this lies in the core/relay folder.

    Building

    Prerequisite: make sure Rust is already installed and that the cargo executable is in your system path (after installation of Rust, this should be available in $HOME/.cargo/bin); you can also ensure this by running source "$HOME/.cargo/env".

    Build the generic (i.e., common to all DLTs) relay module as follows:

    • Navigate to the core/relay folder.
    • Run the following:
      make
    • To avoid errors during Weaver Relay compilation, update certain packages (on which the Weaver Relay is dependent) to their latest versions as follows:
      make update-pkgs

    Deployment

    An instance or a relay can be run using a suitable configuration file. Samples are available in the core/relay/config folder.

    Run a relay for network1 as follows:

    • Navigate to the core/relay folder.
    • To launch the server without TLS, leave the configuration file config/Fabric_Relay.toml in its default state. Otherwise, edit it to set TLS flags for this relay and the other relays and drivers it will connect to in this demonstration as follows:
      .
      .
      cert_path="credentials/fabric_cert.pem"
      key_path="credentials/fabric_key"
      tls=true
      .
      .
      [relays]
      [relays.Corda_Relay]
      hostname="localhost"
      port="9081"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      [relays.Corda_Relay2]
      hostname="localhost"
      port="9082"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      [relays.Fabric_Relay2]
      hostname="localhost"
      port="9083"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      .
      .
      [drivers]
      [drivers.Fabric]
      hostname="localhost"
      port="9090"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      .
      .
    • To launch the server, simply run the following:
      RELAY_CONFIG=config/Fabric_Relay.toml cargo run --bin server

    Run a relay for network2 as follows (do this only if you have launched both Fabric networks network1 and network2 and wish to test interoperation between them)

    • Navigate to the core/relay folder.
    • To launch the server without TLS, leave the configuration file config/Fabric_Relay2.toml in its default state. Otherwise, edit it to set TLS flags for this relay and the other relays and drivers it will connect to in this demonstration as follows:
      .
      .
      cert_path="credentials/fabric_cert.pem"
      key_path="credentials/fabric_key"
      tls=true
      .
      .
      [relays]
      [relays.Corda_Relay]
      hostname="localhost"
      port="9081"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      [relays.Corda_Relay2]
      hostname="localhost"
      port="9082"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      [relays.Fabric_Relay]
      hostname="localhost"
      port="9080"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      .
      .
      [drivers]
      [drivers.Fabric]
      hostname="localhost"
      port="9095"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      .
      .
    • To launch the server, simply run the following:
      RELAY_CONFIG=config/Fabric_Relay2.toml cargo run --bin server

    For more information, see the relay README.

    Fabric Driver

    A driver is a DLT-specific plugin invoked by the relay while conveying external data queries to the local peer network and collecting a response with proofs. The Fabric driver is built as a Fabric client application on the fabric-network NPM package. -The code for this lies in the core/drivers/fabric-driver folder.

    Configuring

    In the core/drivers/fabric-driver folder, copy .env.template to .env and update CONNECTION_PROFILE to point to the connection profile of the Fabric network (e.g. <PATH-TO-WEAVER>/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json)

    Configure fabric-driver for network1 as follows:

    • Navigate to the core/drivers/fabric-driver folder.
    • Create a .env file by copying .env.template and setting suitable parameter values:
      • The CONNECTION_PROFILE should point to the absolute path of the connection profile for network1.
        • For this exercise, specify the path <PATH-TO-WEAVER>/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json (you must specify the full absolute path here).
        • <PATH-TO-WEAVER> here is the absolute path of the weaver-dlt-interoperability clone folder.
      • If you wish to start the driver without TLS, set the following parameter values:
        RELAY_TLS=false
        RELAY_TLSCA_CERT_PATH=
        DRIVER_TLS=false
        DRIVER_TLS_CERT_PATH=
        DRIVER_TLS_KEY_PATH=
        Otherwise, if you wish to start the driver with TLS enabled, set the following parameter values (replace <PATH-TO-WEAVER> with the absolute path of the weaver-dlt-interoperability clone folder):
        RELAY_TLS=true
        RELAY_TLSCA_CERT_PATH=<PATH-TO-WEAVER>/core/relay/credentials/fabric_ca_cert.pem
        DRIVER_TLS=true
        DRIVER_TLS_CERT_PATH=<PATH-TO-WEAVER>/core/relay/credentials/fabric_cert.pem
        DRIVER_TLS_KEY_PATH=<PATH-TO-WEAVER>/core/relay/credentials/fabric_key
      • Leave the default values unchanged for the other parameters. The relay and driver endpoints as well as the network name are already specified.

    Building

    Build the Fabric driver module as follows:

    • Navigate to the core/drivers/fabric-driver folder.
    • Create .npmrc from template .npmrc.template, by replacing <personal-access-token> with yours created above.
    • Run the following:
      make build

    Running

    Run a Fabric driver for network1 as follows:

    • Navigate to the core/drivers/fabric-driver folder.
    • Run the following:
      npm run dev

    Run a Fabric driver for network2 as follows (do this only if you wish to test interoperation between the two Fabric networks network1 and network2)

    • Navigate to the core/drivers/fabric-driver folder.
    • Run the following:
      CONNECTION_PROFILE=<PATH-TO-WEAVER>/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/connection-org1.json NETWORK_NAME=network2 RELAY_ENDPOINT=localhost:9083 DRIVER_ENDPOINT=localhost:9095 npm run dev
    Notes
    The variables we specified earlier in the .env for network1 are now passed in the command line. Alternatively, you can make a copy of the fabric-driver folder with a different name and create a separate .env file within it that contains links to the connection profile, relay, and driver for network2.

    Fabric IIN Agent

    IIN Agent is a client of a member of a DLT network or security domain with special permissions to update security domain identities and configurations on the ledger via the network's interoperation module. The code for this lies in the core/identity-management/iin-agent folder. Navigate to the core/identity-management/iin-agent folder.

    Building

    To build the IIN Agent, run:

    make build-local

    Configuration

    Ledger config file specifies ledger specific IIN Agent details such as identity and which network and organization to connect to.

    1. To create config file for Org1MSP's Fabric IIN Agent of network1, follow the steps:

      • Create copy of template config file for Fabric IIN Agent: src/fabric-ledger/config.json.template, say to location src/fabric-ledger/config-n1-org1.json.
      • Replace <path-to-connection-profile> with <PATH-TO-WEAVER>/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json, where replace <PATH-TO-WEAVER> with the location of your clone of Weaver.
      • Set mspId as Org1MSP.
      • Set agent.affiliation as org1.department1.
    2. To create config file for Org2MSP's Fabric IIN Agent of network1, repeat Step 1 with different name for config file, say src/fabric-ledger/config-n1-org2.json, and replace org1 with org2 and Org1MSP with Org2MSP.

    3. To create config file for Org1MSP's Fabric IIN Agent of network2, repeat Step 1 with different name for config file, say src/fabric-ledger/config-n2-org1.json, and replace network1 with network2.

    4. To create config file for Org2MSP's Fabric IIN Agent of network2, repeat Step 1 with different name for config file, say src/fabric-ledger/config-n2-org2.json, and replace network1 with network2, org1 with org2 and Org1MSP with Org2MSP.

    Security Domain Configuration

    Security Domain config file specifies the scope of security domain, which can be a channel in Fabric networks or list of nodes. File docker-testnet/configs/security-domain-config.json can be used for Weaver testnets.

    DNS Configuration

    To allow an IIN Agent's to be able to discover other IIN Agents, a config file for DNS is required. Create one dnsconfig.json by creating a copy of template dnsconfig.json.template, and replace the values with:

    • If Fabric networks are started with 1 org, and IIN Agent are to be started without TLS, use following values:
    {
    "network1": {
    "Org1MSP": {
    "endpoint": "localhost:9500",
    "tls": false,
    "tlsCACertPath": ""
    }
    },
    "network2": {
    "Org1MSP": {
    "endpoint": "localhost:9501",
    "tls": false,
    "tlsCACertPath": ""
    }
    }
    }
    • If Fabric networks are started with 1 org, and IIN Agent are to be started with TLS, use following values:
    {
    "network1": {
    "Org1MSP": {
    "endpoint": "localhost:9500",
    "tls": true,
    "tlsCACertPath": "../../relay/credentials/fabric_ca_cert.pem"
    }
    },
    "network2": {
    "Org1MSP": {
    "endpoint": "localhost:9501",
    "tls": true,
    "tlsCACertPath": "../../relay/credentials/fabric_ca_cert.pem"
    }
    }
    }
    • If Fabric networks are started with 2 orgs, and IIN Agent are to be started without TLS, use following values:
    {
    "network1": {
    "Org1MSP": {
    "endpoint": "localhost:9500",
    "tls": false,
    "tlsCACertPath": ""
    },
    "Org2MSP": {
    "endpoint": "localhost:9510",
    "tls": false,
    "tlsCACertPath": ""
    }
    },
    "network2": {
    "Org1MSP": {
    "endpoint": "localhost:9501",
    "tls": false,
    "tlsCACertPath": ""
    },
    "Org2MSP": {
    "endpoint": "localhost:9511",
    "tls": false,
    "tlsCACertPath": ""
    }
    }
    }
    • If Fabric networks are started with 2 orgs, and IIN Agent are to be started with TLS, use following values:
    {
    "network1": {
    "Org1MSP": {
    "endpoint": "localhost:9500",
    "tls": true,
    "tlsCACertPath": "../../relay/credentials/fabric_ca_cert.pem"
    },
    "Org2MSP": {
    "endpoint": "localhost:9510",
    "tls": true,
    "tlsCACertPath": "../../relay/credentials/fabric_ca_cert.pem"
    }
    },
    "network2": {
    "Org1MSP": {
    "endpoint": "localhost:9501",
    "tls": true,
    "tlsCACertPath": "../../relay/credentials/fabric_ca_cert.pem"
    },
    "Org2MSP": {
    "endpoint": "localhost:9511",
    "tls": true,
    "tlsCACertPath": "../../relay/credentials/fabric_ca_cert.pem"
    }
    }
    }
    Notes
    The variables we specified earlier in the .env for network1 are now passed in the command line. Alternatively, you can make a copy of the fabric-driver folder with a different name and create a separate .env file within it that contains links to the connection profile, relay, and driver for network2.

    Environment Variables

    To configure environment variables for Org1MSP's Fabric IIN Agent of network1, follow the steps:

    1. Create a copy of .env.template as .env, and update following values based on previous configuration file paths:
    IIN_AGENT_ENDPOINT=localhost:9500
    MEMBER_ID=Org1MSP
    SECURITY_DOMAIN=network1
    DLT_TYPE=fabric
    CONFIG_PATH=./src/fabric-ledger/config-n1-org1.json
    DNS_CONFIG_PATH=./dnsconfig.json
    SECURITY_DOMAIN_CONFIG_PATH=./docker-testnet/configs/security-domain-config.json
    WEAVER_CONTRACT_ID=interop
    AUTO_SYNC=true
    1. If IIN Agent has to be started with TLS enabled, also update following values:
    IIN_AGENT_TLS=false
    IIN_AGENT_TLS_CERT_PATH=../../relay/credentials/fabric_cert.pem
    IIN_AGENT_TLS_KEY_PATH=../../relay/credentials/fabric_key

    Deployment

    Use the following steps to run Fabric IIN Agents in host machine:

    • To start IIN Agent for Org1MSP of network1, run:
    npm run dev
    • To start IIN Agent for Org2MSP of network1 (only required if Fabric network was started with 2 orgs), run:
    IIN_AGENT_ENDPOINT=localhost:9510 MEMBER_ID=Org2MSP CONFIG_PATH=./src/fabric-ledger/config-n1-org2.json npm run dev
    • To start IIN Agent for Org1MSP of network2, run:
    IIN_AGENT_ENDPOINT=localhost:9501 SECURITY_DOMAIN=network2 CONFIG_PATH=./src/fabric-ledger/config-n2-org1.json npm run dev
    • To start IIN Agent for Org2MSP of network2 (only required if Fabric network was started with 2 orgs), run:
    IIN_AGENT_ENDPOINT=localhost:9511 MEMBER_ID=Org2MSP SECURITY_DOMAIN=network2 CONFIG_PATH=./src/fabric-ledger/config-n2-org2.json npm run dev

    Corda Components

    Using the sequence of instructions below, you can start a Corda network and run an application CorDapp on it. You can also run an interoperation CorDapp, a relay and a driver acting on behalf of the network. You can initialize the network's vault with access control policies, foreign networks' security groups (i.e., membership providers' certificate chains), and some sample state values that can be shared during subsequent interoperation flows.

    Corda Network

    The Corda networks' code lies in the tests/network-setups/corda folder. You can launch two separate Corda networks, namely Corda_Network and Corda_Network2. Each network runs the samples/corda/corda-simple-application CorDapp by default, which maintains a state named SimpleState containing a set of key-value pairs (of strings).

    The following steps will, in addition to launching the network, build the CorDapp and a Corda client in samples/corda/corda-simple-application/client.

    Running with Interoperation CorDapp from Github Packages

    Follow the instructions below to build and launch the network:

    • Navigate to the tests/network-setups/corda folder.
    • Create a copy of github.properties.template as github.properties.
    • Replace <GITHUB email> with your github email, and <GITHUB Personal Access Token> with the access token created above.
    • To spin up the Corda networks with the Interoperation CorDapps:
      • Each consisting of 1 node and a notary (for data-transfer), run:
        make start
      • Each consisting of 2 nodes and a notary (for asset-exchange/transfer), run:
        make start PROFILE="2-nodes"
      • Each consisting of 3 nodes and a notary (for asset-exchange/transfer), run:
        make start PROFILE="3-nodes"

    You should see the following message in the terminal:

    Waiting for network node services to start

    The Corda nodes and notary may take a while (several minutes on memory-constrained systems) to start. If they start up successfully, you should something like the following for each network, though the number of node entries will depend on the profile you used to start the network with (replace <network-name> with Corda_Network or Corda_Network2):

    PartyA node services started for network <network-name>
    PartyB node services started for network <network-name>
    PartyC node services started for network <network-name>
    Notary node services started for network <network-name>

    Corda Relay

    The relay was built earlier, so you just need to use a different configuration file to start a relay for the Corda network.

    Run a relay for Corda_Network as follows:

    • Navigate to the core/relay folder.

    • (Make sure you've already built the relay by running make.)

    • To launch the server without TLS, leave the configuration file config/Corda_Relay.toml in its default state. Otherwise, edit it to set TLS flags for this relay and the other relays and drivers it will connect to in this demonstration as follows:

      .
      .
      cert_path="credentials/fabric_cert.pem"
      key_path="credentials/fabric_key"
      tls=true
      .
      .
      [relays]
      [relays.Fabric_Relay]
      hostname="localhost"
      port="9080"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      [relays.Fabric_Relay2]
      hostname="localhost"
      port="9083"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      [relays.Corda_Relay2]
      hostname="localhost"
      port="9082"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      .
      .
      [drivers]
      [drivers.Corda]
      hostname="localhost"
      port="9099"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      .
      .
    • To launch the server, simply run the following:

      RELAY_CONFIG=config/Corda_Relay.toml cargo run --bin server

      If the relay starts up successfully, the following will be logged on your terminal:

      Relay Name: "Corda_Relay"
      RelayServer listening on [::1]:9081

    Run a relay for Corda_Network2 as follows (do this only if you have launched both Corda networks Corda_Network and Corda_Network2 and wish to test interoperation between them)

    • Navigate to the core/relay folder.

    • To launch the server without TLS, leave the configuration file config/Corda_Relay2.toml in its default state. Otherwise, edit it to set TLS flags for this relay and the other relays and drivers it will connect to in this demonstration as follows:

      .
      .
      cert_path="credentials/fabric_cert.pem"
      key_path="credentials/fabric_key"
      tls=true
      .
      .
      [relays]
      [relays.Fabric_Relay]
      hostname="localhost"
      port="9080"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      [relays.Fabric_Relay2]
      hostname="localhost"
      port="9083"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      [relays.Corda_Relay]
      hostname="localhost"
      port="9081"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      .
      .
      [drivers]
      [drivers.Corda]
      hostname="localhost"
      port="9098"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      .
      .
    • To launch the server, simply run the following:

      RELAY_CONFIG=config/Corda_Relay2.toml cargo run --bin server

      If the relay starts up successfully, the following will be logged on your terminal:

      Relay Name: "Corda2_Relay"
      RelayServer listening on [::1]:9082

    Corda Driver

    The code for this lies in the core/drivers/corda-driver folder.

    Building Corda Driver

    Build the Corda driver module as follows:

    • Navigate to the core/drivers/corda-driver folder.
    • Create a copy of github.properties.template as github.properties.
    • Replace <GITHUB email> with your github email, and <GITHUB Personal Access Token> with the access token created above.
    • Run the following:
      make build

    Configuring

    Configure the drivers as follows (you can skip this if you wish to run the drivers without TLS):

    • Navigate to the core/drivers/corda-driver folder and create a .env file.
    • To run the drivers without TLS, set the following default values:
      RELAY_TLS=false
      RELAY_TLSCA_TRUST_STORE=
      RELAY_TLSCA_TRUST_STORE_PASSWORD=
      RELAY_TLSCA_CERT_PATHS=
    • To run the drivers with TLS, set the following values (replace <PATH-TO-WEAVER> with the absolute path of the weaver-dlt-interoperability clone folder):
      RELAY_TLS=true
      RELAY_TLSCA_TRUST_STORE=<PATH-TO-WEAVER>/core/relay/credentials/fabric_trust_store.jks
      RELAY_TLSCA_TRUST_STORE_PASSWORD=trelay
      RELAY_TLSCA_CERT_PATHS=<PATH-TO-WEAVER>/core/relay/credentials/fabric_ca_cert.pem

    Running

    Run a Corda driver as follows:

    • Navigate to the core/drivers/corda-driver folder.
    • Run the following to start Corda driver for Corda_Network:
      ./build/install/corda-driver/bin/corda-driver
      If the driver starts successfully, it should log the following message on your terminal:
      Corda driver gRPC server started. Listening on port 9099
    • Run the following to start Corda driver for Corda_Network2:
      DRIVER_PORT=9098 ./build/install/corda-driver/bin/corda-driver
      If the driver starts successfully, it should log the following message on your terminal:
      Corda driver gRPC server started. Listening on port 9098

    Tear Down the Setup

    Bring down the test network's components as follows:

    • Simply terminate the various relays and drivers, which are running in the foreground in different terminals
    • To bring down the running Corda network:
      • Navigate to the tests/network-setups/corda folder.
      • Run the following:
        make clean
    • To bring down all the running Fabric networks:
      • Navigate to the tests/network-setups/fabric/dev folder.
      • Run the following:
        make clean
    - - +

    Setup with Imported Weaver Components

    In this document, we detail the steps using which you can bring up networks using the default configuration settings and by fetching pre-built Weaver interoperation modules, SDK libraries, and relay drivers from GitHub Package repositories. To customize these settings (e.g., hostnames, ports), refer to the Advanced Configuration page.

    Notes
    The default configuration is for a development setup, therefore all components are run on localhost, many within Docker containers.

    Follow the instructions below to build and run components followed by interoperation flows. These instructions have been tested on Ubuntu Linux (bash shell) and Mac OS. In general, they should work on any system and shell as long as the various dependencies have been installed and configured.

    Prerequisites

    Software

    Before starting, make sure you have the following software installed on your host machine:

    Credentials

    Make sure you have an SSH or GPG key registered in https://github.com to allow seamless cloning of repositories (at present, various setup scripts clone repositories using the https:// prefix but this may change to git@ in the future).

    Create a personal access token with read:packages access in GitHub in order to use modules published in GitHub packages. Refer Creating a Personal Access Token for help.

    Getting the Code and Documentation

    Clone the weaver-dlt-interoperability repository. The code to get a basic test network up and running and test data-sharing interoperation flows lies in the subfolder tests/network-setups, which should be your starting point, though the setups will rely on other parts of the repository, as you will find out in the instructions given on this page.

    Securing Components

    Notes
    The relays and drivers corresponding to the different test networks you will encounter below can be run with or without TLS enabled. But the default files used in the demonstrations assume that either all relays and drivers are TLS-enabled or none are. Therefore, you should determine at the outset whether or not you wish to run the entire set of components in TLS-enabled mode, and select appropriate commands in the provided instructions.

    Hyperledger Fabric Components

    Using the sequence of instructions below, you can start two separate Fabric networks, each with a single channel and application contract (chaincode). You can also start an interoperation contract, a relay, and a driver acting on behalf of each network. You can build a Fabric CLI tool with which you can initialize both networks' ledgers with access control policies, foreign networks' security groups (i.e., membership providers' certificate chains), and some sample key-value pairs that can be shared during subsequent interoperation flows.

    Fabric Network

    The code for this lies in the tests/network-setups folder.

    This folder contains code to create and launch networks network1 and network2 of identical specifications:

    • Network: 1 peer, 1 peer CA, 1 ordering service node, 1 ordering service CA
    • Single channel named mychannel
    • One of the following contracts deployed on mychannel, the choice depending on the interoperability mode you wish to test:
      • simplestate (Data Sharing): supports simple transactions (Create, Read, Update, Delete) involving storage and lookup of <key, value> pairs.
      • simplestatewithacl (Data Sharing): identical to simplestate but with extra security features to ensure that the Weaver infrastructure cannot be bypassed by a malicious client of the network.
      • simpleasset (Asset Exchange): supports creation, modification, transfer, and deletion, as well as locking, unlocking, and claiming, of simple bonds and tokens (examples of non-fungible and fungible assets respectively).
      • simpleassetandinterop (Asset Exchange): identical to simpleasset but where the locking, unlocking, and claiming logic is imported as a library in the chaincode rather than available in the common Fabric Interoperation Chaincode (a Weaver component).
      • simpleassettransfer (Asset Exchange or Asset Transfer): augmentation of simpleasset with asset pledging, claiming, and reclaiming features for cross-network transfers.
    Notes
    For new users, we recommend testing the Data Sharing feature first with the simplestate contract. To test the other modes, you can simply tear down the Fabric networks and restart them with the appropriate chaincodes installed.

    Follow the instructions below to build and launch the networks:

    • Navigate to the tests/network-setups/fabric/dev folder.
    • To spin up both network1 and network2 with the interoperation chaincode and the default simplestate chaincode installed, run:
      make start-interop
    • To launch the networks with a different application chaincode from the above list, run:
      make start-interop CHAINCODE_NAME=<chaincode-name>
    • To launch the networks with 2 organizations, each with a peer (this will enable more variation and experimentation, which you can attempt after testing interoperation protocols across basic network configurations), run:
      make start-interop-local PROFILE="2-nodes"
    Notes
    If you do not wish to test Fabric-Fabric interoperation, you can choose to launch only one of the two networks along with its interoperation chaincode. For network1, run make start-interop-network1, and for network2, run make start-interop-network2
    If you wish to enable end-to-end confidentiality by default in the interoperation modules that are deployed during network launch, set the environment variable E2E_CONFIDENTIALITY to true in the command line as follows: E2E_CONFIDENTIALITY=true make start-interop

    For more information, refer to the associated README.

    Troubleshooting Tips:

    • If you see any errors during the launches, re-check the prerequisites (software installations and credentials). Ensure your network connection is working. As a safe bet, you can retry after cleanup: kill and remove all Docker containers and associated volumes.

    Fabric Client (fabric-cli)

    The CLI is used to interact with a Fabric network, configure it and run chaincode transactions to record data on the channel ledger or query data. It is also used to interact with remote networks through the relay to trigger an interoperation flow for data request and acceptance.

    The fabric-cli Node.js source code is located in the samples/fabric/fabric-cli folder and the Golang source code in the samples/fabric/go-cli folder.

    Prerequisites

    If you are using a Linux system, make sure that lib64 is installed.

    Notes
    For the Node.js version of the fabric-cli, the setup and running instructions below were tested with all Node.js versions from v11.14.0 to v14.17.3.

    Installation

    You can install fabric-cli as follows (for both the Node.js and Golang versions):

    • Navigate to the samples/fabric/fabric-cli folder (for the Node.js version) or the samples/fabric/go-cli folder (for the Golang version).
    • Create .npmrc from template .npmrc.template, by replacing <personal-access-token> with yours created above..
    • Run the following to install dependencies (for the Node.js version) or the executable (for the Golang version):
      make build
    • Use the fabric-cli executable in the bin folder for subsequent actions.

    Fabric Relay

    The relay is a module acting on behalf of a network, enabling interoperation flows with other networks by communicating with their relays. +The code for this lies in the core/relay folder.

    Building

    Prerequisite: make sure Rust is already installed and that the cargo executable is in your system path (after installation of Rust, this should be available in $HOME/.cargo/bin); you can also ensure this by running source "$HOME/.cargo/env".

    Build the generic (i.e., common to all DLTs) relay module as follows:

    • Navigate to the core/relay folder.
    • Run the following:
      make
    • If you observe errors during the above compilation, update certain packages (on which the Weaver Relay is dependent) to their latest versions and recompile as follows:
      make update-pkgs
      make

    Deployment

    An instance or a relay can be run using a suitable configuration file. Samples are available in the core/relay/config folder.

    Run a relay for network1 as follows:

    • Navigate to the core/relay folder.
    • To launch the server without TLS, leave the configuration file config/Fabric_Relay.toml in its default state. Otherwise, edit it to set TLS flags for this relay and the other relays and drivers it will connect to in this demonstration as follows:
      .
      .
      cert_path="credentials/fabric_cert.pem"
      key_path="credentials/fabric_key"
      tls=true
      .
      .
      [relays]
      [relays.Corda_Relay]
      hostname="localhost"
      port="9081"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      [relays.Corda_Relay2]
      hostname="localhost"
      port="9082"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      [relays.Fabric_Relay2]
      hostname="localhost"
      port="9083"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      .
      .
      [drivers]
      [drivers.Fabric]
      hostname="localhost"
      port="9090"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      .
      .
    • To launch the server, simply run the following:
      RELAY_CONFIG=config/Fabric_Relay.toml cargo run --bin server

    Run a relay for network2 as follows (do this only if you have launched both Fabric networks network1 and network2 and wish to test interoperation between them)

    • Navigate to the core/relay folder.
    • To launch the server without TLS, leave the configuration file config/Fabric_Relay2.toml in its default state. Otherwise, edit it to set TLS flags for this relay and the other relays and drivers it will connect to in this demonstration as follows:
      .
      .
      cert_path="credentials/fabric_cert.pem"
      key_path="credentials/fabric_key"
      tls=true
      .
      .
      [relays]
      [relays.Corda_Relay]
      hostname="localhost"
      port="9081"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      [relays.Corda_Relay2]
      hostname="localhost"
      port="9082"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      [relays.Fabric_Relay]
      hostname="localhost"
      port="9080"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      .
      .
      [drivers]
      [drivers.Fabric]
      hostname="localhost"
      port="9095"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      .
      .
    • To launch the server, simply run the following:
      RELAY_CONFIG=config/Fabric_Relay2.toml cargo run --bin server

    For more information, see the relay README.

    Fabric Driver

    A driver is a DLT-specific plugin invoked by the relay while conveying external data queries to the local peer network and collecting a response with proofs. The Fabric driver is built as a Fabric client application on the fabric-network NPM package. +The code for this lies in the core/drivers/fabric-driver folder.

    Configuring

    In the core/drivers/fabric-driver folder, copy .env.template to .env and update CONNECTION_PROFILE to point to the connection profile of the Fabric network (e.g. <PATH-TO-WEAVER>/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json)

    Configure fabric-driver for network1 as follows:

    • Navigate to the core/drivers/fabric-driver folder.
    • Create a .env file by copying .env.template and setting suitable parameter values:
      • The CONNECTION_PROFILE should point to the absolute path of the connection profile for network1.
        • For this exercise, specify the path <PATH-TO-WEAVER>/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json (you must specify the full absolute path here).
        • <PATH-TO-WEAVER> here is the absolute path of the weaver-dlt-interoperability clone folder.
      • If you wish to start the driver without TLS, set the following parameter values:
        RELAY_TLS=false
        RELAY_TLSCA_CERT_PATH=
        DRIVER_TLS=false
        DRIVER_TLS_CERT_PATH=
        DRIVER_TLS_KEY_PATH=
        Otherwise, if you wish to start the driver with TLS enabled, set the following parameter values (replace <PATH-TO-WEAVER> with the absolute path of the weaver-dlt-interoperability clone folder):
        RELAY_TLS=true
        RELAY_TLSCA_CERT_PATH=<PATH-TO-WEAVER>/core/relay/credentials/fabric_ca_cert.pem
        DRIVER_TLS=true
        DRIVER_TLS_CERT_PATH=<PATH-TO-WEAVER>/core/relay/credentials/fabric_cert.pem
        DRIVER_TLS_KEY_PATH=<PATH-TO-WEAVER>/core/relay/credentials/fabric_key
      • Leave the default values unchanged for the other parameters. The relay and driver endpoints as well as the network name are already specified.

    Building

    Build the Fabric driver module as follows:

    • Navigate to the core/drivers/fabric-driver folder.
    • Create .npmrc from template .npmrc.template, by replacing <personal-access-token> with yours created above.
    • Run the following:
      make build

    Running

    Run a Fabric driver for network1 as follows:

    • Navigate to the core/drivers/fabric-driver folder.
    • Run the following:
      npm run dev

    Run a Fabric driver for network2 as follows (do this only if you wish to test interoperation between the two Fabric networks network1 and network2)

    • Navigate to the core/drivers/fabric-driver folder.
    • Run the following:
      CONNECTION_PROFILE=<PATH-TO-WEAVER>/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/connection-org1.json NETWORK_NAME=network2 RELAY_ENDPOINT=localhost:9083 DRIVER_ENDPOINT=localhost:9095 npm run dev
    Notes
    The variables we specified earlier in the .env for network1 are now passed in the command line. Alternatively, you can make a copy of the fabric-driver folder with a different name and create a separate .env file within it that contains links to the connection profile, relay, and driver for network2.

    Fabric IIN Agent

    IIN Agent is a client of a member of a DLT network or security domain with special permissions to update security domain identities and configurations on the ledger via the network's interoperation module. The code for this lies in the core/identity-management/iin-agent folder. Navigate to the core/identity-management/iin-agent folder.

    Building

    Build the IIN Agent as follows:

    • Navigate to the core/drivers/fabric-driver folder.
    • Create .npmrc from template .npmrc.template, by replacing <personal-access-token> with yours created above.
    • Run the following:
      make build

    Configuration

    Ledger config file specifies ledger specific IIN Agent details such as identity and which network and organization to connect to.

    1. To create config file for Org1MSP's Fabric IIN Agent of network1, follow the steps:

      • Create copy of template config file for Fabric IIN Agent: src/fabric-ledger/config.json.template, say to location src/fabric-ledger/config-n1-org1.json.
      • Replace <path-to-connection-profile> with <PATH-TO-WEAVER>/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json, where replace <PATH-TO-WEAVER> with the absolute path location of your clone of Weaver.
      • Set mspId as Org1MSP.
      • Set agent.affiliation as org1.department1.
    2. To create config file for Org2MSP's Fabric IIN Agent of network1, repeat Step 1 with different name for config file, say src/fabric-ledger/config-n1-org2.json, and replace org1 with org2 and Org1MSP with Org2MSP.

    3. To create config file for Org1MSP's Fabric IIN Agent of network2, repeat Step 1 with different name for config file, say src/fabric-ledger/config-n2-org1.json, and replace network1 with network2.

    4. To create config file for Org2MSP's Fabric IIN Agent of network2, repeat Step 1 with different name for config file, say src/fabric-ledger/config-n2-org2.json, and replace network1 with network2, org1 with org2 and Org1MSP with Org2MSP.

    Security Domain Configuration

    Security Domain config file specifies the scope of security domain, which can be a channel in Fabric networks or list of nodes. File docker-testnet/configs/security-domain-config.json can be used for Weaver testnets.

    DNS Configuration

    To allow an IIN Agent's to be able to discover other IIN Agents, a config file for DNS is required. Create one dnsconfig.json by creating a copy of template dnsconfig.json.template, and replace the values with:

    • If Fabric networks are started with 1 org, and IIN Agent are to be started without TLS, use following values:
    {
    "network1": {
    "Org1MSP": {
    "endpoint": "localhost:9500",
    "tls": false,
    "tlsCACertPath": ""
    }
    },
    "network2": {
    "Org1MSP": {
    "endpoint": "localhost:9501",
    "tls": false,
    "tlsCACertPath": ""
    }
    }
    }
    • If Fabric networks are started with 1 org, and IIN Agent are to be started with TLS, use following values:
    {
    "network1": {
    "Org1MSP": {
    "endpoint": "localhost:9500",
    "tls": true,
    "tlsCACertPath": "../../relay/credentials/fabric_ca_cert.pem"
    }
    },
    "network2": {
    "Org1MSP": {
    "endpoint": "localhost:9501",
    "tls": true,
    "tlsCACertPath": "../../relay/credentials/fabric_ca_cert.pem"
    }
    }
    }
    • If Fabric networks are started with 2 orgs, and IIN Agent are to be started without TLS, use following values:
    {
    "network1": {
    "Org1MSP": {
    "endpoint": "localhost:9500",
    "tls": false,
    "tlsCACertPath": ""
    },
    "Org2MSP": {
    "endpoint": "localhost:9510",
    "tls": false,
    "tlsCACertPath": ""
    }
    },
    "network2": {
    "Org1MSP": {
    "endpoint": "localhost:9501",
    "tls": false,
    "tlsCACertPath": ""
    },
    "Org2MSP": {
    "endpoint": "localhost:9511",
    "tls": false,
    "tlsCACertPath": ""
    }
    }
    }
    • If Fabric networks are started with 2 orgs, and IIN Agent are to be started with TLS, use following values:
    {
    "network1": {
    "Org1MSP": {
    "endpoint": "localhost:9500",
    "tls": true,
    "tlsCACertPath": "../../relay/credentials/fabric_ca_cert.pem"
    },
    "Org2MSP": {
    "endpoint": "localhost:9510",
    "tls": true,
    "tlsCACertPath": "../../relay/credentials/fabric_ca_cert.pem"
    }
    },
    "network2": {
    "Org1MSP": {
    "endpoint": "localhost:9501",
    "tls": true,
    "tlsCACertPath": "../../relay/credentials/fabric_ca_cert.pem"
    },
    "Org2MSP": {
    "endpoint": "localhost:9511",
    "tls": true,
    "tlsCACertPath": "../../relay/credentials/fabric_ca_cert.pem"
    }
    }
    }
    Notes
    The variables we specified earlier in the .env for network1 are now passed in the command line. Alternatively, you can make a copy of the fabric-driver folder with a different name and create a separate .env file within it that contains links to the connection profile, relay, and driver for network2.

    Environment Variables

    To configure environment variables for Org1MSP's Fabric IIN Agent of network1, follow the steps:

    1. Create a copy of .env.template as .env, and update following values based on previous configuration file paths:
    IIN_AGENT_ENDPOINT=localhost:9500
    MEMBER_ID=Org1MSP
    SECURITY_DOMAIN=network1
    DLT_TYPE=fabric
    CONFIG_PATH=./src/fabric-ledger/config-n1-org1.json
    DNS_CONFIG_PATH=./dnsconfig.json
    SECURITY_DOMAIN_CONFIG_PATH=./docker-testnet/configs/security-domain-config.json
    WEAVER_CONTRACT_ID=interop
    AUTO_SYNC=true
    1. If IIN Agent has to be started with TLS enabled, also update following values:
    IIN_AGENT_TLS=false
    IIN_AGENT_TLS_CERT_PATH=../../relay/credentials/fabric_cert.pem
    IIN_AGENT_TLS_KEY_PATH=../../relay/credentials/fabric_key

    Deployment

    Use the following steps to run Fabric IIN Agents in host machine:

    • To start IIN Agent for Org1MSP of network1, run:
    npm run dev
    • To start IIN Agent for Org2MSP of network1 (only required if Fabric network was started with 2 orgs), run:
    IIN_AGENT_ENDPOINT=localhost:9510 MEMBER_ID=Org2MSP CONFIG_PATH=./src/fabric-ledger/config-n1-org2.json npm run dev
    • To start IIN Agent for Org1MSP of network2, run:
    IIN_AGENT_ENDPOINT=localhost:9501 SECURITY_DOMAIN=network2 CONFIG_PATH=./src/fabric-ledger/config-n2-org1.json npm run dev
    • To start IIN Agent for Org2MSP of network2 (only required if Fabric network was started with 2 orgs), run:
    IIN_AGENT_ENDPOINT=localhost:9511 MEMBER_ID=Org2MSP SECURITY_DOMAIN=network2 CONFIG_PATH=./src/fabric-ledger/config-n2-org2.json npm run dev

    Corda Components

    Using the sequence of instructions below, you can start a Corda network and run an application CorDapp on it. You can also run an interoperation CorDapp, a relay and a driver acting on behalf of the network. You can initialize the network's vault with access control policies, foreign networks' security groups (i.e., membership providers' certificate chains), and some sample state values that can be shared during subsequent interoperation flows.

    Corda Network

    The Corda networks' code lies in the tests/network-setups/corda folder. You can launch two separate Corda networks, namely Corda_Network and Corda_Network2. Each network runs the samples/corda/corda-simple-application CorDapp by default, which maintains a state named SimpleState containing a set of key-value pairs (of strings).

    The following steps will, in addition to launching the network, build the CorDapp and a Corda client in samples/corda/corda-simple-application/client.

    Running with Interoperation CorDapp from GitHub Packages

    Follow the instructions below to build and launch the network:

    • Navigate to the tests/network-setups/corda folder.
    • Create a copy of github.properties.template as github.properties.
    • Replace <GITHUB email> with your GitHub email, and <GITHUB Personal Access Token> with the access token created above.
    • To spin up the Corda networks with the Interoperation CorDapps:
      • Each consisting of 1 node and a notary (for data-transfer), run:
        make start
      • Each consisting of 2 nodes and a notary (for asset-exchange/transfer), run:
        make start PROFILE="2-nodes"
      • Each consisting of 3 nodes and a notary (for asset-exchange/transfer), run:
        make start PROFILE="3-nodes"

    You should see the following message in the terminal:

    Waiting for network node services to start

    The Corda nodes and notary may take a while (several minutes on memory-constrained systems) to start. If they start up successfully, you should something like the following for each network, though the number of node entries will depend on the profile you used to start the network with (replace <network-name> with Corda_Network or Corda_Network2):

    PartyA node services started for network <network-name>
    PartyB node services started for network <network-name>
    PartyC node services started for network <network-name>
    Notary node services started for network <network-name>

    Corda Relay

    The relay was built earlier, so you just need to use a different configuration file to start a relay for the Corda network.

    Run a relay for Corda_Network as follows:

    • Navigate to the core/relay folder.

    • (Make sure you've already built the relay by running make.)

    • To launch the server without TLS, leave the configuration file config/Corda_Relay.toml in its default state. Otherwise, edit it to set TLS flags for this relay and the other relays and drivers it will connect to in this demonstration as follows:

      .
      .
      cert_path="credentials/fabric_cert.pem"
      key_path="credentials/fabric_key"
      tls=true
      .
      .
      [relays]
      [relays.Fabric_Relay]
      hostname="localhost"
      port="9080"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      [relays.Fabric_Relay2]
      hostname="localhost"
      port="9083"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      [relays.Corda_Relay2]
      hostname="localhost"
      port="9082"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      .
      .
      [drivers]
      [drivers.Corda]
      hostname="localhost"
      port="9099"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      .
      .
    • To launch the server, simply run the following:

      RELAY_CONFIG=config/Corda_Relay.toml cargo run --bin server

      If the relay starts up successfully, the following will be logged on your terminal:

      Relay Name: "Corda_Relay"
      RelayServer listening on [::1]:9081

    Run a relay for Corda_Network2 as follows (do this only if you have launched both Corda networks Corda_Network and Corda_Network2 and wish to test interoperation between them)

    • Navigate to the core/relay folder.

    • To launch the server without TLS, leave the configuration file config/Corda_Relay2.toml in its default state. Otherwise, edit it to set TLS flags for this relay and the other relays and drivers it will connect to in this demonstration as follows:

      .
      .
      cert_path="credentials/fabric_cert.pem"
      key_path="credentials/fabric_key"
      tls=true
      .
      .
      [relays]
      [relays.Fabric_Relay]
      hostname="localhost"
      port="9080"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      [relays.Fabric_Relay2]
      hostname="localhost"
      port="9083"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      [relays.Corda_Relay]
      hostname="localhost"
      port="9081"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      .
      .
      [drivers]
      [drivers.Corda]
      hostname="localhost"
      port="9098"
      tls=true
      tlsca_cert_path="credentials/fabric_ca_cert.pem"
      .
      .
    • To launch the server, simply run the following:

      RELAY_CONFIG=config/Corda_Relay2.toml cargo run --bin server

      If the relay starts up successfully, the following will be logged on your terminal:

      Relay Name: "Corda2_Relay"
      RelayServer listening on [::1]:9082

    Corda Driver

    The code for this lies in the core/drivers/corda-driver folder.

    Building Corda Driver

    Build the Corda driver module as follows:

    • Navigate to the core/drivers/corda-driver folder.
    • Create a copy of github.properties.template as github.properties.
    • Replace <GITHUB email> with your GitHub email, and <GITHUB Personal Access Token> with the access token created above.
    • Run the following:
      make build

    Configuring

    Configure the drivers as follows (you can skip this if you wish to run the drivers without TLS):

    • Navigate to the core/drivers/corda-driver folder and create a .env file.
    • To run the drivers without TLS, set the following default values:
      RELAY_TLS=false
      RELAY_TLSCA_TRUST_STORE=
      RELAY_TLSCA_TRUST_STORE_PASSWORD=
      RELAY_TLSCA_CERT_PATHS=
    • To run the drivers with TLS, set the following values (replace <PATH-TO-WEAVER> with the absolute path of the weaver-dlt-interoperability clone folder):
      RELAY_TLS=true
      RELAY_TLSCA_TRUST_STORE=<PATH-TO-WEAVER>/core/relay/credentials/fabric_trust_store.jks
      RELAY_TLSCA_TRUST_STORE_PASSWORD=trelay
      RELAY_TLSCA_CERT_PATHS=<PATH-TO-WEAVER>/core/relay/credentials/fabric_ca_cert.pem

    Running

    Run a Corda driver as follows:

    • Navigate to the core/drivers/corda-driver folder.
    • Run the following to start Corda driver for Corda_Network:
      ./build/install/corda-driver/bin/corda-driver
      If the driver starts successfully, it should log the following message on your terminal:
      Corda driver gRPC server started. Listening on port 9099
    • Run the following to start Corda driver for Corda_Network2:
      DRIVER_PORT=9098 ./build/install/corda-driver/bin/corda-driver
      If the driver starts successfully, it should log the following message on your terminal:
      Corda driver gRPC server started. Listening on port 9098

    Tear Down the Setup

    Bring down the test network's components as follows:

    • Simply terminate the various relays and drivers, which are running in the foreground in different terminals
    • To bring down the running Corda network:
      • Navigate to the tests/network-setups/corda folder.
      • Run the following:
        make clean
    • To bring down all the running Fabric networks:
      • Navigate to the tests/network-setups/fabric/dev folder.
      • Run the following:
        make clean
    + + \ No newline at end of file diff --git a/docs/external/interoperability-modes/index.html b/docs/external/interoperability-modes/index.html index f1462fd05..f17f16828 100644 --- a/docs/external/interoperability-modes/index.html +++ b/docs/external/interoperability-modes/index.html @@ -4,14 +4,14 @@ Interoperability Modes | Weaver: DLT Interoperability Framework - - - + + +
    -

    Interoperability Modes

    Modes of Interoperability

    We identify distinct modes or patterns of interoperation based on the nature and purpose of the artifact that two networks (or parties within) have a common interest in and the purpose they wish to achieve.

    First, we will classify artifacts present on shared ledgers broadly into the following two types:

    • Assets: This is a ledger item that is associated with a single entity (or limited set of entities), representing the real-world ownership of that item by an entity. Bitcoins in the Bitcoin network and Ether on the Ethereum network are well-known examples, but assets repreenting a wide range of tangible goods can reside on blockchian ledgers, like property titles, bank drafts, precious stones, and financial instruments like bonds and securities.
    • Data Records: This is any information held on a ledger that describes the state of the world, context, or properties of an entity or object. It is not "owned" by, or associated with, specific entities, but is rather common knowledge within a blockchain network.

    The salient distinction between assets and data from an interoperability perspective is that the former may be present only in one network at any given instant in order to maintain its integrity whereas the latter can have copies in multiple networks without losing its value.

    Three common modes in which independent networks will seek to interoperate are as follows. (We can also refer to them as three distinct purposes.)

    Asset Transfer

    This refers to the movement of an asset from its source ledger to a consuming ledger. Since assets has singleton ownership and can't be double spent, the transfer of an asset should result in its burning or locking in the source ledger and its creation on the target ledger.

    A typical asset transfer use case is illustrated in the figure below, where Party X initially holds Asset in Network A, and through interoperation transfers Asset to Party Y in Network B. The loss of Asset to X in A must occur simultaneously with the gain of Asset for Y in B;. i.e, these transactions must be atomic. ("Holding an asset" refers to a record on a network's shared ledger representing the ownership of that asset by a given entity.)

    alt text

    Asset Exchange

    This refers to the change of ownership of an asset in a source network and a corresponding change of ownership in another network. No asset leaves the network it resides in. The well-known terminology for asset exchange is 'Atomic Cross-Chain Swap'.

    For example: two parties with both Bitcoin and Ethereum accounts may trade Bitcoin forEthereum based on an exchange rate agreed upon off-chain. We generalize this to permissioned networks, where it may be harder to provide guarantees of finality, and therby, atomicity.

    The figure below illustrates a typical asset exchange. Initially, Party X holds Asset M in Network A and Party Y holds Asset N in Network B. Through interoperation, an exchange occurs whereby Y holds M in A and X holds N in B. The changes in these two networks occur atomically. (Note: in such a use case, both X and Y must be members of both networks.) See DvP in Financial Markets for an example scenario illustrating asset exchanges.

    alt text

    Both the asset transfer and exchange patterns can be extrapolated to scenarios involving more than 2 parties, 2 assets, and 2 networks. The only fixed criterion is that the actions on all networks happen atomically. For the same reason, the infrastructure and protocols to support both asset transfers and exchanges overlap significantly.

    Data Sharing

    This refers to the transfer of data from its source ledger to a consuming ledger. (In many scenarios, data records in one network ledger may need to be shared with another network ledger in order to drive forward a process on the latter.) The data transferred can be the result of invoking a contract or a database query. There are no technical limits to the number of times a given piece of data can be copied to other ledgers.

    The below figure illustrates this pattern, where initially, Data Record is maintained only on Network A's ledger, and through interoperation, a copy resides on Network B's ledger. (Note: the data record may be transformed within Network B during the sharing process before a transaction is committed to its ledger.) See Global Trade for an example scenario illustrating data sharing.

    alt text

    Identity

    This refers to the process by which identity can be expressed and comprehended beyond the boundaries of a single network. The ability to reason about identities as real-world entities along with credentials proving their membership in various networks is key to creating a trust basis that enables the three interoperability modes listed above. From that perspective, this kind of cross-network identity management lies on a higher plane than data and asset movements. For more details on our thinking, see the Interop RFC pages.

    - - +

    Interoperability Modes

    Modes of Interoperability

    We identify distinct modes or patterns of interoperation based on the nature and purpose of the artifact that two networks (or parties within) have a common interest in and the purpose they wish to achieve.

    First, we will classify artifacts present on shared ledgers broadly into the following two types:

    • Assets: This is a ledger item that is associated with a single entity (or limited set of entities), representing the real-world ownership of that item by an entity. Bitcoins in the Bitcoin network and Ether on the Ethereum network are well-known examples, but assets repreenting a wide range of tangible goods can reside on blockchian ledgers, like property titles, bank drafts, precious stones, and financial instruments like bonds and securities.
    • Data Records: This is any information held on a ledger that describes the state of the world, context, or properties of an entity or object. It is not "owned" by, or associated with, specific entities, but is rather common knowledge within a blockchain network.

    The salient distinction between assets and data from an interoperability perspective is that the former may be present only in one network at any given instant in order to maintain its integrity whereas the latter can have copies in multiple networks without losing its value.

    Three common modes in which independent networks will seek to interoperate are as follows. (We can also refer to them as three distinct purposes.)

    Asset Transfer

    This refers to the movement of an asset from its source ledger to a consuming ledger. Since assets has singleton ownership and can't be double spent, the transfer of an asset should result in its burning or locking in the source ledger and its creation on the target ledger.

    A typical asset transfer use case is illustrated in the figure below, where Party X initially holds Asset in Network A, and through interoperation transfers Asset to Party Y in Network B. The loss of Asset to X in A must occur simultaneously with the gain of Asset for Y in B;. i.e, these transactions must be atomic. ("Holding an asset" refers to a record on a network's shared ledger representing the ownership of that asset by a given entity.)

    alt text

    Asset Exchange

    This refers to the change of ownership of an asset in a source network and a corresponding change of ownership in another network. No asset leaves the network it resides in. The well-known terminology for asset exchange is 'Atomic Cross-Chain Swap'.

    For example: two parties with both Bitcoin and Ethereum accounts may trade Bitcoin forEthereum based on an exchange rate agreed upon off-chain. We generalize this to permissioned networks, where it may be harder to provide guarantees of finality, and therby, atomicity.

    The figure below illustrates a typical asset exchange. Initially, Party X holds Asset M in Network A and Party Y holds Asset N in Network B. Through interoperation, an exchange occurs whereby Y holds M in A and X holds N in B. The changes in these two networks occur atomically. (Note: in such a use case, both X and Y must be members of both networks.) See DvP in Financial Markets for an example scenario illustrating asset exchanges.

    alt text

    Both the asset transfer and exchange patterns can be extrapolated to scenarios involving more than 2 parties, 2 assets, and 2 networks. The only fixed criterion is that the actions on all networks happen atomically. For the same reason, the infrastructure and protocols to support both asset transfers and exchanges overlap significantly.

    Data Sharing

    This refers to the transfer of data from its source ledger to a consuming ledger. (In many scenarios, data records in one network ledger may need to be shared with another network ledger in order to drive forward a process on the latter.) The data transferred can be the result of invoking a contract or a database query. There are no technical limits to the number of times a given piece of data can be copied to other ledgers.

    The below figure illustrates this pattern, where initially, Data Record is maintained only on Network A's ledger, and through interoperation, a copy resides on Network B's ledger. (Note: the data record may be transformed within Network B during the sharing process before a transaction is committed to its ledger.) See Global Trade for an example scenario illustrating data sharing.

    alt text

    Identity

    This refers to the process by which identity can be expressed and comprehended beyond the boundaries of a single network. The ability to reason about identities as real-world entities along with credentials proving their membership in various networks is key to creating a trust basis that enables the three interoperability modes listed above. From that perspective, this kind of cross-network identity management lies on a higher plane than data and asset movements. For more details on our thinking, see the Interop RFC pages.

    + + \ No newline at end of file diff --git a/docs/external/introduction/index.html b/docs/external/introduction/index.html index 1ceab0849..e1795426c 100644 --- a/docs/external/introduction/index.html +++ b/docs/external/introduction/index.html @@ -4,15 +4,15 @@ Weaver Framework | Weaver: DLT Interoperability Framework - - - + + +

    Weaver Framework

    Weaver is a framework that enables scalable interconnectivity between disparate distributed ledgers in a manner that preserves core tenets of decentralisation and security. -The framework, consisting of a family of protocols, is designed and built with the following key guiding principles, which are further discussed in Design Principles:

    • Inclusiveness: Avoid approaches that are specific to a particular DLT implementation and design.
    • Independence: Interoperable networks retain sovereignty on their own processes and access control rules.
    • Minimum Trust: Reduce trust to only what is essentials (i.e. identity providers in the network).
    • Privacy by Design: Interaction between parties across networks should be kept private and confidential and revealed only to the interested parties.
    • No Intermediaries: No third-party intermediary should be relied upon for the purpose of cross-network data verification or settlement.
    • Minimal Shared Infrastructure: Rely on external infrastucture only for discovery, identification, and tracking/auditing, and not for cross-network transactions.
    • Leverage Consensus: Use the respective ledgers' native distributed consensus mechanisms as the trust basis for cross-network transactions.
    • Non-Intrusion: Require no changes to the DLT platforms and consensus mechanisms on which the networks are built, nor any dilution of the networks' security models.
    • Transparency: Facilitate tracking and auditing of cross-network transactions.

    The protocol is designed around the following key elements:

    1. State Proofs: these allow a network to independently verify that any state it consumes from another network is valid according to the rules and policies of that network, or adheres to validity policies it imposes on state from that network.
    2. Asset Locks and Claims: these allow a network to freeze an asset for a given time period on behalf of a user or allow a user to claim a frozen asset from its previous owner, either within a network or from a different network.
    3. Relays: these are decentralised peer-to-peer services that enable communication of messages between networks.

    Weaver has a specification outlined through a set of RFCs and a reference implementation of that specification, which is discussed in this documentation.

    - - +The framework, consisting of a family of protocols, is designed and built with the following key guiding principles, which are further discussed in Design Principles:

    • Inclusiveness: Avoid approaches that are specific to a particular DLT implementation and design.
    • Independence: Interoperable networks retain sovereignty on their own processes and access control rules.
    • Minimum Trust: Reduce trust to only what is essentials (i.e. identity providers in the network).
    • Privacy by Design: Interaction between parties across networks should be kept private and confidential and revealed only to the interested parties.
    • No Intermediaries: No third-party intermediary should be relied upon for the purpose of cross-network data verification or settlement.
    • Minimal Shared Infrastructure: Rely on external infrastucture only for discovery, identification, and tracking/auditing, and not for cross-network transactions.
    • Leverage Consensus: Use the respective ledgers' native distributed consensus mechanisms as the trust basis for cross-network transactions.
    • Non-Intrusion: Require no changes to the DLT platforms and consensus mechanisms on which the networks are built, nor any dilution of the networks' security models.
    • Transparency: Facilitate tracking and auditing of cross-network transactions.

    The protocol is designed around the following key elements:

    1. State Proofs: these allow a network to independently verify that any state it consumes from another network is valid according to the rules and policies of that network, or adheres to validity policies it imposes on state from that network.
    2. Asset Locks and Claims: these allow a network to freeze an asset for a given time period on behalf of a user or allow a user to claim a frozen asset from its previous owner, either within a network or from a different network.
    3. Relays: these are decentralised peer-to-peer services that enable communication of messages between networks.

    Weaver has a specification outlined through a set of RFCs and a reference implementation of that specification, which is discussed in this documentation.

    + + \ No newline at end of file diff --git a/docs/external/publications/index.html b/docs/external/publications/index.html index 4a3794bc3..c73095008 100644 --- a/docs/external/publications/index.html +++ b/docs/external/publications/index.html @@ -4,14 +4,14 @@ Publications | Weaver: DLT Interoperability Framework - - - + + +
    -

    Publications

    2021

    Verifiable Observation of Permissioned Ledgers

    IEEE International Conference on Blockchain and Cryptocurrency, 2021

    Ermyas Abebe, Yining Hu, Allison Irvin, Dileban Karunamoorthy, Vinayaka Pandit, Venkatraman Ramakrishna, Jiangshan Yu

    [arXiv]

    Decentralized Cross-Network Identity Management for Blockchain Interoperation

    IEEE International Conference on Blockchain and Cryptocurrency, 2021

    Bishakh Chandra Ghosh, Sandip Chakraborty, Venkatraman Ramakrishna, Chander Govindarajan,Dushyant Behl, Dileban Karunamoorthy, Ermyas Abebe

    [arXiv]

    2019

    Enabling Enterprise Blockchain Interoperability with Trusted Data Transfer

    Proceedings of the 20th International Middleware Conference Industrial Track, 2019

    Ermyas Abebe, Dushyant Behl, Chander Govindarajan, Yining Hu, Dileban Karunamoorthy, Petr Novotny, Vinayaka Pandit, Venkatraman Ramakrishna, Christian Vecchiola

    [Proceedings] [arXiv]

    On the Interoperability of Distributed Ledgers, Medium

    Dileban Karunamoorthy, Ermyas Abebe

    [Medium]

    - - +

    Publications

    2021

    Verifiable Observation of Permissioned Ledgers

    IEEE International Conference on Blockchain and Cryptocurrency, 2021

    Ermyas Abebe, Yining Hu, Allison Irvin, Dileban Karunamoorthy, Vinayaka Pandit, Venkatraman Ramakrishna, Jiangshan Yu

    [arXiv]

    Decentralized Cross-Network Identity Management for Blockchain Interoperation

    IEEE International Conference on Blockchain and Cryptocurrency, 2021

    Bishakh Chandra Ghosh, Sandip Chakraborty, Venkatraman Ramakrishna, Chander Govindarajan,Dushyant Behl, Dileban Karunamoorthy, Ermyas Abebe

    [arXiv]

    2019

    Enabling Enterprise Blockchain Interoperability with Trusted Data Transfer

    Proceedings of the 20th International Middleware Conference Industrial Track, 2019

    Ermyas Abebe, Dushyant Behl, Chander Govindarajan, Yining Hu, Dileban Karunamoorthy, Petr Novotny, Vinayaka Pandit, Venkatraman Ramakrishna, Christian Vecchiola

    [Proceedings] [arXiv]

    On the Interoperability of Distributed Ledgers, Medium

    Dileban Karunamoorthy, Ermyas Abebe

    [Medium]

    + + \ No newline at end of file diff --git a/docs/external/roadmap/index.html b/docs/external/roadmap/index.html index 8e3b8f3e7..7a09c4adf 100644 --- a/docs/external/roadmap/index.html +++ b/docs/external/roadmap/index.html @@ -4,14 +4,14 @@ Roadmap | Weaver: DLT Interoperability Framework - - - + + + - - +
    + + \ No newline at end of file diff --git a/docs/external/security-model/access-control/index.html b/docs/external/security-model/access-control/index.html index c7898c470..2c861d05f 100644 --- a/docs/external/security-model/access-control/index.html +++ b/docs/external/security-model/access-control/index.html @@ -4,14 +4,14 @@ Access Control | Weaver: DLT Interoperability Framework - - - + + + - - +
    + + \ No newline at end of file diff --git a/docs/external/security-model/authentication/index.html b/docs/external/security-model/authentication/index.html index 2164cc0ac..4b95a45b3 100644 --- a/docs/external/security-model/authentication/index.html +++ b/docs/external/security-model/authentication/index.html @@ -4,14 +4,14 @@ Authentication | Weaver: DLT Interoperability Framework - - - + + + - - +
    + + \ No newline at end of file diff --git a/docs/external/security-model/end-to-end-security/index.html b/docs/external/security-model/end-to-end-security/index.html index 259f17607..eba3bd515 100644 --- a/docs/external/security-model/end-to-end-security/index.html +++ b/docs/external/security-model/end-to-end-security/index.html @@ -4,14 +4,14 @@ End-to-End Security | Weaver: DLT Interoperability Framework - - - + + +
    -

    End-to-End Security

    Relay Security Model

    A Relayer of Cryptographic Proofs

    The primary function of the relay is to orchestrate the flow of cyrptographic messages between networks enabling a variety of interoperability modes:

    • Transfer of data between networks
    • Transfer of assets between networks
    • Exchange of value between networks

    These cryptographic messages represent valid state in a distributed ledger and are generated using a range of cryptographic approaches, such as attestation by a set of authoritative nodes, a non-interactive proof of PoW, or a zero-knowledge proof (proof of computational integrity). The mechanisms for deriving such proofs rely on the model of trust provided by the underlying network of nodes. The relay thus plays no direct role in the generation of proofs, removing the need for remote agents (decentralized networks, applications or users) to trust the relay for proof veracity.

    The relay's message exchange protocol is in a state of development with a view towards supporting multiple interoperability modes. The current implementation however is limited to the transfer of data between networks. Future versions will enable asset and value transfers protocols.

    NOTE: The security models examined below is limited to the transfer of data where remote queries are initiated by applications.

    Deployment Configurations and Security Implications

    The relay acts as a gateway between networks for enabling cross-chain communication and supports flexible deployment configurations.

    The configuration in any deployment must statisfy the goals of the parties involved in the message exchange. These goals inform the security policy and the adversarial assumptions. The mechanisms for threat mitigation is based on these assumptions.

    The configurations described below assume that:

    • A small fraction of the parties (e.g. f < n - m, where 'm' is the minimum threshold required for agreement) in a group or network might be byzantine.
    • The threat imposed by a byzantine party with priviledges to construct a valid proof is no worse if the party is also in control of a relay.
    • A valid proof is one that satisfies a consumer's proof critieria (policy).

    1. Confidential Message Exchange Between Groups of Parties

    Confidential Message Exchange

    Goals

    A group of parties sharing confidential data agree to share a view of their data to remote group. The system configuration will provide the following properties:

    • Preserve confidentiality of messages exchanged between the groups involved.
    • Preserve integrity of messages exchanged across the groups.
    • The system must be available for servicing requests.

    Threat Assumptions

    An adversary in this configuration might seek to:

    • Gain access to the confidential data.
    • Tamper with the integrity of the messages exchanged.
    • Censor messages.
    • Deny service.

    Mechanisms for Threat Mitigation

    A suitable deployment configuration that addresses these threat assumptions:

    • Relays will only be deployed and operated by organizations with access to the confidential data and privileges to construct valid proofs.
    • A secure channel (mutual TLS) between the relays prevents external adversaries from evesdropping on the communication.
    • The inclusion of a nonce in the proof enables replays of past messages to be detected.
    • The deployment of multiple relays ensures availability and resistance to censorship.

    In the following configuration, a group in one network maintains confidential data and have similar goals as above. The data in the providing network is private but visible to all organizations. The relay in the providing network can be operated by any organization with access to the data (the implications of this are examined next).

    Confidential Message Exchange

    2. Private Message Exchange Between Networks

    Goals

    In the following configuration, the data is private to both networks but not confidential to any subset of the members. The system configuration must provide the following properties:

    • Preserve confidentiality of messages exchanged between the networks.
    • Preserve integrity of messages exchanged across the networks.
    • The system must be available for servicing requests.

    Threat Assumptions

    An adversary in this configuration might seek to:

    • Gain access to the private data.
    • Tamper with the integrity of the messages exchanged.
    • Censor messages.
    • Deny service.

    Mechanisms for Threat Mitigation

    A suitable deployment configuration that addresses the threat assumptions:

    • Relays will be deployed and operated by organizations that are members of the network with access to the shared private data and privileges to construct valid proofs.
    • A secure channel (mutual TLS) between the relays prevents external adversaries from evesdropping on the communication.
    • The inclusion of a nonce in the proof enables replays of past messages to be detected.
    • The deployment of multiple relays ensures availability and resistance to censorship.

    Private Message Exchange

    3. Public Message Exchange Between Networks

    Goals

    A private network consumes data from a public permissionless network. The system configuration must provide the following properties:

    • Preserve confidentiality of messages exchanged between the networks.
    • Preserve integrity of messages exchanged across the networks.
    • The system must be available for servicing requests.

    Threat Assumptions

    An adversary in this configuration might seek to:

    • Monitor data accessed by the private network.
    • Tamper with the integrity of the messages exchanged.
    • Censor messages.
    • Deny service.

    Mechanisms for Threat Mitigation

    A suitable deployment configuration that addresses the threat assumptions:

    • Nodes (clients) of the public ledger will be deployed and operated by multiple organizations in the private network (a sufficient distribution to accomodate 'f' faulty nodes)
      • Nodes modified to sign responses with a valid identity certificate (e.g. Hyperledger Besu as Ethereum mainnet client).
    • Relays to private and public nodes will be deployed and operated by organizations within the network.
    • The inclusion of a nonce in the proof enables replays of past messages to be detected.
    • The deployment of multiple relays ensures availability and resistance to censorship.

    Private Public Data Exchange

    The following alternate configuration allows for a public node to be operated by a single organization. The oracle provides trusted meta-data to ensure proofs can be validated correctly (E.g. current validator set used for signing blocks in PoS/BFT sysmtems and block height to verify currency of state. A formal study on mechanisms for proof construction and their short-commings has been deferred).

    Private Public Data Exchange

    In the following configuration an external notary acts as an authoritative source for public ledger data. A secure channel (mutual TLS) between the relays prevents external adversaries from evesdropping on the communication.

    Private Public Data Exchange

    Nonces and Replay Attacks

    - - +

    End-to-End Security

    Relay Security Model

    A Relayer of Cryptographic Proofs

    The primary function of the relay is to orchestrate the flow of cyrptographic messages between networks enabling a variety of interoperability modes:

    • Transfer of data between networks
    • Transfer of assets between networks
    • Exchange of value between networks

    These cryptographic messages represent valid state in a distributed ledger and are generated using a range of cryptographic approaches, such as attestation by a set of authoritative nodes, a non-interactive proof of PoW, or a zero-knowledge proof (proof of computational integrity). The mechanisms for deriving such proofs rely on the model of trust provided by the underlying network of nodes. The relay thus plays no direct role in the generation of proofs, removing the need for remote agents (decentralized networks, applications or users) to trust the relay for proof veracity.

    The relay's message exchange protocol is in a state of development with a view towards supporting multiple interoperability modes. The current implementation however is limited to the transfer of data between networks. Future versions will enable asset and value transfers protocols.

    NOTE: The security models examined below is limited to the transfer of data where remote queries are initiated by applications.

    Deployment Configurations and Security Implications

    The relay acts as a gateway between networks for enabling cross-chain communication and supports flexible deployment configurations.

    The configuration in any deployment must statisfy the goals of the parties involved in the message exchange. These goals inform the security policy and the adversarial assumptions. The mechanisms for threat mitigation is based on these assumptions.

    The configurations described below assume that:

    • A small fraction of the parties (e.g. f < n - m, where 'm' is the minimum threshold required for agreement) in a group or network might be byzantine.
    • The threat imposed by a byzantine party with priviledges to construct a valid proof is no worse if the party is also in control of a relay.
    • A valid proof is one that satisfies a consumer's proof critieria (policy).

    1. Confidential Message Exchange Between Groups of Parties

    Confidential Message Exchange

    Goals

    A group of parties sharing confidential data agree to share a view of their data to remote group. The system configuration will provide the following properties:

    • Preserve confidentiality of messages exchanged between the groups involved.
    • Preserve integrity of messages exchanged across the groups.
    • The system must be available for servicing requests.

    Threat Assumptions

    An adversary in this configuration might seek to:

    • Gain access to the confidential data.
    • Tamper with the integrity of the messages exchanged.
    • Censor messages.
    • Deny service.

    Mechanisms for Threat Mitigation

    A suitable deployment configuration that addresses these threat assumptions:

    • Relays will only be deployed and operated by organizations with access to the confidential data and privileges to construct valid proofs.
    • A secure channel (mutual TLS) between the relays prevents external adversaries from evesdropping on the communication.
    • The inclusion of a nonce in the proof enables replays of past messages to be detected.
    • The deployment of multiple relays ensures availability and resistance to censorship.

    In the following configuration, a group in one network maintains confidential data and have similar goals as above. The data in the providing network is private but visible to all organizations. The relay in the providing network can be operated by any organization with access to the data (the implications of this are examined next).

    Confidential Message Exchange

    2. Private Message Exchange Between Networks

    Goals

    In the following configuration, the data is private to both networks but not confidential to any subset of the members. The system configuration must provide the following properties:

    • Preserve confidentiality of messages exchanged between the networks.
    • Preserve integrity of messages exchanged across the networks.
    • The system must be available for servicing requests.

    Threat Assumptions

    An adversary in this configuration might seek to:

    • Gain access to the private data.
    • Tamper with the integrity of the messages exchanged.
    • Censor messages.
    • Deny service.

    Mechanisms for Threat Mitigation

    A suitable deployment configuration that addresses the threat assumptions:

    • Relays will be deployed and operated by organizations that are members of the network with access to the shared private data and privileges to construct valid proofs.
    • A secure channel (mutual TLS) between the relays prevents external adversaries from evesdropping on the communication.
    • The inclusion of a nonce in the proof enables replays of past messages to be detected.
    • The deployment of multiple relays ensures availability and resistance to censorship.

    Private Message Exchange

    3. Public Message Exchange Between Networks

    Goals

    A private network consumes data from a public permissionless network. The system configuration must provide the following properties:

    • Preserve confidentiality of messages exchanged between the networks.
    • Preserve integrity of messages exchanged across the networks.
    • The system must be available for servicing requests.

    Threat Assumptions

    An adversary in this configuration might seek to:

    • Monitor data accessed by the private network.
    • Tamper with the integrity of the messages exchanged.
    • Censor messages.
    • Deny service.

    Mechanisms for Threat Mitigation

    A suitable deployment configuration that addresses the threat assumptions:

    • Nodes (clients) of the public ledger will be deployed and operated by multiple organizations in the private network (a sufficient distribution to accomodate 'f' faulty nodes)
      • Nodes modified to sign responses with a valid identity certificate (e.g. Hyperledger Besu as Ethereum mainnet client).
    • Relays to private and public nodes will be deployed and operated by organizations within the network.
    • The inclusion of a nonce in the proof enables replays of past messages to be detected.
    • The deployment of multiple relays ensures availability and resistance to censorship.

    Private Public Data Exchange

    The following alternate configuration allows for a public node to be operated by a single organization. The oracle provides trusted meta-data to ensure proofs can be validated correctly (E.g. current validator set used for signing blocks in PoS/BFT sysmtems and block height to verify currency of state. A formal study on mechanisms for proof construction and their short-commings has been deferred).

    Private Public Data Exchange

    In the following configuration an external notary acts as an authoritative source for public ledger data. A secure channel (mutual TLS) between the relays prevents external adversaries from evesdropping on the communication.

    Private Public Data Exchange

    Nonces and Replay Attacks

    + + \ No newline at end of file diff --git a/docs/external/security-model/proofs-and-verification/index.html b/docs/external/security-model/proofs-and-verification/index.html index f2c43596c..b13c6b142 100644 --- a/docs/external/security-model/proofs-and-verification/index.html +++ b/docs/external/security-model/proofs-and-verification/index.html @@ -4,14 +4,14 @@ Proofs and Verification | Weaver: DLT Interoperability Framework - - - + + + - - +
    + + \ No newline at end of file diff --git a/docs/external/specifications/index.html b/docs/external/specifications/index.html index eabc22660..95c15e2e5 100644 --- a/docs/external/specifications/index.html +++ b/docs/external/specifications/index.html @@ -4,14 +4,14 @@ Specifications | Weaver: DLT Interoperability Framework - - - + + +
    -

    Specifications

    The Weaver specifications (RFCs) capture abstractions, models, protocols and data formats for enabling cross-ledger communication.

    For newcomers who wish to find out more details about the Weaver design and wish to contribute to the code base, we recommend starting with the models. Protocol engineers will find in RFC: 01-009 a useful overview of the relay model, and may then progress on to reading one of the existing protocols' design and implementation; e.g., the data sharing protocol in RFC: 02-001. If you are interested in adding support for a new ledger technology, see the existing driver implementations and existing interoperability module implementations. Where relevant we use ABNF for formal syntax definitions.

    - - +

    Specifications

    The Weaver specifications (RFCs) capture abstractions, models, protocols and data formats for enabling cross-ledger communication.

    For newcomers who wish to find out more details about the Weaver design and wish to contribute to the code base, we recommend starting with the models. Protocol engineers will find in RFC: 01-009 a useful overview of the relay model, and may then progress on to reading one of the existing protocols' design and implementation; e.g., the data sharing protocol in RFC: 02-001. If you are interested in adding support for a new ledger technology, see the existing driver implementations and existing interoperability module implementations. Where relevant we use ABNF for formal syntax definitions.

    + + \ No newline at end of file diff --git a/docs/external/user-stories/financial-markets/index.html b/docs/external/user-stories/financial-markets/index.html index 601c8f39c..53bfb9cd8 100644 --- a/docs/external/user-stories/financial-markets/index.html +++ b/docs/external/user-stories/financial-markets/index.html @@ -4,15 +4,15 @@ DvP in Financial Markets | Weaver: DLT Interoperability Framework - - - + + +

    DvP in Financial Markets

    In traditional financial markets parties trade assets such as securities and derivatives for cash or other assets. To reduce risk, various clearing and settlement processes and intermediaries are often involved. One form of settlement is a DvP (delivery versus payment) where the transfer of securities is performed only in the event of a corresponding payment. This arrangement reduces principal risk by ensuring that both parties receive their end of the exchange. However, settlement in financial markets are slow and time consuming. It also involves counterparty risks and requires intermediaries.

    Over the past few years, we have been seeing significant efforts in digitising and tokenising both currencies and securities on Distributed Ledger Technology (DLT) infrastructures. On the one hand we have seen concerted efforts around Central Bank Digital Currencies (CBDC) being added to the landscape of other blockchain based payment networks. On the other hand, we have also seen efforts such as that from the Australian Stock Exchange (ASX) to replace its current settlement system--Clearing House Electronic Subregister System (CHESS) with a DLT based platform by 2021.

    Against this backdrop, a number of central banks have been exploring the potential of performing DvP settlement across a currency ledger and a securities ledger. In this use case, we use this as a motivating use-case for our discussions. The scenario involves two decentralised ledgers, namely, a currency ledger and a securities ledger, based on different DLT protocols performing a coordinated transfer of assets in their respective ledgers.

    The figure below depicts this scenario in the context of two organisations--Org-A and Org-B. Org-B wants to purchase some securities owned by Org-A and both organisations have accounts on both ledgers. This scenario is simplified and leaves out a number of additional real world processes. For instance, the buyer and seller for securities need to discover each other and agree on the price and terms of a sale. In addition, an offer to sell securities might be fulfilled by multiple buyers taking smaller portions of the amount for sale. Such capabilities are often offered by centralised exchanges that offer capabilities such as order books and matching engines to address these needs. In this scenario we instead focus on the settlement process that follows such steps, once the parties of an exchange and the price of the exchange for an asset are determined.

    To effect the settlement of this exchange between Org-A and Org-B, the following two transactions will have to happen atomically across both networks: i) transfer of payment from Org-B's currency account in the CBDC ledger to Org-A while at the same time ii) the entitlements of the designated securities are transferred from Org-A to Org-B. The scenario would need to guarantee that after the transaction execution, either both parties have their end of the exchange or neither does and that this exchange is performed in a timely manner.

    Simple DvP scenario in financial markets

    The settlement of the exchange of securities from Org-A to Org-B in the Financial Securities Network for a simultaneous payment from Org-B to Org-A in the CBDC network is coordinated by Weaver using Hashed Time Lock Contracts. -This protocol essentially has three phases:

    • Fund locking: To initialise an asset exchange, it is common for one or both parties to first lock up funds with a fund-withholding party on his or her own blockchain. Temporary fund locking ensures the locked fund cannot be used for other purposes while the exchange is being executed. This scheme is often used with a specified timeout to provide flexibility for reclaiming locked funds if the exchange does not take place.
    • Fund redeeming: In general, the execution requires a pair of transactions to occur on both blockchains, e.g., from Org-A to Org-B on the FSN ledger and from Org-B to Org-A in CBDC ledger. When certain conditions are met, the locked funds can be redeemed by, or paid to the respective users. The execution of the exchange can be carried out by users themselves, or through other trusted third parties. These trusted third parties can be stand-alone parties that are not otherwise involved in both blockchains, or part of either blockchain. 
    • Refund: For protocols that are initialised with a temporary fund-locking, the locked funds can usually be reclaimed by the initial owner after a specified timeout, if a redemption has not occurred. 

    The process proceeds as follows, and is further illustrated in the figure below:

    1. Org-A locks its securities in FSN ledger: Org-A first creates some secret S, known only to it and locks its securities using the hash of S. The securities are configured to redeemable by Org-B if it presents S within some specified time threshold.
    2. Org-B locks payments tokens in CBDC ledger: Org-B, observes that Org-A has locked its securities in the FSN network and does a corresponding lock of its payment tokens with the hash of S, used by Org-A in locking its securities. The payment tokens are redeemable only by Org-A, if it submits a transaction that reveals S within a specified time.
    3. Org-A checks Org-B's contract in CBDC ledger: Org-A checks the CBDC network to ensure that the payments tokens are locked by Org-B.
    4. Org-A claims payments in CBDC ledger: Org-A submits a transaction to claim the payments tokens, by revealing the secret S.
    5. Org-B claims securities in FSN ledger: Org-B observes that the value of S has been revealed in the CBDC network by Org-A in step 4, and submits a transaction to claim the securities in the FSN network using the revealed secret.

    Simple DvP scenario in financial markets

    - - +This protocol essentially has three phases:

    • Fund locking: To initialise an asset exchange, it is common for one or both parties to first lock up funds with a fund-withholding party on his or her own blockchain. Temporary fund locking ensures the locked fund cannot be used for other purposes while the exchange is being executed. This scheme is often used with a specified timeout to provide flexibility for reclaiming locked funds if the exchange does not take place.
    • Fund redeeming: In general, the execution requires a pair of transactions to occur on both blockchains, e.g., from Org-A to Org-B on the FSN ledger and from Org-B to Org-A in CBDC ledger. When certain conditions are met, the locked funds can be redeemed by, or paid to the respective users. The execution of the exchange can be carried out by users themselves, or through other trusted third parties. These trusted third parties can be stand-alone parties that are not otherwise involved in both blockchains, or part of either blockchain. 
    • Refund: For protocols that are initialised with a temporary fund-locking, the locked funds can usually be reclaimed by the initial owner after a specified timeout, if a redemption has not occurred. 

    The process proceeds as follows, and is further illustrated in the figure below:

    1. Org-A locks its securities in FSN ledger: Org-A first creates some secret S, known only to it and locks its securities using the hash of S. The securities are configured to redeemable by Org-B if it presents S within some specified time threshold.
    2. Org-B locks payments tokens in CBDC ledger: Org-B, observes that Org-A has locked its securities in the FSN network and does a corresponding lock of its payment tokens with the hash of S, used by Org-A in locking its securities. The payment tokens are redeemable only by Org-A, if it submits a transaction that reveals S within a specified time.
    3. Org-A checks Org-B's contract in CBDC ledger: Org-A checks the CBDC network to ensure that the payments tokens are locked by Org-B.
    4. Org-A claims payments in CBDC ledger: Org-A submits a transaction to claim the payments tokens, by revealing the secret S.
    5. Org-B claims securities in FSN ledger: Org-B observes that the value of S has been revealed in the CBDC network by Org-A in step 4, and submits a transaction to claim the securities in the FSN network using the revealed secret.

    Simple DvP scenario in financial markets

    + + \ No newline at end of file diff --git a/docs/external/user-stories/global-trade/index.html b/docs/external/user-stories/global-trade/index.html index 366bd7520..c80552bd3 100644 --- a/docs/external/user-stories/global-trade/index.html +++ b/docs/external/user-stories/global-trade/index.html @@ -4,14 +4,14 @@ Global Trade | Weaver: DLT Interoperability Framework - - - + + +
    -

    Global Trade

    The examples in this page cover the global trade application domain and the data sharing pattern.

    Process Overview

    At its simplest, international trade is about a party in one country buying certain goods from a party in another country. Because the goods cross international boundaries, the buyer is called an importer and the seller is called an exporter. For the same reason, this process is not as straightforward as, say, purchasing an item from a retailer.

    The exporting of goods in most countries is governed by a host of regulatory provisions and authorities, making the very act of clearing the sale and getting the goods ready for shipment a complex one. Further, an exporter must rely on one or more carriers to move the shipment from source to destination while managing all of the risks this entails.

    But this only covers the shipping logistics. The trading parties, i.e., the exporter and importer, both face what is called counterparty risk, or the hazard of giving something up without a guarantee of receiving something in return. If the exporter ships the goods first, the importer may renege on the payment. And if the importer mmakes the payment first, the exporter may renege on the shipment. To hedge against this risk, sophisticated process of trade finance have evolved over centuries, with banks or other financial institutions providing the sorts of guarantees (in exchange for fees) that enable exporters and importers to safely conduct trades.

    Permissioned blockchains are a great fit to manage such trade scenarios, involving multiple independent entities and no governing authorities, using smart contracts. Let us now see two kinds of processes in action, each of which can be managed in its own restricted network:

    1. Trade logistics: preparation, clearance, and export of goods
    2. Trade finance: payment guarantees and fulfillment

    Networks in Isolation

    There exist real business networks in production that manage trade logistics and finance, but they can be very complex. We will present highly simplified versions of these processes, and focus on the aspects that will motivate the need for data sharing across networks.

    Also, we will henceforth use the terms buyer and seller instead of importer and exporter respectively.

    Initiating a Trade

    Our trade process begins offline, with buyer and seller negotiating and agreeing on the sale of particular goods for given payment. We will assume that a purchase order is created and contains a unique id we can use as reference in subsequent steps. This is illustrated in the figure below.

    alt text

    Trade Logistics Network

    The figure below represents a trade logistics network consisting of a seller and a carrier, loosely inspired by the TradeLens network built on Hyperledger Fabric. Think of the seller as a coffee plantation owner is Brazil, for example, and the carrier as a prominent shipping company like Maersk.

    alt text

    The seller begins by booking a shipping consignment (associated with the purchase order id) and then registering its creation. It then hands the consignment over to the carrier. In a real life export scenario, this process involves a lot of documentation and approval cycles, but we are going to ignore all of those here. The carrier supplies documents certifying its possession of the consignment and the contents within it. The bill of lading (B/L for short) is one of these documents, and though there may be others, like a packing list and a shipping manifest, we only need one to motivate interoperability. So we will keep it simple and assume that the carrier simply uploads a B/L. The seller examines and accepts this document, following which the carrier dispatches the consignment.

    Note that, at this point, a valid B/L is recorded on the trade logistics network ledger, a fact we will make use of soon enough.

    Trade Finance Network

    The figure below represents a trade finance network consisting of a seller, a buyer, and their respective banks. This is loosely inspired by the We.Trade network built on Hyperledger Fabric and the Marco Polo network built on R3 Corda. Think of the seller as our coffee plantation owner in the logistics network, the buyer as Starbucks, and the banks as Bank of America and HSBC Bank, for example.

    alt text

    Traders and banks use a variety of mechanisms to mitigate counterparty risk, one of them being open accounting, used in networks like We.Trade. We pick the popular letter of credit (L/C for short) instrument for our trade finance story as this exemplifies the inherent link between logistics and finance (we will see this later). The process begins with the buyer requesting an L/C from its bank for a given trade, referring to the id of the purchase order generated earlier. In simplest terms, an L/C is a promise made by a bank to pay a certain amount to the bearer of certain documents associated with a given export shipment. In our scenario, the buyer's bank issues an L/C promising to pay the seller (through its bank) the amount due to it upon production of a valid B/L. This L/C proposal is recorded on the ledger, and subsequently approved by the seller's bank. After the seller uploads a B/L, the seller's bank is allowed to register a request for payment. This leaves a payment obligation for the buyer's bank on the ledger, which is where we will conclude the scenario, as the actual payment is carried out through a separate process on a different network.

    Note that the seller is supposed to produce and record a valid B/L in Step 4.

    Linking Finance with Logistics

    It is obvious that the logistics and finance processes are linked. Both begin with references to a common purchase order id and both involve bills of lading. Let us focus on the B/L, as it exemplifies a common pattern in these kinds of business networks: that of being generated in one network and being used in another. Because thee are two separate networks, the trade finance network depends on the seller to upload a B/L. But here, we encounter another kind of hazard, one we discussed earlier in the challenges section. The seller has an incentive to produce a fake bill of lading in order to get paid for goods it may not have dispatched and may have no intention of dispatching. In the present setup, the trade finance network as a whole, nor the buyer or its bank, has visibility into the trade logistics network's ledger, and hence have to trust the seller's word.

    This hazard can be avoided if the networks are interoperable, and can share data with each other. Specifically, if the trade logistics network can share a B/L recorded on its ledger institutionally with the trade finance network. To see how this works, see the diagram below, which contains both the networks and merges their flows.

    alt text

    Step 4 in the isolated trade finance network is now replaced with an interoperation step (Step 10) whereby the trade finance network obtains a B/L from the trade logistics network via a data-sharing protocol. This avoids the hazard of having to depend on an unreliable seller to supply a valid B/L. But it is not enough for the trade logistics network to share B/L data. It must also share some proof or evidence that the B/L is presently on record in its shared ledger.

    Note: in general, an interoperation mechanism for data sharing must communicate data as well as an associated proof that can be independently verified by every memebr of the receiving network.

    Extending the Scenario

    The above example conforms to how the logistics and finance processes work today. Letters of credit typically specify bills of lading among the lists of documents that must be supplied to claim a payment. But state-of-the-art blockchain technology and permissioned networks can facilitate a lot more process innovation than earlier technology could.

    The present trade logistics network allows a consignment to be created and dispatched without any knowledge of how the trade will be financed. But in real life, there is a need to track imports and exports carefully to ensure that no regulations are broken, and secondarily, to avoid wasted effort. Therefore, we can envision trade logistics networks requiring some evidence of the financial arrangements of a trade before it allows a seller and a carrier to carry out with the shipping process.

    The process augmentation is illustrated in the figure below with the insertion of a new Step 6 between the booking and the creation of a shipping consignment.

    alt text

    Like Step 11 (Step 10 in the earlier figure), this is a data-sharing interoperation step where the L/C proposed and accepted on the trade finance network's ledger is copied to the trade logistics network's ledger. (As with the B/L sharing, proof of the L/C ledger record must accompany L/C data.) In this new process, the trade logistics network will not waste time processing shipments that do not have a backing L/C guarantee from the trade finance network.

    Note that in the interoperation steps, the artifact being shared by one network with another (B/L or L/C) does not have to be copied verbatim to the receiving network's ledger. The process incorporates transformations carried out through smart contract transactions occurring through their networks' native consensus mechanisms.

    Vision: Network of Networks

    The promise of blockchain was a more decentralized yet trustworthy internet, but as we saw earlier, networks like Bitcoin and Ethereum may not fulfill that promise, largely because they have technical limitations when it comes to performance and scaling, privacy preservation, and auditability. At the same time, private blockchain networks are here to stay, and they do overcome these technical limitations, albeit at smaller scale. In the longer term, a more sustainable and achievable vision will be to allow private networks to exist while possessing the means to interoperate with other private networks. The interlinking of a trade logistics network with a trade finance network was just a sample. There is more aspects to an international trade scenario: more networks and more cross-network dependencies. But as long as we can institute mechanisms to link two networks directly for data-sharing, we can extrapolate our two-network scenario into a network-of-networks scenario.

    To show how this will work, we will add two more networks to the mix. Business networks exist to track the quality and health of perishable goods from the production source to the end retailer. These networks complement networks like Trade Lens, which manage the long-distance shipping that occurs in the middle but have no visibiity into the goods before consignment creation or after delivery at the destination by the carrier. To track goods at either ends is the function of networks like IBM Food Trust, which would be ideal for the coffee shipment example we used earlier. A separate aspect of our trade scenario is the actual payment a buyer makes to the seller. Our trade finance network ends by recording a payment obligation, but the transfer of money needs to occur on a separate payment network, like, for example, the Stellar Network.

    The figure below presents our vision for how cross-network data sharing can help smoothen and simplify all aspects of global trade despite the fact that different sub-processes occur on independent private networks.

    alt text

    The Food Tracking Network is loosely inspired by IBM Food Trust and the Payments Network loosely inspired by Stellar.

    • The seller and buyer, as the trading parties, belong to the food tracking network. The process in this network begins with a registration of a purchase order, following which perishable goods (think coffee seeds, for example) are tracked from farms to a warehouse where a shipping consignment is created. Whenever the carier delivers the shipment, the fact of delivery is recorded as is the condition of the goods within.
    • The payment network has the buyer's and seller's bank as members. Action in this network is triggered by the buyer's bank making a payment, or a monetary transfer, to the seller's bank. Both banks have accounts in this network and the payment succeeds or fails depending on available account balance.

    There are two parallel timelines starting at Step 17:

    • One involves the trade finance network and the payments network (Steps 17-20). Step 18 contains both "Make Payment" and "Receive Payment" as these actions are supposed to occur atomically within the payments network. These pertain to the fulfilment of the payment promised to the seller by the buyer.
    • Another involves the trade logistics network and the food tracking network (Steps 17-19). These pertain to the tracking of goods after dispatch and confirmation of their subsequent delivery and condition.

    You may notice we have augmented the trade logistics and trade finance processes as follows:

    • Step 17 in the trade logistics network illustrates a sequence of transactions, each recording the location and condition of the goods in transit at periodic intervals. We assume that this information can be procured using sensors deployed with the consignment.
    • Step 20 in the trade finance network results in the cancelling of the payment obligation recorded by the seller's bank in Step 17 within that network ("Request Payment"), thereby concluding the trade instance associated with the purchase order id generated in Step 1.

    The data-sharing interoperation steps are as follows:

    • Step 3: The trade finance network fetches a purchase order from the food tracking network before permitting an L/C request to be made.
    • Step 8: The trade logistics network fetches an L/C from the trade finance network before permitting a consignment to be created.
    • Step 9: The food tracking network fetches a consignment booking record and an associated L/C from the trade logistics network before permitting tracking of goods from the source to the shipping warehouse.
    • Step 11: The trade logistics network fetches tracking information indicating delivery of goods to the warehouse before permitting a consignment to be created.
    • Step 16: The trade finance network fetches a B/L from the trade logistics network before permitting the seller's bank to register a payment request.
    • Step 18: This is a recurring step, in each instance of which the food tracking network fetches location and condition information for a given consignment from the trade logistics network, and does not permit the confirmation of consignment delivery and the integrity of the goods within until the shipment reaches its destination and its condition meets the required standard.
    • Step 19: The trade finance network gets confirmation of payment (from buyer's account to seller's account) from the payments network.

    To summarize, internationally traded goods can be tracked from a farm in one country to a retailer in another, the goods can be exported and shipped with all regulations complied with, financial guarantees can be put in place to safeguard the trading parties, and cross-border payments can be processed seamlessly and in a trustworthy manner. But this requires a combination of private blockchain networks willing to share data with each other and also have the ability to verify the authenticity of received data. We hope this scenario makes the motivation for data-sharing interoperation mechanisms perfectly clear.

    - - +

    Global Trade

    The examples in this page cover the global trade application domain and the data sharing pattern.

    Process Overview

    At its simplest, international trade is about a party in one country buying certain goods from a party in another country. Because the goods cross international boundaries, the buyer is called an importer and the seller is called an exporter. For the same reason, this process is not as straightforward as, say, purchasing an item from a retailer.

    The exporting of goods in most countries is governed by a host of regulatory provisions and authorities, making the very act of clearing the sale and getting the goods ready for shipment a complex one. Further, an exporter must rely on one or more carriers to move the shipment from source to destination while managing all of the risks this entails.

    But this only covers the shipping logistics. The trading parties, i.e., the exporter and importer, both face what is called counterparty risk, or the hazard of giving something up without a guarantee of receiving something in return. If the exporter ships the goods first, the importer may renege on the payment. And if the importer mmakes the payment first, the exporter may renege on the shipment. To hedge against this risk, sophisticated process of trade finance have evolved over centuries, with banks or other financial institutions providing the sorts of guarantees (in exchange for fees) that enable exporters and importers to safely conduct trades.

    Permissioned blockchains are a great fit to manage such trade scenarios, involving multiple independent entities and no governing authorities, using smart contracts. Let us now see two kinds of processes in action, each of which can be managed in its own restricted network:

    1. Trade logistics: preparation, clearance, and export of goods
    2. Trade finance: payment guarantees and fulfillment

    Networks in Isolation

    There exist real business networks in production that manage trade logistics and finance, but they can be very complex. We will present highly simplified versions of these processes, and focus on the aspects that will motivate the need for data sharing across networks.

    Also, we will henceforth use the terms buyer and seller instead of importer and exporter respectively.

    Initiating a Trade

    Our trade process begins offline, with buyer and seller negotiating and agreeing on the sale of particular goods for given payment. We will assume that a purchase order is created and contains a unique id we can use as reference in subsequent steps. This is illustrated in the figure below.

    alt text

    Trade Logistics Network

    The figure below represents a trade logistics network consisting of a seller and a carrier, loosely inspired by the TradeLens network built on Hyperledger Fabric. Think of the seller as a coffee plantation owner is Brazil, for example, and the carrier as a prominent shipping company like Maersk.

    alt text

    The seller begins by booking a shipping consignment (associated with the purchase order id) and then registering its creation. It then hands the consignment over to the carrier. In a real life export scenario, this process involves a lot of documentation and approval cycles, but we are going to ignore all of those here. The carrier supplies documents certifying its possession of the consignment and the contents within it. The bill of lading (B/L for short) is one of these documents, and though there may be others, like a packing list and a shipping manifest, we only need one to motivate interoperability. So we will keep it simple and assume that the carrier simply uploads a B/L. The seller examines and accepts this document, following which the carrier dispatches the consignment.

    Note that, at this point, a valid B/L is recorded on the trade logistics network ledger, a fact we will make use of soon enough.

    Trade Finance Network

    The figure below represents a trade finance network consisting of a seller, a buyer, and their respective banks. This is loosely inspired by the We.Trade network built on Hyperledger Fabric and the Marco Polo network built on R3 Corda. Think of the seller as our coffee plantation owner in the logistics network, the buyer as Starbucks, and the banks as Bank of America and HSBC Bank, for example.

    alt text

    Traders and banks use a variety of mechanisms to mitigate counterparty risk, one of them being open accounting, used in networks like We.Trade. We pick the popular letter of credit (L/C for short) instrument for our trade finance story as this exemplifies the inherent link between logistics and finance (we will see this later). The process begins with the buyer requesting an L/C from its bank for a given trade, referring to the id of the purchase order generated earlier. In simplest terms, an L/C is a promise made by a bank to pay a certain amount to the bearer of certain documents associated with a given export shipment. In our scenario, the buyer's bank issues an L/C promising to pay the seller (through its bank) the amount due to it upon production of a valid B/L. This L/C proposal is recorded on the ledger, and subsequently approved by the seller's bank. After the seller uploads a B/L, the seller's bank is allowed to register a request for payment. This leaves a payment obligation for the buyer's bank on the ledger, which is where we will conclude the scenario, as the actual payment is carried out through a separate process on a different network.

    Note that the seller is supposed to produce and record a valid B/L in Step 4.

    Linking Finance with Logistics

    It is obvious that the logistics and finance processes are linked. Both begin with references to a common purchase order id and both involve bills of lading. Let us focus on the B/L, as it exemplifies a common pattern in these kinds of business networks: that of being generated in one network and being used in another. Because thee are two separate networks, the trade finance network depends on the seller to upload a B/L. But here, we encounter another kind of hazard, one we discussed earlier in the challenges section. The seller has an incentive to produce a fake bill of lading in order to get paid for goods it may not have dispatched and may have no intention of dispatching. In the present setup, the trade finance network as a whole, nor the buyer or its bank, has visibility into the trade logistics network's ledger, and hence have to trust the seller's word.

    This hazard can be avoided if the networks are interoperable, and can share data with each other. Specifically, if the trade logistics network can share a B/L recorded on its ledger institutionally with the trade finance network. To see how this works, see the diagram below, which contains both the networks and merges their flows.

    alt text

    Step 4 in the isolated trade finance network is now replaced with an interoperation step (Step 10) whereby the trade finance network obtains a B/L from the trade logistics network via a data-sharing protocol. This avoids the hazard of having to depend on an unreliable seller to supply a valid B/L. But it is not enough for the trade logistics network to share B/L data. It must also share some proof or evidence that the B/L is presently on record in its shared ledger.

    Note: in general, an interoperation mechanism for data sharing must communicate data as well as an associated proof that can be independently verified by every memebr of the receiving network.

    Extending the Scenario

    The above example conforms to how the logistics and finance processes work today. Letters of credit typically specify bills of lading among the lists of documents that must be supplied to claim a payment. But state-of-the-art blockchain technology and permissioned networks can facilitate a lot more process innovation than earlier technology could.

    The present trade logistics network allows a consignment to be created and dispatched without any knowledge of how the trade will be financed. But in real life, there is a need to track imports and exports carefully to ensure that no regulations are broken, and secondarily, to avoid wasted effort. Therefore, we can envision trade logistics networks requiring some evidence of the financial arrangements of a trade before it allows a seller and a carrier to carry out with the shipping process.

    The process augmentation is illustrated in the figure below with the insertion of a new Step 6 between the booking and the creation of a shipping consignment.

    alt text

    Like Step 11 (Step 10 in the earlier figure), this is a data-sharing interoperation step where the L/C proposed and accepted on the trade finance network's ledger is copied to the trade logistics network's ledger. (As with the B/L sharing, proof of the L/C ledger record must accompany L/C data.) In this new process, the trade logistics network will not waste time processing shipments that do not have a backing L/C guarantee from the trade finance network.

    Note that in the interoperation steps, the artifact being shared by one network with another (B/L or L/C) does not have to be copied verbatim to the receiving network's ledger. The process incorporates transformations carried out through smart contract transactions occurring through their networks' native consensus mechanisms.

    Vision: Network of Networks

    The promise of blockchain was a more decentralized yet trustworthy internet, but as we saw earlier, networks like Bitcoin and Ethereum may not fulfill that promise, largely because they have technical limitations when it comes to performance and scaling, privacy preservation, and auditability. At the same time, private blockchain networks are here to stay, and they do overcome these technical limitations, albeit at smaller scale. In the longer term, a more sustainable and achievable vision will be to allow private networks to exist while possessing the means to interoperate with other private networks. The interlinking of a trade logistics network with a trade finance network was just a sample. There is more aspects to an international trade scenario: more networks and more cross-network dependencies. But as long as we can institute mechanisms to link two networks directly for data-sharing, we can extrapolate our two-network scenario into a network-of-networks scenario.

    To show how this will work, we will add two more networks to the mix. Business networks exist to track the quality and health of perishable goods from the production source to the end retailer. These networks complement networks like Trade Lens, which manage the long-distance shipping that occurs in the middle but have no visibiity into the goods before consignment creation or after delivery at the destination by the carrier. To track goods at either ends is the function of networks like IBM Food Trust, which would be ideal for the coffee shipment example we used earlier. A separate aspect of our trade scenario is the actual payment a buyer makes to the seller. Our trade finance network ends by recording a payment obligation, but the transfer of money needs to occur on a separate payment network, like, for example, the Stellar Network.

    The figure below presents our vision for how cross-network data sharing can help smoothen and simplify all aspects of global trade despite the fact that different sub-processes occur on independent private networks.

    alt text

    The Food Tracking Network is loosely inspired by IBM Food Trust and the Payments Network loosely inspired by Stellar.

    • The seller and buyer, as the trading parties, belong to the food tracking network. The process in this network begins with a registration of a purchase order, following which perishable goods (think coffee seeds, for example) are tracked from farms to a warehouse where a shipping consignment is created. Whenever the carier delivers the shipment, the fact of delivery is recorded as is the condition of the goods within.
    • The payment network has the buyer's and seller's bank as members. Action in this network is triggered by the buyer's bank making a payment, or a monetary transfer, to the seller's bank. Both banks have accounts in this network and the payment succeeds or fails depending on available account balance.

    There are two parallel timelines starting at Step 17:

    • One involves the trade finance network and the payments network (Steps 17-20). Step 18 contains both "Make Payment" and "Receive Payment" as these actions are supposed to occur atomically within the payments network. These pertain to the fulfilment of the payment promised to the seller by the buyer.
    • Another involves the trade logistics network and the food tracking network (Steps 17-19). These pertain to the tracking of goods after dispatch and confirmation of their subsequent delivery and condition.

    You may notice we have augmented the trade logistics and trade finance processes as follows:

    • Step 17 in the trade logistics network illustrates a sequence of transactions, each recording the location and condition of the goods in transit at periodic intervals. We assume that this information can be procured using sensors deployed with the consignment.
    • Step 20 in the trade finance network results in the cancelling of the payment obligation recorded by the seller's bank in Step 17 within that network ("Request Payment"), thereby concluding the trade instance associated with the purchase order id generated in Step 1.

    The data-sharing interoperation steps are as follows:

    • Step 3: The trade finance network fetches a purchase order from the food tracking network before permitting an L/C request to be made.
    • Step 8: The trade logistics network fetches an L/C from the trade finance network before permitting a consignment to be created.
    • Step 9: The food tracking network fetches a consignment booking record and an associated L/C from the trade logistics network before permitting tracking of goods from the source to the shipping warehouse.
    • Step 11: The trade logistics network fetches tracking information indicating delivery of goods to the warehouse before permitting a consignment to be created.
    • Step 16: The trade finance network fetches a B/L from the trade logistics network before permitting the seller's bank to register a payment request.
    • Step 18: This is a recurring step, in each instance of which the food tracking network fetches location and condition information for a given consignment from the trade logistics network, and does not permit the confirmation of consignment delivery and the integrity of the goods within until the shipment reaches its destination and its condition meets the required standard.
    • Step 19: The trade finance network gets confirmation of payment (from buyer's account to seller's account) from the payments network.

    To summarize, internationally traded goods can be tracked from a farm in one country to a retailer in another, the goods can be exported and shipped with all regulations complied with, financial guarantees can be put in place to safeguard the trading parties, and cross-border payments can be processed seamlessly and in a trustworthy manner. But this requires a combination of private blockchain networks willing to share data with each other and also have the ability to verify the authenticity of received data. We hope this scenario makes the motivation for data-sharing interoperation mechanisms perfectly clear.

    + + \ No newline at end of file diff --git a/docs/external/user-stories/legacy-integration/index.html b/docs/external/user-stories/legacy-integration/index.html index fcd9c1229..d7f455ef7 100644 --- a/docs/external/user-stories/legacy-integration/index.html +++ b/docs/external/user-stories/legacy-integration/index.html @@ -4,14 +4,14 @@ Legacy Integration | Weaver: DLT Interoperability Framework - - - + + +
    -

    Legacy Integration

    A standard for self-contained messages respresenting state in distributed ledgers, along with proofs of validity, enables interoperability with legacy enterprise applications. These messages can be consumed, stored or forwarded by any traditional centralized application.

    - - +

    Legacy Integration

    A standard for self-contained messages respresenting state in distributed ledgers, along with proofs of validity, enables interoperability with legacy enterprise applications. These messages can be consumed, stored or forwarded by any traditional centralized application.

    + + \ No newline at end of file diff --git a/docs/external/user-stories/overview/index.html b/docs/external/user-stories/overview/index.html index c0c20d06d..8388ff659 100644 --- a/docs/external/user-stories/overview/index.html +++ b/docs/external/user-stories/overview/index.html @@ -4,14 +4,14 @@ Overview | Weaver: DLT Interoperability Framework - - - + + +
    -

    Overview

    In the introduction, we listed various modes (or patterns) of interoperation like asset transfers, asset exchanges, and data sharing. In IT parlance, we can think of this as a horizontal classification of use cases for interoperability. In this section of the documentation, we will discuss the verticals, or application domains, that exemplify the use and necessity of interoperation mechanisms.

    Application Domains

    Distributed ledger technology has been applied gainfully to several areas where legacy processes were inefficient, cumbersome, and error-prone. With the enablement of interoperation among these networks, they have the potential to take the next step toward a truly decentralized yet trustworthy internet. We call out two prominent focus areas.

    Global Trade

    Trade when seen from a global and international perspective is highly complex. In the absence of central coordinating and law-enforcing authorities at the world level, various ad hoc processes have been created and refined over centuries by merchants, financiers, and regulators, to manage complex supply-chain logistics and cross-border financing that underpin global trade. These processes exist to ensure that parties can hedge their risks, mitigate possibilities for non-compliance, and ship goods from one location to another while complying with regulatory guidelines.

    Multiple networks have emerged to handle trade processes limited in scope. There exist networks to handle trade logistics (like TradeLens, built on Hyperledger Fabric), food tracking (IBM Food Trust, built on Hyperledger Fabric), trade finance (like We.Trade, built on Hyperledger Fabric, and Marco Polo, built on R3 Corda), cross-border payments, and know-your-customer, or KYC, processes. An end-to-end trade scenario, involving shipment of goods, financing commitments, documentation, shipping, tracking, and payments, will rely on many or all of these networks. Interoperation will help us overcome this fragmentation and lack of visibility of one network into another, and enable trustworthy and efficient trades at global scale using blockchain technology. See Global Trade for a concrete example.

    Financial Markets

    Securities trading is a common and lucrative transaction in financial markets. As with any form of exchange, when a security is sold in exchange for money, the party that gives up its asset first faces a non-compliance risk; i.e., the other party may renege on the deal after it receives an asset. With the advent of blockchain-backed digital currencies maintained by countries' central banks, opportunities now exist to carry out security trades safely and efficiently. But this requires interoperation between networks managing digital currency on behalf of central banks (like private versions of Bitcoin networks with faster commitment times) and networks managing tracking securities and their ownerships. See DvP in Financial Markets for a concrete example.

    Other Scenarios

    There are other domains or verticals we can think of that would benefit from interoperation. Healthcare is one, where different networks may exist: citizens' identity records, employer network, healthcare provider network, insurance companies' network, etc. For efficiency of operation (with privacy preservation guarantees) and to ensure that service and payments occur promptly and accurately, these networks may seek to interoperate. Similarly, interoperation between networks that manage users' academic and professional credentials may help employers and job seekers.

    - - +

    Overview

    In the introduction, we listed various modes (or patterns) of interoperation like asset transfers, asset exchanges, and data sharing. In IT parlance, we can think of this as a horizontal classification of use cases for interoperability. In this section of the documentation, we will discuss the verticals, or application domains, that exemplify the use and necessity of interoperation mechanisms.

    Application Domains

    Distributed ledger technology has been applied gainfully to several areas where legacy processes were inefficient, cumbersome, and error-prone. With the enablement of interoperation among these networks, they have the potential to take the next step toward a truly decentralized yet trustworthy internet. We call out two prominent focus areas.

    Global Trade

    Trade when seen from a global and international perspective is highly complex. In the absence of central coordinating and law-enforcing authorities at the world level, various ad hoc processes have been created and refined over centuries by merchants, financiers, and regulators, to manage complex supply-chain logistics and cross-border financing that underpin global trade. These processes exist to ensure that parties can hedge their risks, mitigate possibilities for non-compliance, and ship goods from one location to another while complying with regulatory guidelines.

    Multiple networks have emerged to handle trade processes limited in scope. There exist networks to handle trade logistics (like TradeLens, built on Hyperledger Fabric), food tracking (IBM Food Trust, built on Hyperledger Fabric), trade finance (like We.Trade, built on Hyperledger Fabric, and Marco Polo, built on R3 Corda), cross-border payments, and know-your-customer, or KYC, processes. An end-to-end trade scenario, involving shipment of goods, financing commitments, documentation, shipping, tracking, and payments, will rely on many or all of these networks. Interoperation will help us overcome this fragmentation and lack of visibility of one network into another, and enable trustworthy and efficient trades at global scale using blockchain technology. See Global Trade for a concrete example.

    Financial Markets

    Securities trading is a common and lucrative transaction in financial markets. As with any form of exchange, when a security is sold in exchange for money, the party that gives up its asset first faces a non-compliance risk; i.e., the other party may renege on the deal after it receives an asset. With the advent of blockchain-backed digital currencies maintained by countries' central banks, opportunities now exist to carry out security trades safely and efficiently. But this requires interoperation between networks managing digital currency on behalf of central banks (like private versions of Bitcoin networks with faster commitment times) and networks managing tracking securities and their ownerships. See DvP in Financial Markets for a concrete example.

    Other Scenarios

    There are other domains or verticals we can think of that would benefit from interoperation. Healthcare is one, where different networks may exist: citizens' identity records, employer network, healthcare provider network, insurance companies' network, etc. For efficiency of operation (with privacy preservation guarantees) and to ensure that service and payments occur promptly and accurately, these networks may seek to interoperate. Similarly, interoperation between networks that manage users' academic and professional credentials may help employers and job seekers.

    + + \ No newline at end of file diff --git a/docs/external/what-is-interoperability/integration-patterns/index.html b/docs/external/what-is-interoperability/integration-patterns/index.html index 4211e013d..f2179a46a 100644 --- a/docs/external/what-is-interoperability/integration-patterns/index.html +++ b/docs/external/what-is-interoperability/integration-patterns/index.html @@ -4,14 +4,14 @@ Integration Patterns | Weaver: DLT Interoperability Framework - - - + + +
    -

    Integration Patterns

    Integration patterns are well-known reusable solutions for integrating systems together. A number of patterns exist for addressing various types integration problems. The specific pattern applied in practice depends on the nature of the integration problem, the overall objective of the integration task, trade-offs in alternate approaches, and potential risks.

    Distributed Ledger Integration Patterns

    Here we present common patterns for integrating distributed ledgers. Not all problems are equal, some approaches to itegrating ledgers are preferred over others depending on the use case, the purpose of the itegration and the risks involved.

    Consensus-based integration between ledgers

    Consensus-based integration aims to communicate the consensus view of one network to another. The consensus view is a representation of state on the ledger that is collectively agreed by the members of the network. This form of integration provides the highest assurance on the validity of state. The Weaver framework is designed to address consensus-based integration between ledgers built on different distributed ledger protocols.

    Standard API integration between applications

    A standard API integration relies on a single party exposing an endpoint for state exchange. The validity of state relies entirely on the trust placed on the party exposing the endpoint.

    Single enterprise participating in multiple neworks

    A single enterprise participating in multiple networks can integrate state and contract logic across these networks using off-chain workflows. Unlike the previous pattern, this pattern relies on the enterprise having valid membership credentials on multiple networks. Significant trust must be placed on the organization coordianting the exchange of state across these networks.

    Single network deployed on multiple heterogenous infrastructure

    Although not an integration pattern, this pattern demonstrates interoperability at the infrastructure layer. The ability to run nodes on multiple cloud providers, as well as on-prem infrastructure, ensures networks are resilient to failures or censorship by infrastructure providers.

    - - +

    Integration Patterns

    Integration patterns are well-known reusable solutions for integrating systems together. A number of patterns exist for addressing various types integration problems. The specific pattern applied in practice depends on the nature of the integration problem, the overall objective of the integration task, trade-offs in alternate approaches, and potential risks.

    Distributed Ledger Integration Patterns

    Here we present common patterns for integrating distributed ledgers. Not all problems are equal, some approaches to itegrating ledgers are preferred over others depending on the use case, the purpose of the itegration and the risks involved.

    Consensus-based integration between ledgers

    Consensus-based integration aims to communicate the consensus view of one network to another. The consensus view is a representation of state on the ledger that is collectively agreed by the members of the network. This form of integration provides the highest assurance on the validity of state. The Weaver framework is designed to address consensus-based integration between ledgers built on different distributed ledger protocols.

    Standard API integration between applications

    A standard API integration relies on a single party exposing an endpoint for state exchange. The validity of state relies entirely on the trust placed on the party exposing the endpoint.

    Single enterprise participating in multiple neworks

    A single enterprise participating in multiple networks can integrate state and contract logic across these networks using off-chain workflows. Unlike the previous pattern, this pattern relies on the enterprise having valid membership credentials on multiple networks. Significant trust must be placed on the organization coordianting the exchange of state across these networks.

    Single network deployed on multiple heterogenous infrastructure

    Although not an integration pattern, this pattern demonstrates interoperability at the infrastructure layer. The ability to run nodes on multiple cloud providers, as well as on-prem infrastructure, ensures networks are resilient to failures or censorship by infrastructure providers.

    + + \ No newline at end of file diff --git a/docs/external/what-is-interoperability/levels-of-interoperability/index.html b/docs/external/what-is-interoperability/levels-of-interoperability/index.html index 9bf512cd8..f9f61d835 100644 --- a/docs/external/what-is-interoperability/levels-of-interoperability/index.html +++ b/docs/external/what-is-interoperability/levels-of-interoperability/index.html @@ -4,14 +4,14 @@ Levels of Interoperability | Weaver: DLT Interoperability Framework - - - + + +
    -

    Levels of Interoperability

    Established models of information systems interoperability stratify interoperability concerns into multiple levels. This includes technical, syntactic, semantic and application levels as shown below.

    Above the protocol and application levels there are two additional levels that require careful attention when enabling interoperability. These cover governance and policy decisions when communicating state as well as the legal and regulatory implications of networks under different jurisdictions.

    • Technical: The technical level is a low-level concern that focuses on the underlying wire protocol used for communication. Examples of protocols at this level include gRPC, Apache Thrift, ASN.1 and CBOR. Protocols at this level are point-to-point and addresses additional concerns such as version negotiation and message delivery guarantees.

    • Syntactic: The syntactic level is concerned with the structure and format of the messages exchanged. This includes protocol elements such as keywords and types. Examples include protocols defined using Google's Protocol Buffers, JSON-RPC and ASN.1.

    • Semantic: The semantic level provides meaning to the messages exchanged. In the context of cross-chain communication, this includes messages that represent a data transfer or an asset exchange as well as other information such as validity proofs and actors involved.

    • Application: The application level addresses domain or use-case specific concerns. In this level, interoperability deals with industry standard data models (e.g. supply chain standards such as GS1) and business processes. This level is orthogonal to the technology concerns of interoperability.

    • Governance and Policies: The governing members of a ledger play a critical role in extending business processes to external systems. Interoperability necessitates that the governing bodies of the respective systems agree on the nature of their collaboration. The policies enforce these decisions and covers aspects such as access control and conditions for determining the validity of state proofs.

    • Legal and Regulation: Networks residing in different jurisdictions must be comply with existing laws and regulations when communicating state.

    - - +

    Levels of Interoperability

    Established models of information systems interoperability stratify interoperability concerns into multiple levels. This includes technical, syntactic, semantic and application levels as shown below.

    Above the protocol and application levels there are two additional levels that require careful attention when enabling interoperability. These cover governance and policy decisions when communicating state as well as the legal and regulatory implications of networks under different jurisdictions.

    • Technical: The technical level is a low-level concern that focuses on the underlying wire protocol used for communication. Examples of protocols at this level include gRPC, Apache Thrift, ASN.1 and CBOR. Protocols at this level are point-to-point and addresses additional concerns such as version negotiation and message delivery guarantees.

    • Syntactic: The syntactic level is concerned with the structure and format of the messages exchanged. This includes protocol elements such as keywords and types. Examples include protocols defined using Google's Protocol Buffers, JSON-RPC and ASN.1.

    • Semantic: The semantic level provides meaning to the messages exchanged. In the context of cross-chain communication, this includes messages that represent a data transfer or an asset exchange as well as other information such as validity proofs and actors involved.

    • Application: The application level addresses domain or use-case specific concerns. In this level, interoperability deals with industry standard data models (e.g. supply chain standards such as GS1) and business processes. This level is orthogonal to the technology concerns of interoperability.

    • Governance and Policies: The governing members of a ledger play a critical role in extending business processes to external systems. Interoperability necessitates that the governing bodies of the respective systems agree on the nature of their collaboration. The policies enforce these decisions and covers aspects such as access control and conditions for determining the validity of state proofs.

    • Legal and Regulation: Networks residing in different jurisdictions must be comply with existing laws and regulations when communicating state.

    + + \ No newline at end of file diff --git a/docs/external/what-is-interoperability/understanding-interoperability/index.html b/docs/external/what-is-interoperability/understanding-interoperability/index.html index a6f40bb1f..dbfbad47c 100644 --- a/docs/external/what-is-interoperability/understanding-interoperability/index.html +++ b/docs/external/what-is-interoperability/understanding-interoperability/index.html @@ -4,16 +4,16 @@ Understanding Interoperability | Weaver: DLT Interoperability Framework - - - + + +

    Understanding Interoperability

    Permissioned DLTs have been gaining significant traction in industry since their inception. They have enabled enterprises to harness the innovation of public blockchains, while adhering to the privacy, confidentiality and regulatory constraints that businesses operate under. Permissioned DLTs offer enterprises an infrastructure for managing inter-firm asset, data and business workflow, without the need for a central intermediary that introduces additional sources of risk. Businesses are able to transact directly while reducing counter-party risk and mitigating the need for costly and time-consuming dispute resolution processes, often involving legal and judicial systems. Thus far, the application of this technology has enabled digitisation and disintermediation of many entrenched industry processes, resulting in significant improvements in efficiency, transparency, risk and fraud.

    For practical reasons, the adoption of permissioned blockchains has thus far been driven through use-cases. Enterprises have been coalescing into consortia to create specialised networks that address narrowly-scoped use-cases in isolation. This use-case driven approach to blockchain adoption is creating a proliferation of niche and isolated networks that are quickly becoming data and value silos. -In addition, these use-cases often represent a slice of a complex end-to-end business process. To deliver real value, permissioned networks need to seamlessly integrate with each other and with existing systems in order to holistically transform industries. This requirement for interoperation is coming to the fore as networks transition to production and scale towards broader adoption.

    Interoperability in the context of Distributed Ledger Technologies involves enabling the seamless flow of data and value across disparate networks in a manner that preserves their trust and security tenets. This capability can offer a number of benefits such as:

    • Removing data and value silos
    • Increasing market sizes, liquidity and overall efficiency
    • Improving network effects
    • Enabling orchestration of complex business functionality across networks
    • Enabling scale and groawth of networks
    • Encouraging further adoption of the technology

    Unique Technical Challenges

    Enabling interoperation between distributed ledgers presents numerous technical challenges compared to traditional systems integration approaches. This primarily stems from the need to preserve the benefits of decentralised trust beyond the boundaries of a single network. Hence, a naive approach to interoperability based on traditional point-to-point API integration is insufficient for preserving the underlying trust decentralised networks provide. There are two unique challenges present in DLT interoperation:

    Single-party vs Multi-party Trust 

    In distributed ledger architectures, the authority over state lies in a collective and the protocol they employ to ensure its integrity. When one network or an entity consumes state from another, it would need to establish the veracity of the state according to the shared consensus view of parties in the network. This requirement is different than traditional integration with centralised systems wherein the trust for the validity of data is placed on the single party providing the data. Establishing the veracity of state in a decentralized network is not trivial. In most cases, a consumer of state might not be able to observe the full ledger of the network itself. Hence, a consumer needs to obtain an independently verifiable cryptographic proof on the validity of state according to the consensus rules and policies of the source network.

    single-party vs multi-party trust model

    Data vs Asset

    Interoperation should not compromise the invariants enforced by individual networks such as protections against double spends on assets.

    The Role of Standards

    The term ‘interoperability’ is used rather loosely in many contexts and oftentimes without the same implication. What some call ‘interoperability’, others refer to as ‘integration’, ‘interconnectivity’ or ‘compatibility’.

    The primary goal of interoperability is freedom of choice. Interoperability enables users to choose implementations of systems they find suitable for a given problem without constraints on the system’s ability to communicate with other implementations.

    Implicit in the term interoperability is open standards, which distinguishes it from any form of bespoke integration. Open standards can either be de jure standards ratified by a formal standards organization such as ANSI, IETF, or ISO, or de facto standards proposed and adopted by communities, industries and the market. Open standards enable and encourage implementors to build systems that can work together.

    - - +In addition, these use-cases often represent a slice of a complex end-to-end business process. To deliver real value, permissioned networks need to seamlessly integrate with each other and with existing systems in order to holistically transform industries. This requirement for interoperation is coming to the fore as networks transition to production and scale towards broader adoption.

    Interoperability in the context of Distributed Ledger Technologies involves enabling the seamless flow of data and value across disparate networks in a manner that preserves their trust and security tenets. This capability can offer a number of benefits such as:

    • Removing data and value silos
    • Increasing market sizes, liquidity and overall efficiency
    • Improving network effects
    • Enabling orchestration of complex business functionality across networks
    • Enabling scale and groawth of networks
    • Encouraging further adoption of the technology

    Unique Technical Challenges

    Enabling interoperation between distributed ledgers presents numerous technical challenges compared to traditional systems integration approaches. This primarily stems from the need to preserve the benefits of decentralised trust beyond the boundaries of a single network. Hence, a naive approach to interoperability based on traditional point-to-point API integration is insufficient for preserving the underlying trust decentralised networks provide. There are two unique challenges present in DLT interoperation:

    Single-party vs Multi-party Trust 

    In distributed ledger architectures, the authority over state lies in a collective and the protocol they employ to ensure its integrity. When one network or an entity consumes state from another, it would need to establish the veracity of the state according to the shared consensus view of parties in the network. This requirement is different than traditional integration with centralised systems wherein the trust for the validity of data is placed on the single party providing the data. Establishing the veracity of state in a decentralized network is not trivial. In most cases, a consumer of state might not be able to observe the full ledger of the network itself. Hence, a consumer needs to obtain an independently verifiable cryptographic proof on the validity of state according to the consensus rules and policies of the source network.

    single-party vs multi-party trust model

    Data vs Asset

    Interoperation should not compromise the invariants enforced by individual networks such as protections against double spends on assets.

    The Role of Standards

    The term ‘interoperability’ is used rather loosely in many contexts and oftentimes without the same implication. What some call ‘interoperability’, others refer to as ‘integration’, ‘interconnectivity’ or ‘compatibility’.

    The primary goal of interoperability is freedom of choice. Interoperability enables users to choose implementations of systems they find suitable for a given problem without constraints on the system’s ability to communicate with other implementations.

    Implicit in the term interoperability is open standards, which distinguishes it from any form of bespoke integration. Open standards can either be de jure standards ratified by a formal standards organization such as ANSI, IETF, or ISO, or de facto standards proposed and adopted by communities, industries and the market. Open standards enable and encourage implementors to build systems that can work together.

    + + \ No newline at end of file diff --git a/docs/internal/activity-plan/index.html b/docs/internal/activity-plan/index.html deleted file mode 100644 index 99532bec1..000000000 --- a/docs/internal/activity-plan/index.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - -activity-plan | Weaver: DLT Interoperability Framework - - - - - -
    -

    activity-plan


    id: activity-plan -title: Activity Plan


    Milestones and Activities

    - - - - \ No newline at end of file diff --git a/docs/internal/development/cordapp-interop/cordapp-interop-api-assets/index.html b/docs/internal/development/cordapp-interop/cordapp-interop-api-assets/index.html deleted file mode 100644 index 5bdfad7ad..000000000 --- a/docs/internal/development/cordapp-interop/cordapp-interop-api-assets/index.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - -cordapp-interop-api-assets | Weaver: DLT Interoperability Framework - - - - - -
    -

    cordapp-interop-api-assets


    id: cordapp-interop-api-assets -title: API Assets


    class AccessControlIssueRequestState(
    linearId: UniqueIdentifier = UniqueIdentifier(),
    externalNetworkId: String,
    externalNetworkCertificates: List<String>,
    requestApprovals: List<DigitalSignature.WithKey>,
    stateLinearId: UniqueIdentifier,
    participants: List<Party>
    ) : LinearState

    class FormattedResponse(
    organizationName: String,
    decryptedPayload: String,
    certString: String,
    signatureBytes: ByteArray,
    message: ByteArray,
    publicKey: PublicKey
    )

    class RelayRequestObject(
    operationType: String,
    policy: String,
    function: String,
    arguments: List<String>,
    clientOrganizationId: String,
    clientCertificate: String,
    clientSignature: String
    )

    class RelayResponseObject(
    requestId: String,
    status: String,
    response: List<NodeResponse>?
    )

    class NodeResponse(
    proposal: String,
    proposalResponse: String
    )

    class RelayRequestId(
    requestId: String
    )

    class ExternalStateRequest(
    url: String,
    path: String,
    externalNetworkId: String,
    requestId: String,
    function: String,
    participants: List<String>,
    mock: String?
    )

    class ForeignNetworkMapInformationIntermediateResponse(
    CarrierMSP: FNNode,
    SellerMSP: FNNode
    )

    class FNNode(
    admins: List<String>,
    crypto_config: CryptoConfig,
    fabric_node_ous: String?,
    intermediate_certs: List<String>,
    name: String,
    organizational_unit_identifiers: List<String>,
    revocation_list: List<String>,
    root_certs: List<String>,
    signing_identity: String?,
    tls_intermediate_certs: List<String>,
    tls_root_certs: List<String>
    )

    class CryptoConfig(
    identity_identifier_hash_function: String,
    signature_hash_family: String
    )

    class TxIdResponseObject(
    queryResponse: List<List<StateQueryResponse>?>
    )

    class LinearIdResponseObject(
    queryResponse: List<StateQueryResponse>
    )

    class QueryResponse(
    state: String,
    linearId: String
    )

    class ParsedQueryObject(
    linearId: UniqueIdentifier,
    txId: String?
    )

    class ExternalNetworkRequest(
    externalNetworkId: String,
    organizationName: String,
    requesterCertificate: String,
    requesterSignature: String,
    stateLinearId: String
    )

    class NetworkMapObject(
    networkId: String,
    nodes: List<Node>
    )

    class Node(
    name: String,
    address: String,
    hierarchicalCerts: List<ByteArray>,
    hierarchicalCANames: List<String>
    )

    class ExternalNetworkRequestWithTxId(
    externalNetworkId: String,
    organizationName: String,
    requesterCertificate: String,
    requesterSignature: String,
    txId: String
    )

    class FNIMStateRequest(
    networkId: String,
    topology: List<FNNode>,
    participants: List<String>
    )

    class FNIMStateResponse(
    linearId: UniqueIdentifier,
    networkId: String,
    topology: List<FNNode>,
    participants: List<String>
    )

    class AccessControlIssueRequestStateRequest(
    externalNetworkId: String,
    externalNetworkCertificates: List<String>,
    stateLinearId: String,
    participants: List<String>
    )

    class AccessControlIssueRequestStateResponse(
    linearId: UniqueIdentifier,
    externalNetworkId: String,
    externalNetworkCertificates: List<String>,
    requestApprovals: List<String>,
    stateLinearId: String,
    participants: List<String>
    )

    class AccessControlStateResponse(
    linearId: UniqueIdentifier,
    externalNetworkId: String,
    externalNetworkCertificates: List<String>,
    stateLinearId: String,
    participants: List<String>
    )
    - - - - \ No newline at end of file diff --git a/docs/internal/development/cordapp-interop/cordapp-interop-assets/index.html b/docs/internal/development/cordapp-interop/cordapp-interop-assets/index.html deleted file mode 100644 index adb151dbb..000000000 --- a/docs/internal/development/cordapp-interop/cordapp-interop-assets/index.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - -cordapp-interop-assets | Weaver: DLT Interoperability Framework - - - - - -
    -

    cordapp-interop-assets


    id: cordapp-interop-assets -title: CorDapp Assets


    class AccessControlState(
    linearId: UniqueIdentifier = UniqueIdentifier(),
    externalNetworkId: String,
    externalNetworkCertificates: List<String>,
    stateLinearId: UniqueIdentifier,
    participants: List<Party>
    ) : LinearState

    class ExternalStateObjectState(
    linearId: UniqueIdentifier = UniqueIdentifier(),
    participants: List<Party>,
    externalState: String,
    externalNetworkId: String,
    responseObject: List<FormattedResponse>
    ) : LinearState

    class ForeignNetworkInformationManagementState(
    linearId: UniqueIdentifier = UniqueIdentifier(),
    participants: List<Party>,
    networkId: String,
    topology: List<FNNode>
    ) : LinearState
    - - - - \ No newline at end of file diff --git a/docs/internal/development/cordapp-interop/cordapp-interop-flows/index.html b/docs/internal/development/cordapp-interop/cordapp-interop-flows/index.html deleted file mode 100644 index af0cd2d74..000000000 --- a/docs/internal/development/cordapp-interop/cordapp-interop-flows/index.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - -cordapp-interop-flows | Weaver: DLT Interoperability Framework - - - - - -
    -

    cordapp-interop-flows


    id: cordapp-interop-flows -title: Flows


    AccessControlFlows

    class AccessControlIssueRequestInitiator(
    externalNetworkCertificates: List<String>,
    externalNetworkId: String,
    stateLinearId: UniqueIdentifier,
    participants: List<Party> {
    // creates an access control state on the ledger for a particular document
    }

    class AccessControlIssueRequestApprover(
    id: UniqueIdentifier){
    // allows for a party to approve an access control issuance request
    }

    AccessControlQueryFlows

    class QueryAccessControlIssueRequestStates() List<AccessControlIssueRequestState> {
    // returns access control requests
    }

    class QueryAccessControlIssueRequestStateByLinearId(linearId: UniqueIdentifier) AccessControlIssueRequestState {
    // returns access control request by Id
    }

    class QueryAccessControlStates() List<AccessControlState> {
    // returns list of access control states
    }

    class QueryAccessControlStateByLinearId(linearId: UniqueIdentifier) AccessControlState {
    // returns access control state by Id
    }

    FNIMFlows

    class FNIMInitiator(
    networkId: String,
    topology: List<FNNode>,
    participants: List<Party>) {
    // creates FNIM record for an external network
    }

    class FNIMExitInitiator(
    id: String ) {
    // marks FNIM state as consumed
    }

    FNIMQueryFlows

    class QueryForeignNetworkInformationManagementStates : List<ForeignNetworkInformationManagementState> {
    // returns list of FNIM states
    }

    class QueryForeignNetworkInformationManagementStatesById(
    linearId: UniqueIdentifier) ForeignNetworkInformationManagementState {
    // returns FNIM state
    }

    class QueryForeignNetworkInformationManagementStateByNetworkId(
    networkId: String) ForeignNetworkInformationManagementState {
    // returns FNIM state for specified network
    }

    HandleRequestsFromForeignNetworkFlows

    class StateQueryInitiator(
    externalNetworkId: String,
    organizationName: String,
    stateLinearId: UniqueIdentifier,
    requesterCertString: String,
    requesterSignature: String,
    txId: String?
    ) List<StateQueryResponse> {
    // returns requested state
    }

    class GetLinearIdsFromTxId(
    txId: String
    ) List<UniqueIdentifier> {
    // returns list ids for states that match the query criterion
    }

    WriteStateFromExternalNetworkFlows

    class CreateExternalRequestStateObject(
    request: ExternalStateRequest
    ) RelayRequestObject {
    // returns request object to query relay about a foreign network state
    }

    class WriteExternalStateInitiator(
    nodeResponses: List<NodeResponse>,
    externalNetworkId: String,
    participants: List<Party>
    ) UniqueIdentifier {
    // writes external state to ledger and returns unique identifier to be used to query from MarcoPolo
    }
    - - - - \ No newline at end of file diff --git a/docs/internal/development/cordapp-interop/cordapp-interop-rest-api/index.html b/docs/internal/development/cordapp-interop/cordapp-interop-rest-api/index.html deleted file mode 100644 index 9f31ba7b6..000000000 --- a/docs/internal/development/cordapp-interop/cordapp-interop-rest-api/index.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - -cordapp-interop-rest-api | Weaver: DLT Interoperability Framework - - - - - -
    -

    cordapp-interop-rest-api


    id: cordapp-interop-rest-api -title: REST API


    Documentation of the REST API that is intended to be called from the MarcoPolo CordApp with the underlying -flows noted.

    GET networkMapSnapshot
    req: {}
    res: List<NodeInfo>, or failure
    calls: proxy.networkMapSnapshot

    GET registeredFlows
    req: {}
    res: List<String>, or failure
    calls: proxy.registeredFlows

    GET foreignNetworkInfos
    req: {}
    res: List<ForeignNetworkInformationManagementState>, or failure
    calls: QueryForeignNetworkInformationManagementStates

    GET foreignNetworkInfos/{id}
    req: {}
    res: ForeignNetworkInformationManagementState, or failure
    calls: QueryForeignNetworkInformationManagementStatesById

    POST foreignNetworkInfos
    req: FNIMStateRequest
    res: FNIMStateResponse, or failure
    calls: FNIMInitiator

    DELETE foreignNetworkInfos/{id}
    req: {}
    res: id, or failure
    calls: FNIMExitInitiator

    GET accessControlRequests
    req: {}
    res: AccessControlIssueRequestStateResponse, or failure
    calls: QueryAccessControlIssueRequestStateByLinearId

    POST accessControlRequests/new
    req: AccessControlIssueRequestStateRequest
    res: AccessControlIssueRequestStateResponse, or failure
    calls: AccessControlIssueRequestInitiator

    POST /accessControlRequests/approve/{id}
    req: id
    res: AccessControlIssueRequestStateResponse, or failure
    calls: AccessControlIssueRequestApprover

    GET accessControlStates
    req: {}
    res: List<AccessControlState>, or failure
    calls: QueryAccessControlStates

    GET accessControlStates/{id}
    req: {}
    res: AccessControlStateResponse, or failure
    calls: QueryAccessControlIssueRequestStateByLinearId

    POST externalNetworkRequest
    req: ExternalNetworkRequest
    res: LinearIdResponseObject, or failure
    calls: StateQueryInitiator

    POST externalNetworkRequestByTxId
    req: ExternalNetworkRequestWithTxId
    res: TxIdResponseObject, or failure
    calls: GetLinearIdsFromTxId

    GET getNetworkMap/{id}
    req: {}
    res: NetworkMapObject, or failure
    calls: proxy.networkMapSnapshot

    POST requestExternalState
    req: ExternalStateRequest
    res: UniqueIdentifier, or failure
    calls: WriteExternalStateInitiator

    GET storeFNIM
    req: {}
    res: ForeignNetworkMapInformationIntermediateResponse, or failure
    calls: QueryForeignNetworkInformationManagementStateByNetworkId
    - - - - \ No newline at end of file diff --git a/docs/internal/development/cordapp-interop/index.html b/docs/internal/development/cordapp-interop/index.html deleted file mode 100644 index b288ddfda..000000000 --- a/docs/internal/development/cordapp-interop/index.html +++ /dev/null @@ -1,128 +0,0 @@ - - - - - -cordapp-interop | Weaver: DLT Interoperability Framework - - - - - -
    -

    cordapp-interop


    id: cordapp-interop -title: Interoperation CorDapp


    Interoperation CorDapp


    Contributors: Chander Govindarajan, Allison Irvin, Isabell Kiral


    This document contains the specification for the interoperation application including the system, the CorDapp flow design and the application server details. -This CorDapp serves as the bridge between an established CorDapp and the relay. -There are three main functions of the Interoperation CorDapp:

    1. It defines states, contracts and flows for authenticating participants of an external network and providing access control to Corda application states.
    2. It defines flows for enabling an external network to query a Corda application.
    3. It defines flows for enabling a Corda application to query an external network.

    The Corda interoperability application consists of the CorDapp itself, containing flows, contracts and state definitions, as well as a webserver with a REST API that connects to the Corda nodes via RPC to trigger flows. -There is no user interface for the interoperability functionality. -The REST API is designed to be consumed by a Corda application that wishes to incorporate state synchronisation with an external network.

    To view the assets, flows and API specification in full without any of the descriptions see these pages:

    General Corda notes

    Corda provides many state interfaces to aid in standardisation across CorDapps. -States must extend the ContractState interface, which contains a list of AbstractParty, called participants. -This defines which Corda identities must sign off on transactions that consume state of that type. -For states where instances evolve by superseding itself, Corda provides the LinearState interface. -This includes a property linearId, which is a unique identifier that all versions of the state will preserve throughout the lifecycle of the state.

    1. Authentication of external networks

    Foreign Network Information Management

    In order to control access to state in a Corda application or to verify state coming from an external network, the Corda network needs to have some way of authenticating parties in the external network. -The Foreign Network Information Management (FNIM) state contains a network map of the foreign network, including an identifier associated with the foreign network as well as a description of each of the foreign network nodes (FNNodes). -This FNIM state is used to verify the identity of external network parties interacting with the Corda network. -Every interaction requires a signature of the external network party. -The signature is verified against the provided certificate and the authenticity of the certificate is verified against the FNIM state. -In our current design, the definition of these FNNodes is very Fabric-centric, as the Fabric-Fabric interoperability design used the network map the way it was stored on the Ordering Service channel. -In order to not have to make significant changes to the way the Fabric network published its network map, this format was used to consume the FNIM in the Interoperation CorDapp, complete with fields such as crypto_config and fabric_node_ous. -The Fabric nodes' info was also stored as a key-value with the key being the name of the Fabric organisation (e.g. SellerMSP). -In a more generalised interoperation protocol, we should think about common features that all DLT networks are required to provide in order for external networks to be able to properly identify and authenticate participants.

    An FNIM state is created for an external network on the level of a group of Corda participants. -The Corda participants that are listed in the FNIM state are responsible for creating the FNIM state and ensuring it is kept up to date with the external network configuration. -In the current model, this is done manually, with the endpoint to fetch the network map from the external network through the relay hardcoded into the interoperation REST API endpoint. -This endpoint is also used to update the FNIM state when the foreign network topology changes. -The application middleware checks if there is an FNIM state for that networkId already, and if so, deletes it before creating a new state with the updated details. -In our demo, the participants of the FNIM state are also hardcoded. -The flow that creates an FNIM state does not require any manual sign-off by counterparties. -The flow triggers a subflow in all participant nodes listed in the state, that checks the transaction against the contract and signs the transaction if the verification passes.

    In a more generalised protocol, it would be preferable to have a standardised format for the publication of network maps. -For example, having a decentralised identity platform for the storage of DLT network that were discoverable by other networks would be ideal. -Otherwise, having all networks provide their network map through a consistent API, would also be helpful.

    The Corda parties that control the creation and management of FNIM states in the Corda network also needs to be revisited. -For example, ensuring currency of an FNIM state for a particular external network could be up to a group of participants that share some state together that they wish to have synchronised with the external network. -Alternatively, a dedicated group of Corda parties could be responsible for maintaining currency of the configurations of all the external networks that any group of participants may wish to interoperate with in a Corda network. -The mechanism for updating FNIM state when external network configuration changes should also be revisited, rather than deleting the existing state and creating a new one.

    Similarly to the requirement for a Corda network to have access to the network map of an external network, the external network must also have a snapshot of the Corda network they wish to interoperate with in order to validate requests and responses. -The exposure of the network map is currently done through the individual Corda applications as the information that each network wishes to share externally will vary on a case-by-case basis. -This model can be revised if needed for the next iteration of the protocol.

    FNIM CorDapp Assets

    class ForeignNetworkInformationManagementState(
    linearId: UniqueIdentifier = UniqueIdentifier(),
    participants: List<Party>,
    networkId: String,
    topology: List<FNNode>
    ) : LinearState

    class FNNode(
    admins: List<String>,
    crypto_config: CryptoConfig,
    fabric_node_ous: String?,
    intermediate_certs: List<String>,
    name: String,
    organizational_unit_identifiers: List<String>,
    revocation_list: List<String>,
    root_certs: List<String>,
    signing_identity: String?,
    tls_intermediate_certs: List<String>,
    tls_root_certs: List<String>
    )

    class CryptoConfig(
    identity_identifier_hash_function: String,
    signature_hash_family: String
    )

    FNIM API Assets

    class FNIMStateRequest(
    networkId: String,
    topology: List<FNNode>,
    participants: List<String>
    )

    class FNIMStateResponse(
    linearId: UniqueIdentifier,
    networkId: String,
    topology: List<FNNode>,
    participants: List<String>
    )

    class ForeignNetworkMapInformationIntermediateResponse(
    CarrierMSP: FNNode,
    SellerMSP: FNNode
    )

    FNIM Flows

    class FNIMInitiator(
    networkId: String,
    topology: List<FNNode>,
    participants: List<Party>) {
    // creates FNIM record for an external network
    }

    class FNIMExitInitiator(
    id: String ) {
    // marks FNIM state as consumed
    }

    FNIM Query Flows

    class QueryForeignNetworkInformationManagementStates : List<ForeignNetworkInformationManagementState> {
    // returns list of FNIM states
    }

    class QueryForeignNetworkInformationManagementStatesById(
    linearId: UniqueIdentifier) ForeignNetworkInformationManagementState {
    // returns FNIM state
    }

    class QueryForeignNetworkInformationManagementStateByNetworkId(
    networkId: String) ForeignNetworkInformationManagementState {
    // returns FNIM state for specified network
    }

    FNIM application REST API and Corda flow connections

    GET storeFNIM
    req: {}
    res: ForeignNetworkMapInformationIntermediateResponse, or failure
    calls:
    1. <foreign-network-id-and-certs-configuration-url> to get ForeignNetworkMapInformationIntermediateResponse
    2. QueryForeignNetworkInformationManagementStateByNetworkId to check if FNIM exists for this network already
    3. FNIMExitInitiator (if FNIM exists already)
    4. FNIMInitiator

    POST foreignNetworkInfos
    req: FNIMStateRequest
    res: FNIMStateResponse, or failure
    calls: FNIMInitiator

    DELETE foreignNetworkInfos/{id}
    req: {}
    res: id, or failure
    calls: FNIMExitInitiator

    GET foreignNetworkInfos
    req: {}
    res: List<ForeignNetworkInformationManagementState>, or failure
    calls: QueryForeignNetworkInformationManagementStates

    GET foreignNetworkInfos/{id}
    req: {}
    res: ForeignNetworkInformationManagementState, or failure
    calls: QueryForeignNetworkInformationManagementStatesById

    Access Control

    The Interoperation CorDapp allows groups of Corda parties to grant access to their application states through AccessControlStates. -These Access Control states are issued on a per-application state and per-external network basis (for example, for a particular letter of credit and for a particular external network). -The application state for which the Access Control state pertains is denoted by the stateLinearId and the external network is specified by the externalNetworkId that should match the externalNetworkId for the FNIM state. -The Access Control state also lists the certificates of the parties of the external network who are allowed to make requests for state. -These are included in the externalNetworkCertificates field.

    This is just one approach that could be used to grant access to foreign network participants. -It may be desirable to be able to set access control rules on a Corda application level (e.g. allow one Access Control state to govern access to all Corda states for a given application). -Therefore, this may need to be revisited for the next version of the interoperation protocol.

    As the Access Control state defines whether an external party can access state from the Corda ledger, explicit approval needs to be given by each participant of the Corda state. -These approvals are captured in an Access Control Request State. -Once all participants have manually approved the request through initiating the AccessControlIssueRequestApprover, an Access Control state will be created.

    The workflow to grant access to application states needs to be built into the application for a particular CorDapp. -For example, as a part of a trade logistics application, one part of the user interface could include allowing particular external network participants to request a current view of a letter of credit state. -All participants of that letter of credit would have to approve the access control request before it becomes active. -This workflow was not built into the Corda-Fabric interoperability demo, with the creation and approval of an Access Control request being triggered through the interoperation middleware when an external network request for Corda state is received.

    Access Control CorDapp Assets

    class AccessControlIssueRequestState(
    linearId: UniqueIdentifier = UniqueIdentifier(),
    externalNetworkId: String,
    externalNetworkCertificates: List<String>,
    requestApprovals: List<DigitalSignature.WithKey>,
    stateLinearId: UniqueIdentifier,
    participants: List<Party>
    ) : LinearState

    class AccessControlState(
    linearId: UniqueIdentifier = UniqueIdentifier(),
    externalNetworkId: String,
    externalNetworkCertificates: List<String>,
    stateLinearId: UniqueIdentifier,
    participants: List<Party>
    ) : LinearState

    Access Control API Assets

    class AccessControlIssueRequestStateRequest(
    externalNetworkId: String,
    externalNetworkCertificates: List<String>,
    stateLinearId: String,
    participants: List<String>
    )

    class AccessControlIssueRequestStateResponse(
    linearId: UniqueIdentifier,
    externalNetworkId: String,
    externalNetworkCertificates: List<String>,
    requestApprovals: List<String>,
    stateLinearId: String,
    participants: List<String>
    )

    class AccessControlStateResponse(
    linearId: UniqueIdentifier,
    externalNetworkId: String,
    externalNetworkCertificates: List<String>,
    stateLinearId: String,
    participants: List<String>
    )

    Access Control Flows

    class AccessControlIssueRequestInitiator(
    externalNetworkCertificates: List<String>,
    externalNetworkId: String,
    stateLinearId: UniqueIdentifier,
    participants: List<Party> {
    // Creates an access control request on the ledger for a particular document
    }

    class AccessControlIssueRequestApprover(
    id: UniqueIdentifier){
    // Allows for a party to approve an access control issuance request
    // Once all parties listed as a participant of the state the access control request pertains to
    // have approved the request, an AccessControlState is created
    }

    Access Control Query Flows

    class QueryAccessControlIssueRequestStates() List<AccessControlIssueRequestState> {
    // returns access control requests
    }

    class QueryAccessControlIssueRequestStateByLinearId(linearId: UniqueIdentifier) AccessControlIssueRequestState {
    // returns access control request by Id
    }

    class QueryAccessControlStates() List<AccessControlState> {
    // returns list of access control states
    }

    class QueryAccessControlStateByLinearId(linearId: UniqueIdentifier) AccessControlState {
    // returns access control state by Id
    }

    class QueryAccessControlStatesByStateIdAndNetworkId(
    stateLinearId: UniqueIdentifier,
    externalNetworkId: String
    ) AccessControlState {
    // returns access control state by the linearId of the application state and the external network Id
    }

    Access Control Application REST API and Corda Flow Connections

    POST accessControlRequests/new
    req: AccessControlIssueRequestStateRequest
    res: AccessControlIssueRequestStateResponse, or failure
    calls: AccessControlIssueRequestInitiator

    POST /accessControlRequests/approve/{id}
    req: id
    res: AccessControlIssueRequestStateResponse, or failure
    calls: AccessControlIssueRequestApprover

    GET accessControlRequests
    req: {}
    res: AccessControlIssueRequestStateResponse, or failure
    calls: QueryAccessControlIssueRequestStateByLinearId

    GET accessControlStates
    req: {}
    res: List<AccessControlState>, or failure
    calls: QueryAccessControlStates

    GET accessControlStates/{id}
    req: {}
    res: AccessControlStateResponse, or failure
    calls: QueryAccessControlIssueRequestStateByLinearId

    2. Handle external networks querying a Corda application for state

    An external network can make a request for Corda state by reaching the interoperability CorDapp through the relay.

    For an external network request to be successful it must fulfill the following:

    1. The identity of the requester needs to be authenticated through a signature on the request and a provided certificate. The signature is either made on the linearId or the txId that is provided in the request.
    2. The certificate needs to be validated against the FNIM stored for the external network (i.e. the certificate needs to be issued by an issuing CA listed in the FNIM and the hierarchy of certificates in the FNIM needs to be validated up to the rootCA).
    3. The desired state needs to be located in the vault of the Corda node processing the request.
    4. A corresponding Access Control state needs to be found for the desired state and the certificate of the requester needs to be listed in the Access Control state.

    The Corda node processing the request then needs to assemble a response object that includes the desired state and a signature on the state that provides evidence that this was the current view of the state according to that node. -The Corda node then needs to forward the request on to all participants of the state, who run through the same process for validation of the request and assembly of the response object. -The responses from each of the Corda nodes are collected by the initial Corda node and returned to the relay who pass the response back to the requesting network. -Collectively, the responses from all Corda nodes (provided they shared the same view of the state) should be enough to convince the requester of the current state in the Corda ledger. -This assumes that the requesting network trusts that the Corda network participants are not colluding to misrepresent the state. -Whether we want to provide stronger assurances of the currency and finality of state by requiring the Notary also sign off on the state can be assessed in the next iteration.

    There must be some way of identifying the desired Corda state without necessitating that the interoperation Cordapp be aware of the data classes of the Corda application. -In Fabric, this was done by the requesting network passing the chaincode query function name and the query in the request. -In Corda, this approach needs to be revisited because there is no concept of a chaincode query function. -The initial approach taken in the demo was to identify the Corda state by linearId as this guarantees that the state can be uniquely identified in the vault. -However, there is no guarantee that states will have a unique identifier as not all application states will extend the LinearState interface. -As well, the linearId is a property generated in Corda on creation of the state and may be meaningless in the business process. -Therefore, it cannot be assumed that an external network will have visibility of the linearId. -Our workaround for the demo was to create a custom endpoint externalNetworkRequestByTxId where the desired state was identified by a property unique to a letter of credit - the txId. -A set of linearIds that corresponded to that txId were then found using a custom flow called GetLinearIdsFromTxId. -The request was then validated according to the criteria above (valid signature, valid certificate according to FNIM, valid Access Control state) and a response object generated for each state located by linearId. -Other approaches that could be more appropriate for Corda may include creating query flows in the CorDapp application that work in a similar way to chaincode query functions. -This would involve investigating if cross-CorDapp triggering of flows is possible, and if so, how they can be executed. -Another approach could be requiring a CustomQueryCriteria in the request that comes from the external network. -Again, we would have to investigate if CustomQueryCriteria can be used in a CorDapp that has no knowledge of the application states for which that query pertains. -Regardless of the approach to address state within Corda, for the next iteration of the protocol we need to think about how to generalise this across enterprise DLTs.

    Another workaround for the demo also of note here is the automatic generation of an Access Control state for the states specified in the request. -As we had not implemented any workflow or user interface in the Corda application for granting access to external network participants, creation of an Access Control state was triggered when the interoperation CorDapp received a request from an external network. -Note that the functionality for a Corda application to incorporate the creation of Access Control states into their workflows is present in the interoperation APIs. -This workaround was put in place purely because the demo did not include a demonstration of this workflow. -Some further thought will need to be put into the workflow in the application CorDapp, especially with how external network parties are represented (for example, will the application CorDapp require access to the participant certificates listed in the FNIM?).

    Things to think about in the next iteration of the protocol:

    • Trust model of the relay - does the request need to be encrypted?
    • How do we address the Corda nodes in the request so the relay can know which node to forward the request on to
    • Do we need to include guidelines about the encryption and signature schemes that can be used? Will accepted encryption and signature schemes vary on a network-by-network basis? If so, do we need some way of publishing what encryption and signature schemes a network accepts?
    • How to generalise the addressing of state? In Corda this could be a CustomQueryCriteria, in Fabric this is currently done through chaincode function and query
    • How to handle multiple states being found
    • Next iteration needs to handle replay attacks - provide a nonce in the request
    • Currently the organizationName of the requester is required in the request. We need a more general way of linking the requester identity with the issuing CA in the FNIM.

    Handle Requests From Foreign Network - CorDapp Assets

    The StateQueryResponse is the object assembled by each Corda node for each requested state. -The requestedState field is a JSON string of the QueryResponse that is encoded in Base64 as a bytearray. -The certificate is the certificate of the Corda node providing the state and is used by the requesting network to validate the signature and the identity of the Corda node against their locally stored copy of the Corda network FNIM. -The signature is the signature of the Corda node signed on the requestedState bytearray.

    The state field in QueryResponse is a JSON string of the Corda application state. -For the demo, some of the JSON attributes were manipulated by converting to lowercase from camelcase, and renaming some fields. -This was done as the Fabric application was expecting the letter of credit state to be returned in a particular form. -Ideally, the Interoperation CorDapp would not manipulate the state in any way before it is returned. -It also cannot be expected that the Corda application needs to modify its data structures in any way to conform with an external network's data structure. -It should be up to the consuming network to parse the state it receives into a meaningful format for its own application.

    class StateQueryResponse(
    requestedState: ByteArray,
    certificate: ByteArray,
    signature: ByteArray
    )

    class QueryResponse(
    state: String,
    linearId: String
    )

    Handle Requests From Foreign Network - API Assets

    ExternalNetworkRequest or ExternalNetworkRequestWithTxId are the two request bodies that the external network can provide. -These are based on whether the external network is identifying the Corda application state by linearId or txId. -As mentioned previously, for the demo the latter request type was used as we assumed that the external network would not have any visibility of the linearId property of a Corda state. -The externalNetworkId needs to match with the externalNetworkId used to store the FNIM for the requesting network. -The organizationName is a Fabric-specific artifact that stems from the way identities are grouped under organizations. -This field is needed in order to validate the identity of the requester in the FNIM by finding the correct issuing CA of the credentials. -This will need to be revised in the next iteration of the protocol as the FNIM will need to be generalised to be applicable to all enterprise DLTs.

    class ExternalNetworkRequest(
    externalNetworkId: String,
    organizationName: String,
    requesterCertificate: String,
    requesterSignature: String,
    stateLinearId: String
    )

    class ExternalNetworkRequestWithTxId(
    externalNetworkId: String,
    organizationName: String,
    requesterCertificate: String,
    requesterSignature: String,
    txId: String
    )

    Handle Requests From Foreign Network - Flows

    class StateQueryInitiator(
    externalNetworkId: String,
    organizationName: String,
    stateLinearId: UniqueIdentifier,
    requesterCertString: String,
    requesterSignature: String,
    txId: String?
    ) List<StateQueryResponse> {
    // returns requested state and associated proof
    }

    class GetLinearIdsFromTxId(
    txId: String
    ) List<UniqueIdentifier> {
    // returns list ids for states that match the query criterion
    }

    Handle Requests From Foreign Network - Application REST API and Corda Flow Connections

    The externalNetworkRequest POST endpoint is used to find the Corda application state based on linearId. -It will return a StateQueryResponse for each Corda node listed as a participant in the state, or in the case that a state is not found or access is denied for the requester, will fail. -The externalNetworkRequestByTxId POST endpoint finds Corda application state based on txId and could potentially match with multiple states. -Therefore, for each accessible state found, each Corda node listed as a participant in the state will provide a StateQueryResponse. -If no states are found or the requester does not have permission to access the state, an empty list will be returned. -Note that the access control calls that are made are purely a workaround from the fact that the setup of state access control was not built into the demo.

    POST externalNetworkRequest
    req: ExternalNetworkRequest
    res: List<StateQueryResponse>, or failure
    calls:
    1. <interoperation-webserver1-url>/accessControlRequests/new
    2. <interoperation-webserver2-url>/accessControlRequests/approve
    3. StateQueryInitiator

    POST externalNetworkRequestByTxId
    req: ExternalNetworkRequestWithTxId
    res: List<List<StateQueryResponse>?>
    calls:
    1. <interoperation-webserver1-url>/accessControlRequests/new
    2. <interoperation-webserver2-url>/accessControlRequests/approve
    3. GetLinearIdsFromTxId
    4. StateQueryInitiator (for each linearId)

    3. Requests to get state from external networks

    In the opposite case from the previous section, the Interoperation CorDapp also allows a Corda application to request a state from an external network. -This consists of the following steps:

    1. A Corda application uses the Interoperation CorDapp API to trigger the request to the external network (takes a ExternalStateRequest)
    2. The Interoperation CorDapp creates a request object to send to the foreign network's relay (RelayRequestObject)
    3. The returned state and proofs are validated
    4. The external network's state is stored in the vault along with the associated proofs
    5. The linearId of the state is returned to the Corda application
    6. The Corda application retrieves the state from the vault

    Request State from External Network - CorDapp Assets

    The ExternalStateRequest is the request object the webserver receives as part of the POST requestExternalState endpoint. -It is used by the webserver to know how to address the relay and it is also passed on to the CreateExternalRequestStateObject flow to construct the request object that will be forwarded to the relay. -The url and the path are required to the webserver knows how to address the relay to forward the request on to. -The externalNetworkId identifies the external network the relay needs to forward the request to and needs to match the id used in the FNIM. -The arguments contains the arguments that will be passed to the specified chaincode function, function. -These parameters, arguments and function are very Fabric-centric and we should generalise the method of addressing state across DLTs for future iterations of the interoperation protocol. -The participants is the list of Corda participants that will need own the Fabric state when it is stored in Corda. -To make this code a little cleaner, we should probably have the request object received by the webserver defined in the API assets, which should include url, path, participants and requestParameters. -The requestParameters would be forwarded on to the CreateExternalRequestStateObject flow, and would only include those fields relevant to the flow (externalNetworkId, function and arguments). -However, seeing as the way we address state in a more general protocol is going to change, we probably don't need to worry about cleaning this up in the demo code.

    class ExternalStateRequest(
    url: String,
    path: String,
    externalNetworkId: String,
    arguments: String,
    function: String,
    participants: List<String>
    )

    The RelayRequestObject is what the interoperation CorDapp sends to the relay to forward on to the Fabric network. -operationType defines the type of operation the Corda network wants to perform on the chaincode - either INVOKE or QUERY. -For now, the QUERY operation is the only one that is supported on the Fabric end and is hardcoded in the CreateExternalRequestStateObject flow where an instance of RelayRequestObject is created. -To be consistent, operationType should probably have been included in the ExternalStateRequest that was passed into the flow. -Again, seeing as the way we address state is going to change, we won't worry about changing the demo code. -The policy refers to the endorsement policy of the Fabric channel for the particular state that the Corda application is requesting. -A more detailed discussion of how the policy is defined and how it should be defined is in the flows section. -The fields function and arguments are copied across from what is provided in the ExternalStateRequest that comes from the client application. -On the Fabric end, the Fabric nodes will want to authenticate the Corda node making the request - enabled through clientOrganizationId, clientCertificate and clientSignature.

    class RelayRequestObject(
    operationType: String,
    policy: String,
    function: String,
    arguments: List<String>,
    clientOrganizationId: String,
    clientCertificate: String,
    clientSignature: String
    )

    The ExternalStateObjectState is the way the state and proof that is returned from the external network is saved as a state in the Corda vault.

    class ExternalStateObjectState(
    linearId: UniqueIdentifier = UniqueIdentifier(),
    participants: List<Party>,
    externalState: String,
    externalNetworkId: String,
    responseObject: List<FormattedResponse>
    ) : LinearState

    class FormattedResponse(
    organizationName: String,
    decryptedPayload: String,
    certString: String,
    signatureBytes: ByteArray,
    message: ByteArray,
    publicKey: PublicKey
    )

    class RelayResponseObject(
    requestId: String,
    status: String,
    response: List<NodeResponse>?
    )

    class NodeResponse(
    proposal: String,
    proposalResponse: String
    )

    class RelayRequestId(
    requestId: String
    )

    class ParsedQueryObject(
    linearId: UniqueIdentifier,
    txId: String?
    )

    class NetworkMapObject(
    networkId: String,
    nodes: List<Node>
    )

    class Node(
    name: String,
    address: String,
    hierarchicalCerts: List<ByteArray>,
    hierarchicalCANames: List<String>
    )

    WriteStateFromExternalNetworkFlows

    The CreateExternalRequestStateObject flow takes the request from the Corda application (through the webserver) and creates the request object that the relay needs to pass on to the external network. -It first looks up the FNIM for the external network based off the provided external netowrk id. -The policy for the RelayRequestObject is created by concatenating the name of each of the FNNodes that are present in the ForeignNetworkInformationManagementState for that network, separated by the & symbol (e.g. for the demo SellerMSP & CarrierMSP). -This approach is not ideal as it is very Fabric-centric and is currently hardcoded to be all of the nodes listed in the FNIM for the network, which may or may not be the correct endorsement policy needed for the state. -How endorsement policy should be represented in the interoperation CorDapp has been raised as an issue in the cordapp-interop repo. -The endorsement policy is a concept that is present in all permissioned DLTs (although not always called "endorsement policy"). -It refers to the set of parties who have ownership of a state, or who control the update of a state. -We should generalise this concept in the next iteration of the protocol and store the endorsement policies for an external network as states that can be looked up by the interop CorDapp. -The clientCertificate is a string of the Corda node X.509 certificate in PEM format. -The signature is a Base 64 string, signed on a concatenation of the function, arguments and clientOrganizationId represented as Base 64 byte arrays.

    class CreateExternalRequestStateObject(
    request: ExternalStateRequest
    ) RelayRequestObject {
    // returns request object to query relay about a foreign network state
    }

    The WriteExternalStateInitiator flow is used to verify the state proof that is returned from the external network and commit the state to the vault.

    class WriteExternalStateInitiator(
    nodeResponses: List<NodeResponse>,
    externalNetworkId: String,
    participants: List<Party>
    ) UniqueIdentifier {
    // writes external state to ledger and returns unique identifier to be used to query from MarcoPolo
    }

    Application REST API and Corda flow connections


    POST requestExternalState
    req: ExternalStateRequest
    res: UniqueIdentifier, or failure
    calls:
    1. CreateExternalRequestStateObject
    2. HTTP POST request to relay with the provided url and path
    3. HTTP GET request to relay to get the response from the external network
    4. WriteExternalStateInitiator
    - - - - \ No newline at end of file diff --git a/docs/internal/documentation-guidelines/index.html b/docs/internal/documentation-guidelines/index.html deleted file mode 100644 index 42cc92f61..000000000 --- a/docs/internal/documentation-guidelines/index.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - -documentation-guidelines | Weaver: DLT Interoperability Framework - - - - - -
    -

    documentation-guidelines


    id: documentation-guidelines -title: Documentation Guidelines


    Documentation Guidelines

    - - - - \ No newline at end of file diff --git a/docs/internal/team/index.html b/docs/internal/team/index.html deleted file mode 100644 index b6e64b25d..000000000 --- a/docs/internal/team/index.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - -team | Weaver: DLT Interoperability Framework - - - - - -
    -
    - - - - \ No newline at end of file diff --git a/index.html b/index.html index b012d35cd..f0d5c0e08 100644 --- a/index.html +++ b/index.html @@ -4,14 +4,14 @@ Hello from Weaver: DLT Interoperability Framework | Weaver: DLT Interoperability Framework - - - + + +
    -

    Weaver: DLT Interoperability Framework

    Documentation

    Network Neutral

    Network Neutral

    Weaver is designed to be agnostic to the underlying distributed ledger protocol and is based on a set of standard specifications.

    Secure

    Secure

    Verifiable state proofs and secure communication ensures integrity and confidentiality.

    Enterprise Grade

    Enterprise Grade

    A high availability architecture with flexible deployment models meets the needs of enterprises deploying Weaver.

    - - +

    Weaver: DLT Interoperability Framework

    Documentation

    Network Neutral

    Network Neutral

    Weaver is designed to be agnostic to the underlying distributed ledger protocol and is based on a set of standard specifications.

    Secure

    Secure

    Verifiable state proofs and secure communication ensures integrity and confidentiality.

    Enterprise Grade

    Enterprise Grade

    A high availability architecture with flexible deployment models meets the needs of enterprises deploying Weaver.

    + + \ No newline at end of file diff --git a/sitemap.xml b/sitemap.xml index 94ef4af7c..4c284b7c5 100644 --- a/sitemap.xml +++ b/sitemap.xml @@ -1 +1 @@ -https://hyperledger-labs.github.io/weaver-dlt-interoperability/blogweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/blog/2021/01/21/cross-chain-assetweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/blog/2021/01/21/emergence-enterprise-interoperabilityweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/blog/archiveweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/architecture-and-design/decentralized-identityweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/architecture-and-design/driversweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/architecture-and-design/overviewweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/architecture-and-design/relayweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/architecture-and-design/weaver-dappsweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/deployment-considerations/deployment-patternsweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/deployment-considerations/governance-and-policiesweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/deployment-considerations/legal-and-regulationweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/design-principlesweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/besuweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/cordaweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/fabricweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/overviewweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/getting-started/guideweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchangeweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/besu-besuweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/corda-besuweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/corda-cordaweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-besuweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-cordaweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-fabricweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overviewweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-transferweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/getting-started/interop/data-sharingweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/getting-started/interop/overviewweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/getting-started/test-network/advanced-configurationweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/getting-started/test-network/ledger-initializationweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/getting-started/test-network/overviewweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-localweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-local-dockerweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-packagesweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-packages-dockerweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/interoperability-modesweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/introductionweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/publicationsweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/roadmapweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/security-model/access-controlweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/security-model/authenticationweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/security-model/end-to-end-securityweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/security-model/proofs-and-verificationweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/specificationsweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/user-stories/financial-marketsweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/user-stories/global-tradeweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/user-stories/legacy-integrationweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/user-stories/overviewweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/what-is-interoperability/integration-patternsweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/what-is-interoperability/levels-of-interoperabilityweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/what-is-interoperability/understanding-interoperabilityweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/internal/activity-planweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/internal/development/cordapp-interop/weekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/internal/development/cordapp-interop/cordapp-interop-api-assetsweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/internal/development/cordapp-interop/cordapp-interop-assetsweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/internal/development/cordapp-interop/cordapp-interop-flowsweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/internal/development/cordapp-interop/cordapp-interop-rest-apiweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/internal/documentation-guidelinesweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/internal/teamweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/weekly0.5 \ No newline at end of file +https://hyperledger-labs.github.io/weaver-dlt-interoperability/blogweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/blog/2021/01/21/cross-chain-assetweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/blog/2021/01/21/emergence-enterprise-interoperabilityweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/blog/archiveweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/architecture-and-design/decentralized-identityweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/architecture-and-design/driversweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/architecture-and-design/overviewweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/architecture-and-design/relayweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/architecture-and-design/weaver-dappsweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/deployment-considerations/deployment-patternsweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/deployment-considerations/governance-and-policiesweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/deployment-considerations/legal-and-regulationweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/design-principlesweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/besuweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/cordaweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/fabricweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/getting-started/enabling-weaver-network/overviewweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/getting-started/guideweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/besu-besuweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/corda-besuweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/corda-cordaweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-besuweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-cordaweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/fabric-fabricweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-exchange/overviewweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/getting-started/interop/asset-transferweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/getting-started/interop/data-sharingweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/getting-started/interop/overviewweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/getting-started/test-network/advanced-configurationweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/getting-started/test-network/ledger-initializationweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/getting-started/test-network/overviewweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-localweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-local-dockerweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-packagesweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-packages-dockerweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/interoperability-modesweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/introductionweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/publicationsweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/roadmapweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/security-model/access-controlweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/security-model/authenticationweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/security-model/end-to-end-securityweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/security-model/proofs-and-verificationweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/specificationsweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/user-stories/financial-marketsweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/user-stories/global-tradeweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/user-stories/legacy-integrationweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/user-stories/overviewweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/what-is-interoperability/integration-patternsweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/what-is-interoperability/levels-of-interoperabilityweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/docs/external/what-is-interoperability/understanding-interoperabilityweekly0.5https://hyperledger-labs.github.io/weaver-dlt-interoperability/weekly0.5 \ No newline at end of file