From 9e0defbb2d1dd0e6d0186005b50d31bf171a56a4 Mon Sep 17 00:00:00 2001 From: Jenkins Date: Tue, 11 May 2021 09:46:38 +0000 Subject: [PATCH] Updates --- 404.html | 10 +- about.html | 12 +- assets/css/0.styles.1d3235b8.css | 1 - assets/css/0.styles.74783a08.css | 1 + assets/js/10.2c46fdf3.js | 1 - assets/js/10.a7e5f96d.js | 1 + assets/js/11.b620ddcc.js | 1 + assets/js/11.bbf981b9.js | 1 - assets/js/12.cf1bd068.js | 1 + assets/js/13.9dfac9d9.js | 1 + assets/js/13.c624f59e.js | 1 - assets/js/{12.af14dcd6.js => 14.1ce3f7fe.js} | 2 +- assets/js/2.8e6705b7.js | 1 - assets/js/2.fd7e9e0b.js | 1 + assets/js/3.8d00273c.js | 1 - assets/js/3.c5869ccf.js | 1 + assets/js/4.b9b777bd.js | 1 + assets/js/5.073c37d9.js | 1 + assets/js/{4.27329ebd.js => 6.7db49fe2.js} | 2 +- assets/js/{5.80ea750d.js => 7.852d0869.js} | 2 +- assets/js/8.9a0afdb5.js | 1 - assets/js/{6.ccddad9d.js => 8.b8ee59fd.js} | 2 +- assets/js/{7.11707fb6.js => 9.249d32d4.js} | 2 +- assets/js/9.40f78cab.js | 1 - assets/js/app.0bbcba5f.js | 13 -- assets/js/app.b6b895fe.js | 8 ++ index.html | 16 +-- lib/nim-chronicles/index.html | 28 ++-- lib/nim-chronos/index.html | 136 ++++++++++++++++-- lib/nim-eth/index.html | 143 +++++++++++++------ lib/nim-libp2p/index.html | 123 ++-------------- lib/nim-stew/index.html | 18 +-- lib/nimcrypto/index.html | 18 +-- 33 files changed, 314 insertions(+), 238 deletions(-) delete mode 100644 assets/css/0.styles.1d3235b8.css create mode 100644 assets/css/0.styles.74783a08.css delete mode 100644 assets/js/10.2c46fdf3.js create mode 100644 assets/js/10.a7e5f96d.js create mode 100644 assets/js/11.b620ddcc.js delete mode 100644 assets/js/11.bbf981b9.js create mode 100644 assets/js/12.cf1bd068.js create mode 100644 assets/js/13.9dfac9d9.js delete mode 100644 assets/js/13.c624f59e.js rename assets/js/{12.af14dcd6.js => 14.1ce3f7fe.js} (98%) delete mode 100644 assets/js/2.8e6705b7.js create mode 100644 assets/js/2.fd7e9e0b.js delete mode 100644 assets/js/3.8d00273c.js create mode 100644 assets/js/3.c5869ccf.js create mode 100644 assets/js/4.b9b777bd.js create mode 100644 assets/js/5.073c37d9.js rename assets/js/{4.27329ebd.js => 6.7db49fe2.js} (72%) rename assets/js/{5.80ea750d.js => 7.852d0869.js} (96%) delete mode 100644 assets/js/8.9a0afdb5.js rename assets/js/{6.ccddad9d.js => 8.b8ee59fd.js} (93%) rename assets/js/{7.11707fb6.js => 9.249d32d4.js} (91%) delete mode 100644 assets/js/9.40f78cab.js delete mode 100644 assets/js/app.0bbcba5f.js create mode 100644 assets/js/app.b6b895fe.js diff --git a/404.html b/404.html index 780c6c7..25639d5 100644 --- a/404.html +++ b/404.html @@ -4,17 +4,17 @@ Nimbus Libraries - - + + - - + +

404

There's nothing here.
Take me home.
- + diff --git a/about.html b/about.html index b11930e..79d99bf 100644 --- a/about.html +++ b/about.html @@ -4,12 +4,12 @@ About | Nimbus Libraries - - + + - - + +
- +

# About

This documentation suite was created as a comprehensive guide for using the Nim libraries produced by the Nimbus team at Status.im.

# What is Nimbus?

Nimbus (opens new window) is an Ethereum 2.0 client, but these libraries are designed to be used outside of that context too. If your project needs good cryptography or verbose logging output, these libraries should fit the bill nicely.

You do not need to be a Nimbus user or developer to make use of these libraries.

# Why not Nimdoc?

We actually do use Nimdoc for the API reference included in each library's documentation on this site. However, Nimdoc's template isn't the easiest to modify and it can produce some buggy results, so we use its JSON output to feed the API docs into this tome, and we use Vuepress for the rest of the functionality, like custom layouts, styling, SEO support, searchability, and of course - custom documentation support, like guides, tutorials, references, and more.

# Contributing

You can contribute to these docs by submitting issues or pull requests in the official repository at status-im/nimbus-libs-site (opens new window).

Keep in mind the following:

  • the API reference is generated from individual libraries. Thus, if you notice a mistake in the API reference, to submit a fix you should submit a PR to the library in question and fix its docblock.
  • the guides are curated and not everything that's written about the libraries will be included here.
+ diff --git a/assets/css/0.styles.1d3235b8.css b/assets/css/0.styles.1d3235b8.css deleted file mode 100644 index 761ac1a..0000000 --- a/assets/css/0.styles.1d3235b8.css +++ /dev/null @@ -1 +0,0 @@ -#nprogress{pointer-events:none}#nprogress .bar{background:#ff9c00;position:fixed;z-index:1031;top:0;left:0;width:100%;height:2px}#nprogress .peg{display:block;position:absolute;right:0;width:100px;height:100%;box-shadow:0 0 10px #ff9c00,0 0 5px #ff9c00;opacity:1;transform:rotate(3deg) translateY(-4px)}#nprogress .spinner{display:block;position:fixed;z-index:1031;top:15px;right:15px}#nprogress .spinner-icon{width:18px;height:18px;box-sizing:border-box;border-color:#ff9c00 transparent transparent #ff9c00;border-style:solid;border-width:2px;border-radius:50%;-webkit-animation:nprogress-spinner .4s linear infinite;animation:nprogress-spinner .4s linear infinite}.nprogress-custom-parent{overflow:hidden;position:relative}.nprogress-custom-parent #nprogress .bar,.nprogress-custom-parent #nprogress .spinner{position:absolute}@-webkit-keyframes nprogress-spinner{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}@keyframes nprogress-spinner{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.icon.outbound{color:#aaa;display:inline-block;vertical-align:middle;position:relative;top:-1px}.home{padding:3.6rem 2rem 0;max-width:960px;margin:0 auto;display:block}.home .hero{text-align:center}.home .hero img{max-width:100%;max-height:280px;display:block;margin:3rem auto 1.5rem}.home .hero h1{font-size:3rem}.home .hero .action,.home .hero .description,.home .hero h1{margin:1.8rem auto}.home .hero .description{max-width:35rem;font-size:1.6rem;line-height:1.3;color:#6a8bad}.home .hero .action-button{display:inline-block;font-size:1.2rem;color:#fff;background-color:#ff9c00;padding:.8rem 1.6rem;border-radius:4px;transition:background-color .1s ease;box-sizing:border-box;border-bottom:1px solid #e68c00}.home .hero .action-button:hover{background-color:#ffa61a}.home .features{border-top:1px solid #eaecef;padding:1.2rem 0;margin-top:2.5rem;display:flex;flex-wrap:wrap;align-items:flex-start;align-content:stretch;justify-content:space-between}.home .feature{flex-grow:1;flex-basis:30%;max-width:30%}.home .feature h2{font-size:1.4rem;font-weight:500;border-bottom:none;padding-bottom:0;color:#3a5169}.home .feature p{color:#4e6e8e}.home .footer{padding:2.5rem;border-top:1px solid #eaecef;text-align:center;color:#4e6e8e}@media (max-width:719px){.home .features{flex-direction:column}.home .feature{max-width:100%;padding:0 2.5rem}}@media (max-width:419px){.home{padding-left:1.5rem;padding-right:1.5rem}.home .hero img{max-height:210px;margin:2rem auto 1.2rem}.home .hero h1{font-size:2rem}.home .hero .action,.home .hero .description,.home .hero h1{margin:1.2rem auto}.home .hero .description{font-size:1.2rem}.home .hero .action-button{font-size:1rem;padding:.6rem 1.2rem}.home .feature h2{font-size:1.25rem}}.search-box{display:inline-block;position:relative;margin-right:1rem}.search-box input{cursor:text;width:10rem;height:2rem;color:#4e6e8e;display:inline-block;border:1px solid #cfd4db;border-radius:2rem;font-size:.9rem;line-height:2rem;padding:0 .5rem 0 2rem;outline:none;transition:all .2s ease;background:#fff url(/assets/img/search.83621669.svg) .6rem .5rem no-repeat;background-size:1rem}.search-box input:focus{cursor:auto;border-color:#ff9c00}.search-box .suggestions{background:#fff;width:20rem;position:absolute;top:1.5rem;border:1px solid #cfd4db;border-radius:6px;padding:.4rem;list-style-type:none}.search-box .suggestions.align-right{right:0}.search-box .suggestion{line-height:1.4;padding:.4rem .6rem;border-radius:4px;cursor:pointer}.search-box .suggestion a{white-space:normal;color:#5d82a6}.search-box .suggestion a .page-title{font-weight:600}.search-box .suggestion a .header{font-size:.9em;margin-left:.25em}.search-box .suggestion.focused{background-color:#f3f4f5}.search-box .suggestion.focused a{color:#ff9c00}@media (max-width:959px){.search-box input{cursor:pointer;width:0;border-color:transparent;position:relative}.search-box input:focus{cursor:text;left:0;width:10rem}}@media (-ms-high-contrast:none){.search-box input{height:2rem}}@media (max-width:959px) and (min-width:719px){.search-box .suggestions{left:0}}@media (max-width:719px){.search-box{margin-right:0}.search-box input{left:1rem}.search-box .suggestions{right:0}}@media (max-width:419px){.search-box .suggestions{width:calc(100vw - 4rem)}.search-box input:focus{width:8rem}}.sidebar-button{cursor:pointer;display:none;width:1.25rem;height:1.25rem;position:absolute;padding:.6rem;top:.6rem;left:1rem}.sidebar-button .icon{display:block;width:1.25rem;height:1.25rem}@media (max-width:719px){.sidebar-button{display:block}}.dropdown-enter,.dropdown-leave-to{height:0!important}.dropdown-wrapper{cursor:pointer}.dropdown-wrapper .dropdown-title{display:block;font-size:.9rem;font-family:inherit;cursor:inherit;padding:inherit;line-height:1.4rem;background:transparent;border:none;font-weight:500;color:#2c3e50}.dropdown-wrapper .dropdown-title:hover{border-color:transparent}.dropdown-wrapper .dropdown-title .arrow{vertical-align:middle;margin-top:-1px;margin-left:.4rem}.dropdown-wrapper .nav-dropdown .dropdown-item{color:inherit;line-height:1.7rem}.dropdown-wrapper .nav-dropdown .dropdown-item h4{margin:.45rem 0 0;border-top:1px solid #eee;padding:.45rem 1.5rem 0 1.25rem}.dropdown-wrapper .nav-dropdown .dropdown-item .dropdown-subitem-wrapper{padding:0;list-style:none}.dropdown-wrapper .nav-dropdown .dropdown-item .dropdown-subitem-wrapper .dropdown-subitem{font-size:.9em}.dropdown-wrapper .nav-dropdown .dropdown-item a{display:block;line-height:1.7rem;position:relative;border-bottom:none;font-weight:400;margin-bottom:0;padding:0 1.5rem 0 1.25rem}.dropdown-wrapper .nav-dropdown .dropdown-item a.router-link-active,.dropdown-wrapper .nav-dropdown .dropdown-item a:hover{color:#ff9c00}.dropdown-wrapper .nav-dropdown .dropdown-item a.router-link-active:after{content:"";width:0;height:0;border-left:5px solid #ff9c00;border-top:3px solid transparent;border-bottom:3px solid transparent;position:absolute;top:calc(50% - 2px);left:9px}.dropdown-wrapper .nav-dropdown .dropdown-item:first-child h4{margin-top:0;padding-top:0;border-top:0}@media (max-width:719px){.dropdown-wrapper.open .dropdown-title{margin-bottom:.5rem}.dropdown-wrapper .dropdown-title{font-weight:600;font-size:inherit}.dropdown-wrapper .dropdown-title:hover{color:#ff9c00}.dropdown-wrapper .nav-dropdown{transition:height .1s ease-out;overflow:hidden}.dropdown-wrapper .nav-dropdown .dropdown-item h4{border-top:0;margin-top:0;padding-top:0}.dropdown-wrapper .nav-dropdown .dropdown-item>a,.dropdown-wrapper .nav-dropdown .dropdown-item h4{font-size:15px;line-height:2rem}.dropdown-wrapper .nav-dropdown .dropdown-item .dropdown-subitem{font-size:14px;padding-left:1rem}}@media (min-width:719px){.dropdown-wrapper{height:1.8rem}.dropdown-wrapper.open .nav-dropdown,.dropdown-wrapper:hover .nav-dropdown{display:block!important}.dropdown-wrapper.open:blur{display:none}.dropdown-wrapper .dropdown-title .arrow{border-left:4px solid transparent;border-right:4px solid transparent;border-top:6px solid #ccc;border-bottom:0}.dropdown-wrapper .nav-dropdown{display:none;height:auto!important;box-sizing:border-box;max-height:calc(100vh - 2.7rem);overflow-y:auto;position:absolute;top:100%;right:0;background-color:#fff;padding:.6rem 0;border:1px solid;border-color:#ddd #ddd #ccc;text-align:left;border-radius:.25rem;white-space:nowrap;margin:0}}.nav-links{display:inline-block}.nav-links a{line-height:1.4rem;color:inherit}.nav-links a.router-link-active,.nav-links a:hover{color:#ff9c00}.nav-links .nav-item{position:relative;display:inline-block;margin-left:1.5rem;line-height:2rem}.nav-links .nav-item:first-child{margin-left:0}.nav-links .repo-link{margin-left:1.5rem}@media (max-width:719px){.nav-links .nav-item,.nav-links .repo-link{margin-left:0}}@media (min-width:719px){.nav-links a.router-link-active,.nav-links a:hover{color:#2c3e50}.nav-item>a:not(.external).router-link-active,.nav-item>a:not(.external):hover{margin-bottom:-2px;border-bottom:2px solid #ffa414}}.navbar{padding:.7rem 1.5rem;line-height:2.2rem}.navbar a,.navbar img,.navbar span{display:inline-block}.navbar .logo{height:2.2rem;min-width:2.2rem;margin-right:.8rem;vertical-align:top}.navbar .site-name{font-size:1.3rem;font-weight:600;color:#2c3e50;position:relative}.navbar .links{padding-left:1.5rem;box-sizing:border-box;background-color:#fff;white-space:nowrap;font-size:.9rem;position:absolute;right:1.5rem;top:.7rem;display:flex}.navbar .links .search-box{flex:0 0 auto;vertical-align:top}@media (max-width:719px){.navbar{padding-left:4rem}.navbar .can-hide{display:none}.navbar .links{padding-left:1.5rem}.navbar .site-name{width:calc(100vw - 9.4rem);overflow:hidden;white-space:nowrap;text-overflow:ellipsis}}.page-edit{max-width:740px;margin:0 auto;padding:2rem 2.5rem}@media (max-width:959px){.page-edit{padding:2rem}}@media (max-width:419px){.page-edit{padding:1.5rem}}.page-edit{padding-top:1rem;padding-bottom:1rem;overflow:auto}.page-edit .edit-link{display:inline-block}.page-edit .edit-link a{color:#4e6e8e;margin-right:.25rem}.page-edit .last-updated{float:right;font-size:.9em}.page-edit .last-updated .prefix{font-weight:500;color:#4e6e8e}.page-edit .last-updated .time{font-weight:400;color:#aaa}@media (max-width:719px){.page-edit .edit-link{margin-bottom:.5rem}.page-edit .last-updated{font-size:.8em;float:none;text-align:left}}.page-nav{max-width:740px;margin:0 auto;padding:2rem 2.5rem}@media (max-width:959px){.page-nav{padding:2rem}}@media (max-width:419px){.page-nav{padding:1.5rem}}.page-nav{padding-top:1rem;padding-bottom:0}.page-nav .inner{min-height:2rem;margin-top:0;border-top:1px solid #eaecef;padding-top:1rem;overflow:auto}.page-nav .next{float:right}.page{padding-bottom:2rem;display:block}.sidebar-group .sidebar-group{padding-left:.5em}.sidebar-group:not(.collapsable) .sidebar-heading:not(.clickable){cursor:auto;color:inherit}.sidebar-group.is-sub-group{padding-left:0}.sidebar-group.is-sub-group>.sidebar-heading{font-size:.95em;line-height:1.4;font-weight:400;padding-left:2rem}.sidebar-group.is-sub-group>.sidebar-heading:not(.clickable){opacity:.5}.sidebar-group.is-sub-group>.sidebar-group-items{padding-left:1rem}.sidebar-group.is-sub-group>.sidebar-group-items>li>.sidebar-link{font-size:.95em;border-left:none}.sidebar-group.depth-2>.sidebar-heading{border-left:none}.sidebar-heading{color:#2c3e50;transition:color .15s ease;cursor:pointer;font-size:1.1em;font-weight:700;padding:.35rem 1.5rem .35rem 1.25rem;width:100%;box-sizing:border-box;margin:0;border-left:.25rem solid transparent}.sidebar-heading.open,.sidebar-heading:hover{color:inherit}.sidebar-heading .arrow{position:relative;top:-.12em;left:.5em}.sidebar-heading.clickable.active{font-weight:600;color:#ff9c00;border-left-color:#ff9c00}.sidebar-heading.clickable:hover{color:#ff9c00}.sidebar-group-items{transition:height .1s ease-out;font-size:.95em;overflow:hidden}.sidebar .sidebar-sub-headers{padding-left:1rem;font-size:.95em}a.sidebar-link{font-size:1em;font-weight:400;display:inline-block;color:#2c3e50;border-left:.25rem solid transparent;padding:.35rem 1rem .35rem 1.25rem;line-height:1.4;width:100%;box-sizing:border-box}a.sidebar-link:hover{color:#ff9c00}a.sidebar-link.active{font-weight:600;color:#ff9c00;border-left-color:#ff9c00}.sidebar-group a.sidebar-link{padding-left:2rem}.sidebar-sub-headers a.sidebar-link{padding-top:.25rem;padding-bottom:.25rem;border-left:none}.sidebar-sub-headers a.sidebar-link.active{font-weight:500}.sidebar ul{padding:0;margin:0;list-style-type:none}.sidebar a{display:inline-block}.sidebar .nav-links{display:none;border-bottom:1px solid #eaecef;padding:.5rem 0 .75rem}.sidebar .nav-links a{font-weight:600}.sidebar .nav-links .nav-item,.sidebar .nav-links .repo-link{display:block;line-height:1.25rem;font-size:1.1em;padding:.5rem 0 .5rem 1.5rem}.sidebar>.sidebar-links{padding:1.5rem 0}.sidebar>.sidebar-links>li>a.sidebar-link{font-size:1.1em;line-height:1.7;font-weight:700}.sidebar>.sidebar-links>li:not(:first-child){margin-top:.75rem}@media (max-width:719px){.sidebar .nav-links{display:block}.sidebar .nav-links .dropdown-wrapper .nav-dropdown .dropdown-item a.router-link-active:after{top:calc(1rem - 2px)}.sidebar>.sidebar-links{padding:1rem 0}}code[class*=language-],pre[class*=language-]{color:#ccc;background:none;font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-ms-hyphens:none;hyphens:none}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#2d2d2d}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.block-comment,.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#999}.token.punctuation{color:#ccc}.token.attr-name,.token.deleted,.token.namespace,.token.tag{color:#e2777a}.token.function-name{color:#6196cc}.token.boolean,.token.function,.token.number{color:#f08d49}.token.class-name,.token.constant,.token.property,.token.symbol{color:#f8c555}.token.atrule,.token.builtin,.token.important,.token.keyword,.token.selector{color:#cc99cd}.token.attr-value,.token.char,.token.regex,.token.string,.token.variable{color:#7ec699}.token.entity,.token.operator,.token.url{color:#67cdcc}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}.token.inserted{color:green}.theme-default-content code{color:#476582;padding:.25rem .5rem;margin:0;font-size:.85em;background-color:rgba(27,31,35,.05);border-radius:3px}.theme-default-content code .token.deleted{color:#ec5975}.theme-default-content code .token.inserted{color:#ff9c00}.theme-default-content pre,.theme-default-content pre[class*=language-]{line-height:1.4;padding:1.25rem 1.5rem;margin:.85rem 0;background-color:#282c34;border-radius:6px;overflow:auto}.theme-default-content pre[class*=language-] code,.theme-default-content pre code{color:#fff;padding:0;background-color:transparent;border-radius:0}div[class*=language-]{position:relative;background-color:#282c34;border-radius:6px}div[class*=language-] .highlight-lines{-webkit-user-select:none;-ms-user-select:none;user-select:none;padding-top:1.3rem;position:absolute;top:0;left:0;width:100%;line-height:1.4}div[class*=language-] .highlight-lines .highlighted{background-color:rgba(0,0,0,.66)}div[class*=language-] pre,div[class*=language-] pre[class*=language-]{background:transparent;position:relative;z-index:1}div[class*=language-]:before{position:absolute;z-index:3;top:.8em;right:1em;font-size:.75rem;color:hsla(0,0%,100%,.4)}div[class*=language-]:not(.line-numbers-mode) .line-numbers-wrapper{display:none}div[class*=language-].line-numbers-mode .highlight-lines .highlighted{position:relative}div[class*=language-].line-numbers-mode .highlight-lines .highlighted:before{content:" ";position:absolute;z-index:3;left:0;top:0;display:block;width:3.5rem;height:100%;background-color:rgba(0,0,0,.66)}div[class*=language-].line-numbers-mode pre{padding-left:4.5rem;vertical-align:middle}div[class*=language-].line-numbers-mode .line-numbers-wrapper{position:absolute;top:0;width:3.5rem;text-align:center;color:hsla(0,0%,100%,.3);padding:1.25rem 0;line-height:1.4}div[class*=language-].line-numbers-mode .line-numbers-wrapper br{-webkit-user-select:none;-ms-user-select:none;user-select:none}div[class*=language-].line-numbers-mode .line-numbers-wrapper .line-number{position:relative;z-index:4;-webkit-user-select:none;-ms-user-select:none;user-select:none;font-size:.85em}div[class*=language-].line-numbers-mode:after{content:"";position:absolute;z-index:2;top:0;left:0;width:3.5rem;height:100%;border-radius:6px 0 0 6px;border-right:1px solid rgba(0,0,0,.66);background-color:#282c34}div[class~=language-js]:before{content:"js"}div[class~=language-ts]:before{content:"ts"}div[class~=language-html]:before{content:"html"}div[class~=language-md]:before{content:"md"}div[class~=language-vue]:before{content:"vue"}div[class~=language-css]:before{content:"css"}div[class~=language-sass]:before{content:"sass"}div[class~=language-scss]:before{content:"scss"}div[class~=language-less]:before{content:"less"}div[class~=language-stylus]:before{content:"stylus"}div[class~=language-go]:before{content:"go"}div[class~=language-java]:before{content:"java"}div[class~=language-c]:before{content:"c"}div[class~=language-sh]:before{content:"sh"}div[class~=language-yaml]:before{content:"yaml"}div[class~=language-py]:before{content:"py"}div[class~=language-docker]:before{content:"docker"}div[class~=language-dockerfile]:before{content:"dockerfile"}div[class~=language-makefile]:before{content:"makefile"}div[class~=language-javascript]:before{content:"js"}div[class~=language-typescript]:before{content:"ts"}div[class~=language-markup]:before{content:"html"}div[class~=language-markdown]:before{content:"md"}div[class~=language-json]:before{content:"json"}div[class~=language-ruby]:before{content:"rb"}div[class~=language-python]:before{content:"py"}div[class~=language-bash]:before{content:"sh"}div[class~=language-php]:before{content:"php"}.custom-block .custom-block-title{font-weight:600;margin-bottom:-.4rem}.custom-block.danger,.custom-block.tip,.custom-block.warning{padding:.1rem 1.5rem;border-left-width:.5rem;border-left-style:solid;margin:1rem 0}.custom-block.tip{background-color:#f3f5f7;border-color:#42b983}.custom-block.warning{background-color:rgba(255,229,100,.3);border-color:#e7c000;color:#6b5900}.custom-block.warning .custom-block-title{color:#b29400}.custom-block.warning a{color:#2c3e50}.custom-block.danger{background-color:#ffe6e6;border-color:#c00;color:#4d0000}.custom-block.danger .custom-block-title{color:#900}.custom-block.danger a{color:#2c3e50}.custom-block.details{display:block;position:relative;border-radius:2px;margin:1.6em 0;padding:1.6em;background-color:#eee}.custom-block.details h4{margin-top:0}.custom-block.details figure:last-child,.custom-block.details p:last-child{margin-bottom:0;padding-bottom:0}.custom-block.details summary{outline:none;cursor:pointer}.arrow{display:inline-block;width:0;height:0}.arrow.up{border-bottom:6px solid #ccc}.arrow.down,.arrow.up{border-left:4px solid transparent;border-right:4px solid transparent}.arrow.down{border-top:6px solid #ccc}.arrow.right{border-left:6px solid #ccc}.arrow.left,.arrow.right{border-top:4px solid transparent;border-bottom:4px solid transparent}.arrow.left{border-right:6px solid #ccc}.theme-default-content:not(.custom){max-width:740px;margin:0 auto;padding:2rem 2.5rem}@media (max-width:959px){.theme-default-content:not(.custom){padding:2rem}}@media (max-width:419px){.theme-default-content:not(.custom){padding:1.5rem}}.table-of-contents .badge{vertical-align:middle}body,html{padding:0;margin:0;background-color:#fff}body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-size:16px;color:#2c3e50}.page{padding-left:20rem}.navbar{z-index:20;right:0;height:3.6rem;background-color:#fff;box-sizing:border-box;border-bottom:1px solid #eaecef}.navbar,.sidebar-mask{position:fixed;top:0;left:0}.sidebar-mask{z-index:9;width:100vw;height:100vh;display:none}.sidebar{font-size:16px;background-color:#fff;width:20rem;position:fixed;z-index:10;margin:0;top:3.6rem;left:0;bottom:0;box-sizing:border-box;border-right:1px solid #eaecef;overflow-y:auto}.theme-default-content:not(.custom)>:first-child{margin-top:3.6rem}.theme-default-content:not(.custom) a:hover{text-decoration:underline}.theme-default-content:not(.custom) p.demo{padding:1rem 1.5rem;border:1px solid #ddd;border-radius:4px}.theme-default-content:not(.custom) img{max-width:100%}.theme-default-content.custom{padding:0;margin:0}.theme-default-content.custom img{max-width:100%}a{font-weight:500;text-decoration:none}a,p a code{color:#ff9c00}p a code{font-weight:400}kbd{background:#eee;border:.15rem solid #ddd;border-bottom:.25rem solid #ddd;border-radius:.15rem;padding:0 .15em}blockquote{font-size:1rem;color:#999;border-left:.2rem solid #dfe2e5;margin:1rem 0;padding:.25rem 0 .25rem 1rem}blockquote>p{margin:0}ol,ul{padding-left:1.2em}strong{font-weight:600}h1,h2,h3,h4,h5,h6{font-weight:600;line-height:1.25}.theme-default-content:not(.custom)>h1,.theme-default-content:not(.custom)>h2,.theme-default-content:not(.custom)>h3,.theme-default-content:not(.custom)>h4,.theme-default-content:not(.custom)>h5,.theme-default-content:not(.custom)>h6{margin-top:-3.1rem;padding-top:4.6rem;margin-bottom:0}.theme-default-content:not(.custom)>h1:first-child,.theme-default-content:not(.custom)>h2:first-child,.theme-default-content:not(.custom)>h3:first-child,.theme-default-content:not(.custom)>h4:first-child,.theme-default-content:not(.custom)>h5:first-child,.theme-default-content:not(.custom)>h6:first-child{margin-top:-1.5rem;margin-bottom:1rem}.theme-default-content:not(.custom)>h1:first-child+.custom-block,.theme-default-content:not(.custom)>h1:first-child+p,.theme-default-content:not(.custom)>h1:first-child+pre,.theme-default-content:not(.custom)>h2:first-child+.custom-block,.theme-default-content:not(.custom)>h2:first-child+p,.theme-default-content:not(.custom)>h2:first-child+pre,.theme-default-content:not(.custom)>h3:first-child+.custom-block,.theme-default-content:not(.custom)>h3:first-child+p,.theme-default-content:not(.custom)>h3:first-child+pre,.theme-default-content:not(.custom)>h4:first-child+.custom-block,.theme-default-content:not(.custom)>h4:first-child+p,.theme-default-content:not(.custom)>h4:first-child+pre,.theme-default-content:not(.custom)>h5:first-child+.custom-block,.theme-default-content:not(.custom)>h5:first-child+p,.theme-default-content:not(.custom)>h5:first-child+pre,.theme-default-content:not(.custom)>h6:first-child+.custom-block,.theme-default-content:not(.custom)>h6:first-child+p,.theme-default-content:not(.custom)>h6:first-child+pre{margin-top:2rem}h1:hover .header-anchor,h2:hover .header-anchor,h3:hover .header-anchor,h4:hover .header-anchor,h5:hover .header-anchor,h6:hover .header-anchor{opacity:1}h1{font-size:2.2rem}h2{font-size:1.65rem;padding-bottom:.3rem;border-bottom:1px solid #eaecef}h3{font-size:1.35rem}a.header-anchor{font-size:.85em;float:left;margin-left:-.87em;padding-right:.23em;margin-top:.125em;opacity:0}a.header-anchor:hover{text-decoration:none}.line-number,code,kbd{font-family:source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace}ol,p,ul{line-height:1.7}hr{border:0;border-top:1px solid #eaecef}table{border-collapse:collapse;margin:1rem 0;display:block;overflow-x:auto}tr{border-top:1px solid #dfe2e5}tr:nth-child(2n){background-color:#f6f8fa}td,th{border:1px solid #dfe2e5;padding:.6em 1em}.theme-container.sidebar-open .sidebar-mask{display:block}.theme-container.no-navbar .theme-default-content:not(.custom)>h1,.theme-container.no-navbar h2,.theme-container.no-navbar h3,.theme-container.no-navbar h4,.theme-container.no-navbar h5,.theme-container.no-navbar h6{margin-top:1.5rem;padding-top:0}.theme-container.no-navbar .sidebar{top:0}@media (min-width:720px){.theme-container.no-sidebar .sidebar{display:none}.theme-container.no-sidebar .page{padding-left:0}}@media (max-width:959px){.sidebar{font-size:15px;width:16.4rem}.page{padding-left:16.4rem}}@media (max-width:719px){.sidebar{top:0;padding-top:3.6rem;transform:translateX(-100%);transition:transform .2s ease}.page{padding-left:0}.theme-container.sidebar-open .sidebar{transform:translateX(0)}.theme-container.no-navbar .sidebar{padding-top:0}}@media (max-width:419px){h1{font-size:1.9rem}.theme-default-content div[class*=language-]{margin:.85rem -1.5rem;border-radius:0}}.navbar{background-color:#ff9c00}.navbar .site-name{color:#fff}.navbar .links{color:#fff;background-color:#ff9c00}.navbar .links a.router-link-active,.navbar .links a:hover{border-bottom-color:#fff;color:#fff}.navbar .links .nav-dropdown{color:#000}.theorem{margin:1rem 0;padding:.1rem 1.5rem;border-bottom:1px solid silver}.theorem .title{font-weight:700;font-size:x-large}.theorem .title a{color:#000;text-decoration:underline}.custom-block.right{color:rgba(0,0,0,.4);font-size:.9rem;text-align:right}.badge[data-v-15b7b770]{display:inline-block;font-size:14px;height:18px;line-height:18px;border-radius:3px;padding:0 6px;color:#fff}.badge.green[data-v-15b7b770],.badge.tip[data-v-15b7b770],.badge[data-v-15b7b770]{background-color:#42b983}.badge.error[data-v-15b7b770]{background-color:#da5961}.badge.warn[data-v-15b7b770],.badge.warning[data-v-15b7b770],.badge.yellow[data-v-15b7b770]{background-color:#e7c000}.badge+.badge[data-v-15b7b770]{margin-left:5px} \ No newline at end of file diff --git a/assets/css/0.styles.74783a08.css b/assets/css/0.styles.74783a08.css new file mode 100644 index 0000000..74f53b4 --- /dev/null +++ b/assets/css/0.styles.74783a08.css @@ -0,0 +1 @@ +code[class*=language-],pre[class*=language-]{color:#ccc;background:none;font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-ms-hyphens:none;hyphens:none}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#2d2d2d}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.block-comment,.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#999}.token.punctuation{color:#ccc}.token.attr-name,.token.deleted,.token.namespace,.token.tag{color:#e2777a}.token.function-name{color:#6196cc}.token.boolean,.token.function,.token.number{color:#f08d49}.token.class-name,.token.constant,.token.property,.token.symbol{color:#f8c555}.token.atrule,.token.builtin,.token.important,.token.keyword,.token.selector{color:#cc99cd}.token.attr-value,.token.char,.token.regex,.token.string,.token.variable{color:#7ec699}.token.entity,.token.operator,.token.url{color:#67cdcc}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}.token.inserted{color:green}.theme-default-content code{color:#476582;padding:.25rem .5rem;margin:0;font-size:.85em;background-color:rgba(27,31,35,.05);border-radius:3px}.theme-default-content code .token.deleted{color:#ec5975}.theme-default-content code .token.inserted{color:#ff9c00}.theme-default-content pre,.theme-default-content pre[class*=language-]{line-height:1.4;padding:1.25rem 1.5rem;margin:.85rem 0;background-color:#282c34;border-radius:6px;overflow:auto}.theme-default-content pre[class*=language-] code,.theme-default-content pre code{color:#fff;padding:0;background-color:transparent;border-radius:0}div[class*=language-]{position:relative;background-color:#282c34;border-radius:6px}div[class*=language-] .highlight-lines{-webkit-user-select:none;user-select:none;padding-top:1.3rem;position:absolute;top:0;left:0;width:100%;line-height:1.4}div[class*=language-] .highlight-lines .highlighted{background-color:rgba(0,0,0,.66)}div[class*=language-] pre,div[class*=language-] pre[class*=language-]{background:transparent;position:relative;z-index:1}div[class*=language-]:before{position:absolute;z-index:3;top:.8em;right:1em;font-size:.75rem;color:hsla(0,0%,100%,.4)}div[class*=language-]:not(.line-numbers-mode) .line-numbers-wrapper{display:none}div[class*=language-].line-numbers-mode .highlight-lines .highlighted{position:relative}div[class*=language-].line-numbers-mode .highlight-lines .highlighted:before{content:" ";position:absolute;z-index:3;left:0;top:0;display:block;width:3.5rem;height:100%;background-color:rgba(0,0,0,.66)}div[class*=language-].line-numbers-mode pre{padding-left:4.5rem;vertical-align:middle}div[class*=language-].line-numbers-mode .line-numbers-wrapper{position:absolute;top:0;width:3.5rem;text-align:center;color:hsla(0,0%,100%,.3);padding:1.25rem 0;line-height:1.4}div[class*=language-].line-numbers-mode .line-numbers-wrapper br{-webkit-user-select:none;user-select:none}div[class*=language-].line-numbers-mode .line-numbers-wrapper .line-number{position:relative;z-index:4;-webkit-user-select:none;user-select:none;font-size:.85em}div[class*=language-].line-numbers-mode:after{content:"";position:absolute;z-index:2;top:0;left:0;width:3.5rem;height:100%;border-radius:6px 0 0 6px;border-right:1px solid rgba(0,0,0,.66);background-color:#282c34}div[class~=language-js]:before{content:"js"}div[class~=language-ts]:before{content:"ts"}div[class~=language-html]:before{content:"html"}div[class~=language-md]:before{content:"md"}div[class~=language-vue]:before{content:"vue"}div[class~=language-css]:before{content:"css"}div[class~=language-sass]:before{content:"sass"}div[class~=language-scss]:before{content:"scss"}div[class~=language-less]:before{content:"less"}div[class~=language-stylus]:before{content:"stylus"}div[class~=language-go]:before{content:"go"}div[class~=language-java]:before{content:"java"}div[class~=language-c]:before{content:"c"}div[class~=language-sh]:before{content:"sh"}div[class~=language-yaml]:before{content:"yaml"}div[class~=language-py]:before{content:"py"}div[class~=language-docker]:before{content:"docker"}div[class~=language-dockerfile]:before{content:"dockerfile"}div[class~=language-makefile]:before{content:"makefile"}div[class~=language-javascript]:before{content:"js"}div[class~=language-typescript]:before{content:"ts"}div[class~=language-markup]:before{content:"html"}div[class~=language-markdown]:before{content:"md"}div[class~=language-json]:before{content:"json"}div[class~=language-ruby]:before{content:"rb"}div[class~=language-python]:before{content:"py"}div[class~=language-bash]:before{content:"sh"}div[class~=language-php]:before{content:"php"}.custom-block .custom-block-title{font-weight:600;margin-bottom:-.4rem}.custom-block.danger,.custom-block.tip,.custom-block.warning{padding:.1rem 1.5rem;border-left-width:.5rem;border-left-style:solid;margin:1rem 0}.custom-block.tip{background-color:#f3f5f7;border-color:#42b983}.custom-block.warning{background-color:rgba(255,229,100,.3);border-color:#e7c000;color:#6b5900}.custom-block.warning .custom-block-title{color:#b29400}.custom-block.warning a{color:#2c3e50}.custom-block.danger{background-color:#ffe6e6;border-color:#c00;color:#4d0000}.custom-block.danger .custom-block-title{color:#900}.custom-block.danger a{color:#2c3e50}.custom-block.details{display:block;position:relative;border-radius:2px;margin:1.6em 0;padding:1.6em;background-color:#eee}.custom-block.details h4{margin-top:0}.custom-block.details figure:last-child,.custom-block.details p:last-child{margin-bottom:0;padding-bottom:0}.custom-block.details summary{outline:none;cursor:pointer}.arrow{display:inline-block;width:0;height:0}.arrow.up{border-bottom:6px solid #ccc}.arrow.down,.arrow.up{border-left:4px solid transparent;border-right:4px solid transparent}.arrow.down{border-top:6px solid #ccc}.arrow.right{border-left:6px solid #ccc}.arrow.left,.arrow.right{border-top:4px solid transparent;border-bottom:4px solid transparent}.arrow.left{border-right:6px solid #ccc}.theme-default-content:not(.custom){max-width:740px;margin:0 auto;padding:2rem 2.5rem}@media (max-width:959px){.theme-default-content:not(.custom){padding:2rem}}@media (max-width:419px){.theme-default-content:not(.custom){padding:1.5rem}}.table-of-contents .badge{vertical-align:middle}body,html{padding:0;margin:0;background-color:#fff}body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-size:16px;color:#2c3e50}.page{padding-left:20rem}.navbar{z-index:20;right:0;height:3.6rem;background-color:#fff;box-sizing:border-box;border-bottom:1px solid #eaecef}.navbar,.sidebar-mask{position:fixed;top:0;left:0}.sidebar-mask{z-index:9;width:100vw;height:100vh;display:none}.sidebar{font-size:16px;background-color:#fff;width:20rem;position:fixed;z-index:10;margin:0;top:3.6rem;left:0;bottom:0;box-sizing:border-box;border-right:1px solid #eaecef;overflow-y:auto}.theme-default-content:not(.custom)>:first-child{margin-top:3.6rem}.theme-default-content:not(.custom) a:hover{text-decoration:underline}.theme-default-content:not(.custom) p.demo{padding:1rem 1.5rem;border:1px solid #ddd;border-radius:4px}.theme-default-content:not(.custom) img{max-width:100%}.theme-default-content.custom{padding:0;margin:0}.theme-default-content.custom img{max-width:100%}a{font-weight:500;text-decoration:none}a,p a code{color:#ff9c00}p a code{font-weight:400}kbd{background:#eee;border:.15rem solid #ddd;border-bottom:.25rem solid #ddd;border-radius:.15rem;padding:0 .15em}blockquote{font-size:1rem;color:#999;border-left:.2rem solid #dfe2e5;margin:1rem 0;padding:.25rem 0 .25rem 1rem}blockquote>p{margin:0}ol,ul{padding-left:1.2em}strong{font-weight:600}h1,h2,h3,h4,h5,h6{font-weight:600;line-height:1.25}.theme-default-content:not(.custom)>h1,.theme-default-content:not(.custom)>h2,.theme-default-content:not(.custom)>h3,.theme-default-content:not(.custom)>h4,.theme-default-content:not(.custom)>h5,.theme-default-content:not(.custom)>h6{margin-top:-3.1rem;padding-top:4.6rem;margin-bottom:0}.theme-default-content:not(.custom)>h1:first-child,.theme-default-content:not(.custom)>h2:first-child,.theme-default-content:not(.custom)>h3:first-child,.theme-default-content:not(.custom)>h4:first-child,.theme-default-content:not(.custom)>h5:first-child,.theme-default-content:not(.custom)>h6:first-child{margin-top:-1.5rem;margin-bottom:1rem}.theme-default-content:not(.custom)>h1:first-child+.custom-block,.theme-default-content:not(.custom)>h1:first-child+p,.theme-default-content:not(.custom)>h1:first-child+pre,.theme-default-content:not(.custom)>h2:first-child+.custom-block,.theme-default-content:not(.custom)>h2:first-child+p,.theme-default-content:not(.custom)>h2:first-child+pre,.theme-default-content:not(.custom)>h3:first-child+.custom-block,.theme-default-content:not(.custom)>h3:first-child+p,.theme-default-content:not(.custom)>h3:first-child+pre,.theme-default-content:not(.custom)>h4:first-child+.custom-block,.theme-default-content:not(.custom)>h4:first-child+p,.theme-default-content:not(.custom)>h4:first-child+pre,.theme-default-content:not(.custom)>h5:first-child+.custom-block,.theme-default-content:not(.custom)>h5:first-child+p,.theme-default-content:not(.custom)>h5:first-child+pre,.theme-default-content:not(.custom)>h6:first-child+.custom-block,.theme-default-content:not(.custom)>h6:first-child+p,.theme-default-content:not(.custom)>h6:first-child+pre{margin-top:2rem}h1:focus .header-anchor,h1:hover .header-anchor,h2:focus .header-anchor,h2:hover .header-anchor,h3:focus .header-anchor,h3:hover .header-anchor,h4:focus .header-anchor,h4:hover .header-anchor,h5:focus .header-anchor,h5:hover .header-anchor,h6:focus .header-anchor,h6:hover .header-anchor{opacity:1}h1{font-size:2.2rem}h2{font-size:1.65rem;padding-bottom:.3rem;border-bottom:1px solid #eaecef}h3{font-size:1.35rem}a.header-anchor{font-size:.85em;float:left;margin-left:-.87em;padding-right:.23em;margin-top:.125em;opacity:0}a.header-anchor:focus,a.header-anchor:hover{text-decoration:none}.line-number,code,kbd{font-family:source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace}ol,p,ul{line-height:1.7}hr{border:0;border-top:1px solid #eaecef}table{border-collapse:collapse;margin:1rem 0;display:block;overflow-x:auto}tr{border-top:1px solid #dfe2e5}tr:nth-child(2n){background-color:#f6f8fa}td,th{border:1px solid #dfe2e5;padding:.6em 1em}.theme-container.sidebar-open .sidebar-mask{display:block}.theme-container.no-navbar .theme-default-content:not(.custom)>h1,.theme-container.no-navbar h2,.theme-container.no-navbar h3,.theme-container.no-navbar h4,.theme-container.no-navbar h5,.theme-container.no-navbar h6{margin-top:1.5rem;padding-top:0}.theme-container.no-navbar .sidebar{top:0}@media (min-width:720px){.theme-container.no-sidebar .sidebar{display:none}.theme-container.no-sidebar .page{padding-left:0}}@media (max-width:959px){.sidebar{font-size:15px;width:16.4rem}.page{padding-left:16.4rem}}@media (max-width:719px){.sidebar{top:0;padding-top:3.6rem;transform:translateX(-100%);transition:transform .2s ease}.page{padding-left:0}.theme-container.sidebar-open .sidebar{transform:translateX(0)}.theme-container.no-navbar .sidebar{padding-top:0}}@media (max-width:419px){h1{font-size:1.9rem}.theme-default-content div[class*=language-]{margin:.85rem -1.5rem;border-radius:0}}.navbar{background-color:#ff9c00}.navbar .site-name{color:#fff}.navbar .links{color:#fff;background-color:#ff9c00}.navbar .links a.router-link-active,.navbar .links a:hover{border-bottom-color:#fff;color:#fff}.navbar .links .nav-dropdown{color:#000}.theorem{margin:1rem 0;padding:.1rem 1.5rem;border-bottom:1px solid silver}.theorem .title{font-weight:700;font-size:x-large}.theorem .title a{color:#000;text-decoration:underline}.custom-block.right{color:rgba(0,0,0,.4);font-size:.9rem;text-align:right}#nprogress{pointer-events:none}#nprogress .bar{background:#ff9c00;position:fixed;z-index:1031;top:0;left:0;width:100%;height:2px}#nprogress .peg{display:block;position:absolute;right:0;width:100px;height:100%;box-shadow:0 0 10px #ff9c00,0 0 5px #ff9c00;opacity:1;transform:rotate(3deg) translateY(-4px)}#nprogress .spinner{display:block;position:fixed;z-index:1031;top:15px;right:15px}#nprogress .spinner-icon{width:18px;height:18px;box-sizing:border-box;border-color:#ff9c00 transparent transparent #ff9c00;border-style:solid;border-width:2px;border-radius:50%;-webkit-animation:nprogress-spinner .4s linear infinite;animation:nprogress-spinner .4s linear infinite}.nprogress-custom-parent{overflow:hidden;position:relative}.nprogress-custom-parent #nprogress .bar,.nprogress-custom-parent #nprogress .spinner{position:absolute}@-webkit-keyframes nprogress-spinner{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}@keyframes nprogress-spinner{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.icon.outbound{color:#aaa;display:inline-block;vertical-align:middle;position:relative;top:-1px}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.home{padding:3.6rem 2rem 0;max-width:960px;margin:0 auto;display:block}.home .hero{text-align:center}.home .hero img{max-width:100%;max-height:280px;display:block;margin:3rem auto 1.5rem}.home .hero h1{font-size:3rem}.home .hero .action,.home .hero .description,.home .hero h1{margin:1.8rem auto}.home .hero .description{max-width:35rem;font-size:1.6rem;line-height:1.3;color:#6a8bad}.home .hero .action-button{display:inline-block;font-size:1.2rem;color:#fff;background-color:#ff9c00;padding:.8rem 1.6rem;border-radius:4px;transition:background-color .1s ease;box-sizing:border-box;border-bottom:1px solid #e68c00}.home .hero .action-button:hover{background-color:#ffa61a}.home .features{border-top:1px solid #eaecef;padding:1.2rem 0;margin-top:2.5rem;display:flex;flex-wrap:wrap;align-items:flex-start;align-content:stretch;justify-content:space-between}.home .feature{flex-grow:1;flex-basis:30%;max-width:30%}.home .feature h2{font-size:1.4rem;font-weight:500;border-bottom:none;padding-bottom:0;color:#3a5169}.home .feature p{color:#4e6e8e}.home .footer{padding:2.5rem;border-top:1px solid #eaecef;text-align:center;color:#4e6e8e}@media (max-width:719px){.home .features{flex-direction:column}.home .feature{max-width:100%;padding:0 2.5rem}}@media (max-width:419px){.home{padding-left:1.5rem;padding-right:1.5rem}.home .hero img{max-height:210px;margin:2rem auto 1.2rem}.home .hero h1{font-size:2rem}.home .hero .action,.home .hero .description,.home .hero h1{margin:1.2rem auto}.home .hero .description{font-size:1.2rem}.home .hero .action-button{font-size:1rem;padding:.6rem 1.2rem}.home .feature h2{font-size:1.25rem}}.search-box{display:inline-block;position:relative;margin-right:1rem}.search-box input{cursor:text;width:10rem;height:2rem;color:#4e6e8e;display:inline-block;border:1px solid #cfd4db;border-radius:2rem;font-size:.9rem;line-height:2rem;padding:0 .5rem 0 2rem;outline:none;transition:all .2s ease;background:#fff url(/assets/img/search.83621669.svg) .6rem .5rem no-repeat;background-size:1rem}.search-box input:focus{cursor:auto;border-color:#ff9c00}.search-box .suggestions{background:#fff;width:20rem;position:absolute;top:2rem;border:1px solid #cfd4db;border-radius:6px;padding:.4rem;list-style-type:none}.search-box .suggestions.align-right{right:0}.search-box .suggestion{line-height:1.4;padding:.4rem .6rem;border-radius:4px;cursor:pointer}.search-box .suggestion a{white-space:normal;color:#5d82a6}.search-box .suggestion a .page-title{font-weight:600}.search-box .suggestion a .header{font-size:.9em;margin-left:.25em}.search-box .suggestion.focused{background-color:#f3f4f5}.search-box .suggestion.focused a{color:#ff9c00}@media (max-width:959px){.search-box input{cursor:pointer;width:0;border-color:transparent;position:relative}.search-box input:focus{cursor:text;left:0;width:10rem}}@media (-ms-high-contrast:none){.search-box input{height:2rem}}@media (max-width:959px) and (min-width:719px){.search-box .suggestions{left:0}}@media (max-width:719px){.search-box{margin-right:0}.search-box input{left:1rem}.search-box .suggestions{right:0}}@media (max-width:419px){.search-box .suggestions{width:calc(100vw - 4rem)}.search-box input:focus{width:8rem}}.sidebar-button{cursor:pointer;display:none;width:1.25rem;height:1.25rem;position:absolute;padding:.6rem;top:.6rem;left:1rem}.sidebar-button .icon{display:block;width:1.25rem;height:1.25rem}@media (max-width:719px){.sidebar-button{display:block}}.dropdown-enter,.dropdown-leave-to{height:0!important}.dropdown-wrapper{cursor:pointer}.dropdown-wrapper .dropdown-title,.dropdown-wrapper .mobile-dropdown-title{display:block;font-size:.9rem;font-family:inherit;cursor:inherit;padding:inherit;line-height:1.4rem;background:transparent;border:none;font-weight:500;color:#2c3e50}.dropdown-wrapper .dropdown-title:hover,.dropdown-wrapper .mobile-dropdown-title:hover{border-color:transparent}.dropdown-wrapper .dropdown-title .arrow,.dropdown-wrapper .mobile-dropdown-title .arrow{vertical-align:middle;margin-top:-1px;margin-left:.4rem}.dropdown-wrapper .mobile-dropdown-title{display:none;font-weight:600}.dropdown-wrapper .mobile-dropdown-title font-size inherit:hover{color:#ff9c00}.dropdown-wrapper .nav-dropdown .dropdown-item{color:inherit;line-height:1.7rem}.dropdown-wrapper .nav-dropdown .dropdown-item h4{margin:.45rem 0 0;border-top:1px solid #eee;padding:1rem 1.5rem .45rem 1.25rem}.dropdown-wrapper .nav-dropdown .dropdown-item .dropdown-subitem-wrapper{padding:0;list-style:none}.dropdown-wrapper .nav-dropdown .dropdown-item .dropdown-subitem-wrapper .dropdown-subitem{font-size:.9em}.dropdown-wrapper .nav-dropdown .dropdown-item a{display:block;line-height:1.7rem;position:relative;border-bottom:none;font-weight:400;margin-bottom:0;padding:0 1.5rem 0 1.25rem}.dropdown-wrapper .nav-dropdown .dropdown-item a.router-link-active,.dropdown-wrapper .nav-dropdown .dropdown-item a:hover{color:#ff9c00}.dropdown-wrapper .nav-dropdown .dropdown-item a.router-link-active:after{content:"";width:0;height:0;border-left:5px solid #ff9c00;border-top:3px solid transparent;border-bottom:3px solid transparent;position:absolute;top:calc(50% - 2px);left:9px}.dropdown-wrapper .nav-dropdown .dropdown-item:first-child h4{margin-top:0;padding-top:0;border-top:0}@media (max-width:719px){.dropdown-wrapper.open .dropdown-title{margin-bottom:.5rem}.dropdown-wrapper .dropdown-title{display:none}.dropdown-wrapper .mobile-dropdown-title{display:block}.dropdown-wrapper .nav-dropdown{transition:height .1s ease-out;overflow:hidden}.dropdown-wrapper .nav-dropdown .dropdown-item h4{border-top:0;margin-top:0;padding-top:0}.dropdown-wrapper .nav-dropdown .dropdown-item>a,.dropdown-wrapper .nav-dropdown .dropdown-item h4{font-size:15px;line-height:2rem}.dropdown-wrapper .nav-dropdown .dropdown-item .dropdown-subitem{font-size:14px;padding-left:1rem}}@media (min-width:719px){.dropdown-wrapper{height:1.8rem}.dropdown-wrapper.open .nav-dropdown,.dropdown-wrapper:hover .nav-dropdown{display:block!important}.dropdown-wrapper.open:blur{display:none}.dropdown-wrapper .nav-dropdown{display:none;height:auto!important;box-sizing:border-box;max-height:calc(100vh - 2.7rem);overflow-y:auto;position:absolute;top:100%;right:0;background-color:#fff;padding:.6rem 0;border:1px solid;border-color:#ddd #ddd #ccc;text-align:left;border-radius:.25rem;white-space:nowrap;margin:0}}.nav-links{display:inline-block}.nav-links a{line-height:1.4rem;color:inherit}.nav-links a.router-link-active,.nav-links a:hover{color:#ff9c00}.nav-links .nav-item{position:relative;display:inline-block;margin-left:1.5rem;line-height:2rem}.nav-links .nav-item:first-child{margin-left:0}.nav-links .repo-link{margin-left:1.5rem}@media (max-width:719px){.nav-links .nav-item,.nav-links .repo-link{margin-left:0}}@media (min-width:719px){.nav-links a.router-link-active,.nav-links a:hover{color:#2c3e50}.nav-item>a:not(.external).router-link-active,.nav-item>a:not(.external):hover{margin-bottom:-2px;border-bottom:2px solid #ffa414}}.navbar{padding:.7rem 1.5rem;line-height:2.2rem}.navbar a,.navbar img,.navbar span{display:inline-block}.navbar .logo{height:2.2rem;min-width:2.2rem;margin-right:.8rem;vertical-align:top}.navbar .site-name{font-size:1.3rem;font-weight:600;color:#2c3e50;position:relative}.navbar .links{padding-left:1.5rem;box-sizing:border-box;background-color:#fff;white-space:nowrap;font-size:.9rem;position:absolute;right:1.5rem;top:.7rem;display:flex}.navbar .links .search-box{flex:0 0 auto;vertical-align:top}@media (max-width:719px){.navbar{padding-left:4rem}.navbar .can-hide{display:none}.navbar .links{padding-left:1.5rem}.navbar .site-name{width:calc(100vw - 9.4rem);overflow:hidden;white-space:nowrap;text-overflow:ellipsis}}.page-edit{max-width:740px;margin:0 auto;padding:2rem 2.5rem}@media (max-width:959px){.page-edit{padding:2rem}}@media (max-width:419px){.page-edit{padding:1.5rem}}.page-edit{padding-top:1rem;padding-bottom:1rem;overflow:auto}.page-edit .edit-link{display:inline-block}.page-edit .edit-link a{color:#4e6e8e;margin-right:.25rem}.page-edit .last-updated{float:right;font-size:.9em}.page-edit .last-updated .prefix{font-weight:500;color:#4e6e8e}.page-edit .last-updated .time{font-weight:400;color:#767676}@media (max-width:719px){.page-edit .edit-link{margin-bottom:.5rem}.page-edit .last-updated{font-size:.8em;float:none;text-align:left}}.page-nav{max-width:740px;margin:0 auto;padding:2rem 2.5rem}@media (max-width:959px){.page-nav{padding:2rem}}@media (max-width:419px){.page-nav{padding:1.5rem}}.page-nav{padding-top:1rem;padding-bottom:0}.page-nav .inner{min-height:2rem;margin-top:0;border-top:1px solid #eaecef;padding-top:1rem;overflow:auto}.page-nav .next{float:right}.page{padding-bottom:2rem;display:block}.sidebar-group .sidebar-group{padding-left:.5em}.sidebar-group:not(.collapsable) .sidebar-heading:not(.clickable){cursor:auto;color:inherit}.sidebar-group.is-sub-group{padding-left:0}.sidebar-group.is-sub-group>.sidebar-heading{font-size:.95em;line-height:1.4;font-weight:400;padding-left:2rem}.sidebar-group.is-sub-group>.sidebar-heading:not(.clickable){opacity:.5}.sidebar-group.is-sub-group>.sidebar-group-items{padding-left:1rem}.sidebar-group.is-sub-group>.sidebar-group-items>li>.sidebar-link{font-size:.95em;border-left:none}.sidebar-group.depth-2>.sidebar-heading{border-left:none}.sidebar-heading{color:#2c3e50;transition:color .15s ease;cursor:pointer;font-size:1.1em;font-weight:700;padding:.35rem 1.5rem .35rem 1.25rem;width:100%;box-sizing:border-box;margin:0;border-left:.25rem solid transparent}.sidebar-heading.open,.sidebar-heading:hover{color:inherit}.sidebar-heading .arrow{position:relative;top:-.12em;left:.5em}.sidebar-heading.clickable.active{font-weight:600;color:#ff9c00;border-left-color:#ff9c00}.sidebar-heading.clickable:hover{color:#ff9c00}.sidebar-group-items{transition:height .1s ease-out;font-size:.95em;overflow:hidden}.sidebar .sidebar-sub-headers{padding-left:1rem;font-size:.95em}a.sidebar-link{font-size:1em;font-weight:400;display:inline-block;color:#2c3e50;border-left:.25rem solid transparent;padding:.35rem 1rem .35rem 1.25rem;line-height:1.4;width:100%;box-sizing:border-box}a.sidebar-link:hover{color:#ff9c00}a.sidebar-link.active{font-weight:600;color:#ff9c00;border-left-color:#ff9c00}.sidebar-group a.sidebar-link{padding-left:2rem}.sidebar-sub-headers a.sidebar-link{padding-top:.25rem;padding-bottom:.25rem;border-left:none}.sidebar-sub-headers a.sidebar-link.active{font-weight:500}.sidebar ul{padding:0;margin:0;list-style-type:none}.sidebar a{display:inline-block}.sidebar .nav-links{display:none;border-bottom:1px solid #eaecef;padding:.5rem 0 .75rem}.sidebar .nav-links a{font-weight:600}.sidebar .nav-links .nav-item,.sidebar .nav-links .repo-link{display:block;line-height:1.25rem;font-size:1.1em;padding:.5rem 0 .5rem 1.5rem}.sidebar>.sidebar-links{padding:1.5rem 0}.sidebar>.sidebar-links>li>a.sidebar-link{font-size:1.1em;line-height:1.7;font-weight:700}.sidebar>.sidebar-links>li:not(:first-child){margin-top:.75rem}@media (max-width:719px){.sidebar .nav-links{display:block}.sidebar .nav-links .dropdown-wrapper .nav-dropdown .dropdown-item a.router-link-active:after{top:calc(1rem - 2px)}.sidebar>.sidebar-links{padding:1rem 0}}.badge[data-v-15b7b770]{display:inline-block;font-size:14px;height:18px;line-height:18px;border-radius:3px;padding:0 6px;color:#fff}.badge.green[data-v-15b7b770],.badge.tip[data-v-15b7b770],.badge[data-v-15b7b770]{background-color:#42b983}.badge.error[data-v-15b7b770]{background-color:#da5961}.badge.warn[data-v-15b7b770],.badge.warning[data-v-15b7b770],.badge.yellow[data-v-15b7b770]{background-color:#e7c000}.badge+.badge[data-v-15b7b770]{margin-left:5px}.theme-code-block[data-v-759a7d02]{display:none}.theme-code-block__active[data-v-759a7d02]{display:block}.theme-code-block>pre[data-v-759a7d02]{background-color:orange}.theme-code-group__nav[data-v-deefee04]{margin-bottom:-35px;background-color:#282c34;padding-bottom:22px;border-top-left-radius:6px;border-top-right-radius:6px;padding-left:10px;padding-top:10px}.theme-code-group__ul[data-v-deefee04]{margin:auto 0;padding-left:0;display:inline-flex;list-style:none}.theme-code-group__nav-tab[data-v-deefee04]{border:0;padding:5px;cursor:pointer;background-color:transparent;font-size:.85em;line-height:1.4;color:hsla(0,0%,100%,.9);font-weight:600}.theme-code-group__nav-tab-active[data-v-deefee04]{border-bottom:1px solid #42b983}.pre-blank[data-v-deefee04]{color:#42b983} \ No newline at end of file diff --git a/assets/js/10.2c46fdf3.js b/assets/js/10.2c46fdf3.js deleted file mode 100644 index 4f960a5..0000000 --- a/assets/js/10.2c46fdf3.js +++ /dev/null @@ -1 +0,0 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[10],{205:function(t,s,a){"use strict";a.r(s);var n=a(28),e=Object(n.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"libp2p"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#libp2p"}},[t._v("#")]),t._v(" libp2p")]),t._v(" "),a("h3",{attrs:{id:"running-against-the-go-daemon"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#running-against-the-go-daemon"}},[t._v("#")]),t._v(" Running against the Go daemon")]),t._v(" "),a("p",[t._v("An implementation of "),a("a",{attrs:{href:"https://libp2p.io/",target:"_blank",rel:"noopener noreferrer"}},[t._v("libp2p"),a("OutboundLink")],1),t._v(" in Nim, as a wrapper of the "),a("a",{attrs:{href:"https://github.com/libp2p/go-libp2p",target:"_blank",rel:"noopener noreferrer"}},[t._v("Libp2p Go daemon"),a("OutboundLink")],1),t._v(".")]),t._v(" "),a("p",[t._v("Note that you need Go 1.12+ for the below instructions to work!")]),t._v(" "),a("p",[t._v("Install dependencies and run tests with:")]),t._v(" "),a("div",{staticClass:"language-bash line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token function"}},[t._v("git")]),t._v(" clone https://github.com/status-im/nim-libp2p "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&&")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v("cd")]),t._v(" nim-libp2p\nnimble "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("install")]),t._v("\nnimble "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v("test")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("git")]),t._v(" submodule update --init --recursive\ngo version\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("git")]),t._v(" clone https://github.com/libp2p/go-libp2p-daemon\n"),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v("cd")]),t._v(" go-libp2p-daemon\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("git")]),t._v(" checkout v0.0.1\ngo "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("install")]),t._v(" ./"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("..")]),t._v(".\n"),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v("cd")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("..")]),t._v("\n")])]),t._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[t._v("1")]),a("br"),a("span",{staticClass:"line-number"},[t._v("2")]),a("br"),a("span",{staticClass:"line-number"},[t._v("3")]),a("br"),a("span",{staticClass:"line-number"},[t._v("4")]),a("br"),a("span",{staticClass:"line-number"},[t._v("5")]),a("br"),a("span",{staticClass:"line-number"},[t._v("6")]),a("br"),a("span",{staticClass:"line-number"},[t._v("7")]),a("br"),a("span",{staticClass:"line-number"},[t._v("8")]),a("br"),a("span",{staticClass:"line-number"},[t._v("9")]),a("br"),a("span",{staticClass:"line-number"},[t._v("10")]),a("br")])]),a("p",[t._v("Try out the chat example:")]),t._v(" "),a("div",{staticClass:"language-bash line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[t._v("nim c -r --threads:on examples"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("chat.nim\n")])]),t._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[t._v("1")]),a("br")])]),a("p",[t._v("This will output a peer ID such as "),a("code",[t._v("QmbmHfVvouKammmQDJck4hz33WvVktNEe7pasxz2HgseRu")]),t._v(" which you can use in another instance to connect to it.")]),t._v(" "),a("div",{staticClass:"language-bash line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[t._v("./example/chat\n/connect QmbmHfVvouKammmQDJck4hz33WvVktNEe7pasxz2HgseRu\n")])]),t._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[t._v("1")]),a("br"),a("span",{staticClass:"line-number"},[t._v("2")]),a("br")])]),a("p",[t._v("You can now chat between the instances!")]),t._v(" "),a("p",[a("img",{attrs:{src:"https://imgur.com/caYRu8K.gif",alt:"Chat example"}})]),t._v(" "),a("h2",{attrs:{id:"api"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#api"}},[t._v("#")]),t._v(" API")]),t._v(" "),a("p",[t._v("Coming soon...")]),t._v(" "),a("h2",{attrs:{id:"experimental-native-implementation"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#experimental-native-implementation"}},[t._v("#")]),t._v(" Experimental native implementation")]),t._v(" "),a("p",[t._v("The native Nim libp2p implementation has finally arrived. Currently, it's support is experimental and shouldn't be relied on for production use. It is however under active development and we hope to achieve a reasonable level of stability in the upcoming months, as we will be integrating it across our own set of products, such as the Nim Beacon Chain.")]),t._v(" "),a("h3",{attrs:{id:"what-to-expect"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#what-to-expect"}},[t._v("#")]),t._v(" What to expect?")]),t._v(" "),a("p",[t._v("This implementation has a bare minimum set of components in order to provide a functional and interoperable libp2p stack. These are:")]),t._v(" "),a("ul",[a("li",[t._v("A TCP transport")]),t._v(" "),a("li",[t._v("multistream-select")]),t._v(" "),a("li",[t._v("Secio")]),t._v(" "),a("li",[t._v("Mplex")]),t._v(" "),a("li",[t._v("Identify")]),t._v(" "),a("li",[t._v("FloodSub")]),t._v(" "),a("li",[t._v("GossipSub")])]),t._v(" "),a("p",[t._v("This stack reflects the minimal requirements for the upcoming Eth2 implementation.")]),t._v(" "),a("h3",{attrs:{id:"how-to-try-it-out"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#how-to-try-it-out"}},[t._v("#")]),t._v(" How to try it out?")]),t._v(" "),a("p",[t._v("To run it, add nim-libp2p to your project's nimble file and spawn a node as follows:")]),t._v(" "),a("div",{staticClass:"language-nim line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-nim"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" tables\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" chronos\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("../")]),t._v("libp2p"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("switch"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n multistream"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n protocols"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),t._v("identify"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n connection"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n transports"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),t._v("transport"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n transports"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),t._v("tcptransport"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n multiaddress"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n peerinfo"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n crypto"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),t._v("crypto"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n peer"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n protocols"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),t._v("protocol"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n muxers"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),t._v("muxer"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n muxers"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),t._v("mplex"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),t._v("mplex"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n muxers"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),t._v("mplex"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),t._v("types"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n protocols"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),t._v("secure"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),t._v("secio"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n protocols"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),t._v("secure"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),t._v("secure"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("const")]),t._v(" TestCodec "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"/test/proto/1.0.0"')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# custom protocol string")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("type")]),t._v("\n TestProto "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("ref")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("object")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("of")]),t._v(" LPProtocol "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# declare a custom protocol")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("method")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("init")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("p"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" TestProto"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{.")]),t._v("gcsafe"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# handle incoming connections in closure")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("handle")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("conn"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Connection"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" proto"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" string"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{.")]),t._v("async"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" gcsafe"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n echo "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Got from remote - "')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("cast")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("string"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("await conn"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("readLp")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n await conn"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("writeLp")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Hello!"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n await conn"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("close")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n p"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("codec "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" TestCodec "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# init proto with the correct string id")]),t._v("\n p"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("handler "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" handle "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# set proto handler")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("createSwitch")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ma"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" MultiAddress"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Switch"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" PeerInfo"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("## Helper to create a swith")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" seckey "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" PrivateKey"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("random")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("RSA"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# use a random key for peer id")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" peerInfo "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" PeerInfo"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("init")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("seckey"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# create a peer id and assign")]),t._v("\n peerInfo"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("addrs"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("add")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ma"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# set this peer's multiaddresses (can be any number)")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" identify "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("newIdentify")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("peerInfo"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# create the identify proto")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("createMplex")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("conn"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Connection"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Muxer "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# helper proc to create multiplexers,")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# use this to perform any custom setup up,")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# such as adjusting timeout or anything else")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# that the muxer requires")]),t._v("\n result "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("newMplex")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" mplexProvider "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("newMuxerProvider")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("createMplex"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" MplexCodec"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# create multiplexer")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" transports "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("@")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Transport")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("newTransport")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("TcpTransport"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# add all transports (tcp only for now, but can be anything in the future)")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" muxers "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("MplexCodec"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" mplexProvider"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("toTable")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# add all muxers")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" secureManagers "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("SecioCodec"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Secure")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("newSecio")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("seckey"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("toTable")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# setup the secio and any other secure provider")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# create the switch")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" switch "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("newSwitch")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("peerInfo"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n transports"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n identify"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n muxers"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n secureManagers"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n result "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("switch"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" peerInfo"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("main")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{.")]),t._v("async"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" gcsafe"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" ma1"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" MultiAddress "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" Multiaddress"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("init")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"/ip4/0.0.0.0/tcp/0"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" ma2"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" MultiAddress "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" Multiaddress"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("init")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"/ip4/0.0.0.0/tcp/0"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" peerInfo1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" peerInfo2"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" PeerInfo\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" switch1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" switch2"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Switch")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("switch1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" peerInfo1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("createSwitch")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ma1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# create node 1")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# setup the custom proto")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" testProto "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" new TestProto\n testProto"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("init")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# run it's init method to perform any required initialization")]),t._v("\n switch1"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("mount")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("testProto"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# mount the proto")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" switch1Fut "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" await switch1"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("start")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# start the node")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("switch2"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" peerInfo2"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("createSwitch")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ma2"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# create node 2")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" switch2Fut "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" await switch2"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("start")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# start second node")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" conn "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" await switch2"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("dial")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("switch1"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("peerInfo"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" TestCodec"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# dial the first node")]),t._v("\n\n await conn"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("writeLp")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Hello!"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# writeLp send a length prefixed buffer over the wire")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# readLp reads length prefixed bytes and returns a buffer without the prefix")]),t._v("\n echo "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Remote responded with - "')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("cast")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("string"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("await conn"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("readLp")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n await "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("allFutures")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("switch1"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("stop")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" switch2"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("stop")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# close connections and shutdown all transports")]),t._v("\n await "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("allFutures")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("switch1Fut "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v(" switch2Fut"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# wait for all transports to shutdown")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("waitFor")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("main")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])]),t._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[t._v("1")]),a("br"),a("span",{staticClass:"line-number"},[t._v("2")]),a("br"),a("span",{staticClass:"line-number"},[t._v("3")]),a("br"),a("span",{staticClass:"line-number"},[t._v("4")]),a("br"),a("span",{staticClass:"line-number"},[t._v("5")]),a("br"),a("span",{staticClass:"line-number"},[t._v("6")]),a("br"),a("span",{staticClass:"line-number"},[t._v("7")]),a("br"),a("span",{staticClass:"line-number"},[t._v("8")]),a("br"),a("span",{staticClass:"line-number"},[t._v("9")]),a("br"),a("span",{staticClass:"line-number"},[t._v("10")]),a("br"),a("span",{staticClass:"line-number"},[t._v("11")]),a("br"),a("span",{staticClass:"line-number"},[t._v("12")]),a("br"),a("span",{staticClass:"line-number"},[t._v("13")]),a("br"),a("span",{staticClass:"line-number"},[t._v("14")]),a("br"),a("span",{staticClass:"line-number"},[t._v("15")]),a("br"),a("span",{staticClass:"line-number"},[t._v("16")]),a("br"),a("span",{staticClass:"line-number"},[t._v("17")]),a("br"),a("span",{staticClass:"line-number"},[t._v("18")]),a("br"),a("span",{staticClass:"line-number"},[t._v("19")]),a("br"),a("span",{staticClass:"line-number"},[t._v("20")]),a("br"),a("span",{staticClass:"line-number"},[t._v("21")]),a("br"),a("span",{staticClass:"line-number"},[t._v("22")]),a("br"),a("span",{staticClass:"line-number"},[t._v("23")]),a("br"),a("span",{staticClass:"line-number"},[t._v("24")]),a("br"),a("span",{staticClass:"line-number"},[t._v("25")]),a("br"),a("span",{staticClass:"line-number"},[t._v("26")]),a("br"),a("span",{staticClass:"line-number"},[t._v("27")]),a("br"),a("span",{staticClass:"line-number"},[t._v("28")]),a("br"),a("span",{staticClass:"line-number"},[t._v("29")]),a("br"),a("span",{staticClass:"line-number"},[t._v("30")]),a("br"),a("span",{staticClass:"line-number"},[t._v("31")]),a("br"),a("span",{staticClass:"line-number"},[t._v("32")]),a("br"),a("span",{staticClass:"line-number"},[t._v("33")]),a("br"),a("span",{staticClass:"line-number"},[t._v("34")]),a("br"),a("span",{staticClass:"line-number"},[t._v("35")]),a("br"),a("span",{staticClass:"line-number"},[t._v("36")]),a("br"),a("span",{staticClass:"line-number"},[t._v("37")]),a("br"),a("span",{staticClass:"line-number"},[t._v("38")]),a("br"),a("span",{staticClass:"line-number"},[t._v("39")]),a("br"),a("span",{staticClass:"line-number"},[t._v("40")]),a("br"),a("span",{staticClass:"line-number"},[t._v("41")]),a("br"),a("span",{staticClass:"line-number"},[t._v("42")]),a("br"),a("span",{staticClass:"line-number"},[t._v("43")]),a("br"),a("span",{staticClass:"line-number"},[t._v("44")]),a("br"),a("span",{staticClass:"line-number"},[t._v("45")]),a("br"),a("span",{staticClass:"line-number"},[t._v("46")]),a("br"),a("span",{staticClass:"line-number"},[t._v("47")]),a("br"),a("span",{staticClass:"line-number"},[t._v("48")]),a("br"),a("span",{staticClass:"line-number"},[t._v("49")]),a("br"),a("span",{staticClass:"line-number"},[t._v("50")]),a("br"),a("span",{staticClass:"line-number"},[t._v("51")]),a("br"),a("span",{staticClass:"line-number"},[t._v("52")]),a("br"),a("span",{staticClass:"line-number"},[t._v("53")]),a("br"),a("span",{staticClass:"line-number"},[t._v("54")]),a("br"),a("span",{staticClass:"line-number"},[t._v("55")]),a("br"),a("span",{staticClass:"line-number"},[t._v("56")]),a("br"),a("span",{staticClass:"line-number"},[t._v("57")]),a("br"),a("span",{staticClass:"line-number"},[t._v("58")]),a("br"),a("span",{staticClass:"line-number"},[t._v("59")]),a("br"),a("span",{staticClass:"line-number"},[t._v("60")]),a("br"),a("span",{staticClass:"line-number"},[t._v("61")]),a("br"),a("span",{staticClass:"line-number"},[t._v("62")]),a("br"),a("span",{staticClass:"line-number"},[t._v("63")]),a("br"),a("span",{staticClass:"line-number"},[t._v("64")]),a("br"),a("span",{staticClass:"line-number"},[t._v("65")]),a("br"),a("span",{staticClass:"line-number"},[t._v("66")]),a("br"),a("span",{staticClass:"line-number"},[t._v("67")]),a("br"),a("span",{staticClass:"line-number"},[t._v("68")]),a("br"),a("span",{staticClass:"line-number"},[t._v("69")]),a("br"),a("span",{staticClass:"line-number"},[t._v("70")]),a("br"),a("span",{staticClass:"line-number"},[t._v("71")]),a("br"),a("span",{staticClass:"line-number"},[t._v("72")]),a("br"),a("span",{staticClass:"line-number"},[t._v("73")]),a("br"),a("span",{staticClass:"line-number"},[t._v("74")]),a("br"),a("span",{staticClass:"line-number"},[t._v("75")]),a("br"),a("span",{staticClass:"line-number"},[t._v("76")]),a("br"),a("span",{staticClass:"line-number"},[t._v("77")]),a("br"),a("span",{staticClass:"line-number"},[t._v("78")]),a("br"),a("span",{staticClass:"line-number"},[t._v("79")]),a("br"),a("span",{staticClass:"line-number"},[t._v("80")]),a("br"),a("span",{staticClass:"line-number"},[t._v("81")]),a("br"),a("span",{staticClass:"line-number"},[t._v("82")]),a("br"),a("span",{staticClass:"line-number"},[t._v("83")]),a("br"),a("span",{staticClass:"line-number"},[t._v("84")]),a("br"),a("span",{staticClass:"line-number"},[t._v("85")]),a("br"),a("span",{staticClass:"line-number"},[t._v("86")]),a("br"),a("span",{staticClass:"line-number"},[t._v("87")]),a("br"),a("span",{staticClass:"line-number"},[t._v("88")]),a("br"),a("span",{staticClass:"line-number"},[t._v("89")]),a("br")])]),a("p",[t._v("For a more complete example, checkout the "),a("a",{attrs:{href:"examples/directchat.nim"}},[t._v("directchat.nim")]),t._v(" example in the "),a("code",[t._v("examples")]),t._v(" directory.")])])}),[],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/10.a7e5f96d.js b/assets/js/10.a7e5f96d.js new file mode 100644 index 0000000..4a03a3c --- /dev/null +++ b/assets/js/10.a7e5f96d.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[10],{369:function(t,s,a){"use strict";a.r(s);var n=a(44),e=Object(n.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"chronos"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#chronos"}},[t._v("#")]),t._v(" Chronos")]),t._v(" "),a("p",[t._v("Chronos is an efficient "),a("a",{attrs:{href:"https://en.wikipedia.org/wiki/Async/await",target:"_blank",rel:"noopener noreferrer"}},[t._v("async/await"),a("OutboundLink")],1),t._v(" framework for Nim. Features include:")]),t._v(" "),a("ul",[a("li",[t._v("Efficient dispatch pipeline for asynchronous execution")]),t._v(" "),a("li",[t._v("HTTP server with SSL/TLS support out of the box (no OpenSSL needed)")]),t._v(" "),a("li",[t._v("Cancellation support")]),t._v(" "),a("li",[t._v("Synchronization primitivies like queues, events and locks")]),t._v(" "),a("li",[t._v("FIFO processing order of dispatch queue")]),t._v(" "),a("li",[t._v("Minimal exception effect support (see "),a("a",{attrs:{href:"#exception-effects"}},[t._v("exception effects")]),t._v(")")])]),t._v(" "),a("h2",{attrs:{id:"installation"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#installation"}},[t._v("#")]),t._v(" Installation")]),t._v(" "),a("p",[t._v("You can use Nim's official package manager Nimble to install Chronos:")]),t._v(" "),a("div",{staticClass:"language-text line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[t._v("nimble install https://github.com/status-im/nim-chronos.git\n")])]),t._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[t._v("1")]),a("br")])]),a("p",[t._v("or add a dependency to your "),a("code",[t._v(".nimble")]),t._v(" file:")]),t._v(" "),a("div",{staticClass:"language-text line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[t._v('requires "chronos"\n')])]),t._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[t._v("1")]),a("br")])]),a("h2",{attrs:{id:"projects-using-chronos"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#projects-using-chronos"}},[t._v("#")]),t._v(" Projects using "),a("code",[t._v("chronos")])]),t._v(" "),a("ul",[a("li",[a("a",{attrs:{href:"https://github.com/status-im/nim-libp2p",target:"_blank",rel:"noopener noreferrer"}},[t._v("libp2p"),a("OutboundLink")],1),t._v(" - Peer-to-Peer networking stack implemented in many languages")]),t._v(" "),a("li",[a("a",{attrs:{href:"https://github.com/bung87/Looper",target:"_blank",rel:"noopener noreferrer"}},[t._v("Looper"),a("OutboundLink")],1),t._v(" - Web framework")]),t._v(" "),a("li",[a("a",{attrs:{href:"https://github.com/gogolxdong/2DeFi",target:"_blank",rel:"noopener noreferrer"}},[t._v("2DeFi"),a("OutboundLink")],1),t._v(" - Decentralised file system")])]),t._v(" "),a("p",[a("code",[t._v("chronos")]),t._v(" is available in the "),a("a",{attrs:{href:"https://play.nim-lang.org/#ix=2TpS",target:"_blank",rel:"noopener noreferrer"}},[t._v("Nim Playground"),a("OutboundLink")],1)]),t._v(" "),a("p",[t._v("Submit a PR to add yours!")]),t._v(" "),a("h2",{attrs:{id:"documentation"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#documentation"}},[t._v("#")]),t._v(" Documentation")]),t._v(" "),a("h3",{attrs:{id:"concepts"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#concepts"}},[t._v("#")]),t._v(" Concepts")]),t._v(" "),a("p",[t._v("Chronos implements the async/await paradigm in a self-contained library, using\nmacros, with no specific helpers from the compiler.")]),t._v(" "),a("p",[t._v('Our event loop is called a "dispatcher" and a single instance per thread is\ncreated, as soon as one is needed.')]),t._v(" "),a("p",[t._v("To trigger a dispatcher's processing step, we need to call "),a("code",[t._v("poll()")]),t._v(" - either\ndirectly or through a wrapper like "),a("code",[t._v("runForever()")]),t._v(" or "),a("code",[t._v("waitFor()")]),t._v(". This step\nhandles any file descriptors, timers and callbacks that are ready to be\nprocessed.")]),t._v(" "),a("p",[a("code",[t._v("Future")]),t._v(" objects encapsulate the result of an async procedure, upon successful\ncompletion, and a list of callbacks to be scheduled after any type of\ncompletion - be that success, failure or cancellation.")]),t._v(" "),a("p",[t._v("(These explicit callbacks are rarely used outside Chronos, being replaced by\nimplicit ones generated by async procedure execution and "),a("code",[t._v("await")]),t._v(" chaining.)")]),t._v(" "),a("p",[t._v("Async procedures (those using the "),a("code",[t._v("{.async.}")]),t._v(" pragma) return "),a("code",[t._v("Future")]),t._v(" objects.")]),t._v(" "),a("p",[t._v("Inside an async procedure, you can "),a("code",[t._v("await")]),t._v(" the future returned by another async\nprocedure. At this point, control will be handled to the event loop until that\nfuture is completed.")]),t._v(" "),a("p",[t._v("Future completion is tested with "),a("code",[t._v("Future.finished()")]),t._v(" and is defined as success,\nfailure or cancellation. This means that a future is either pending or completed.")]),t._v(" "),a("p",[t._v("To differentiate between completion states, we have "),a("code",[t._v("Future.failed()")]),t._v(" and\n"),a("code",[t._v("Future.cancelled()")]),t._v(".")]),t._v(" "),a("h3",{attrs:{id:"dispatcher"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#dispatcher"}},[t._v("#")]),t._v(" Dispatcher")]),t._v(" "),a("p",[t._v('You can run the "dispatcher" event loop forever, with '),a("code",[t._v("runForever()")]),t._v(" which is defined as:")]),t._v(" "),a("div",{staticClass:"language-nim line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-nim"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("runForever"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")])]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("while")]),t._v(" true"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("poll")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])]),t._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[t._v("1")]),a("br"),a("span",{staticClass:"line-number"},[t._v("2")]),a("br"),a("span",{staticClass:"line-number"},[t._v("3")]),a("br")])]),a("p",[t._v("You can also run it until a certain future is completed, with "),a("code",[t._v("waitFor()")]),t._v(" which\nwill also call "),a("code",[t._v("Future.read()")]),t._v(" on it:")]),t._v(" "),a("div",{staticClass:"language-nim line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-nim"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("p")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Future"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("int"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{.")]),t._v("async"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n await "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("sleepAsync")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("100.")]),t._v("milliseconds"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),t._v("\n\necho waitFor "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("p")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v('# prints "1"')]),t._v("\n")])]),t._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[t._v("1")]),a("br"),a("span",{staticClass:"line-number"},[t._v("2")]),a("br"),a("span",{staticClass:"line-number"},[t._v("3")]),a("br"),a("span",{staticClass:"line-number"},[t._v("4")]),a("br"),a("span",{staticClass:"line-number"},[t._v("5")]),a("br")])]),a("p",[a("code",[t._v("waitFor()")]),t._v(" is defined like this:")]),t._v(" "),a("div",{staticClass:"language-nim line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-nim"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("waitFor*[T]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("fut"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Future"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("T"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" T "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("while")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("not")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("fut"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("finished")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("poll")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" fut"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("read")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])]),t._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[t._v("1")]),a("br"),a("span",{staticClass:"line-number"},[t._v("2")]),a("br"),a("span",{staticClass:"line-number"},[t._v("3")]),a("br"),a("span",{staticClass:"line-number"},[t._v("4")]),a("br")])]),a("h3",{attrs:{id:"async-procedures-and-methods"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#async-procedures-and-methods"}},[t._v("#")]),t._v(" Async procedures and methods")]),t._v(" "),a("p",[t._v("The "),a("code",[t._v("{.async.}")]),t._v(" pragma will transform a procedure (or a method) returning a\nspecialised "),a("code",[t._v("Future")]),t._v(" type into a closure iterator. If there is no return type\nspecified, a "),a("code",[t._v("Future[void]")]),t._v(" is returned.")]),t._v(" "),a("div",{staticClass:"language-nim line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-nim"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("p")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{.")]),t._v("async"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n await "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("sleepAsync")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("100.")]),t._v("milliseconds"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\necho "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("p")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("type")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v('# prints "Future[system.void]"')]),t._v("\n")])]),t._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[t._v("1")]),a("br"),a("span",{staticClass:"line-number"},[t._v("2")]),a("br"),a("span",{staticClass:"line-number"},[t._v("3")]),a("br"),a("span",{staticClass:"line-number"},[t._v("4")]),a("br")])]),a("p",[t._v("Whenever "),a("code",[t._v("await")]),t._v(" is encountered inside an async procedure, control is passed\nback to the dispatcher for as many steps as it's necessary for the awaited\nfuture to complete successfully, fail or be cancelled. "),a("code",[t._v("await")]),t._v(" calls the\nequivalent of "),a("code",[t._v("Future.read()")]),t._v(" on the completed future and returns the\nencapsulated value.")]),t._v(" "),a("div",{staticClass:"language-nim line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-nim"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("p1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{.")]),t._v("async"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n await "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("sleepAsync")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1.")]),t._v("seconds"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("p2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{.")]),t._v("async"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n await "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("sleepAsync")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1.")]),t._v("seconds"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("p3")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{.")]),t._v("async"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v("\n fut1 "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("p1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n fut2 "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("p2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Just by executing the async procs, both resulting futures entered the")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v('# dispatcher\'s queue and their "clocks" started ticking.')]),t._v("\n await fut1\n await fut2\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Only one second passed while awaiting them both, not two.")]),t._v("\n\nwaitFor "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("p3")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])]),t._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[t._v("1")]),a("br"),a("span",{staticClass:"line-number"},[t._v("2")]),a("br"),a("span",{staticClass:"line-number"},[t._v("3")]),a("br"),a("span",{staticClass:"line-number"},[t._v("4")]),a("br"),a("span",{staticClass:"line-number"},[t._v("5")]),a("br"),a("span",{staticClass:"line-number"},[t._v("6")]),a("br"),a("span",{staticClass:"line-number"},[t._v("7")]),a("br"),a("span",{staticClass:"line-number"},[t._v("8")]),a("br"),a("span",{staticClass:"line-number"},[t._v("9")]),a("br"),a("span",{staticClass:"line-number"},[t._v("10")]),a("br"),a("span",{staticClass:"line-number"},[t._v("11")]),a("br"),a("span",{staticClass:"line-number"},[t._v("12")]),a("br"),a("span",{staticClass:"line-number"},[t._v("13")]),a("br"),a("span",{staticClass:"line-number"},[t._v("14")]),a("br"),a("span",{staticClass:"line-number"},[t._v("15")]),a("br"),a("span",{staticClass:"line-number"},[t._v("16")]),a("br"),a("span",{staticClass:"line-number"},[t._v("17")]),a("br")])]),a("p",[t._v("Don't let "),a("code",[t._v("await")]),t._v("'s behaviour of giving back control to the dispatcher surprise\nyou. If an async procedure modifies global state, and you can't predict when it\nwill start executing, the only way to avoid that state changing underneath your\nfeet, in a certain section, is to not use "),a("code",[t._v("await")]),t._v(" in it.")]),t._v(" "),a("h3",{attrs:{id:"error-handling"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#error-handling"}},[t._v("#")]),t._v(" Error handling")]),t._v(" "),a("p",[t._v("Exceptions inheriting from "),a("code",[t._v("CatchableError")]),t._v(" are caught by hidden "),a("code",[t._v("try")]),t._v(" blocks\nand placed in the "),a("code",[t._v("Future.error")]),t._v(" field, changing the future's status to\n"),a("code",[t._v("Failed")]),t._v(".")]),t._v(" "),a("p",[t._v("When a future is awaited, that exception is re-raised, only to be caught again\nby a hidden "),a("code",[t._v("try")]),t._v(" block in the calling async procedure. That's how these\nexceptions move up the async chain.")]),t._v(" "),a("p",[t._v("A failed future's callbacks will still be scheduled, but it's not possible to\nresume execution from the point an exception was raised.")]),t._v(" "),a("div",{staticClass:"language-nim line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-nim"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("p1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{.")]),t._v("async"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n await "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("sleepAsync")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1.")]),t._v("seconds"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("raise")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("newException")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ValueError"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"ValueError inherits from CatchableError"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("p2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{.")]),t._v("async"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n await "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("sleepAsync")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1.")]),t._v("seconds"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("p3")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{.")]),t._v("async"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v("\n fut1 "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("p1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n fut2 "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("p2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n await fut1\n echo "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"unreachable code here"')]),t._v("\n await fut2\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# `waitFor()` would call `Future.read()` unconditionally, which would raise the")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# exception in `Future.error`.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" fut3 "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("p3")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("while")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("not")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("fut3"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("finished")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("poll")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\necho "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"fut3.state = "')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fut3"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("state "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v('# "Failed"')]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" fut3"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("failed")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("\n echo "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"p3() failed: "')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fut3"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("error"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('": "')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fut3"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("error"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("msg\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v('# prints "p3() failed: ValueError: ValueError inherits from CatchableError"')]),t._v("\n")])]),t._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[t._v("1")]),a("br"),a("span",{staticClass:"line-number"},[t._v("2")]),a("br"),a("span",{staticClass:"line-number"},[t._v("3")]),a("br"),a("span",{staticClass:"line-number"},[t._v("4")]),a("br"),a("span",{staticClass:"line-number"},[t._v("5")]),a("br"),a("span",{staticClass:"line-number"},[t._v("6")]),a("br"),a("span",{staticClass:"line-number"},[t._v("7")]),a("br"),a("span",{staticClass:"line-number"},[t._v("8")]),a("br"),a("span",{staticClass:"line-number"},[t._v("9")]),a("br"),a("span",{staticClass:"line-number"},[t._v("10")]),a("br"),a("span",{staticClass:"line-number"},[t._v("11")]),a("br"),a("span",{staticClass:"line-number"},[t._v("12")]),a("br"),a("span",{staticClass:"line-number"},[t._v("13")]),a("br"),a("span",{staticClass:"line-number"},[t._v("14")]),a("br"),a("span",{staticClass:"line-number"},[t._v("15")]),a("br"),a("span",{staticClass:"line-number"},[t._v("16")]),a("br"),a("span",{staticClass:"line-number"},[t._v("17")]),a("br"),a("span",{staticClass:"line-number"},[t._v("18")]),a("br"),a("span",{staticClass:"line-number"},[t._v("19")]),a("br"),a("span",{staticClass:"line-number"},[t._v("20")]),a("br"),a("span",{staticClass:"line-number"},[t._v("21")]),a("br"),a("span",{staticClass:"line-number"},[t._v("22")]),a("br"),a("span",{staticClass:"line-number"},[t._v("23")]),a("br"),a("span",{staticClass:"line-number"},[t._v("24")]),a("br"),a("span",{staticClass:"line-number"},[t._v("25")]),a("br")])]),a("p",[t._v("You can put the "),a("code",[t._v("await")]),t._v(" in a "),a("code",[t._v("try")]),t._v(" block, to deal with that exception sooner:")]),t._v(" "),a("div",{staticClass:"language-nim line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-nim"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("p3")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{.")]),t._v("async"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v("\n fut1 "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("p1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n fut2 "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("p2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("try")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("\n await fut1\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("except")]),t._v(" CachableError"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("\n echo "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"p1() failed: "')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fut1"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("error"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('": "')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fut1"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("error"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("msg\n echo "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"reachable code here"')]),t._v("\n await fut2\n")])]),t._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[t._v("1")]),a("br"),a("span",{staticClass:"line-number"},[t._v("2")]),a("br"),a("span",{staticClass:"line-number"},[t._v("3")]),a("br"),a("span",{staticClass:"line-number"},[t._v("4")]),a("br"),a("span",{staticClass:"line-number"},[t._v("5")]),a("br"),a("span",{staticClass:"line-number"},[t._v("6")]),a("br"),a("span",{staticClass:"line-number"},[t._v("7")]),a("br"),a("span",{staticClass:"line-number"},[t._v("8")]),a("br"),a("span",{staticClass:"line-number"},[t._v("9")]),a("br"),a("span",{staticClass:"line-number"},[t._v("10")]),a("br")])]),a("p",[t._v("Chronos does not allow that future continuations and other callbacks raise\n"),a("code",[t._v("CatchableError")]),t._v(" - as such, calls to "),a("code",[t._v("poll")]),t._v(" will never raise exceptions caused\noriginating from tasks on the dispatcher queue. It is however possible that\n"),a("code",[t._v("Defect")]),t._v(" that happen in tasks bubble up through "),a("code",[t._v("poll")]),t._v(" as these are not caught\nby the transformation.")]),t._v(" "),a("h3",{attrs:{id:"platform-independence"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#platform-independence"}},[t._v("#")]),t._v(" Platform independence")]),t._v(" "),a("p",[t._v("Several functions in "),a("code",[t._v("chronos")]),t._v(" are backed by the operating system, such as\nwaiting for network events, creating files and sockets etc. The specific\nexceptions that are raised by the OS is platform-dependent, thus such functions\nare declared as raising "),a("code",[t._v("CatchableError")]),t._v(" but will in general raise something\nmore specific. In particular, it's possible that some functions that are\nannotated as raising "),a("code",[t._v("CatchableError")]),t._v(" only raise on "),a("em",[t._v("some")]),t._v(" platforms - in order\nto work on all platforms, calling code must assume that they will raise even\nwhen they don't seem to do so on one platform.")]),t._v(" "),a("h3",{attrs:{id:"exception-effects"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#exception-effects"}},[t._v("#")]),t._v(" Exception effects")]),t._v(" "),a("p",[a("code",[t._v("chronos")]),t._v(" currently offers minimal support for exception effects and "),a("code",[t._v("raises")]),t._v("\nannotations. In general, during the "),a("code",[t._v("async")]),t._v(" transformation, a generic\n"),a("code",[t._v("except CatchableError")]),t._v(" handler is added around the entire function being\ntransformed, in order to catch any exceptions and transfer them to the "),a("code",[t._v("Future")]),t._v('.\nBecause of this, the effect system thinks no exceptions are "leaking" because in\nfact, exception '),a("em",[t._v("handling")]),t._v(" is deferred to when the future is being read.")]),t._v(" "),a("p",[t._v("Effectively, this means that while code can be compiled with\n"),a("code",[t._v("{.push raises: [Defect]}")]),t._v(", the intended effect propagation and checking is\n"),a("strong",[t._v("disabled")]),t._v(" for "),a("code",[t._v("async")]),t._v(" functions.")]),t._v(" "),a("p",[t._v("To enable checking exception effects in "),a("code",[t._v("async")]),t._v(" code, enable strict mode with\n"),a("code",[t._v("-d:chronosStrictException")]),t._v(".")]),t._v(" "),a("p",[t._v("In the strict mode, "),a("code",[t._v("async")]),t._v(" functions are checked such that they only raise\n"),a("code",[t._v("CatchableError")]),t._v(" and thus must make sure to explicitly specify exception\neffects on forward declarations, callbacks and methods using\n"),a("code",[t._v("{.raises: [CatchableError].}")]),t._v(" (or more strict) annotations.")]),t._v(" "),a("h2",{attrs:{id:"todo"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#todo"}},[t._v("#")]),t._v(" TODO")]),t._v(" "),a("ul",[a("li",[t._v("Pipe/Subprocess Transports.")]),t._v(" "),a("li",[t._v("Multithreading Stream/Datagram servers")])])])}),[],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/11.b620ddcc.js b/assets/js/11.b620ddcc.js new file mode 100644 index 0000000..26d3711 --- /dev/null +++ b/assets/js/11.b620ddcc.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[11],{368:function(t,e,s){"use strict";s.r(e);var a=s(44),n=Object(a.a)({},(function(){var t=this,e=t.$createElement,s=t._self._c||e;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"eth"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#eth"}},[t._v("#")]),t._v(" Eth")]),t._v(" "),s("p",[t._v("Ethereum-related utilities written in Nim. Includes things like Bloom filters, private/public key utilities, RLP, devp2p, and more.")]),t._v(" "),s("h2",{attrs:{id:"rlp"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#rlp"}},[t._v("#")]),t._v(" rlp")]),t._v(" "),s("h3",{attrs:{id:"introduction"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#introduction"}},[t._v("#")]),t._v(" Introduction")]),t._v(" "),s("p",[t._v("A Nim implementation of the Recursive Length Prefix encoding (RLP) as specified\nin the Ethereum's "),s("a",{attrs:{href:"https://ethereum.github.io/yellowpaper/paper.pdf",target:"_blank",rel:"noopener noreferrer"}},[t._v("Yellow Paper"),s("OutboundLink")],1),t._v("\nand "),s("a",{attrs:{href:"https://github.com/ethereum/wiki/wiki/RLP",target:"_blank",rel:"noopener noreferrer"}},[t._v("Wiki"),s("OutboundLink")],1),t._v(".")]),t._v(" "),s("h3",{attrs:{id:"reading-rlp-data"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#reading-rlp-data"}},[t._v("#")]),t._v(" Reading RLP data")]),t._v(" "),s("p",[t._v("The "),s("code",[t._v("Rlp")]),t._v(" type provided by this library represents a cursor over an RLP-encoded\nbyte stream.")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("rlpFromBytes"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("data"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" openArray"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("byte"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Rlp\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("h3",{attrs:{id:"streaming-api"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#streaming-api"}},[t._v("#")]),t._v(" Streaming API")]),t._v(" "),s("p",[t._v("Once created, the "),s("code",[t._v("Rlp")]),t._v(" object will offer procs such as "),s("code",[t._v("isList")]),t._v(", "),s("code",[t._v("isBlob")]),t._v(",\n"),s("code",[t._v("getType")]),t._v(", "),s("code",[t._v("listLen")]),t._v(", "),s("code",[t._v("blobLen")]),t._v(" to determine the type of the value under\nthe cursor. The contents of blobs can be extracted with procs such as\n"),s("code",[t._v("toString")]),t._v(", "),s("code",[t._v("toBytes")]),t._v(" and "),s("code",[t._v("toInt")]),t._v(" without advancing the cursor.")]),t._v(" "),s("p",[t._v("Lists can be traversed with the standard "),s("code",[t._v("items")]),t._v(" iterator, which will advance\nthe cursor to each sub-item position and yield the "),s("code",[t._v("Rlp")]),t._v(" object at that point.\nAs an alternative, "),s("code",[t._v("listElem")]),t._v(" can return a new "),s("code",[t._v("Rlp")]),t._v(" object adjusted to a\nparticular sub-item position without advancing the original cursor.\nKeep in mind that copying "),s("code",[t._v("Rlp")]),t._v(" objects is cheap and you can create as many\ncursors pointing to different positions in the RLP stream as necessary.")]),t._v(" "),s("p",[s("code",[t._v("skipElem")]),t._v(" will advance the cursor to the next position in the current list.\n"),s("code",[t._v("hasData")]),t._v(" will indicate that there are no more bytes in the stream that can\nbe consumed.")]),t._v(" "),s("p",[t._v("Another way to extract data from the stream is through the universal "),s("code",[t._v("read")]),t._v("\nproc that accepts a type as a parameter. You can pass any supported type\nsuch as "),s("code",[t._v("string")]),t._v(", "),s("code",[t._v("int")]),t._v(", "),s("code",[t._v("seq[T]")]),t._v(", etc, including composite user-defined\ntypes (see "),s("a",{attrs:{href:"#object-serialization"}},[t._v("Object Serialization")]),t._v("). The cursor\nwill be advanced just past the end of the consumed object.")]),t._v(" "),s("p",[t._v("The "),s("code",[t._v("toXX")]),t._v(" and "),s("code",[t._v("read")]),t._v(" family of procs may raise a "),s("code",[t._v("RlpTypeMismatch")]),t._v(" in case\nof type mismatch with the stream contents under the cursor. A corrupted\nRLP stream or an attemp to read past the stream end will be signaled\nwith the "),s("code",[t._v("MalformedRlpError")]),t._v(" exception. If the RLP stream includes data\nthat cannot be processed on the current platform (e.g. an integer value\nthat is too large), the library will raise an "),s("code",[t._v("UnsupportedRlpError")]),t._v(" exception.")]),t._v(" "),s("h3",{attrs:{id:"dom-api"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#dom-api"}},[t._v("#")]),t._v(" DOM API")]),t._v(" "),s("p",[t._v("Calling "),s("code",[t._v("Rlp.toNodes")]),t._v(" at any position within the stream will return a tree\nof "),s("code",[t._v("RlpNode")]),t._v(" objects representing the collection of values starting at that\nposition:")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("type")]),t._v("\n RlpNodeType"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("enum")]),t._v("\n rlpBlob\n rlpList\n\n RlpNode"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("object")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" kind"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*:")]),t._v(" RlpNodeType\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("of")]),t._v(" rlpBlob"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("\n bytes"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*:")]),t._v(" seq"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("byte"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("of")]),t._v(" rlpList"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("\n elems"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*:")]),t._v(" seq"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("RlpNode"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br"),s("span",{staticClass:"line-number"},[t._v("9")]),s("br"),s("span",{staticClass:"line-number"},[t._v("10")]),s("br"),s("span",{staticClass:"line-number"},[t._v("11")]),s("br")])]),s("p",[t._v("As a short-cut, you can also call "),s("code",[t._v("decode")]),t._v(" directly on a byte sequence to\navoid creating a "),s("code",[t._v("Rlp")]),t._v(" object when obtaining the nodes.\nFor debugging purposes, you can also create a human readable representation\nof the Rlp nodes by calling the "),s("code",[t._v("inspect")]),t._v(" proc:")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("inspect"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("self"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Rlp"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" indent "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" string\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("h3",{attrs:{id:"creating-rlp-data"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#creating-rlp-data"}},[t._v("#")]),t._v(" Creating RLP data")]),t._v(" "),s("p",[t._v("The "),s("code",[t._v("RlpWriter")]),t._v(" type can be used to encode RLP data. Instances are created\nwith the "),s("code",[t._v("initRlpWriter")]),t._v(" proc. This should be followed by one or more calls\nto "),s("code",[t._v("append")]),t._v(" which is overloaded to accept arbitrary values. Finally, you can\ncall "),s("code",[t._v("finish")]),t._v(" to obtain the final "),s("code",[t._v("seq[byte]")]),t._v(".")]),t._v(" "),s("p",[t._v("If the end result should be a RLP list of particular length, you can replace\nthe initial call to "),s("code",[t._v("initRlpWriter")]),t._v(" with "),s("code",[t._v("initRlpList(n)")]),t._v(". Calling "),s("code",[t._v("finish")]),t._v("\nbefore writing the sufficient number of elements will then result in an assertion failure.")]),t._v(" "),s("p",[t._v("As an alternative short-cut, you can also call "),s("code",[t._v("encode")]),t._v(" on an arbitrary value\n(including sequences and user-defined types) to execute all of the steps at\nonce and directly obtain the final RLP bytes. "),s("code",[t._v("encodeList(varargs)")]),t._v(" is another\nshort-cut for creating RLP lists.")]),t._v(" "),s("h3",{attrs:{id:"object-serialization"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#object-serialization"}},[t._v("#")]),t._v(" Object serialization")]),t._v(" "),s("p",[t._v("As previously explained, generic procs such as "),s("code",[t._v("read")]),t._v(", "),s("code",[t._v("append")]),t._v(", "),s("code",[t._v("encode")]),t._v(" and\n"),s("code",[t._v("decode")]),t._v(" can be used with arbitrary used-defined object types. By default, the\nlibrary will serialize all of the fields of the object using the "),s("code",[t._v("fields")]),t._v("\niterator, but you can also include only a subset of the fields or modify the\norder of serialization or by employing the "),s("code",[t._v("rlpIgnore")]),t._v(" pragma or by using the\n"),s("code",[t._v("rlpFields")]),t._v(" macro:")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("macro")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("rlpFields"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("T"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" typedesc"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fields"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" varargs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("untyped"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("## example usage:")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("type")]),t._v("\n Transaction "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("object")]),t._v("\n amount"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" int\n time"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" DateTime\n sender"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" string\n receiver"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" string\n\nrlpFields Transaction"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n sender"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" receiver"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" amount\n\n"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("...")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" t1 "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" rlp"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("read")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Transaction"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" bytes "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("encode")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("t1"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" t2 "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" bytes"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("decode")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Transaction"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br"),s("span",{staticClass:"line-number"},[t._v("9")]),s("br"),s("span",{staticClass:"line-number"},[t._v("10")]),s("br"),s("span",{staticClass:"line-number"},[t._v("11")]),s("br"),s("span",{staticClass:"line-number"},[t._v("12")]),s("br"),s("span",{staticClass:"line-number"},[t._v("13")]),s("br"),s("span",{staticClass:"line-number"},[t._v("14")]),s("br"),s("span",{staticClass:"line-number"},[t._v("15")]),s("br"),s("span",{staticClass:"line-number"},[t._v("16")]),s("br"),s("span",{staticClass:"line-number"},[t._v("17")]),s("br"),s("span",{staticClass:"line-number"},[t._v("18")]),s("br"),s("span",{staticClass:"line-number"},[t._v("19")]),s("br")])]),s("p",[t._v("By default, sub-fields within objects are wrapped in RLP lists. You can avoid this\nbehavior by adding the custom pragma "),s("code",[t._v("rlpInline")]),t._v(" on a particular field. In rare\ncircumstances, you may need to serialize the same field type differently depending\non the enclosing object type. You can use the "),s("code",[t._v("rlpCustomSerialization")]),t._v(" pragma to\nachieve this.")]),t._v(" "),s("h3",{attrs:{id:"contributing-testing"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#contributing-testing"}},[t._v("#")]),t._v(" Contributing / Testing")]),t._v(" "),s("p",[t._v("To test the correctness of any modifications to the library, please execute\n"),s("code",[t._v("nimble test_rlp")]),t._v(" at the root of the repo.")]),t._v(" "),s("h2",{attrs:{id:"p2p"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#p2p"}},[t._v("#")]),t._v(" p2p")]),t._v(" "),s("h3",{attrs:{id:"introduction-2"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#introduction-2"}},[t._v("#")]),t._v(" Introduction")]),t._v(" "),s("p",[t._v("This library implements the DevP2P family of networking protocols used\nin the Ethereum world.")]),t._v(" "),s("h3",{attrs:{id:"connecting-to-the-ethereum-network"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#connecting-to-the-ethereum-network"}},[t._v("#")]),t._v(" Connecting to the Ethereum network")]),t._v(" "),s("p",[t._v("A connection to the Ethereum network can be created by instantiating\nthe "),s("code",[t._v("EthereumNode")]),t._v(" type:")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("newEthereumNode"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("keys"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" KeyPair"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n listeningAddress"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Address"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n networkId"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" uint"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n chain"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" AbstractChainDB"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n clientId "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"nim-eth-p2p"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n addAllCapabilities "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" true"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" EthereumNode "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br")])]),s("h4",{attrs:{id:"parameters"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#parameters"}},[t._v("#")]),t._v(" Parameters:")]),t._v(" "),s("p",[s("code",[t._v("keys")]),t._v(":\nA pair of public and private keys used to authenticate the node\non the network and to determine its node ID.\nSee the "),s("RouterLink",{attrs:{to:"/lib/nim-eth/keys.html"}},[t._v("keys")]),t._v("\nlibrary for utilities that will help you generate and manage\nsuch keys.")],1),t._v(" "),s("p",[s("code",[t._v("listeningAddress")]),t._v(":\nThe network interface and port where your client will be\naccepting incoming connections.")]),t._v(" "),s("p",[s("code",[t._v("networkId")]),t._v(":\nThe Ethereum network ID. The client will disconnect immediately\nfrom any peers who don't use the same network.")]),t._v(" "),s("p",[s("code",[t._v("chain")]),t._v(":\nAn abstract instance of the Ethereum blockchain associated\nwith the node. This library allows you to plug any instance\nconforming to the abstract interface defined in the\n"),s("a",{attrs:{href:"https://github.com/status-im/nim-eth-common",target:"_blank",rel:"noopener noreferrer"}},[t._v("eth_common"),s("OutboundLink")],1),t._v("\npackage.")]),t._v(" "),s("p",[s("code",[t._v("clientId")]),t._v(":\nA name used to identify the software package connecting\nto the network (i.e. similar to the "),s("code",[t._v("User-Agent")]),t._v(" string\nin a browser).")]),t._v(" "),s("p",[s("code",[t._v("addAllCapabilities")]),t._v(":\nBy default, the node will support all RPLx protocols imported in\nyour project. You can specify "),s("code",[t._v("false")]),t._v(" if you prefer to create a\nnode with a more limited set of protocols. Use one or more calls\nto "),s("code",[t._v("node.addCapability")]),t._v(" to specify the desired set:")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[t._v("node"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("addCapability")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("eth"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nnode"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("addCapability")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("shh"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br")])]),s("p",[t._v("Each supplied protocol identifier is a name of a protocol introduced\nby the "),s("code",[t._v("p2pProtocol")]),t._v(" macro discussed later in this document.")]),t._v(" "),s("p",[t._v("Instantiating an "),s("code",[t._v("EthereumNode")]),t._v(" does not immediately connect you to\nthe network. To start the connection process, call "),s("code",[t._v("node.connectToNetwork")]),t._v(":")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("connectToNetwork"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("node"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" EthereumNode"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n bootstrapNodes"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" openarray"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("ENode"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n startListening "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" true"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n enableDiscovery "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" true"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br")])]),s("p",[t._v("The "),s("code",[t._v("EthereumNode")]),t._v(" will automatically find and maintain a pool of peers\nusing the Ethereum node discovery protocol. You can access the pool as\n"),s("code",[t._v("node.peers")]),t._v(".")]),t._v(" "),s("h3",{attrs:{id:"communicating-with-peers-using-rlpx"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#communicating-with-peers-using-rlpx"}},[t._v("#")]),t._v(" Communicating with Peers using RLPx")]),t._v(" "),s("p",[s("a",{attrs:{href:"https://github.com/ethereum/devp2p/blob/master/rlpx.md",target:"_blank",rel:"noopener noreferrer"}},[t._v("RLPx"),s("OutboundLink")],1),t._v(" is the\nhigh-level protocol for exchanging messages between peers in the Ethereum\nnetwork. Most of the client code of this library should not be concerned\nwith the implementation details of the underlying protocols and should use\nthe high-level APIs described in this section.")]),t._v(" "),s("p",[t._v("The RLPx protocols are defined as a collection of strongly-typed messages,\nwhich are grouped into sub-protocols multiplexed over the same TCP connection.")]),t._v(" "),s("p",[t._v("This library represents each such message as a regular Nim function call\nover the "),s("code",[t._v("Peer")]),t._v(" object. Certain messages act only as notifications, while\nothers fit the request/response pattern.")]),t._v(" "),s("p",[t._v("To understand more about how messages are defined and used, let's look at\nthe definition of a RLPx protocol:")]),t._v(" "),s("h4",{attrs:{id:"rlpx-sub-protocols"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#rlpx-sub-protocols"}},[t._v("#")]),t._v(" RLPx sub-protocols")]),t._v(" "),s("p",[t._v("The sub-protocols are defined with the "),s("code",[t._v("p2pProtocol")]),t._v(" macro. It will accept\na short identifier for the protocol and the current protocol version:")]),t._v(" "),s("p",[t._v("Here is how the "),s("a",{attrs:{href:"https://github.com/ethereum/devp2p/blob/master/rlpx.md#p2p-capability",target:"_blank",rel:"noopener noreferrer"}},[t._v("DevP2P wire protocol"),s("OutboundLink")],1),t._v(" might look like:")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[t._v("p2pProtocol "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("DevP2P")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("version "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" rlpxName "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"p2p"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("hello")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("peer"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Peer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n version"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" uint"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n clientId"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" string"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n capabilities"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" openarray"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("Capability"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n listenPort"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" uint"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n nodeId"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" P2PNodeId"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n peer"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("id "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" nodeId\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("disconnect")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("peer"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Peer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" reason"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" DisconnectionReason"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ping")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("peer"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Peer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n await peer"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("pong")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("pong")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("peer"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Peer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n echo "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"received pong from "')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" peer"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("id\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br"),s("span",{staticClass:"line-number"},[t._v("9")]),s("br"),s("span",{staticClass:"line-number"},[t._v("10")]),s("br"),s("span",{staticClass:"line-number"},[t._v("11")]),s("br"),s("span",{staticClass:"line-number"},[t._v("12")]),s("br"),s("span",{staticClass:"line-number"},[t._v("13")]),s("br"),s("span",{staticClass:"line-number"},[t._v("14")]),s("br"),s("span",{staticClass:"line-number"},[t._v("15")]),s("br"),s("span",{staticClass:"line-number"},[t._v("16")]),s("br")])]),s("p",[t._v("As seen in the example above, a protocol definition determines both the\navailable messages that can be sent to another peer (e.g. as in "),s("code",[t._v("peer.pong()")]),t._v(")\nand the asynchronous code responsible for handling the incoming messages.")]),t._v(" "),s("h4",{attrs:{id:"protocol-state"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#protocol-state"}},[t._v("#")]),t._v(" Protocol state")]),t._v(" "),s("p",[t._v("The protocol implementations are expected to maintain a state and to act\nlike a state machine handling the incoming messages. You are allowed to\ndefine an arbitrary state type that can be specified in the "),s("code",[t._v("peerState")]),t._v("\nprotocol option. Later, instances of the state object can be obtained\nthough the "),s("code",[t._v("state")]),t._v(" pseudo-field of the "),s("code",[t._v("Peer")]),t._v(" object:")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("type")]),t._v(" AbcPeerState "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("object")]),t._v("\n receivedMsgsCount"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" int\n\np2pProtocol "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("abc")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("version "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n peerState "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" AbcPeerState"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("incomingMessage")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("p"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Peer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n p"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("state"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("receivedMsgsCount "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),t._v("\n\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br"),s("span",{staticClass:"line-number"},[t._v("9")]),s("br")])]),s("p",[t._v("Besides the per-peer state demonstrated above, there is also support\nfor maintaining a network-wide state. It's enabled by specifying the\n"),s("code",[t._v("networkState")]),t._v(" option of the protocol and the state object can be obtained\nthrough accessor of the same name.")]),t._v(" "),s("p",[t._v("The state objects are initialized to zero by default, but you can modify\nthis behaviour by overriding the following procs for your state types:")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("initProtocolState"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("state"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" MyPeerState"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" p"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Peer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("initProtocolState"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("state"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" MyNetworkState"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" n"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" EthereumNode"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br")])]),s("p",[t._v("Sometimes, you'll need to access the state of another protocol.\nTo do this, specify the protocol identifier to the "),s("code",[t._v("state")]),t._v(" accessors:")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[t._v(" echo "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"ABC protocol messages: "')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" peer"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("state")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("abc"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("receivedMsgCount\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("p",[t._v("While the state machine approach may be a particularly robust way of\nimplementing sub-protocols (it is more amenable to proving the correctness\nof the implementation through formal verification methods), sometimes it may\nbe more convenient to use more imperative style of communication where the\ncode is able to wait for a particular response after sending a particular\nrequest. The library provides two mechanisms for achieving this:")]),t._v(" "),s("h4",{attrs:{id:"waiting-particular-messages-with-nextmsg"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#waiting-particular-messages-with-nextmsg"}},[t._v("#")]),t._v(" Waiting particular messages with "),s("code",[t._v("nextMsg")])]),t._v(" "),s("p",[t._v("The "),s("code",[t._v("nextMsg")]),t._v(" helper proc can be used to pause the execution of an async\nproc until a particular incoming message from a peer arrives:")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("helloExample")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("peer"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Peer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("...")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# send a hello message")]),t._v("\n await peer"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("hello")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("..")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".)")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# wait for a matching hello response, might want to add a timeout here")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" response "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" await peer"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("nextMsg")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("p2p"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("hello"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n echo response"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("clientId "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# print the name of the Ethereum client")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# used by the other peer (Geth, Parity, Nimbus, etc)")]),t._v("\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br"),s("span",{staticClass:"line-number"},[t._v("9")]),s("br")])]),s("p",[t._v("There are few things to note in the above example:")]),t._v(" "),s("ol",[s("li",[s("p",[t._v("The "),s("code",[t._v("p2pProtocol")]),t._v(" definition created a pseudo-variable named after the\nprotocol holding various properties of the protocol.")])]),t._v(" "),s("li",[s("p",[t._v("Each message defined in the protocol received a corresponding type name,\nmatching the message name (e.g. "),s("code",[t._v("p2p.hello")]),t._v("). This type will have fields\nmatching the parameter names of the message. If the messages has "),s("code",[t._v("openarray")]),t._v("\nparams, these will be remapped to "),s("code",[t._v("seq")]),t._v(" types.")])])]),t._v(" "),s("p",[t._v("If the designated messages also has an attached handler, the future returned\nby "),s("code",[t._v("nextMsg")]),t._v(" will be resolved only after the handler has been fully executed\n(so you can count on any side effects produced by the handler to have taken\nplace). If there are multiple outstanding calls to "),s("code",[t._v("nextMsg")]),t._v(", they will\ncomplete together. Any other messages received in the meantime will still\nbe dispatched to their respective handlers.")]),t._v(" "),s("p",[t._v("Please also note that the "),s("code",[t._v("p2pProtocol")]),t._v(" macro will make this "),s("code",[t._v("helloExample")]),t._v(" proc\n"),s("code",[t._v("async")]),t._v(". Practically see it as "),s("code",[t._v("proc helloExample(peer: Peer) {.async.}")]),t._v(", and\nthus never use "),s("code",[t._v("waitFor")]),t._v(", but rather "),s("code",[t._v("await")]),t._v(" inside this proc.")]),t._v(" "),s("p",[t._v("For implementing protocol handshakes with "),s("code",[t._v("nextMsg")]),t._v(" there are specific helpers\nwhich are explained "),s("a",{attrs:{href:"https://github.com/status-im/nim-eth/blob/master/doc/p2p.md#implementing-handshakes-and-reacting-to-other-events",target:"_blank",rel:"noopener noreferrer"}},[t._v("below"),s("OutboundLink")],1),t._v(".")]),t._v(" "),s("h4",{attrs:{id:"requestresponse-pairs"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#requestresponse-pairs"}},[t._v("#")]),t._v(" "),s("code",[t._v("requestResponse")]),t._v(" pairs")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[t._v("p2pProtocol "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("les")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("version "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("...")]),t._v("\n\n requestResponse"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getProofs")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("p"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Peer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" proofs"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" openarray"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("ProofRequest"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("proofs")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("p"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Peer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" BV"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" uint"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" proofs"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" openarray"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("Blob"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("...")]),t._v("\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br")])]),s("p",[t._v("Two or more messages within the protocol may be grouped into a\n"),s("code",[t._v("requestResponse")]),t._v(" block. The last message in the group is assumed\nto be the response while all other messages are considered requests.")]),t._v(" "),s("p",[t._v("When a request message is sent, the return type will be a "),s("code",[t._v("Future")]),t._v("\nthat will be completed once the response is received. Please note\nthat there is a mandatory timeout parameter, so the actual return\ntype is "),s("code",[t._v("Future[Option[MessageType]]")]),t._v(". The "),s("code",[t._v("timeout")]),t._v(" parameter can\nbe specified for each individual call and the default value can be\noverridden on the level of individual message, or the entire protocol:")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[t._v("p2pProtocol "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("abc")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("version "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n useRequestIds "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" false"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n timeout "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("5000")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# value in milliseconds")]),t._v("\n requestResponse"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("myReq")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("dataId"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" int"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" timeout "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("3000")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("myRes")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("data"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" string"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br")])]),s("p",[t._v("By default, the library will take care of inserting a hidden "),s("code",[t._v("reqId")]),t._v("\nparameter as used in the "),s("a",{attrs:{href:"https://github.com/zsfelfoldi/go-ethereum/wiki/Light-Ethereum-Subprotocol-%28LES%29",target:"_blank",rel:"noopener noreferrer"}},[t._v("LES protocol"),s("OutboundLink")],1),t._v(",\nbut you can disable this behavior by overriding the protocol setting\n"),s("code",[t._v("useRequestIds")]),t._v(".")]),t._v(" "),s("h4",{attrs:{id:"implementing-handshakes-and-reacting-to-other-events"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#implementing-handshakes-and-reacting-to-other-events"}},[t._v("#")]),t._v(" Implementing handshakes and reacting to other events")]),t._v(" "),s("p",[t._v("Besides message definitions and implementations, a protocol specification may\nalso include handlers for certain important events such as newly connected\npeers or misbehaving or disconnecting peers:")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[t._v("p2pProtocol "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("foo")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("version "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" fooVersion"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("\n onPeerConnected "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("do")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("peer"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Peer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" m "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" await peer"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("status")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("fooVersion"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n timeout "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" chronos"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("milliseconds")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("5000")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" m"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("protocolVersion "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" fooVersion"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("\n debug "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Foo peer"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" peer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fooVersion\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("else")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("raise")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("newException")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("UselessPeerError"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Incompatible Foo version"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n onPeerDisconnected "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("do")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("peer"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Peer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" reason"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" DisconnectionReason"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("\n debug "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"peer disconnected"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" peer\n\n handshake"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("status")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("peer"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Peer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n protocolVersion"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" uint"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br"),s("span",{staticClass:"line-number"},[t._v("9")]),s("br"),s("span",{staticClass:"line-number"},[t._v("10")]),s("br"),s("span",{staticClass:"line-number"},[t._v("11")]),s("br"),s("span",{staticClass:"line-number"},[t._v("12")]),s("br"),s("span",{staticClass:"line-number"},[t._v("13")]),s("br"),s("span",{staticClass:"line-number"},[t._v("14")]),s("br"),s("span",{staticClass:"line-number"},[t._v("15")]),s("br"),s("span",{staticClass:"line-number"},[t._v("16")]),s("br")])]),s("p",[t._v("For handshake messages, where the same type of message needs to be send to and\nreceived from the peer, a "),s("code",[t._v("handshake")]),t._v(" helper is introduced, as you can see in\nthe code example above.")]),t._v(" "),s("p",[t._v("Thanks to the "),s("code",[t._v("handshake")]),t._v(" helper the "),s("code",[t._v("status")]),t._v(" message will both be send, and be\nawaited for receival from the peer, with the defined timeout. In case no "),s("code",[t._v("status")]),t._v("\nmessage is received within the defined timeout, an error will be raised which\nwill result in a disconnect from the peer.")]),t._v(" "),s("p",[s("strong",[t._v("Note:")]),t._v(" Be aware that if currently one of the subprotocol "),s("code",[t._v("onPeerConnected")]),t._v("\ncalls fails, the client will be disconnected as "),s("code",[t._v("UselessPeer")]),t._v(" but no\n"),s("code",[t._v("onPeerDisconnect")]),t._v(" calls are run.")]),t._v(" "),s("h4",{attrs:{id:"checking-the-other-peer-s-supported-sub-protocols"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#checking-the-other-peer-s-supported-sub-protocols"}},[t._v("#")]),t._v(" Checking the other peer's supported sub-protocols")]),t._v(" "),s("p",[t._v("Upon establishing a connection, RLPx will automatically negotiate the list of\nmutually supported protocols by the peers. To check whether a particular peer\nsupports a particular sub-protocol, use the following code:")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" peer"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("supports")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("les"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# `les` is the identifier of the light clients sub-protocol")]),t._v("\n peer"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getReceipts")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("nextReqId")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("neededReceipts")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br")])]),s("h2",{attrs:{id:"keys"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#keys"}},[t._v("#")]),t._v(" keys")]),t._v(" "),s("p",[t._v("This library is a Nim re-implementation of "),s("a",{attrs:{href:"https://github.com/ethereum/eth-keys",target:"_blank",rel:"noopener noreferrer"}},[t._v("eth-keys"),s("OutboundLink")],1),t._v(": the common API for working with Ethereum's public and private keys, signatures, and addresses.")]),t._v(" "),s("p",[t._v("By default, Nim eth-keys uses Bitcoin's "),s("a",{attrs:{href:"https://github.com/bitcoin-core/secp256k1",target:"_blank",rel:"noopener noreferrer"}},[t._v("libsecp256k1"),s("OutboundLink")],1),t._v(" as a backend. Make sure libsecp256k1 is available on your system.")]),t._v(" "),s("p",[t._v("An experimental pure Nim backend (Warning ⚠: do not use in production) is available with the compilation switch "),s("code",[t._v("-d:backend_native")])]),t._v(" "),s("h2",{attrs:{id:"keyfile"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#keyfile"}},[t._v("#")]),t._v(" keyfile")]),t._v(" "),s("h3",{attrs:{id:"introduction-3"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#introduction-3"}},[t._v("#")]),t._v(" Introduction")]),t._v(" "),s("p",[t._v("This library is a Nim reimplementation of "),s("a",{attrs:{href:"https://github.com/ethereum/eth-keyfile",target:"_blank",rel:"noopener noreferrer"}},[t._v("ethereum/eth-keyfile"),s("OutboundLink")],1),t._v(", which is used to create and load Ethereum "),s("code",[t._v("keyfile")]),t._v(" format and the tools for handling the format and for storing private keys. Currently, the library supports only the PBKDF2 method and does not support the Scrypt method.")]),t._v(" "),s("h2",{attrs:{id:"trie"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#trie"}},[t._v("#")]),t._v(" trie")]),t._v(" "),s("h2",{attrs:{id:"nim-implementation-of-the-ethereum-trie-structure"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#nim-implementation-of-the-ethereum-trie-structure"}},[t._v("#")]),t._v(" Nim Implementation of the Ethereum Trie structure")]),t._v(" "),s("h3",{attrs:{id:"hexary-trie"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#hexary-trie"}},[t._v("#")]),t._v(" Hexary Trie")]),t._v(" "),s("h3",{attrs:{id:"binary-trie"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#binary-trie"}},[t._v("#")]),t._v(" Binary Trie")]),t._v(" "),s("p",[t._v("Binary-trie is a dictionary-like data structure to store key-value pair.\nMuch like it's sibling Hexary-trie, the key-value pair will be stored into key-value flat-db.\nThe primary difference with Hexary-trie is, each node of Binary-trie only consist of one or two child,\nwhile Hexary-trie node can contains up to 16 or 17 child-nodes.")]),t._v(" "),s("p",[t._v("Unlike Hexary-trie, Binary-trie store it's data into flat-db without using rlp encoding.\nBinary-trie store its value using simple "),s("strong",[t._v("Node-Types")]),t._v(" encoding.\nThe encoded-node will be hashed by keccak_256 and the hash value will be the key to flat-db.\nEach entry in the flat-db will looks like:")]),t._v(" "),s("table",[s("thead",[s("tr",[s("th",[t._v("key")]),t._v(" "),s("th",[t._v("value")])])]),t._v(" "),s("tbody",[s("tr",[s("td",[t._v("32-bytes-keccak-hash")]),t._v(" "),s("td",[t._v("encoded-node(KV or BRANCH or LEAF encoded)")])])])]),t._v(" "),s("h4",{attrs:{id:"node-types"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#node-types"}},[t._v("#")]),t._v(" Node-Types")]),t._v(" "),s("ul",[s("li",[t._v("KV = [0, encoded-key-path, 32 bytes hash of child]")]),t._v(" "),s("li",[t._v("BRANCH = [1, 32 bytes hash of left child, 32 bytes hash of right child]")]),t._v(" "),s("li",[t._v("LEAF = [2, value]")])]),t._v(" "),s("p",[t._v("The KV node can have BRANCH node or LEAF node as it's child, but cannot a KV node.\nThe internal algorithm will merge a KV(parent)->KV(child) into one KV node.\nEvery KV node contains encoded keypath to reduce the number of blank nodes.")]),t._v(" "),s("p",[t._v("The BRANCH node can have KV, BRANCH, or LEAF node as it's children.")]),t._v(" "),s("p",[t._v("The LEAF node is the terminal node, it contains the value of a key.")]),t._v(" "),s("h4",{attrs:{id:"encoded-key-path"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#encoded-key-path"}},[t._v("#")]),t._v(" encoded-key-path")]),t._v(" "),s("p",[t._v("While Hexary-trie encode the path using Hex-Prefix encoding, Binary-trie\nencode the path using binary encoding, the scheme looks like this table below.")]),t._v(" "),s("div",{staticClass:"language-text line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v(" |--------- odd --------|\n 00mm yyyy xxxx xxxx xxxx xxxx\n |------ even -----|\n 1000 00mm yyyy xxxx xxxx xxxx\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br")])]),s("table",[s("thead",[s("tr",[s("th",[t._v("symbol")]),t._v(" "),s("th",[t._v("explanation")])])]),t._v(" "),s("tbody",[s("tr",[s("td",[t._v("xxxx")]),t._v(" "),s("td",[t._v("nibble of binary keypath in bits, 0 = left, 1 = right")])]),t._v(" "),s("tr",[s("td",[t._v("yyyy")]),t._v(" "),s("td",[t._v("nibble contains 0-3 bits padding + binary keypath")])]),t._v(" "),s("tr",[s("td",[t._v("mm")]),t._v(" "),s("td",[t._v("number of binary keypath bits modulo 4 (0-3)")])]),t._v(" "),s("tr",[s("td",[t._v("00")]),t._v(" "),s("td",[t._v("zero zero prefix")])]),t._v(" "),s("tr",[s("td",[t._v("1000")]),t._v(" "),s("td",[t._v("even numbered nibbles prefix")])])])]),t._v(" "),s("p",[t._v("if there is no padding, then yyyy bit sequence is absent, mm also zero.\nyyyy = mm bits + padding bits must be 4 bits length.")]),t._v(" "),s("h4",{attrs:{id:"the-api"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#the-api"}},[t._v("#")]),t._v(" The API")]),t._v(" "),s("p",[t._v("The primary API for Binary-trie is "),s("code",[t._v("set")]),t._v(" and "),s("code",[t._v("get")]),t._v(".")]),t._v(" "),s("ul",[s("li",[t._v("set(key, value) --- "),s("em",[t._v("store a value associated with a key")])]),t._v(" "),s("li",[t._v("get(key): value --- "),s("em",[t._v("get a value using a key")])])]),t._v(" "),s("p",[t._v("Both "),s("code",[t._v("key")]),t._v(" and "),s("code",[t._v("value")]),t._v(" are of "),s("code",[t._v("seq[byte]")]),t._v(" type. And they cannot have zero length.")]),t._v(" "),s("p",[t._v("Getting a non-existent key will return zero length seq[byte].")]),t._v(" "),s("p",[t._v("Binary-trie also provide dictionary syntax API for "),s("code",[t._v("set")]),t._v(" and "),s("code",[t._v("get")]),t._v(".")]),t._v(" "),s("ul",[s("li",[t._v("trie[key] = value -- same as "),s("code",[t._v("set")])]),t._v(" "),s("li",[t._v("value = trie[key] -- same as "),s("code",[t._v("get")])]),t._v(" "),s("li",[t._v("contains(key) a.k.a. "),s("code",[t._v("in")]),t._v(" operator")])]),t._v(" "),s("p",[t._v("Additional APIs are:")]),t._v(" "),s("ul",[s("li",[t._v("exists(key) -- returns "),s("code",[t._v("bool")]),t._v(", to check key-value existence -- same as contains")]),t._v(" "),s("li",[t._v("delete(key) -- remove a key-value from the trie")]),t._v(" "),s("li",[t._v("deleteSubtrie(key) -- remove a key-value from the trie plus all of it's subtrie\nthat starts with the same key prefix")]),t._v(" "),s("li",[t._v("rootNode() -- get root node")]),t._v(" "),s("li",[t._v("rootNode(node) -- replace the root node")]),t._v(" "),s("li",[t._v("getRootHash(): "),s("code",[t._v("KeccakHash")]),t._v(" with "),s("code",[t._v("seq[byte]")]),t._v(" type")]),t._v(" "),s("li",[t._v("getDB(): "),s("code",[t._v("DB")]),t._v(" -- get flat-db pointer")])]),t._v(" "),s("p",[t._v("Constructor API:")]),t._v(" "),s("ul",[s("li",[t._v("initBinaryTrie(DB, rootHash[optional]) -- rootHash has "),s("code",[t._v("seq[byte]")]),t._v(" or KeccakHash type")]),t._v(" "),s("li",[t._v("init(BinaryTrie, DB, rootHash[optional])")])]),t._v(" "),s("p",[t._v("Normally you would not set the rootHash when constructing an empty Binary-trie.\nSetting the rootHash occured in a scenario where you have a populated DB\nwith existing trie structure and you know the rootHash,\nand then you want to continue/resume the trie operations.")]),t._v(" "),s("h3",{attrs:{id:"examples"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#examples"}},[t._v("#")]),t._v(" Examples")]),t._v(" "),s("div",{staticClass:"language-Nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v("\n eth"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),t._v("trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("db"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" binary"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" utils"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" db "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("newMemoryDB")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" trie "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("initBinaryTrie")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("db"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\ntrie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("set")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"key1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\ntrie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("set")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"key2"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value2"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\ndoAssert trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("get")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"key1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value1"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("toBytes\ndoAssert trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("get")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"key2"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value2"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("toBytes\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v('## delete all subtrie with key prefixes "key"')]),t._v("\ntrie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("deleteSubtrie")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"key"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\ndoAssert trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("get")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"key1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\ndoAssert trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("get")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"key2"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n\ntrie"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"moon"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"sun"')]),t._v("\ndoAssert "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"moon"')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("in")]),t._v(" trie\ndoAssert trie"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"moon"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"sun"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("toBytes\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br"),s("span",{staticClass:"line-number"},[t._v("9")]),s("br"),s("span",{staticClass:"line-number"},[t._v("10")]),s("br"),s("span",{staticClass:"line-number"},[t._v("11")]),s("br"),s("span",{staticClass:"line-number"},[t._v("12")]),s("br"),s("span",{staticClass:"line-number"},[t._v("13")]),s("br"),s("span",{staticClass:"line-number"},[t._v("14")]),s("br"),s("span",{staticClass:"line-number"},[t._v("15")]),s("br"),s("span",{staticClass:"line-number"},[t._v("16")]),s("br"),s("span",{staticClass:"line-number"},[t._v("17")]),s("br"),s("span",{staticClass:"line-number"},[t._v("18")]),s("br")])]),s("p",[t._v("Remember, "),s("code",[t._v("set")]),t._v(" and "),s("code",[t._v("get")]),t._v(" are trie operations. A single "),s("code",[t._v("set")]),t._v(" operation may invoke\nmore than one store/lookup operation into the underlying DB. The same is also happened to "),s("code",[t._v("get")]),t._v(" operation,\nit could do more than one flat-db lookup before it return the requested value.")]),t._v(" "),s("h3",{attrs:{id:"the-truth-behind-a-lie"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#the-truth-behind-a-lie"}},[t._v("#")]),t._v(" The truth behind a lie")]),t._v(" "),s("p",[t._v("What kind of lie? actually, "),s("code",[t._v("delete")]),t._v(" and "),s("code",[t._v("deleteSubtrie")]),t._v(" doesn't remove the\n'deleted' node from the underlying DB. It only make the node inaccessible\nfrom the user of the trie. The same also happened if you update the value of a key,\nthe old value node is not removed from the underlying DB.\nA more subtle lie also happened when you add new entrie into the trie using "),s("code",[t._v("set")]),t._v(" operation.\nThe previous hash of affected branch become obsolete and replaced by new hash,\nthe old hash become inaccessible to the user.\nYou may think that is a waste of storage space.\nLuckily, we also provide some utilities to deal with this situation, the branch utils.")]),t._v(" "),s("h3",{attrs:{id:"the-branch-utils"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#the-branch-utils"}},[t._v("#")]),t._v(" The branch utils")]),t._v(" "),s("p",[t._v("The branch utils consist of these API:")]),t._v(" "),s("ul",[s("li",[t._v("checkIfBranchExist(DB; rootHash; keyPrefix): bool")]),t._v(" "),s("li",[t._v("getBranch(DB; rootHash; key): branch")]),t._v(" "),s("li",[t._v("isValidBranch(branch, rootHash, key, value): bool")]),t._v(" "),s("li",[t._v("getWitness(DB; nodeHash; key): branch")]),t._v(" "),s("li",[t._v("getTrieNodes(DB; nodeHash): branch")])]),t._v(" "),s("p",[s("code",[t._v("keyPrefix")]),t._v(", "),s("code",[t._v("key")]),t._v(", and "),s("code",[t._v("value")]),t._v(" are bytes container with length greater than zero.\nThey can be openArray[byte].")]),t._v(" "),s("p",[s("code",[t._v("rootHash")]),t._v(" and "),s("code",[t._v("nodeHash")]),t._v(" also bytes container,\nbut they have constraint: must be 32 bytes in length, and it must be a keccak_256 hash value.")]),t._v(" "),s("p",[s("code",[t._v("branch")]),t._v(" is a list of nodes, or in this case a "),s("code",[t._v("seq[seq[byte]]")]),t._v(".\nA list? yes, the structure is stored along with the encoded node.\nTherefore a list is enough to reconstruct the entire trie/branch.")]),t._v(" "),s("div",{staticClass:"language-Nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v("\n eth"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),t._v("trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("db"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" binary"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" utils"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" db "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("newMemoryDB")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" trie "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("initBinaryTrie")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("db"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\ntrie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("set")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"key1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\ntrie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("set")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"key2"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value2"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\ndoAssert "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("checkIfBranchExist")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("db"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getRootHash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"key"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" true\ndoAssert "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("checkIfBranchExist")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("db"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getRootHash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"key1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" true\ndoAssert "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("checkIfBranchExist")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("db"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getRootHash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"ken"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" false\ndoAssert "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("checkIfBranchExist")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("db"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getRootHash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"key123"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" false\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br"),s("span",{staticClass:"line-number"},[t._v("9")]),s("br"),s("span",{staticClass:"line-number"},[t._v("10")]),s("br"),s("span",{staticClass:"line-number"},[t._v("11")]),s("br"),s("span",{staticClass:"line-number"},[t._v("12")]),s("br")])]),s("p",[t._v("The tree will looks like:")]),t._v(" "),s("div",{staticClass:"language-text line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v(" root ---\x3e A(kvnode, *common key prefix*)\n |\n |\n |\n B(branchnode)\n / \\\n / \\\n / \\\nC1(kvnode, *remain kepath*) C2(kvnode, *remain kepath*)\n | |\n | |\n | |\n D1(leafnode, b'value1') D2(leafnode, b'value2')\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br"),s("span",{staticClass:"line-number"},[t._v("9")]),s("br"),s("span",{staticClass:"line-number"},[t._v("10")]),s("br"),s("span",{staticClass:"line-number"},[t._v("11")]),s("br"),s("span",{staticClass:"line-number"},[t._v("12")]),s("br"),s("span",{staticClass:"line-number"},[t._v("13")]),s("br")])]),s("div",{staticClass:"language-Nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" branchA "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getBranch")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("db"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getRootHash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"key1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("## ==> [A, B, C1, D1]")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" branchB "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getBranch")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("db"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getRootHash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"key2"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("## ==> [A, B, C2, D2]")]),t._v("\n\ndoAssert "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("isValidBranch")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("branchA"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getRootHash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"key1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" true\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("## wrong key, return zero bytes")]),t._v("\ndoAssert "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("isValidBranch")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("branchA"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getRootHash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"key5"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('""')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" true\n\ndoAssert "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("isValidBranch")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("branchB"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getRootHash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"key1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# InvalidNode")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" x "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getBranch")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("db"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getRootHash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"key"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("## ==> [A]")]),t._v("\n\nx "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getBranch")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("db"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getRootHash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"key123"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# InvalidKeyError")]),t._v("\nx "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getBranch")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("db"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getRootHash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"key5"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# there is still branch for non-exist key")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("## ==> [A]")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" branch "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getWitness")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("db"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getRootHash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"key1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v('## equivalent to `getBranch(db, trie.getRootHash(), "key1")`')]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("## ==> [A, B, C1, D1]")]),t._v("\n\nbranch "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getWitness")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("db"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getRootHash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"key"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v('## this will include additional nodes of "key2"')]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("## ==> [A, B, C1, D1, C2, D2]")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" wholeTrie "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getWitness")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("db"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getRootHash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('""')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("## this will return the whole trie")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("## ==> [A, B, C1, D1, C2, D2]")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" node "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" branch"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# B")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" nodeHash "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" keccak256"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("digest")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("node"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("baseAddr"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("uint")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("node"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("len"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" nodes "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getTrieNodes")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("db"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" nodeHash"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\ndoAssert nodes"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("len "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" wholeTrie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("len "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("## ==> [B, C1, D1, C2, D2]")]),t._v("\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br"),s("span",{staticClass:"line-number"},[t._v("9")]),s("br"),s("span",{staticClass:"line-number"},[t._v("10")]),s("br"),s("span",{staticClass:"line-number"},[t._v("11")]),s("br"),s("span",{staticClass:"line-number"},[t._v("12")]),s("br"),s("span",{staticClass:"line-number"},[t._v("13")]),s("br"),s("span",{staticClass:"line-number"},[t._v("14")]),s("br"),s("span",{staticClass:"line-number"},[t._v("15")]),s("br"),s("span",{staticClass:"line-number"},[t._v("16")]),s("br"),s("span",{staticClass:"line-number"},[t._v("17")]),s("br"),s("span",{staticClass:"line-number"},[t._v("18")]),s("br"),s("span",{staticClass:"line-number"},[t._v("19")]),s("br"),s("span",{staticClass:"line-number"},[t._v("20")]),s("br"),s("span",{staticClass:"line-number"},[t._v("21")]),s("br"),s("span",{staticClass:"line-number"},[t._v("22")]),s("br"),s("span",{staticClass:"line-number"},[t._v("23")]),s("br"),s("span",{staticClass:"line-number"},[t._v("24")]),s("br"),s("span",{staticClass:"line-number"},[t._v("25")]),s("br"),s("span",{staticClass:"line-number"},[t._v("26")]),s("br"),s("span",{staticClass:"line-number"},[t._v("27")]),s("br"),s("span",{staticClass:"line-number"},[t._v("28")]),s("br"),s("span",{staticClass:"line-number"},[t._v("29")]),s("br"),s("span",{staticClass:"line-number"},[t._v("30")]),s("br"),s("span",{staticClass:"line-number"},[t._v("31")]),s("br"),s("span",{staticClass:"line-number"},[t._v("32")]),s("br"),s("span",{staticClass:"line-number"},[t._v("33")]),s("br"),s("span",{staticClass:"line-number"},[t._v("34")]),s("br"),s("span",{staticClass:"line-number"},[t._v("35")]),s("br"),s("span",{staticClass:"line-number"},[t._v("36")]),s("br")])]),s("h3",{attrs:{id:"remember-the-lie"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#remember-the-lie"}},[t._v("#")]),t._v(" Remember the lie?")]),t._v(" "),s("p",[t._v("Because trie "),s("code",[t._v("delete")]),t._v(", "),s("code",[t._v("deleteSubtrie")]),t._v(" and "),s("code",[t._v("set")]),t._v(" operation create inaccessible nodes in the underlying DB,\nwe need to remove them if necessary. We already see that "),s("code",[t._v('wholeTrie = getWitness(db, trie.getRootHash(), "")')]),t._v("\nwill return the whole trie, a list of accessible nodes.\nThen we can write the clean tree into a new DB instance to replace the old one.")]),t._v(" "),s("h3",{attrs:{id:"sparse-merkle-trie"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#sparse-merkle-trie"}},[t._v("#")]),t._v(" Sparse Merkle Trie")]),t._v(" "),s("p",[t._v("Sparse Merkle Trie(SMT) is a variant of Binary Trie which uses binary encoding to\nrepresent path during trie travelsal. When Binary Trie uses three types of node,\nSMT only use one type of node without any additional special encoding to store it's key-path.")]),t._v(" "),s("p",[t._v("Actually, it doesn't even store it's key-path anywhere like Binary Trie,\nthe key-path is stored implicitly in the trie structure during key-value insertion.")]),t._v(" "),s("p",[t._v("Because the key-path is not encoded in any special ways, the bits can be extracted directly from\nthe key without any conversion.")]),t._v(" "),s("p",[t._v("However, the key restricted to a fixed length because the algorithm demand a fixed height trie\nto works properly. In this case, the trie height is limited to 160 level,\nor the key is of fixed length 20 bytes (8 bits x 20 = 160).")]),t._v(" "),s("p",[t._v("To be able to use variable length key, the algorithm can be adapted slightly using hashed key before\nconstructing the binary key-path. For example, if using keccak256 as the hashing function,\nthen the height of the tree will be 256, but the key itself can be any length.")]),t._v(" "),s("h4",{attrs:{id:"the-api-2"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#the-api-2"}},[t._v("#")]),t._v(" The API")]),t._v(" "),s("p",[t._v("The primary API for Binary-trie is "),s("code",[t._v("set")]),t._v(" and "),s("code",[t._v("get")]),t._v(".")]),t._v(" "),s("ul",[s("li",[t._v("set(key, value, rootHash[optional]) --- "),s("em",[t._v("store a value associated with a key")])]),t._v(" "),s("li",[t._v("get(key, rootHash[optional]): value --- "),s("em",[t._v("get a value using a key")])])]),t._v(" "),s("p",[t._v("Both "),s("code",[t._v("key")]),t._v(" and "),s("code",[t._v("value")]),t._v(" are of "),s("code",[t._v("BytesRange")]),t._v(" type. And they cannot have zero length.\nYou can also use convenience API "),s("code",[t._v("get")]),t._v(" and "),s("code",[t._v("set")]),t._v(" which accepts\n"),s("code",[t._v("Bytes")]),t._v(" or "),s("code",[t._v("string")]),t._v(" (a "),s("code",[t._v("string")]),t._v(" is conceptually wrong in this context\nand may costlier than a "),s("code",[t._v("BytesRange")]),t._v(", but it is good for testing purpose).")]),t._v(" "),s("p",[t._v("rootHash is an optional parameter. When used, "),s("code",[t._v("get")]),t._v(" will get a key from specific root,\nand "),s("code",[t._v("set")]),t._v(" will also set a key at specific root.")]),t._v(" "),s("p",[t._v("Getting a non-existent key will return zero length BytesRange or a zeroBytesRange.")]),t._v(" "),s("p",[t._v("Sparse Merkle Trie also provide dictionary syntax API for "),s("code",[t._v("set")]),t._v(" and "),s("code",[t._v("get")]),t._v(".")]),t._v(" "),s("ul",[s("li",[t._v("trie[key] = value -- same as "),s("code",[t._v("set")])]),t._v(" "),s("li",[t._v("value = trie[key] -- same as "),s("code",[t._v("get")])]),t._v(" "),s("li",[t._v("contains(key) a.k.a. "),s("code",[t._v("in")]),t._v(" operator")])]),t._v(" "),s("p",[t._v("Additional APIs are:")]),t._v(" "),s("ul",[s("li",[t._v("exists(key) -- returns "),s("code",[t._v("bool")]),t._v(", to check key-value existence -- same as contains")]),t._v(" "),s("li",[t._v("delete(key) -- remove a key-value from the trie")]),t._v(" "),s("li",[t._v("getRootHash(): "),s("code",[t._v("KeccakHash")]),t._v(" with "),s("code",[t._v("BytesRange")]),t._v(" type")]),t._v(" "),s("li",[t._v("getDB(): "),s("code",[t._v("DB")]),t._v(" -- get flat-db pointer")]),t._v(" "),s("li",[t._v("prove(key, rootHash[optional]): proof -- useful for merkling")])]),t._v(" "),s("p",[t._v("Constructor API:")]),t._v(" "),s("ul",[s("li",[t._v("initSparseBinaryTrie(DB, rootHash[optional])")]),t._v(" "),s("li",[t._v("init(SparseBinaryTrie, DB, rootHash[optional])")])]),t._v(" "),s("p",[t._v("Normally you would not set the rootHash when constructing an empty Sparse Merkle Trie.\nSetting the rootHash occured in a scenario where you have a populated DB\nwith existing trie structure and you know the rootHash,\nand then you want to continue/resume the trie operations.")]),t._v(" "),s("h3",{attrs:{id:"examples-2"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#examples-2"}},[t._v("#")]),t._v(" Examples")]),t._v(" "),s("div",{staticClass:"language-Nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v("\n eth"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),t._v("trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("db"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" sparse_binary"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" utils"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v("\n db "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("newMemoryDB")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n trie "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("initSparseMerkleTrie")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("db"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v("\n key1 "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"01234567890123456789"')]),t._v("\n key2 "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"abcdefghijklmnopqrst"')]),t._v("\n\ntrie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("set")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("key1"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\ntrie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("set")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("key2"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value2"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\ndoAssert trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("get")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("key1"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value1"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("toBytes\ndoAssert trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("get")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("key2"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value2"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("toBytes\n\ntrie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("delete")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("key1"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\ndoAssert trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("get")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("key1"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n\ntrie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("delete")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("key2"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\ndoAssert trie"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("key2"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br"),s("span",{staticClass:"line-number"},[t._v("9")]),s("br"),s("span",{staticClass:"line-number"},[t._v("10")]),s("br"),s("span",{staticClass:"line-number"},[t._v("11")]),s("br"),s("span",{staticClass:"line-number"},[t._v("12")]),s("br"),s("span",{staticClass:"line-number"},[t._v("13")]),s("br"),s("span",{staticClass:"line-number"},[t._v("14")]),s("br"),s("span",{staticClass:"line-number"},[t._v("15")]),s("br"),s("span",{staticClass:"line-number"},[t._v("16")]),s("br"),s("span",{staticClass:"line-number"},[t._v("17")]),s("br"),s("span",{staticClass:"line-number"},[t._v("18")]),s("br"),s("span",{staticClass:"line-number"},[t._v("19")]),s("br"),s("span",{staticClass:"line-number"},[t._v("20")]),s("br"),s("span",{staticClass:"line-number"},[t._v("21")]),s("br")])]),s("p",[t._v("Remember, "),s("code",[t._v("set")]),t._v(" and "),s("code",[t._v("get")]),t._v(" are trie operations. A single "),s("code",[t._v("set")]),t._v(" operation may invoke\nmore than one store/lookup operation into the underlying DB. The same is also happened to "),s("code",[t._v("get")]),t._v(" operation,\nit could do more than one flat-db lookup before it return the requested value.\nWhile Binary Trie perform a variable numbers of lookup and store operations, Sparse Merkle Trie\nwill do constant numbers of lookup and store operations each "),s("code",[t._v("get")]),t._v(" and "),s("code",[t._v("set")]),t._v(" operation.")]),t._v(" "),s("h3",{attrs:{id:"merkle-proofing"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#merkle-proofing"}},[t._v("#")]),t._v(" Merkle Proofing")]),t._v(" "),s("p",[t._v("Using "),s("code",[t._v("prove")]),t._v(" dan "),s("code",[t._v("verifyProof")]),t._v(" API, we can do some merkling with SMT.")]),t._v(" "),s("div",{staticClass:"language-Nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v("\n value1 "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"hello world"')]),t._v("\n badValue "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"bad value"')]),t._v("\n\n trie"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("key1"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" value1\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" proof "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("prove")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("key1"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n doAssert "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("verifyProof")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("proof"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getRootHash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" key1"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" value1"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" true\n doAssert "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("verifyProof")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("proof"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getRootHash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" key1"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" badValue"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" false\n doAssert "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("verifyProof")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("proof"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getRootHash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" key2"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" value1"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" false\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br"),s("span",{staticClass:"line-number"},[t._v("9")]),s("br"),s("span",{staticClass:"line-number"},[t._v("10")]),s("br")])]),s("h2",{attrs:{id:"bloom-an-ethereum-bloom-filter"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#bloom-an-ethereum-bloom-filter"}},[t._v("#")]),t._v(" bloom: an Ethereum Bloom Filter")]),t._v(" "),s("h2",{attrs:{id:"introduction-4"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#introduction-4"}},[t._v("#")]),t._v(" Introduction")]),t._v(" "),s("p",[t._v("A Nim implementation of the bloom filter used by Ethereum.")]),t._v(" "),s("h2",{attrs:{id:"description"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#description"}},[t._v("#")]),t._v(" Description")]),t._v(" "),s("p",[s("a",{attrs:{href:"https://en.wikipedia.org/wiki/Bloom_filter",target:"_blank",rel:"noopener noreferrer"}},[t._v("Bloom filters"),s("OutboundLink")],1),t._v(" are data structures that use hash functions to test whether an element is a member of a set. They work like other data structures but are probabilistic in nature: that is, they allow false positive matches but not false negative. Bloom filters use less storage space than other data structures.")]),t._v(" "),s("p",[t._v("Ethereum bloom filters are implemented with the Keccak-256 cryptographic hash function.")]),t._v(" "),s("p",[t._v("To see the bloom filter used in the context of Ethereum, please refer to the "),s("a",{attrs:{href:"https://ethereum.github.io/yellowpaper/paper.pdf",target:"_blank",rel:"noopener noreferrer"}},[t._v("Ethereum Yellow Paper"),s("OutboundLink")],1),t._v(".")]),t._v(" "),s("h2",{attrs:{id:"usage"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#usage"}},[t._v("#")]),t._v(" Usage")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" eth"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),t._v("bloom"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stint\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" f"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" BloomFilter\nf"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("incl")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"test1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("doAssert")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"test1"')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("in")]),t._v(" f"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("doAssert")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"test2"')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("notin")]),t._v(" f"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nf"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("incl")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"test2"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("doAssert")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"test2"')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("in")]),t._v(" f"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("doAssert")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("f"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("value"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("toHex "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000200000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br")])]),s("h2",{attrs:{id:"node-discovery-protocol-v5"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#node-discovery-protocol-v5"}},[t._v("#")]),t._v(" Node Discovery Protocol v5")]),t._v(" "),s("h3",{attrs:{id:"introduction-5"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#introduction-5"}},[t._v("#")]),t._v(" Introduction")]),t._v(" "),s("p",[t._v("The "),s("code",[t._v("eth/p2p/discoveryv5")]),t._v(" directory holds a Nim implementation of the\n"),s("a",{attrs:{href:"https://github.com/ethereum/devp2p/blob/master/discv5/discv5.md",target:"_blank",rel:"noopener noreferrer"}},[t._v("Node Discovery Protocol v5.1"),s("OutboundLink")],1),t._v(".")]),t._v(" "),s("p",[t._v("The implemented specification is Protocol version v5.1.")]),t._v(" "),s("p",[t._v('This implementation does not support "Topic Advertisement" yet as this part of\nthe specification is not complete.')]),t._v(" "),s("p",[t._v("The implementation relies on other modules in the "),s("code",[t._v("eth")]),t._v(" package, namely: "),s("code",[t._v("keys")]),t._v(",\n"),s("code",[t._v("rlp")]),t._v(" and "),s("code",[t._v("async_utils")]),t._v(".")]),t._v(" "),s("h3",{attrs:{id:"how-to-use"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#how-to-use"}},[t._v("#")]),t._v(" How to use")]),t._v(" "),s("div",{staticClass:"language-Nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v("\n rng "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" keys"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("newRng\n privKey "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" PrivateKey"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("random")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("rng"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ip"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" tcpPort"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" udpPort"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("setupNat")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("config"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Or fill in external IP/ports manually")]),t._v("\n d "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("newProtocol")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("privKey"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" ip"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" tcpPort"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" udpPort"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" rng "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" rng"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\nd"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("open")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Start listening")]),t._v("\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br")])]),s("p",[t._v("This will initialize the "),s("code",[t._v("Protocol")]),t._v(" and start listening. However, as no\nbootstrap nodes were passed in the "),s("code",[t._v("newProtocol")]),t._v(' call, the created ENR will need\nto be advertised somehow ("out of band"), so that the node can become known to\nother nodes in the network.')]),t._v(" "),s("p",[t._v("To initialize with a bootnode or a set of bootnodes, the ENRs need to be passed\nas parameter in "),s("code",[t._v("newProtocol")]),t._v(".")]),t._v(" "),s("div",{staticClass:"language-Nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[t._v("d "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("newProtocol")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("privKey"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" ip"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" tcpPort"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" udpPort"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n bootstrapRecords "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" bootnodes"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nd"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("open")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Start listening and add bootstrap nodes to the routing table.")]),t._v("\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br")])]),s("p",[t._v("Next there are two ways to run the protocol.")]),t._v(" "),s("p",[t._v("One can call "),s("code",[t._v("d.start()")]),t._v(" and two loops will be started:")]),t._v(" "),s("ol",[s("li",[t._v("Refresh loop")]),t._v(" "),s("li",[t._v("Revalidation loop")])]),t._v(" "),s("p",[t._v("The first loop will at specific interval do a query with a random "),s("code",[t._v("NodeId")]),t._v(" if no\nmanual queries were done for more than that interval period.\nThis query will add discovered nodes to the routing table.\nThe second loop will at random ranged interval send a ping to the least recently\nseen node in a random bucket. This is to keep the routing table cleared of\nunreachable/dead nodes.")]),t._v(" "),s("p",[t._v("Now within the application, manual queries or lookups can be done, for which\nthe discovered nodes can be used. Nodes discovered during this process will be\nattempted to be added to the routing table. One can use the "),s("code",[t._v("query")]),t._v(", "),s("code",[t._v("queryRandom")]),t._v("\nor "),s("code",[t._v("lookup")]),t._v(" calls for this. "),s("code",[t._v("randomNodes")]),t._v(" can also be used to find nodes,\nbut this will only look into the current routing table and not actively\nsearch for nodes on the network.")]),t._v(" "),s("p",[t._v("Or, one can decide not to run "),s("code",[t._v("d.start()")]),t._v(" and do this manually within its\napplication by using the available calls:")]),t._v(" "),s("ul",[s("li",[s("code",[t._v("query")]),t._v(", "),s("code",[t._v("queryRandom")]),t._v(" or "),s("code",[t._v("lookup")]),t._v(" for discovering more peers.")]),t._v(" "),s("li",[s("code",[t._v("revalidateNode")]),t._v(" or directly "),s("code",[t._v("ping")]),t._v(" for revalidating nodes.")])]),t._v(" "),s("p",[t._v("Of course, in either scenario, lookups can still be done for actually finding a\nspecific node. There is a "),s("code",[t._v("resolve")]),t._v(" call that can help with this, it will first\nlook in the local routing table and if it finds the node it will try to contact\nthe node directly to check if the ENR is up to date. If any of this fail a\n"),s("code",[t._v("lookup")]),t._v(" will be done.")]),t._v(" "),s("h3",{attrs:{id:"test-suite"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#test-suite"}},[t._v("#")]),t._v(" Test suite")]),t._v(" "),s("p",[t._v("To run the test suite specifically for discovery v5 related (discovery v5 + its\nnim-eth dependencies) tests, one can run following command:")]),t._v(" "),s("div",{staticClass:"language-sh line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-sh"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("## Install required modules")]),t._v("\nnimble "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("install")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("## Run only discovery v5 related test suite")]),t._v("\nnimble tests_discv5_full\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br")])]),s("h3",{attrs:{id:"dcli"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#dcli"}},[t._v("#")]),t._v(" dcli")]),t._v(" "),s("p",[t._v("This is a small command line application that allows you to run a discovery\nnode. It also has the options to do a "),s("code",[t._v("ping")]),t._v(" or "),s("code",[t._v("findNode")]),t._v(" request to a specific\nnode, by providing its ENR.")]),t._v(" "),s("h4",{attrs:{id:"example-usage"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#example-usage"}},[t._v("#")]),t._v(" Example usage")]),t._v(" "),s("div",{staticClass:"language-sh line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-sh"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("## Install required modules")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("## Make sure you have the latest modules, do NOT trust nimble on this.")]),t._v("\nnimble "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("install")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("## Build dcli")]),t._v("\nnim c -d:chronicles_log_level:trace -d:release --threads:on eth/p2p/discoveryv5/dcli\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("## See all options")]),t._v("\n./eth/p2p/discoveryv5/dcli --help\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("## Ping another node")]),t._v("\n./eth/p2p/discoveryv5/dcli "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ping")]),t._v(" enr:"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("base64 encoding of ENR"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("## Run discovery node")]),t._v("\n./eth/p2p/discoveryv5/dcli --log-level:debug --bootnode:enr:"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("base64 encoding of ENR"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v("\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br"),s("span",{staticClass:"line-number"},[t._v("9")]),s("br"),s("span",{staticClass:"line-number"},[t._v("10")]),s("br"),s("span",{staticClass:"line-number"},[t._v("11")]),s("br")])]),s("h4",{attrs:{id:"metrics"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#metrics"}},[t._v("#")]),t._v(" Metrics")]),t._v(" "),s("p",[t._v("To run dcli with metrics enabled provide the "),s("code",[t._v("metrics")]),t._v(" flag:")]),t._v(" "),s("div",{staticClass:"language-sh line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-sh"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("## Run dcli with metrics")]),t._v("\n./eth/p2p/discoveryv5/dcli --metrics --bootnode:enr:"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("base64 encoding of ENR"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v("\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br")])]),s("p",[t._v("You can now see the metrics at http://localhost:8008/metrics. Or use e.g.\nPrometheus to grab the data.")]),t._v(" "),s("h2",{attrs:{id:"prerequisites"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#prerequisites"}},[t._v("#")]),t._v(" Prerequisites")]),t._v(" "),s("ul",[s("li",[t._v("Nim & Nimble")]),t._v(" "),s("li",[t._v("RocksDB, SQLite, LMDB (required for the trie backend tests)")])]),t._v(" "),s("p",[t._v("E.g. on Ubuntu one can run:")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("apt install -y librocksdb-dev liblmdb-dev sqlite3\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("h2",{attrs:{id:"building-testing"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#building-testing"}},[t._v("#")]),t._v(" Building & Testing")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("# Install required modules\nnimble install\n# Run full test suite\nnimble test\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br")])]),s("p",[t._v("You can also run specific parts of the test suite, e.g.:")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("# Test p2p functionality\nnimble test_p2p\n# Test rlp functionality\nnimble test_rlp\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br")])]),s("h2",{attrs:{id:"fuzzing"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#fuzzing"}},[t._v("#")]),t._v(" Fuzzing")]),t._v(" "),s("p",[t._v("Next to the test suite, there are also several fuzzing test cases available.\nHow these can be run is explained in the "),s("a",{attrs:{href:"https://github.com/status-im/nim-eth/blob/master/tests/fuzzing/readme.md",target:"_blank",rel:"noopener noreferrer"}},[t._v("fuzzing readme"),s("OutboundLink")],1),t._v(".")])])}),[],!1,null,null,null);e.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/11.bbf981b9.js b/assets/js/11.bbf981b9.js deleted file mode 100644 index 36512c1..0000000 --- a/assets/js/11.bbf981b9.js +++ /dev/null @@ -1 +0,0 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[11],{208:function(t,s,e){"use strict";e.r(s);var a=e(28),n=Object(a.a)({},(function(){var t=this,s=t.$createElement,e=t._self._c||s;return e("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[e("h1",{attrs:{id:"stew"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#stew"}},[t._v("#")]),t._v(" Stew")]),t._v(" "),e("h1",{attrs:{id:"stew-status-e-something-w-something"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#stew-status-e-something-w-something"}},[t._v("#")]),t._v(" stew - status e-something w-something")]),t._v(" "),e("p",[e("a",{attrs:{href:"https://travis-ci.org/status-im/nim-stew",target:"_blank",rel:"noopener noreferrer"}},[e("img",{attrs:{src:"https://img.shields.io/travis/status-im/nim-stew/master.svg?label=Linux%20/%20macOS",alt:"Build Status (Travis)",title:"Linux/macOS build status (Travis)"}}),e("OutboundLink")],1),t._v(" "),e("a",{attrs:{href:"https://ci.appveyor.com/project/nimbus/nim-stew",target:"_blank",rel:"noopener noreferrer"}},[e("img",{attrs:{src:"https://img.shields.io/appveyor/ci/nimbus/nim-stew/master.svg?label=Windows",alt:"Windows build status (Appveyor)",title:"Windows build status (Appveyor)"}}),e("OutboundLink")],1),t._v(" "),e("a",{attrs:{href:"https://opensource.org/licenses/Apache-2.0",target:"_blank",rel:"noopener noreferrer"}},[e("img",{attrs:{src:"https://img.shields.io/badge/License-Apache%202.0-blue.svg",alt:"License: Apache"}}),e("OutboundLink")],1),t._v(" "),e("a",{attrs:{href:"https://opensource.org/licenses/MIT",target:"_blank",rel:"noopener noreferrer"}},[e("img",{attrs:{src:"https://img.shields.io/badge/License-MIT-blue.svg",alt:"License: MIT"}}),e("OutboundLink")],1),t._v(" "),e("img",{attrs:{src:"https://img.shields.io/badge/stability-experimental-orange.svg",alt:"Stability: experimental"}})]),t._v(" "),e("p",[e("code",[t._v("stew")]),t._v(" is collection of utilities, std library extensions and budding libraries\nthat are frequently used at Status, but are too small to deserve their own\ngit repository.")]),t._v(" "),e("p",[t._v("We also use "),e("code",[t._v("stew")]),t._v(" as a staging ground for code that has yet to be\nbattle-tested.")]),t._v(" "),e("p",[t._v("Some of these libraries may eventually be proposed for inclusion in Nim or\nbroken out into separate repositories.")]),t._v(" "),e("h2",{attrs:{id:"notable-libraries"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#notable-libraries"}},[t._v("#")]),t._v(" Notable libraries")]),t._v(" "),e("p",[t._v("Libraries are documented either in-module or on a separate README in their\nrespective folders")]),t._v(" "),e("ul",[e("li",[e("code",[t._v("bitops2")]),t._v(" - an updated version of "),e("code",[t._v("bitops.nim")]),t._v(", filling in gaps in original code")]),t._v(" "),e("li",[e("code",[t._v("byteutils")]),t._v(" - utilities that make working with the Nim "),e("code",[t._v("byte")]),t._v(" type convenient")]),t._v(" "),e("li",[e("code",[t._v("endians2")]),t._v(" - utilities for converting to and from little / big endian integers")]),t._v(" "),e("li",[e("code",[t._v("ptrops")]),t._v(" - pointer arithmetic utilities")]),t._v(" "),e("li",[e("code",[t._v("ranges")]),t._v(" - utility functions for working with parts and blobs of memory")]),t._v(" "),e("li",[e("code",[t._v("shims")]),t._v(" - backports of nim "),e("code",[t._v("devel")]),t._v(" code to the stable version that Status is using")])]),t._v(" "),e("h2",{attrs:{id:"layout"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#layout"}},[t._v("#")]),t._v(" Layout")]),t._v(" "),e("p",[e("code",[t._v("stew")]),t._v(" modules are made to be fairly independent of each other, but generally\nfollow the following layout - if you've used C++'s "),e("code",[t._v("boost")]),t._v(", you'll feel right at\nhome:")]),t._v(" "),e("div",{staticClass:"language-bash line-numbers-mode"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Single-module libraries")]),t._v("\nstew/small.nim "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# small libraries that fits in one module")]),t._v("\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Multi-module libraries")]),t._v("\nstew/libname.nim "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Main import file")]),t._v("\nstew/libname/stuff.nim "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Detail import file")]),t._v("\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Nim standard library shims that contain forwards-compatibility code to manage")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# support for multiple nim versions - code in here typically has been taken")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# from nim `devel` branch and `name` will reexport the corresponding std lib")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# module")]),t._v("\nstew/shims/macros.nim "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# module that reexports `macros.nim` adding code from newer nim versions")]),t._v("\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Tests are in the tests folder (duh!)")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# To execute, run either `all_tests.nim` or specific `test_xxx.nim` files:")]),t._v("\nnim c -r tests/all_tests\n")])]),t._v(" "),e("div",{staticClass:"line-numbers-wrapper"},[e("span",{staticClass:"line-number"},[t._v("1")]),e("br"),e("span",{staticClass:"line-number"},[t._v("2")]),e("br"),e("span",{staticClass:"line-number"},[t._v("3")]),e("br"),e("span",{staticClass:"line-number"},[t._v("4")]),e("br"),e("span",{staticClass:"line-number"},[t._v("5")]),e("br"),e("span",{staticClass:"line-number"},[t._v("6")]),e("br"),e("span",{staticClass:"line-number"},[t._v("7")]),e("br"),e("span",{staticClass:"line-number"},[t._v("8")]),e("br"),e("span",{staticClass:"line-number"},[t._v("9")]),e("br"),e("span",{staticClass:"line-number"},[t._v("10")]),e("br"),e("span",{staticClass:"line-number"},[t._v("11")]),e("br"),e("span",{staticClass:"line-number"},[t._v("12")]),e("br"),e("span",{staticClass:"line-number"},[t._v("13")]),e("br"),e("span",{staticClass:"line-number"},[t._v("14")]),e("br"),e("span",{staticClass:"line-number"},[t._v("15")]),e("br"),e("span",{staticClass:"line-number"},[t._v("16")]),e("br")])]),e("h2",{attrs:{id:"compatibility"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#compatibility"}},[t._v("#")]),t._v(" Compatibility")]),t._v(" "),e("p",[t._v("One of the goals of "),e("code",[t._v("stew")]),t._v(" is to provide backwards and forwards compatibility\nfor different Nim versions, such that code using "),e("code",[t._v("stew")]),t._v(" works well with multiple\nversions of Nim. If "),e("code",[t._v("stew")]),t._v(" is not working with the Nim version you're using, we\nwelcome patches.")]),t._v(" "),e("p",[t._v("You can create multiple versions of your code using the following pattern:")]),t._v(" "),e("div",{staticClass:"language-nim line-numbers-mode"},[e("pre",{pre:!0,attrs:{class:"language-nim"}},[e("code",[e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("when")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("NimMajor"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("NimMinor"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("NimPatch"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">=")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("19")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("9")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("discard")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("elif")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("NimMajor"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("NimMinor"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("NimPatch"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">=")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("19")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("discard")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("else")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{.")]),t._v("fatal"),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"unsupported nim version"')]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])]),t._v(" "),e("div",{staticClass:"line-numbers-wrapper"},[e("span",{staticClass:"line-number"},[t._v("1")]),e("br"),e("span",{staticClass:"line-number"},[t._v("2")]),e("br"),e("span",{staticClass:"line-number"},[t._v("3")]),e("br"),e("span",{staticClass:"line-number"},[t._v("4")]),e("br"),e("span",{staticClass:"line-number"},[t._v("5")]),e("br"),e("span",{staticClass:"line-number"},[t._v("6")]),e("br")])]),e("h2",{attrs:{id:"using-stew-in-your-project"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#using-stew-in-your-project"}},[t._v("#")]),t._v(" Using stew in your project")]),t._v(" "),e("p",[t._v("We do not recommend using this library as a normal "),e("code",[t._v("nimble")]),t._v(" dependency - there\nare no versioned releases and we will not maintain API/ABI stability. Instead,\nmake sure you pin your dependency to a specific git hash (for example using a\nsubmodule) or copy the file to your project instead.")]),t._v(" "),e("p",[t._v("Typically, you will import either a top-level library or drill down into its\nsubmodules:")]),t._v(" "),e("div",{staticClass:"language-nim line-numbers-mode"},[e("pre",{pre:!0,attrs:{class:"language-nim"}},[e("code",[e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" stew"),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),t._v("bitops2\n"),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" stew"),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),t._v("ranges"),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),t._v("bitranges\n")])]),t._v(" "),e("div",{staticClass:"line-numbers-wrapper"},[e("span",{staticClass:"line-number"},[t._v("1")]),e("br"),e("span",{staticClass:"line-number"},[t._v("2")]),e("br")])]),e("p",[t._v("⚠️ No API/ABI stability - pick a commit and stick with it ⚠️")])])}),[],!1,null,null,null);s.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/12.cf1bd068.js b/assets/js/12.cf1bd068.js new file mode 100644 index 0000000..71ed3af --- /dev/null +++ b/assets/js/12.cf1bd068.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[12],{366:function(t,e,r){"use strict";r.r(e);var a=r(44),s=Object(a.a)({},(function(){var t=this,e=t.$createElement,r=t._self._c||e;return r("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[r("h1",{attrs:{id:"libp2p"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#libp2p"}},[t._v("#")]),t._v(" libp2p")]),t._v(" "),r("p",[t._v("An implementation of "),r("a",{attrs:{href:"https://libp2p.io/",target:"_blank",rel:"noopener noreferrer"}},[t._v("libp2p"),r("OutboundLink")],1),t._v(" in Nim. Also provides a Nim wrapper of the "),r("a",{attrs:{href:"https://github.com/libp2p/go-libp2p",target:"_blank",rel:"noopener noreferrer"}},[t._v("Libp2p Go daemon"),r("OutboundLink")],1),t._v(".")]),t._v(" "),r("h2",{attrs:{id:"project-status"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#project-status"}},[t._v("#")]),t._v(" Project Status")]),t._v(" "),r("p",[t._v("The current native Nim libp2p implementation support is experimental and shouldn't be relied on for production use. It is under active development and contributions are highly welcomed. 😃")]),t._v(" "),r("p",[t._v("Check our "),r("a",{attrs:{href:"/examples"}},[t._v("examples folder")]),t._v(" to get started!")]),t._v(" "),r("h1",{attrs:{id:"table-of-contents"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#table-of-contents"}},[t._v("#")]),t._v(" Table of Contents")]),t._v(" "),r("ul",[r("li",[r("a",{attrs:{href:"#background"}},[t._v("Background")])]),t._v(" "),r("li",[r("a",{attrs:{href:"#install"}},[t._v("Install")]),t._v(" "),r("ul",[r("li",[r("a",{attrs:{href:"#prerequisite"}},[t._v("Prerequisite")])])])]),t._v(" "),r("li",[r("a",{attrs:{href:"#usage"}},[t._v("Usage")]),t._v(" "),r("ul",[r("li",[r("a",{attrs:{href:"#api"}},[t._v("API")])]),t._v(" "),r("li",[r("a",{attrs:{href:"#getting-started"}},[t._v("Getting Started")])]),t._v(" "),r("li",[r("a",{attrs:{href:"#tutorials-and-examples"}},[t._v("Tutorials and Examples")])]),t._v(" "),r("li",[r("a",{attrs:{href:"#using-the-go-daemon"}},[t._v("Using the Go Daemon")])])])]),t._v(" "),r("li",[r("a",{attrs:{href:"#development"}},[t._v("Development")]),t._v(" "),r("ul",[r("li",[r("a",{attrs:{href:"#tests"}},[t._v("Tests")])]),t._v(" "),r("li",[r("a",{attrs:{href:"#packages"}},[t._v("Packages")])])])]),t._v(" "),r("li",[r("a",{attrs:{href:"#contribute"}},[t._v("Contribute")]),t._v(" "),r("ul",[r("li",[r("a",{attrs:{href:"#core-developers"}},[t._v("Core Developers")])])])]),t._v(" "),r("li",[r("a",{attrs:{href:"#license"}},[t._v("License")])])]),t._v(" "),r("h2",{attrs:{id:"background"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#background"}},[t._v("#")]),t._v(" Background")]),t._v(" "),r("p",[t._v("libp2p is a networking stack and library modularized out of "),r("a",{attrs:{href:"https://github.com/ipfs/ipfs",target:"_blank",rel:"noopener noreferrer"}},[t._v("The IPFS Project"),r("OutboundLink")],1),t._v(", and bundled separately for other tools to use.")]),t._v(" "),r("p",[t._v('libp2p is the product of a long and arduous quest of understanding; a deep dive into the internet\'s network stack and the peer-to-peer protocols from the past. Building large scale peer-to-peer systems has been complex and difficult in the last 15 years and libp2p is a way to fix that. It is a "network stack", a suite of networking protocols that cleanly separates concerns and enables sophisticated applications to only use the protocols they absolutely need, without giving up interoperability and upgradeability.')]),t._v(" "),r("p",[t._v("libp2p grew out of IPFS, but it is built so that lots of people can use it, for lots of different projects.")]),t._v(" "),r("ul",[r("li",[t._v("Learn more about libp2p at "),r("a",{attrs:{href:"https://libp2p.io",target:"_blank",rel:"noopener noreferrer"}},[r("strong",[t._v("libp2p.io")]),r("OutboundLink")],1),t._v(" and follow our evolving documentation efforts at "),r("a",{attrs:{href:"https://docs.libp2p.io",target:"_blank",rel:"noopener noreferrer"}},[r("strong",[t._v("docs.libp2p.io")]),r("OutboundLink")],1),t._v(".")]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/libp2p/libp2p#description",target:"_blank",rel:"noopener noreferrer"}},[t._v("Here"),r("OutboundLink")],1),t._v(" is an overview of libp2p and its implementations in other programming languages.")])]),t._v(" "),r("h2",{attrs:{id:"install"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#install"}},[t._v("#")]),t._v(" Install")]),t._v(" "),r("div",{staticClass:"language- line-numbers-mode"},[r("pre",{pre:!0,attrs:{class:"language-text"}},[r("code",[t._v("nimble install libp2p\n")])]),t._v(" "),r("div",{staticClass:"line-numbers-wrapper"},[r("span",{staticClass:"line-number"},[t._v("1")]),r("br")])]),r("h3",{attrs:{id:"prerequisite"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#prerequisite"}},[t._v("#")]),t._v(" Prerequisite")]),t._v(" "),r("ul",[r("li",[r("a",{attrs:{href:"https://nim-lang.org/install.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Nim"),r("OutboundLink")],1)])]),t._v(" "),r("h2",{attrs:{id:"usage"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#usage"}},[t._v("#")]),t._v(" Usage")]),t._v(" "),r("h3",{attrs:{id:"api"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#api"}},[t._v("#")]),t._v(" API")]),t._v(" "),r("p",[t._v("The specification is available in the "),r("a",{attrs:{href:"docs/api"}},[t._v("docs/api")]),t._v(" folder.")]),t._v(" "),r("h3",{attrs:{id:"getting-started"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#getting-started"}},[t._v("#")]),t._v(" Getting Started")]),t._v(" "),r("p",[t._v("Please read the "),r("RouterLink",{attrs:{to:"/lib/nim-libp2p/docs/GETTING_STARTED.html"}},[t._v("GETTING_STARTED.md")]),t._v(" guide.")],1),t._v(" "),r("h3",{attrs:{id:"tutorials-and-examples"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#tutorials-and-examples"}},[t._v("#")]),t._v(" Tutorials and Examples")]),t._v(" "),r("p",[t._v("Example code can be found in the "),r("a",{attrs:{href:"/examples"}},[t._v("examples folder")]),t._v(".")]),t._v(" "),r("h4",{attrs:{id:"direct-chat-tutorial"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#direct-chat-tutorial"}},[t._v("#")]),t._v(" Direct Chat Tutorial")]),t._v(" "),r("ul",[r("li",[r("a",{attrs:{href:"https://our.status.im/nim-libp2p-tutorial-a-peer-to-peer-chat-example-1/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Part I"),r("OutboundLink")],1),t._v(": Set up the main function and use multi-thread for processing IO.")]),t._v(" "),r("li",[r("a",{attrs:{href:"https://our.status.im/nim-libp2p-tutorial-a-peer-to-peer-chat-example-2/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Part II"),r("OutboundLink")],1),t._v(": Dial remote peer and allow customized user input commands.")]),t._v(" "),r("li",[r("a",{attrs:{href:"https://our.status.im/nim-libp2p-tutorial-a-peer-to-peer-chat-example-3/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Part III"),r("OutboundLink")],1),t._v(": Configure and establish a libp2p node.")])]),t._v(" "),r("h3",{attrs:{id:"using-the-go-daemon"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#using-the-go-daemon"}},[t._v("#")]),t._v(" Using the Go Daemon")]),t._v(" "),r("p",[t._v("Please find the installation and usage intructions in "),r("RouterLink",{attrs:{to:"/lib/nim-libp2p/docs/api/libp2p/daemonapi.html"}},[t._v("daemonapi.md")]),t._v(".")],1),t._v(" "),r("p",[t._v("Examples can be found in the "),r("a",{attrs:{href:"https://github.com/status-im/nim-libp2p/tree/readme/examples/go-daemon",target:"_blank",rel:"noopener noreferrer"}},[t._v("examples/go-daemon folder"),r("OutboundLink")],1),t._v(";")]),t._v(" "),r("h2",{attrs:{id:"development"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#development"}},[t._v("#")]),t._v(" Development")]),t._v(" "),r("p",[r("strong",[t._v("Clone and Install dependencies:")])]),t._v(" "),r("div",{staticClass:"language-sh line-numbers-mode"},[r("pre",{pre:!0,attrs:{class:"language-sh"}},[r("code",[r("span",{pre:!0,attrs:{class:"token function"}},[t._v("git")]),t._v(" clone https://github.com/status-im/nim-libp2p\n"),r("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v("cd")]),t._v(" nim-libp2p\nnimble "),r("span",{pre:!0,attrs:{class:"token function"}},[t._v("install")]),t._v("\n")])]),t._v(" "),r("div",{staticClass:"line-numbers-wrapper"},[r("span",{staticClass:"line-number"},[t._v("1")]),r("br"),r("span",{staticClass:"line-number"},[t._v("2")]),r("br"),r("span",{staticClass:"line-number"},[t._v("3")]),r("br")])]),r("h3",{attrs:{id:"tests"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#tests"}},[t._v("#")]),t._v(" Tests")]),t._v(" "),r("h4",{attrs:{id:"prerequisite-2"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#prerequisite-2"}},[t._v("#")]),t._v(" Prerequisite")]),t._v(" "),r("ul",[r("li",[r("a",{attrs:{href:"https://golang.org/dl/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Go 1.12+"),r("OutboundLink")],1)])]),t._v(" "),r("h4",{attrs:{id:"run-unit-tests"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#run-unit-tests"}},[t._v("#")]),t._v(" Run unit tests")]),t._v(" "),r("div",{staticClass:"language-sh line-numbers-mode"},[r("pre",{pre:!0,attrs:{class:"language-sh"}},[r("code",[r("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# run all the unit tests")]),t._v("\nnimble "),r("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v("test")]),t._v("\n")])]),t._v(" "),r("div",{staticClass:"line-numbers-wrapper"},[r("span",{staticClass:"line-number"},[t._v("1")]),r("br"),r("span",{staticClass:"line-number"},[t._v("2")]),r("br")])]),r("h3",{attrs:{id:"packages"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#packages"}},[t._v("#")]),t._v(" Packages")]),t._v(" "),r("p",[t._v("List of packages currently in existence for nim-libp2p:")]),t._v(" "),r("h4",{attrs:{id:"libp2p-2"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#libp2p-2"}},[t._v("#")]),t._v(" Libp2p")]),t._v(" "),r("ul",[r("li",[r("a",{attrs:{href:"https://github.com/status-im/nim-libp2p",target:"_blank",rel:"noopener noreferrer"}},[t._v("libp2p"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/status-im/nim-libp2p/blob/master/libp2p/daemon/daemonapi.nim",target:"_blank",rel:"noopener noreferrer"}},[t._v("libp2p-daemon-client"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/status-im/nim-libp2p/blob/master/tests/testinterop.nim",target:"_blank",rel:"noopener noreferrer"}},[t._v("interop-libp2p"),r("OutboundLink")],1)])]),t._v(" "),r("h4",{attrs:{id:"transports"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#transports"}},[t._v("#")]),t._v(" Transports")]),t._v(" "),r("ul",[r("li",[r("a",{attrs:{href:"https://github.com/status-im/nim-libp2p/blob/master/libp2p/transports/tcptransport.nim",target:"_blank",rel:"noopener noreferrer"}},[t._v("libp2p-tcp"),r("OutboundLink")],1)])]),t._v(" "),r("h4",{attrs:{id:"secure-channels"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#secure-channels"}},[t._v("#")]),t._v(" Secure Channels")]),t._v(" "),r("ul",[r("li",[r("a",{attrs:{href:"https://github.com/status-im/nim-libp2p/blob/master/libp2p/protocols/secure/secio.nim",target:"_blank",rel:"noopener noreferrer"}},[t._v("libp2p-secio"),r("OutboundLink")],1)])]),t._v(" "),r("h4",{attrs:{id:"stream-multiplexers"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#stream-multiplexers"}},[t._v("#")]),t._v(" Stream Multiplexers")]),t._v(" "),r("ul",[r("li",[r("a",{attrs:{href:"https://github.com/status-im/nim-libp2p/blob/master/libp2p/muxers/mplex/mplex.nim",target:"_blank",rel:"noopener noreferrer"}},[t._v("libp2p-mplex"),r("OutboundLink")],1)])]),t._v(" "),r("h4",{attrs:{id:"utilities"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#utilities"}},[t._v("#")]),t._v(" Utilities")]),t._v(" "),r("ul",[r("li",[r("a",{attrs:{href:"https://github.com/status-im/nim-libp2p/tree/master/libp2p/crypto",target:"_blank",rel:"noopener noreferrer"}},[t._v("libp2p-crypto"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/status-im/nim-libp2p/blob/master/libp2p/crypto/secp.nim",target:"_blank",rel:"noopener noreferrer"}},[t._v("libp2p-crypto-secp256k1"),r("OutboundLink")],1)])]),t._v(" "),r("h4",{attrs:{id:"data-types"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#data-types"}},[t._v("#")]),t._v(" Data Types")]),t._v(" "),r("ul",[r("li",[r("a",{attrs:{href:"https://github.com/status-im/nim-libp2p/blob/master/libp2p/peer.nim",target:"_blank",rel:"noopener noreferrer"}},[t._v("peer-id"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/status-im/nim-libp2p/blob/master/libp2p/peerinfo.nim",target:"_blank",rel:"noopener noreferrer"}},[t._v("peer-info"),r("OutboundLink")],1)])]),t._v(" "),r("h4",{attrs:{id:"pubsub"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#pubsub"}},[t._v("#")]),t._v(" Pubsub")]),t._v(" "),r("ul",[r("li",[r("a",{attrs:{href:"https://github.com/status-im/nim-libp2p/blob/master/libp2p/protocols/pubsub/pubsub.nim",target:"_blank",rel:"noopener noreferrer"}},[t._v("libp2p-pubsub"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/status-im/nim-libp2p/blob/master/libp2p/protocols/pubsub/floodsub.nim",target:"_blank",rel:"noopener noreferrer"}},[t._v("libp2p-floodsub"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/status-im/nim-libp2p/blob/master/libp2p/protocols/pubsub/gossipsub.nim",target:"_blank",rel:"noopener noreferrer"}},[t._v("libp2p-gossipsub"),r("OutboundLink")],1)])]),t._v(" "),r("p",[t._v("Packages that exist in the original libp2p specs and are under active development:")]),t._v(" "),r("ul",[r("li",[t._v("libp2p-daemon")]),t._v(" "),r("li",[t._v("libp2p-webrtc-direct")]),t._v(" "),r("li",[t._v("libp2p-webrtc-star")]),t._v(" "),r("li",[t._v("libp2p-websockets")]),t._v(" "),r("li",[t._v("libp2p-spdy")]),t._v(" "),r("li",[t._v("libp2p-bootstrap")]),t._v(" "),r("li",[t._v("libp2p-kad-dht")]),t._v(" "),r("li",[t._v("libp2p-mdns")]),t._v(" "),r("li",[t._v("libp2p-webrtc-star")]),t._v(" "),r("li",[t._v("libp2p-delegated-content-routing")]),t._v(" "),r("li",[t._v("libp2p-delegated-peer-routing")]),t._v(" "),r("li",[t._v("libp2p-nat-mgnr")]),t._v(" "),r("li",[t._v("libp2p-utils")])]),t._v(" "),r("p",[t._v("** Note that the current stack reflects the minimal requirements for the upcoming Eth2 implementation.")]),t._v(" "),r("h3",{attrs:{id:"tips-and-tricks"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#tips-and-tricks"}},[t._v("#")]),t._v(" Tips and tricks")]),t._v(" "),r("h4",{attrs:{id:"enable-expensive-metrics"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#enable-expensive-metrics"}},[t._v("#")]),t._v(" enable expensive metrics:")]),t._v(" "),r("div",{staticClass:"language-bash line-numbers-mode"},[r("pre",{pre:!0,attrs:{class:"language-bash"}},[r("code",[t._v("nim c -d:libp2p_expensive_metrics some_file.nim\n")])]),t._v(" "),r("div",{staticClass:"line-numbers-wrapper"},[r("span",{staticClass:"line-number"},[t._v("1")]),r("br")])]),r("h4",{attrs:{id:"use-identify-metrics"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#use-identify-metrics"}},[t._v("#")]),t._v(" use identify metrics")]),t._v(" "),r("div",{staticClass:"language-bash line-numbers-mode"},[r("pre",{pre:!0,attrs:{class:"language-bash"}},[r("code",[t._v("nim c -d:libp2p_agents_metrics -d:KnownLibP2PAgents"),r("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("nimbus,lighthouse,prysm,teku some_file.nim\n")])]),t._v(" "),r("div",{staticClass:"line-numbers-wrapper"},[r("span",{staticClass:"line-number"},[t._v("1")]),r("br")])]),r("h3",{attrs:{id:"specify-gossipsub-specific-topics-to-measure"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#specify-gossipsub-specific-topics-to-measure"}},[t._v("#")]),t._v(" specify gossipsub specific topics to measure")]),t._v(" "),r("div",{staticClass:"language-bash line-numbers-mode"},[r("pre",{pre:!0,attrs:{class:"language-bash"}},[r("code",[t._v("nim c -d:KnownLibP2PTopics"),r("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("topic1,topic2,topic3 some_file.nim\n")])]),t._v(" "),r("div",{staticClass:"line-numbers-wrapper"},[r("span",{staticClass:"line-number"},[t._v("1")]),r("br")])]),r("h2",{attrs:{id:"contribute"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#contribute"}},[t._v("#")]),t._v(" Contribute")]),t._v(" "),r("p",[t._v("The libp2p implementation in Nim is a work in progress. We welcome contributors to help out! Specifically, you can:")]),t._v(" "),r("ul",[r("li",[t._v("Go through the modules and "),r("strong",[t._v("check out existing issues")]),t._v(". This would be especially useful for modules in active development. Some knowledge of IPFS/libp2p may be required, as well as the infrastructure behind it.")]),t._v(" "),r("li",[r("strong",[t._v("Perform code reviews")]),t._v(". Feel free to let us know if you found anything that can a) speed up the project development b) ensure better quality and c) reduce possible future bugs.")]),t._v(" "),r("li",[r("strong",[t._v("Add tests")]),t._v(". Help nim-libp2p to be more robust by adding more tests to the "),r("a",{attrs:{href:"https://github.com/status-im/nim-libp2p/tree/master/tests",target:"_blank",rel:"noopener noreferrer"}},[t._v("tests folder"),r("OutboundLink")],1),t._v(".")])]),t._v(" "),r("h3",{attrs:{id:"core-developers"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#core-developers"}},[t._v("#")]),t._v(" Core Developers")]),t._v(" "),r("p",[r("a",{attrs:{href:"https://github.com/cheatfate",target:"_blank",rel:"noopener noreferrer"}},[t._v("@cheatfate"),r("OutboundLink")],1),t._v(", "),r("a",{attrs:{href:"https://github.com/dryajov",target:"_blank",rel:"noopener noreferrer"}},[t._v("Dmitriy Ryajov"),r("OutboundLink")],1),t._v(", "),r("a",{attrs:{href:"https://github.com/sinkingsugar",target:"_blank",rel:"noopener noreferrer"}},[t._v("Giovanni Petrantoni"),r("OutboundLink")],1),t._v(", "),r("a",{attrs:{href:"https://github.com/zah",target:"_blank",rel:"noopener noreferrer"}},[t._v("Zahary Karadjov"),r("OutboundLink")],1)])])}),[],!1,null,null,null);e.default=s.exports}}]); \ No newline at end of file diff --git a/assets/js/13.9dfac9d9.js b/assets/js/13.9dfac9d9.js new file mode 100644 index 0000000..ceb9c4d --- /dev/null +++ b/assets/js/13.9dfac9d9.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[13],{370:function(t,s,e){"use strict";e.r(s);var a=e(44),n=Object(a.a)({},(function(){var t=this,s=t.$createElement,e=t._self._c||s;return e("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[e("h1",{attrs:{id:"stew"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#stew"}},[t._v("#")]),t._v(" Stew")]),t._v(" "),e("h1",{attrs:{id:"stew-status-e-something-w-something"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#stew-status-e-something-w-something"}},[t._v("#")]),t._v(" stew - status e-something w-something")]),t._v(" "),e("p",[e("a",{attrs:{href:"https://travis-ci.org/status-im/nim-stew",target:"_blank",rel:"noopener noreferrer"}},[e("img",{attrs:{src:"https://img.shields.io/travis/status-im/nim-stew/master.svg?label=Linux%20/%20macOS",alt:"Build Status (Travis)",title:"Linux/macOS build status (Travis)"}}),e("OutboundLink")],1),t._v(" "),e("a",{attrs:{href:"https://ci.appveyor.com/project/nimbus/nim-stew",target:"_blank",rel:"noopener noreferrer"}},[e("img",{attrs:{src:"https://img.shields.io/appveyor/ci/nimbus/nim-stew/master.svg?label=Windows",alt:"Windows build status (Appveyor)",title:"Windows build status (Appveyor)"}}),e("OutboundLink")],1),t._v(" "),e("a",{attrs:{href:"https://opensource.org/licenses/Apache-2.0",target:"_blank",rel:"noopener noreferrer"}},[e("img",{attrs:{src:"https://img.shields.io/badge/License-Apache%202.0-blue.svg",alt:"License: Apache"}}),e("OutboundLink")],1),t._v(" "),e("a",{attrs:{href:"https://opensource.org/licenses/MIT",target:"_blank",rel:"noopener noreferrer"}},[e("img",{attrs:{src:"https://img.shields.io/badge/License-MIT-blue.svg",alt:"License: MIT"}}),e("OutboundLink")],1),t._v(" "),e("img",{attrs:{src:"https://img.shields.io/badge/stability-experimental-orange.svg",alt:"Stability: experimental"}}),t._v(" "),e("img",{attrs:{src:"https://github.com/status-im/nim-stew/workflows/nim-stew%20CI/badge.svg",alt:"Github action"}})]),t._v(" "),e("p",[e("code",[t._v("stew")]),t._v(" is collection of utilities, std library extensions and budding libraries\nthat are frequently used at Status, but are too small to deserve their own\ngit repository.")]),t._v(" "),e("p",[t._v("We also use "),e("code",[t._v("stew")]),t._v(" as a staging ground for code that has yet to be\nbattle-tested.")]),t._v(" "),e("p",[t._v("Some of these libraries may eventually be proposed for inclusion in Nim or\nbroken out into separate repositories.")]),t._v(" "),e("h2",{attrs:{id:"notable-libraries"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#notable-libraries"}},[t._v("#")]),t._v(" Notable libraries")]),t._v(" "),e("p",[t._v("Libraries are documented either in-module or on a separate README in their\nrespective folders")]),t._v(" "),e("ul",[e("li",[e("code",[t._v("arrayops")]),t._v(" - small helpers and operations on "),e("code",[t._v("array")]),t._v("/"),e("code",[t._v("openArray")])]),t._v(" "),e("li",[e("code",[t._v("assign2")]),t._v(" - fast assignments (unlike the "),e("code",[t._v("=")]),t._v(" operator in nim which is very slow)")]),t._v(" "),e("li",[e("code",[t._v("bitops2")]),t._v(" - an updated version of "),e("code",[t._v("bitops.nim")]),t._v(", filling in gaps in original code")]),t._v(" "),e("li",[e("code",[t._v("byteutils")]),t._v(" - utilities that make working with the Nim "),e("code",[t._v("byte")]),t._v(" type convenient")]),t._v(" "),e("li",[e("code",[t._v("endians2")]),t._v(" - utilities for converting to and from little / big endian integers")]),t._v(" "),e("li",[e("code",[t._v("objects")]),t._v(" - get an object's base type at runtime, as a string")]),t._v(" "),e("li",[e("code",[t._v("ptrops")]),t._v(" - pointer arithmetic utilities")]),t._v(" "),e("li",[e("code",[t._v("result")]),t._v(" - friendly, exception-free value-or-error returns, similar to "),e("code",[t._v("Option[T]")]),t._v(", from "),e("a",{attrs:{href:"https://github.com/arnetheduck/nim-result/",target:"_blank",rel:"noopener noreferrer"}},[t._v("nim-result"),e("OutboundLink")],1)]),t._v(" "),e("li",[e("code",[t._v("shims")]),t._v(" - backports of nim "),e("code",[t._v("devel")]),t._v(" code to the stable version that Status is using")]),t._v(" "),e("li",[e("code",[t._v("sequtils2")]),t._v(" - extensions to the "),e("code",[t._v("sequtils")]),t._v(" module for working conveniently with "),e("code",[t._v("seq")])]),t._v(" "),e("li",[e("code",[t._v("varints")]),t._v(" - helpers for working with variable length integers")])]),t._v(" "),e("h2",{attrs:{id:"layout"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#layout"}},[t._v("#")]),t._v(" Layout")]),t._v(" "),e("p",[e("code",[t._v("stew")]),t._v(" modules are made to be fairly independent of each other, but generally\nfollow the following layout - if you've used C++'s "),e("code",[t._v("boost")]),t._v(", you'll feel right at\nhome:")]),t._v(" "),e("div",{staticClass:"language-bash line-numbers-mode"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Single-module libraries")]),t._v("\nstew/small.nim "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# small libraries that fits in one module")]),t._v("\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Multi-module libraries")]),t._v("\nstew/libname.nim "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Main import file")]),t._v("\nstew/libname/stuff.nim "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Detail import file")]),t._v("\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Nim standard library shims that contain forwards-compatibility code to manage")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# support for multiple nim versions - code in here typically has been taken")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# from nim `devel` branch and `name` will reexport the corresponding std lib")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# module")]),t._v("\nstew/shims/macros.nim "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# module that reexports `macros.nim` adding code from newer nim versions")]),t._v("\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Tests are in the tests folder (duh!)")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# To execute, run either `all_tests.nim` or specific `test_xxx.nim` files:")]),t._v("\nnim c -r tests/all_tests\n")])]),t._v(" "),e("div",{staticClass:"line-numbers-wrapper"},[e("span",{staticClass:"line-number"},[t._v("1")]),e("br"),e("span",{staticClass:"line-number"},[t._v("2")]),e("br"),e("span",{staticClass:"line-number"},[t._v("3")]),e("br"),e("span",{staticClass:"line-number"},[t._v("4")]),e("br"),e("span",{staticClass:"line-number"},[t._v("5")]),e("br"),e("span",{staticClass:"line-number"},[t._v("6")]),e("br"),e("span",{staticClass:"line-number"},[t._v("7")]),e("br"),e("span",{staticClass:"line-number"},[t._v("8")]),e("br"),e("span",{staticClass:"line-number"},[t._v("9")]),e("br"),e("span",{staticClass:"line-number"},[t._v("10")]),e("br"),e("span",{staticClass:"line-number"},[t._v("11")]),e("br"),e("span",{staticClass:"line-number"},[t._v("12")]),e("br"),e("span",{staticClass:"line-number"},[t._v("13")]),e("br"),e("span",{staticClass:"line-number"},[t._v("14")]),e("br"),e("span",{staticClass:"line-number"},[t._v("15")]),e("br"),e("span",{staticClass:"line-number"},[t._v("16")]),e("br")])]),e("h2",{attrs:{id:"compatibility"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#compatibility"}},[t._v("#")]),t._v(" Compatibility")]),t._v(" "),e("p",[t._v("One of the goals of "),e("code",[t._v("stew")]),t._v(" is to provide backwards and forwards compatibility\nfor different Nim versions, such that code using "),e("code",[t._v("stew")]),t._v(" works well with multiple\nversions of Nim. If "),e("code",[t._v("stew")]),t._v(" is not working with the Nim version you're using, we\nwelcome patches.")]),t._v(" "),e("p",[t._v("You can create multiple versions of your code using the following pattern:")]),t._v(" "),e("div",{staticClass:"language-nim line-numbers-mode"},[e("pre",{pre:!0,attrs:{class:"language-nim"}},[e("code",[e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("when")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("NimMajor"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("NimMinor"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("NimPatch"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">=")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("19")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("9")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("discard")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("elif")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("NimMajor"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("NimMinor"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("NimPatch"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">=")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("19")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("discard")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("else")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{.")]),t._v("fatal"),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"unsupported nim version"')]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])]),t._v(" "),e("div",{staticClass:"line-numbers-wrapper"},[e("span",{staticClass:"line-number"},[t._v("1")]),e("br"),e("span",{staticClass:"line-number"},[t._v("2")]),e("br"),e("span",{staticClass:"line-number"},[t._v("3")]),e("br"),e("span",{staticClass:"line-number"},[t._v("4")]),e("br"),e("span",{staticClass:"line-number"},[t._v("5")]),e("br"),e("span",{staticClass:"line-number"},[t._v("6")]),e("br")])]),e("h2",{attrs:{id:"using-stew-in-your-project"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#using-stew-in-your-project"}},[t._v("#")]),t._v(" Using stew in your project")]),t._v(" "),e("p",[t._v("We do not recommend using this library as a normal "),e("code",[t._v("nimble")]),t._v(" dependency - there\nare no versioned releases and we will not maintain API/ABI stability. Instead,\nmake sure you pin your dependency to a specific git hash (for example using a\nsubmodule) or copy the file to your project instead.")]),t._v(" "),e("p",[t._v("Typically, you will import either a top-level library or drill down into its\nsubmodules:")]),t._v(" "),e("div",{staticClass:"language-nim line-numbers-mode"},[e("pre",{pre:!0,attrs:{class:"language-nim"}},[e("code",[e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" stew"),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),t._v("bitops2\n"),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" stew"),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),t._v("ranges"),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),t._v("bitranges\n")])]),t._v(" "),e("div",{staticClass:"line-numbers-wrapper"},[e("span",{staticClass:"line-number"},[t._v("1")]),e("br"),e("span",{staticClass:"line-number"},[t._v("2")]),e("br")])]),e("p",[t._v("⚠️ No API/ABI stability - pick a commit and stick with it ⚠️")])])}),[],!1,null,null,null);s.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/13.c624f59e.js b/assets/js/13.c624f59e.js deleted file mode 100644 index 7477656..0000000 --- a/assets/js/13.c624f59e.js +++ /dev/null @@ -1 +0,0 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[13],{142:function(n,w,o){}}]); \ No newline at end of file diff --git a/assets/js/12.af14dcd6.js b/assets/js/14.1ce3f7fe.js similarity index 98% rename from assets/js/12.af14dcd6.js rename to assets/js/14.1ce3f7fe.js index 6db9d6f..19c87df 100644 --- a/assets/js/12.af14dcd6.js +++ b/assets/js/14.1ce3f7fe.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[12],{213:function(t,e,r){"use strict";r.r(e);var s=r(28),a=Object(s.a)({},(function(){var t=this,e=t.$createElement,r=t._self._c||e;return r("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[r("h1",{attrs:{id:"nimcrypto"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#nimcrypto"}},[t._v("#")]),t._v(" Nimcrypto")]),t._v(" "),r("p",[t._v("Nimcrypto is Nim's cryptographic library. It implements several popular cryptographic algorithms and their tests with some "),r("a",{attrs:{href:"https://github.com/cheatfate/nimcrypto/tree/master/examples",target:"_blank",rel:"noopener noreferrer"}},[t._v("examples"),r("OutboundLink")],1),t._v(".")]),t._v(" "),r("p",[t._v("Most notably, this library has been used in the "),r("a",{attrs:{href:"https://our.status.im/nimbus-for-newbies/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Nimbus Ethereum client"),r("OutboundLink")],1),t._v(". To see the implementation, check out its "),r("a",{attrs:{href:"https://github.com/status-im/nimbus",target:"_blank",rel:"noopener noreferrer"}},[t._v("Github repository"),r("OutboundLink")],1),t._v(".")]),t._v(" "),r("h2",{attrs:{id:"the-most-basic-usage"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#the-most-basic-usage"}},[t._v("#")]),t._v(" The most basic usage")]),t._v(" "),r("div",{staticClass:"language-bash line-numbers-mode"},[r("pre",{pre:!0,attrs:{class:"language-bash"}},[r("code",[t._v("nimble "),r("span",{pre:!0,attrs:{class:"token function"}},[t._v("install")]),t._v(" nimcrypto "),r("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# installation")]),t._v("\n")])]),t._v(" "),r("div",{staticClass:"line-numbers-wrapper"},[r("span",{staticClass:"line-number"},[t._v("1")]),r("br")])]),r("div",{staticClass:"language-nim line-numbers-mode"},[r("pre",{pre:!0,attrs:{class:"language-nim"}},[r("code",[r("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# example.nim")]),t._v("\n"),r("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" nimcrypto\n\necho keccak_256"),r("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),r("span",{pre:!0,attrs:{class:"token function"}},[t._v("digest")]),r("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),r("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Alice makes a hash"')]),r("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" \n"),r("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# outputs EF0CC652868DF797522FB1D5A39E58E069154D9E47E5D7DB288B7200DB6EDFEE")]),t._v("\n")])]),t._v(" "),r("div",{staticClass:"line-numbers-wrapper"},[r("span",{staticClass:"line-number"},[t._v("1")]),r("br"),r("span",{staticClass:"line-number"},[t._v("2")]),r("br"),r("span",{staticClass:"line-number"},[t._v("3")]),r("br"),r("span",{staticClass:"line-number"},[t._v("4")]),r("br"),r("span",{staticClass:"line-number"},[t._v("5")]),r("br")])]),r("h2",{attrs:{id:"documentation"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#documentation"}},[t._v("#")]),t._v(" Documentation")]),t._v(" "),r("p",[t._v("For usage examples of the below algorithm implementations see each module's individual page. In depth documentation also available at "),r("a",{attrs:{href:"https://nimbus-libs.status.im",target:"_blank",rel:"noopener noreferrer"}},[t._v("Nimbus Libs"),r("OutboundLink")],1),t._v(".")]),t._v(" "),r("h3",{attrs:{id:"nimcrypto-hash"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#nimcrypto-hash"}},[t._v("#")]),t._v(" "),r("RouterLink",{attrs:{to:"/lib/nimcrypto/docs/hash.html"}},[t._v("nimcrypto/hash")])],1),t._v(" "),r("p",[t._v("This module provides helper procedures for calculating secure digests supported by nimcrypto library.")]),t._v(" "),r("h3",{attrs:{id:"nimcrypto-sha2"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#nimcrypto-sha2"}},[t._v("#")]),t._v(" "),r("RouterLink",{attrs:{to:"/lib/nimcrypto/docs/sha2.html"}},[t._v("nimcrypto/sha2")])],1),t._v(" "),r("p",[t._v("This module implements SHA2 (Secure Hash Algorithm 2) set of cryptographic hash functions designed by National Security Agency, version FIPS-180-4. "),r("a",{attrs:{href:"http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf",target:"_blank",rel:"noopener noreferrer"}},[t._v("http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf"),r("OutboundLink")],1)]),t._v(" "),r("h3",{attrs:{id:"nimcrypto-ripemd"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#nimcrypto-ripemd"}},[t._v("#")]),t._v(" "),r("RouterLink",{attrs:{to:"/lib/nimcrypto/docs/ripemd.html"}},[t._v("nimcrypto/ripemd")])],1),t._v(" "),r("p",[t._v("This module implements RIPEMD set of cryptographic hash functions, designed by Hans Dobbertin, Antoon Bosselaers and Bart Preneel. "),r("a",{attrs:{href:"http://www.esat.kuleuven.be/~bosselae/ripemd160/pdf/AB-9601/AB-9601.pdf",target:"_blank",rel:"noopener noreferrer"}},[t._v("http://www.esat.kuleuven.be/~bosselae/ripemd160/pdf/AB-9601/AB-9601.pdf"),r("OutboundLink")],1)]),t._v(" "),r("p",[t._v("This module is Nim adoptation of original C source code by Antoon Bosselaers. "),r("a",{attrs:{href:"https://homes.esat.kuleuven.be/~bosselae/ripemd160/ps/AB-9601/rmd160.c",target:"_blank",rel:"noopener noreferrer"}},[t._v("https://homes.esat.kuleuven.be/~bosselae/ripemd160/ps/AB-9601/rmd160.c"),r("OutboundLink")],1)]),t._v(" "),r("p",[t._v("This module includes support of RIPEMD-128/160/256/320.")]),t._v(" "),r("h3",{attrs:{id:"nimcrypto-keccak"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#nimcrypto-keccak"}},[t._v("#")]),t._v(" "),r("RouterLink",{attrs:{to:"/lib/nimcrypto/docs/keccak.html"}},[t._v("nimcrypto/keccak")])],1),t._v(" "),r("p",[t._v("This module implements SHA3 (Secure Hash Algorithm 3) set of cryptographic hash functions designed by Guido Bertoni, Joan Daemen, Michaël Peeters and Gilles Van Assche.")]),t._v(" "),r("p",[t._v("This module supports SHA3-224/256/384/512 and SHAKE-128/256.")]),t._v(" "),r("h3",{attrs:{id:"nimcrypto-blake2"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#nimcrypto-blake2"}},[t._v("#")]),t._v(" "),r("RouterLink",{attrs:{to:"/lib/nimcrypto/docs/blake2.html"}},[t._v("nimcrypto/blake2")])],1),t._v(" "),r("p",[t._v("This module implements BLAKE2 set of cryptographic hash functions designed by Jean-Philippe Aumasson, Luca Henzen, Willi Meier, Raphael C.W. Phan.")]),t._v(" "),r("p",[t._v("This module supports BLAKE2s-224/256 and BLAKE2b-384/512.")]),t._v(" "),r("h3",{attrs:{id:"nimcrypto-hmac"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#nimcrypto-hmac"}},[t._v("#")]),t._v(" "),r("RouterLink",{attrs:{to:"/lib/nimcrypto/docs/hmac.html"}},[t._v("nimcrypto/hmac")])],1),t._v(" "),r("p",[t._v("This module implements HMAC (Keyed-Hashing for Message Authentication) "),r("a",{attrs:{href:"http://www.ietf.org/rfc/rfc2104.txt",target:"_blank",rel:"noopener noreferrer"}},[t._v("http://www.ietf.org/rfc/rfc2104.txt"),r("OutboundLink")],1),t._v(".")]),t._v(" "),r("h3",{attrs:{id:"nimcrypto-rijndael"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#nimcrypto-rijndael"}},[t._v("#")]),t._v(" "),r("RouterLink",{attrs:{to:"/lib/nimcrypto/docs/rijndael.html"}},[t._v("nimcrypto/rijndael")])],1),t._v(" "),r("p",[t._v("This module implements Rijndael(AES) crypto algorithm by Vincent Rijmen, Antoon Bosselaers and Paulo Barreto.")]),t._v(" "),r("p",[t._v("Code based on version 3.0 (December 2000) of "),r("em",[t._v("Optimised ANSI C code for the Rijndael cipher")]),t._v(" "),r("a",{attrs:{href:"http://www.fastcrypto.org/front/misc/rijndael-alg-fst.c",target:"_blank",rel:"noopener noreferrer"}},[t._v("http://www.fastcrypto.org/front/misc/rijndael-alg-fst.c"),r("OutboundLink")],1),t._v(".")]),t._v(" "),r("h3",{attrs:{id:"nimcrypto-blowfish"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#nimcrypto-blowfish"}},[t._v("#")]),t._v(" "),r("RouterLink",{attrs:{to:"/lib/nimcrypto/docs/blowfish.html"}},[t._v("nimcrypto/blowfish")])],1),t._v(" "),r("p",[t._v("This module implements Blowfish crypto algorithm by Bruce Schneier")]),t._v(" "),r("p",[t._v("Code based on "),r("em",[t._v("C implementation of the Blowfish algorithm")]),t._v(" created by Paul Kocher "),r("a",{attrs:{href:"https://www.schneier.com/code/bfsh-koc.zip",target:"_blank",rel:"noopener noreferrer"}},[t._v("https://www.schneier.com/code/bfsh-koc.zip"),r("OutboundLink")],1),t._v(".")]),t._v(" "),r("h3",{attrs:{id:"nimcrypto-twofish"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#nimcrypto-twofish"}},[t._v("#")]),t._v(" "),r("RouterLink",{attrs:{to:"/lib/nimcrypto/docs/twofish.html"}},[t._v("nimcrypto/twofish")])],1),t._v(" "),r("p",[t._v("This module implements Twofish crypto algorithm by Bruce Schneier.")]),t._v(" "),r("p",[t._v("Code based on "),r("em",[t._v("Optimized C")]),t._v(" created by Drew Csillag "),r("a",{attrs:{href:"https://www.schneier.com/code/twofish-cpy.zip",target:"_blank",rel:"noopener noreferrer"}},[t._v("https://www.schneier.com/code/twofish-cpy.zip"),r("OutboundLink")],1),t._v(".")]),t._v(" "),r("h3",{attrs:{id:"nimcrypto-bcmode"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#nimcrypto-bcmode"}},[t._v("#")]),t._v(" "),r("RouterLink",{attrs:{to:"/lib/nimcrypto/docs/bcmode.html"}},[t._v("nimcrypto/bcmode")])],1),t._v(" "),r("p",[t._v("This module implements various Block Cipher Modes.")]),t._v(" "),r("p",[t._v("The five modes currently supported:")]),t._v(" "),r("ul",[r("li",[t._v("ECB (Electronic Code Book)")]),t._v(" "),r("li",[t._v("CBC (Cipher Block Chaining)")]),t._v(" "),r("li",[t._v("CFB (Cipher FeedBack)")]),t._v(" "),r("li",[t._v("OFB (Output FeedBack)")]),t._v(" "),r("li",[t._v("CTR (Counter)")]),t._v(" "),r("li",[t._v("GCM (Galois/Counter Mode)")])]),t._v(" "),r("p",[t._v("You can use any of this modes with all the block ciphers of nimcrypto library")]),t._v(" "),r("p",[t._v("GHASH implementation is Nim version of "),r("code",[t._v("ghash_ctmul64.c")]),t._v(" which is part of decent BearSSL project "),r("a",{attrs:{href:"https://bearssl.org",target:"_blank",rel:"noopener noreferrer"}},[t._v("https://bearssl.org"),r("OutboundLink")],1),t._v(". Copyright (c) 2016 "),r("a",{attrs:{href:"mailto:pornin@bolet.org"}},[t._v("Thomas Pornin")])]),t._v(" "),r("h3",{attrs:{id:"nimcrypto-utils"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#nimcrypto-utils"}},[t._v("#")]),t._v(" "),r("RouterLink",{attrs:{to:"/lib/nimcrypto/docs/utils.html"}},[t._v("nimcrypto/utils")])],1),t._v(" "),r("p",[t._v("Utility functions common to all submodules.")]),t._v(" "),r("h3",{attrs:{id:"nimcrypto-sysrand"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#nimcrypto-sysrand"}},[t._v("#")]),t._v(" "),r("RouterLink",{attrs:{to:"/lib/nimcrypto/docs/sysrand.html"}},[t._v("nimcrypto/sysrand")])],1),t._v(" "),r("p",[t._v("This module implements interface to operation system's random number generator.")]),t._v(" "),r("p",[r("strong",[t._v("Windows")]),t._v(" using BCryptGenRandom (if available), CryptGenRandom("),r("code",[t._v("PROV_INTEL_SEC")]),t._v(") (if available), RtlGenRandom.")]),t._v(" "),r("p",[t._v("RtlGenRandom (available from Windows XP) BCryptGenRandom (available from Windows Vista SP1) CryptGenRandom(PROV_INTEL_SEC) (only when Intel SandyBridge CPU is available).")]),t._v(" "),r("p",[r("strong",[t._v("Linux")]),t._v(" using genrandom (if available), "),r("code",[t._v("/dev/urandom")]),t._v(".")]),t._v(" "),r("p",[r("strong",[t._v("OpenBSD")]),t._v(" using getentropy.")]),t._v(" "),r("p",[r("strong",[t._v("NetBSD, FreeBSD, MacOS, Solaris")]),t._v(" using "),r("code",[t._v("/dev/urandom")]),t._v(".")])])}),[],!1,null,null,null);e.default=a.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[14],{371:function(t,e,r){"use strict";r.r(e);var s=r(44),a=Object(s.a)({},(function(){var t=this,e=t.$createElement,r=t._self._c||e;return r("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[r("h1",{attrs:{id:"nimcrypto"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#nimcrypto"}},[t._v("#")]),t._v(" Nimcrypto")]),t._v(" "),r("p",[t._v("Nimcrypto is Nim's cryptographic library. It implements several popular cryptographic algorithms and their tests with some "),r("a",{attrs:{href:"https://github.com/cheatfate/nimcrypto/tree/master/examples",target:"_blank",rel:"noopener noreferrer"}},[t._v("examples"),r("OutboundLink")],1),t._v(".")]),t._v(" "),r("p",[t._v("Most notably, this library has been used in the "),r("a",{attrs:{href:"https://our.status.im/nimbus-for-newbies/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Nimbus Ethereum client"),r("OutboundLink")],1),t._v(". To see the implementation, check out its "),r("a",{attrs:{href:"https://github.com/status-im/nimbus",target:"_blank",rel:"noopener noreferrer"}},[t._v("Github repository"),r("OutboundLink")],1),t._v(".")]),t._v(" "),r("h2",{attrs:{id:"the-most-basic-usage"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#the-most-basic-usage"}},[t._v("#")]),t._v(" The most basic usage")]),t._v(" "),r("div",{staticClass:"language-bash line-numbers-mode"},[r("pre",{pre:!0,attrs:{class:"language-bash"}},[r("code",[t._v("nimble "),r("span",{pre:!0,attrs:{class:"token function"}},[t._v("install")]),t._v(" nimcrypto "),r("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# installation")]),t._v("\n")])]),t._v(" "),r("div",{staticClass:"line-numbers-wrapper"},[r("span",{staticClass:"line-number"},[t._v("1")]),r("br")])]),r("div",{staticClass:"language-nim line-numbers-mode"},[r("pre",{pre:!0,attrs:{class:"language-nim"}},[r("code",[r("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# example.nim")]),t._v("\n"),r("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" nimcrypto\n\necho keccak_256"),r("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),r("span",{pre:!0,attrs:{class:"token function"}},[t._v("digest")]),r("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),r("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Alice makes a hash"')]),r("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" \n"),r("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# outputs EF0CC652868DF797522FB1D5A39E58E069154D9E47E5D7DB288B7200DB6EDFEE")]),t._v("\n")])]),t._v(" "),r("div",{staticClass:"line-numbers-wrapper"},[r("span",{staticClass:"line-number"},[t._v("1")]),r("br"),r("span",{staticClass:"line-number"},[t._v("2")]),r("br"),r("span",{staticClass:"line-number"},[t._v("3")]),r("br"),r("span",{staticClass:"line-number"},[t._v("4")]),r("br"),r("span",{staticClass:"line-number"},[t._v("5")]),r("br")])]),r("h2",{attrs:{id:"documentation"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#documentation"}},[t._v("#")]),t._v(" Documentation")]),t._v(" "),r("p",[t._v("For usage examples of the below algorithm implementations see each module's individual page. In depth documentation also available at "),r("a",{attrs:{href:"https://nimbus-libs.status.im",target:"_blank",rel:"noopener noreferrer"}},[t._v("Nimbus Libs"),r("OutboundLink")],1),t._v(".")]),t._v(" "),r("h3",{attrs:{id:"nimcrypto-hash"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#nimcrypto-hash"}},[t._v("#")]),t._v(" "),r("RouterLink",{attrs:{to:"/lib/nimcrypto/docs/hash.html"}},[t._v("nimcrypto/hash")])],1),t._v(" "),r("p",[t._v("This module provides helper procedures for calculating secure digests supported by nimcrypto library.")]),t._v(" "),r("h3",{attrs:{id:"nimcrypto-sha2"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#nimcrypto-sha2"}},[t._v("#")]),t._v(" "),r("RouterLink",{attrs:{to:"/lib/nimcrypto/docs/sha2.html"}},[t._v("nimcrypto/sha2")])],1),t._v(" "),r("p",[t._v("This module implements SHA2 (Secure Hash Algorithm 2) set of cryptographic hash functions designed by National Security Agency, version FIPS-180-4. "),r("a",{attrs:{href:"http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf",target:"_blank",rel:"noopener noreferrer"}},[t._v("http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf"),r("OutboundLink")],1)]),t._v(" "),r("h3",{attrs:{id:"nimcrypto-ripemd"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#nimcrypto-ripemd"}},[t._v("#")]),t._v(" "),r("RouterLink",{attrs:{to:"/lib/nimcrypto/docs/ripemd.html"}},[t._v("nimcrypto/ripemd")])],1),t._v(" "),r("p",[t._v("This module implements RIPEMD set of cryptographic hash functions, designed by Hans Dobbertin, Antoon Bosselaers and Bart Preneel. "),r("a",{attrs:{href:"http://www.esat.kuleuven.be/~bosselae/ripemd160/pdf/AB-9601/AB-9601.pdf",target:"_blank",rel:"noopener noreferrer"}},[t._v("http://www.esat.kuleuven.be/~bosselae/ripemd160/pdf/AB-9601/AB-9601.pdf"),r("OutboundLink")],1)]),t._v(" "),r("p",[t._v("This module is Nim adoptation of original C source code by Antoon Bosselaers. "),r("a",{attrs:{href:"https://homes.esat.kuleuven.be/~bosselae/ripemd160/ps/AB-9601/rmd160.c",target:"_blank",rel:"noopener noreferrer"}},[t._v("https://homes.esat.kuleuven.be/~bosselae/ripemd160/ps/AB-9601/rmd160.c"),r("OutboundLink")],1)]),t._v(" "),r("p",[t._v("This module includes support of RIPEMD-128/160/256/320.")]),t._v(" "),r("h3",{attrs:{id:"nimcrypto-keccak"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#nimcrypto-keccak"}},[t._v("#")]),t._v(" "),r("RouterLink",{attrs:{to:"/lib/nimcrypto/docs/keccak.html"}},[t._v("nimcrypto/keccak")])],1),t._v(" "),r("p",[t._v("This module implements SHA3 (Secure Hash Algorithm 3) set of cryptographic hash functions designed by Guido Bertoni, Joan Daemen, Michaël Peeters and Gilles Van Assche.")]),t._v(" "),r("p",[t._v("This module supports SHA3-224/256/384/512 and SHAKE-128/256.")]),t._v(" "),r("h3",{attrs:{id:"nimcrypto-blake2"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#nimcrypto-blake2"}},[t._v("#")]),t._v(" "),r("RouterLink",{attrs:{to:"/lib/nimcrypto/docs/blake2.html"}},[t._v("nimcrypto/blake2")])],1),t._v(" "),r("p",[t._v("This module implements BLAKE2 set of cryptographic hash functions designed by Jean-Philippe Aumasson, Luca Henzen, Willi Meier, Raphael C.W. Phan.")]),t._v(" "),r("p",[t._v("This module supports BLAKE2s-224/256 and BLAKE2b-384/512.")]),t._v(" "),r("h3",{attrs:{id:"nimcrypto-hmac"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#nimcrypto-hmac"}},[t._v("#")]),t._v(" "),r("RouterLink",{attrs:{to:"/lib/nimcrypto/docs/hmac.html"}},[t._v("nimcrypto/hmac")])],1),t._v(" "),r("p",[t._v("This module implements HMAC (Keyed-Hashing for Message Authentication) "),r("a",{attrs:{href:"http://www.ietf.org/rfc/rfc2104.txt",target:"_blank",rel:"noopener noreferrer"}},[t._v("http://www.ietf.org/rfc/rfc2104.txt"),r("OutboundLink")],1),t._v(".")]),t._v(" "),r("h3",{attrs:{id:"nimcrypto-rijndael"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#nimcrypto-rijndael"}},[t._v("#")]),t._v(" "),r("RouterLink",{attrs:{to:"/lib/nimcrypto/docs/rijndael.html"}},[t._v("nimcrypto/rijndael")])],1),t._v(" "),r("p",[t._v("This module implements Rijndael(AES) crypto algorithm by Vincent Rijmen, Antoon Bosselaers and Paulo Barreto.")]),t._v(" "),r("p",[t._v("Code based on version 3.0 (December 2000) of "),r("em",[t._v("Optimised ANSI C code for the Rijndael cipher")]),t._v(" "),r("a",{attrs:{href:"http://www.fastcrypto.org/front/misc/rijndael-alg-fst.c",target:"_blank",rel:"noopener noreferrer"}},[t._v("http://www.fastcrypto.org/front/misc/rijndael-alg-fst.c"),r("OutboundLink")],1),t._v(".")]),t._v(" "),r("h3",{attrs:{id:"nimcrypto-blowfish"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#nimcrypto-blowfish"}},[t._v("#")]),t._v(" "),r("RouterLink",{attrs:{to:"/lib/nimcrypto/docs/blowfish.html"}},[t._v("nimcrypto/blowfish")])],1),t._v(" "),r("p",[t._v("This module implements Blowfish crypto algorithm by Bruce Schneier")]),t._v(" "),r("p",[t._v("Code based on "),r("em",[t._v("C implementation of the Blowfish algorithm")]),t._v(" created by Paul Kocher "),r("a",{attrs:{href:"https://www.schneier.com/code/bfsh-koc.zip",target:"_blank",rel:"noopener noreferrer"}},[t._v("https://www.schneier.com/code/bfsh-koc.zip"),r("OutboundLink")],1),t._v(".")]),t._v(" "),r("h3",{attrs:{id:"nimcrypto-twofish"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#nimcrypto-twofish"}},[t._v("#")]),t._v(" "),r("RouterLink",{attrs:{to:"/lib/nimcrypto/docs/twofish.html"}},[t._v("nimcrypto/twofish")])],1),t._v(" "),r("p",[t._v("This module implements Twofish crypto algorithm by Bruce Schneier.")]),t._v(" "),r("p",[t._v("Code based on "),r("em",[t._v("Optimized C")]),t._v(" created by Drew Csillag "),r("a",{attrs:{href:"https://www.schneier.com/code/twofish-cpy.zip",target:"_blank",rel:"noopener noreferrer"}},[t._v("https://www.schneier.com/code/twofish-cpy.zip"),r("OutboundLink")],1),t._v(".")]),t._v(" "),r("h3",{attrs:{id:"nimcrypto-bcmode"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#nimcrypto-bcmode"}},[t._v("#")]),t._v(" "),r("RouterLink",{attrs:{to:"/lib/nimcrypto/docs/bcmode.html"}},[t._v("nimcrypto/bcmode")])],1),t._v(" "),r("p",[t._v("This module implements various Block Cipher Modes.")]),t._v(" "),r("p",[t._v("The five modes currently supported:")]),t._v(" "),r("ul",[r("li",[t._v("ECB (Electronic Code Book)")]),t._v(" "),r("li",[t._v("CBC (Cipher Block Chaining)")]),t._v(" "),r("li",[t._v("CFB (Cipher FeedBack)")]),t._v(" "),r("li",[t._v("OFB (Output FeedBack)")]),t._v(" "),r("li",[t._v("CTR (Counter)")]),t._v(" "),r("li",[t._v("GCM (Galois/Counter Mode)")])]),t._v(" "),r("p",[t._v("You can use any of this modes with all the block ciphers of nimcrypto library")]),t._v(" "),r("p",[t._v("GHASH implementation is Nim version of "),r("code",[t._v("ghash_ctmul64.c")]),t._v(" which is part of decent BearSSL project "),r("a",{attrs:{href:"https://bearssl.org",target:"_blank",rel:"noopener noreferrer"}},[t._v("https://bearssl.org"),r("OutboundLink")],1),t._v(". Copyright (c) 2016 "),r("a",{attrs:{href:"mailto:pornin@bolet.org"}},[t._v("Thomas Pornin")])]),t._v(" "),r("h3",{attrs:{id:"nimcrypto-utils"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#nimcrypto-utils"}},[t._v("#")]),t._v(" "),r("RouterLink",{attrs:{to:"/lib/nimcrypto/docs/utils.html"}},[t._v("nimcrypto/utils")])],1),t._v(" "),r("p",[t._v("Utility functions common to all submodules.")]),t._v(" "),r("h3",{attrs:{id:"nimcrypto-sysrand"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#nimcrypto-sysrand"}},[t._v("#")]),t._v(" "),r("RouterLink",{attrs:{to:"/lib/nimcrypto/docs/sysrand.html"}},[t._v("nimcrypto/sysrand")])],1),t._v(" "),r("p",[t._v("This module implements interface to operation system's random number generator.")]),t._v(" "),r("p",[r("strong",[t._v("Windows")]),t._v(" using BCryptGenRandom (if available), CryptGenRandom("),r("code",[t._v("PROV_INTEL_SEC")]),t._v(") (if available), RtlGenRandom.")]),t._v(" "),r("p",[t._v("RtlGenRandom (available from Windows XP) BCryptGenRandom (available from Windows Vista SP1) CryptGenRandom(PROV_INTEL_SEC) (only when Intel SandyBridge CPU is available).")]),t._v(" "),r("p",[r("strong",[t._v("Linux")]),t._v(" using genrandom (if available), "),r("code",[t._v("/dev/urandom")]),t._v(".")]),t._v(" "),r("p",[r("strong",[t._v("OpenBSD")]),t._v(" using getentropy.")]),t._v(" "),r("p",[r("strong",[t._v("NetBSD, FreeBSD, MacOS, Solaris")]),t._v(" using "),r("code",[t._v("/dev/urandom")]),t._v(".")])])}),[],!1,null,null,null);e.default=a.exports}}]); \ No newline at end of file diff --git a/assets/js/2.8e6705b7.js b/assets/js/2.8e6705b7.js deleted file mode 100644 index 048564a..0000000 --- a/assets/js/2.8e6705b7.js +++ /dev/null @@ -1 +0,0 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[2],Array(143).concat([function(t,e,n){"use strict";n.d(e,"d",(function(){return i})),n.d(e,"a",(function(){return a})),n.d(e,"i",(function(){return s})),n.d(e,"f",(function(){return u})),n.d(e,"g",(function(){return l})),n.d(e,"h",(function(){return c})),n.d(e,"b",(function(){return f})),n.d(e,"e",(function(){return h})),n.d(e,"k",(function(){return p})),n.d(e,"l",(function(){return d})),n.d(e,"c",(function(){return g})),n.d(e,"j",(function(){return v}));n(17),n(66),n(103),n(160),n(169),n(40),n(29),n(144),n(41),n(170),n(67);var i=/#.*$/,r=/\.(md|html)$/,a=/\/$/,s=/^[a-z]+:/i;function o(t){return decodeURI(t).replace(i,"").replace(r,"")}function u(t){return s.test(t)}function l(t){return/^mailto:/.test(t)}function c(t){return/^tel:/.test(t)}function f(t){if(u(t))return t;var e=t.match(i),n=e?e[0]:"",r=o(t);return a.test(r)?t:r+".html"+n}function h(t,e){var n=decodeURIComponent(t.hash),r=function(t){var e=t.match(i);if(e)return e[0]}(e);return(!r||n===r)&&o(t.path)===o(e)}function p(t,e,n){if(u(e))return{type:"external",path:e};n&&(e=function(t,e,n){var i=t.charAt(0);if("/"===i)return t;if("?"===i||"#"===i)return e+t;var r=e.split("/");n&&r[r.length-1]||r.pop();for(var a=t.replace(/^\//,"").split("/"),s=0;s3&&void 0!==arguments[3]?arguments[3]:1;if("string"==typeof e)return p(n,e,i);if(Array.isArray(e))return Object.assign(p(n,e[0],i),{title:e[1]});r>3&&console.error("[vuepress] detected a too deep nested sidebar group.");var a=e.children||[];return 0===a.length&&e.path?Object.assign(p(n,e.path,i),{title:e.title}):{type:"group",path:e.path,title:e.title,sidebarDepth:e.sidebarDepth,children:a.map((function(e){return t(e,n,i,r+1)})),collapsable:!1!==e.collapsable}}(t,r,l)})):[]}return[]}function g(t){var e;return(t=t.map((function(t){return Object.assign({},t)}))).forEach((function(t){2===t.level?e=t:e&&(e.children||(e.children=[])).push(t)})),t.filter((function(t){return 2===t.level}))}function v(t){return Object.assign(t,{type:t.items&&t.items.length?"links":"link"})}},function(t,e,n){"use strict";var i=n(100),r=n(8),a=n(12),s=n(16),o=n(101),u=n(102);i("match",1,(function(t,e,n){return[function(e){var n=s(this),i=null==e?void 0:e[t];return void 0!==i?i.call(e,n):new RegExp(e)[t](String(n))},function(t){var i=n(e,t,this);if(i.done)return i.value;var s=r(t),l=String(this);if(!s.global)return u(s,l);var c=s.unicode;s.lastIndex=0;for(var f,h=[],p=0;null!==(f=u(s,l));){var d=String(f[0]);h[p]=d,""===d&&(s.lastIndex=o(l,a(s.lastIndex),c)),p++}return 0===p?null:h}]}))},function(t,e,n){},function(t,e){t.exports="\t\n\v\f\r                 \u2028\u2029\ufeff"},function(t,e,n){},function(t,e,n){},function(t,e,n){},function(t,e,n){},function(t,e,n){},function(t,e,n){},function(t,e,n){},function(t,e,n){},function(t,e,n){},function(t,e,n){},function(t,e,n){},function(t,e,n){},,function(t,e,n){n(0)({target:"Array",stat:!0},{isArray:n(42)})},function(t,e,n){var i=n(16),r="["+n(146)+"]",a=RegExp("^"+r+r+"*"),s=RegExp(r+r+"*$"),o=function(t){return function(e){var n=String(i(e));return 1&t&&(n=n.replace(a,"")),2&t&&(n=n.replace(s,"")),n}};t.exports={start:o(1),end:o(2),trim:o(3)}},function(t,e){t.exports=function(t){return null==t}},function(t,e,n){var i=n(190).Symbol;t.exports=i},function(t,e,n){"use strict";n.r(e);n(97);var i=n(143),r={name:"SidebarGroup",components:{DropdownTransition:n(165).a},props:["item","open","collapsable","depth"],beforeCreate:function(){this.$options.components.SidebarLinks=n(164).default},methods:{isActive:i.e}},a=(n(198),n(28)),s=Object(a.a)(r,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("section",{staticClass:"sidebar-group",class:[{collapsable:t.collapsable,"is-sub-group":0!==t.depth},"depth-"+t.depth]},[t.item.path?n("RouterLink",{staticClass:"sidebar-heading clickable",class:{open:t.open,active:t.isActive(t.$route,t.item.path)},attrs:{to:t.item.path},nativeOn:{click:function(e){return t.$emit("toggle")}}},[n("span",[t._v(t._s(t.item.title))]),t._v(" "),t.collapsable?n("span",{staticClass:"arrow",class:t.open?"down":"right"}):t._e()]):n("p",{staticClass:"sidebar-heading",class:{open:t.open},on:{click:function(e){return t.$emit("toggle")}}},[n("span",[t._v(t._s(t.item.title))]),t._v(" "),t.collapsable?n("span",{staticClass:"arrow",class:t.open?"down":"right"}):t._e()]),t._v(" "),n("DropdownTransition",[t.open||!t.collapsable?n("SidebarLinks",{staticClass:"sidebar-group-items",attrs:{items:t.item.children,"sidebar-depth":t.item.sidebarDepth,depth:t.depth+1}}):t._e()],1)],1)}),[],!1,null,null,null).exports;n(199),n(40);function o(t,e,n,i,r){var a={props:{to:e,activeClass:"",exactActiveClass:""},class:{active:i,"sidebar-link":!0}};return r>2&&(a.style={"padding-left":r+"rem"}),t("RouterLink",a,n)}function u(t,e,n,r,a){var s=arguments.length>5&&void 0!==arguments[5]?arguments[5]:1;return!e||s>a?null:t("ul",{class:"sidebar-sub-headers"},e.map((function(e){var l=Object(i.e)(r,n+"#"+e.slug);return t("li",{class:"sidebar-sub-header"},[o(t,n+"#"+e.slug,e.title,l,e.level-1),u(t,e.children,n,r,a,s+1)])})))}var l={functional:!0,props:["item","sidebarDepth"],render:function(t,e){var n=e.parent,r=n.$page,a=(n.$site,n.$route),s=n.$themeConfig,l=n.$themeLocaleConfig,c=e.props,f=c.item,h=c.sidebarDepth,p=Object(i.e)(a,f.path),d="auto"===f.type?p||f.children.some((function(t){return Object(i.e)(a,f.basePath+"#"+t.slug)})):p,g="external"===f.type?function(t,e,n){return t("a",{attrs:{href:e,target:"_blank",rel:"noopener noreferrer"},class:{"sidebar-link":!0}},[n,t("OutboundLink")])}(t,f.path,f.title||f.path):o(t,f.path,f.title||f.path,d),v=[r.frontmatter.sidebarDepth,h,l.sidebarDepth,s.sidebarDepth,1].find((function(t){return void 0!==t})),m=l.displayAllHeaders||s.displayAllHeaders;return"auto"===f.type?[g,u(t,f.children,f.basePath,a,v)]:(d||m)&&f.headers&&!i.d.test(f.path)?[g,u(t,Object(i.c)(f.headers),f.path,a,v)]:g}};n(200);function c(t,e){return"group"===e.type&&e.children.some((function(e){return"group"===e.type?c(t,e):"page"===e.type&&Object(i.e)(t,e.path)}))}var f={name:"SidebarLinks",components:{SidebarGroup:s,SidebarLink:Object(a.a)(l,void 0,void 0,!1,null,null,null).exports},props:["items","depth","sidebarDepth"],data:function(){return{openGroupIndex:0}},watch:{$route:function(){this.refreshIndex()}},created:function(){this.refreshIndex()},methods:{refreshIndex:function(){var t=function(t,e){for(var n=0;n-1&&(this.openGroupIndex=t)},toggleGroup:function(t){this.openGroupIndex=t===this.openGroupIndex?-1:t},isActive:function(t){return Object(i.e)(this.$route,t.regularPath)}}},h=Object(a.a)(f,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return t.items.length?n("ul",{staticClass:"sidebar-links"},t._l(t.items,(function(e,i){return n("li",{key:i},["group"===e.type?n("SidebarGroup",{attrs:{item:e,open:i===t.openGroupIndex,collapsable:e.collapsable||e.collapsible,depth:t.depth},on:{toggle:function(e){return t.toggleGroup(i)}}}):n("SidebarLink",{attrs:{"sidebar-depth":t.sidebarDepth,item:e}})],1)})),0):t._e()}),[],!1,null,null,null);e.default=h.exports},function(t,e,n){"use strict";var i={name:"DropdownTransition",methods:{setHeight:function(t){t.style.height=t.scrollHeight+"px"},unsetHeight:function(t){t.style.height=""}}},r=(n(182),n(28)),a=Object(r.a)(i,(function(){var t=this.$createElement;return(this._self._c||t)("transition",{attrs:{name:"dropdown"},on:{enter:this.setHeight,"after-enter":this.unsetHeight,"before-leave":this.setHeight}},[this._t("default")],2)}),[],!1,null,null,null);e.a=a.exports},function(t,e,n){"use strict";var i=n(0),r=n(167);i({target:"String",proto:!0,forced:n(168)("link")},{link:function(t){return r(this,"a","href",t)}})},function(t,e,n){var i=n(16),r=/"/g;t.exports=function(t,e,n,a){var s=String(i(t)),o="<"+e;return""!==n&&(o+=" "+n+'="'+String(a).replace(r,""")+'"'),o+">"+s+""}},function(t,e,n){var i=n(2);t.exports=function(t){return i((function(){var e=""[t]('"');return e!==e.toLowerCase()||e.split('"').length>3}))}},function(t,e,n){"use strict";var i=n(0),r=n(43),a=n(10),s=n(30),o=[].join,u=r!=Object,l=s("join",",");i({target:"Array",proto:!0,forced:u||!l},{join:function(t){return o.call(a(this),void 0===t?",":t)}})},function(t,e,n){"use strict";var i=n(100),r=n(98),a=n(8),s=n(16),o=n(171),u=n(101),l=n(12),c=n(102),f=n(46),h=n(2),p=[].push,d=Math.min,g=!h((function(){return!RegExp(4294967295,"y")}));i("split",2,(function(t,e,n){var i;return i="c"=="abbc".split(/(b)*/)[1]||4!="test".split(/(?:)/,-1).length||2!="ab".split(/(?:ab)*/).length||4!=".".split(/(.?)(.?)/).length||".".split(/()()/).length>1||"".split(/.?/).length?function(t,n){var i=String(s(this)),a=void 0===n?4294967295:n>>>0;if(0===a)return[];if(void 0===t)return[i];if(!r(t))return e.call(i,t,a);for(var o,u,l,c=[],h=(t.ignoreCase?"i":"")+(t.multiline?"m":"")+(t.unicode?"u":"")+(t.sticky?"y":""),d=0,g=new RegExp(t.source,h+"g");(o=f.call(g,i))&&!((u=g.lastIndex)>d&&(c.push(i.slice(d,o.index)),o.length>1&&o.index=a));)g.lastIndex===o.index&&g.lastIndex++;return d===i.length?!l&&g.test("")||c.push(""):c.push(i.slice(d)),c.length>a?c.slice(0,a):c}:"0".split(void 0,0).length?function(t,n){return void 0===t&&0===n?[]:e.call(this,t,n)}:e,[function(e,n){var r=s(this),a=null==e?void 0:e[t];return void 0!==a?a.call(e,r,n):i.call(String(r),e,n)},function(t,r){var s=n(i,t,this,r,i!==e);if(s.done)return s.value;var f=a(t),h=String(this),p=o(f,RegExp),v=f.unicode,m=(f.ignoreCase?"i":"")+(f.multiline?"m":"")+(f.unicode?"u":"")+(g?"y":"g"),b=new p(g?f:"^(?:"+f.source+")",m),k=void 0===r?4294967295:r>>>0;if(0===k)return[];if(0===h.length)return null===c(b,h)?[h]:[];for(var _=0,x=0,y=[];x>>0||(o.test(n)?16:10))}:s},function(t,e,n){"use strict";var i=n(0),r=n(161).trim;i({target:"String",proto:!0,forced:n(176)("trim")},{trim:function(){return r(this)}})},function(t,e,n){var i=n(2),r=n(146);t.exports=function(t){return i((function(){return!!r[t]()||"​…᠎"!="​…᠎"[t]()||r[t].name!==t}))}},function(t,e,n){"use strict";var i=n(147);n.n(i).a},function(t,e,n){"use strict";var i=n(148);n.n(i).a},function(t,e,n){"use strict";var i=n(0),r=n(2),a=n(42),s=n(4),o=n(14),u=n(12),l=n(64),c=n(104),f=n(45),h=n(1),p=n(105),d=h("isConcatSpreadable"),g=p>=51||!r((function(){var t=[];return t[d]=!1,t.concat()[0]!==t})),v=f("concat"),m=function(t){if(!s(t))return!1;var e=t[d];return void 0!==e?!!e:a(t)};i({target:"Array",proto:!0,forced:!g||!v},{concat:function(t){var e,n,i,r,a,s=o(this),f=c(s,0),h=0;for(e=-1,i=arguments.length;e9007199254740991)throw TypeError("Maximum allowed index exceeded");for(n=0;n=9007199254740991)throw TypeError("Maximum allowed index exceeded");l(f,h++,a)}return f.length=h,f}})},function(t,e,n){var i=n(6),r=n(3),a=n(62),s=n(109),o=n(7).f,u=n(44).f,l=n(98),c=n(99),f=n(107),h=n(13),p=n(2),d=n(18).set,g=n(110),v=n(1)("match"),m=r.RegExp,b=m.prototype,k=/a/g,_=/a/g,x=new m(k)!==k,y=f.UNSUPPORTED_Y;if(i&&a("RegExp",!x||y||p((function(){return _[v]=!1,m(k)!=k||m(_)==_||"/a/i"!=m(k,"i")})))){for(var C=function(t,e){var n,i=this instanceof C,r=l(t),a=void 0===e;if(!i&&r&&t.constructor===C&&a)return t;x?r&&!a&&(t=t.source):t instanceof C&&(a&&(e=c.call(t)),t=t.source),y&&(n=!!e&&e.indexOf("y")>-1)&&(e=e.replace(/y/g,""));var o=s(x?new m(t,e):m(t,e),i?this:b,C);return y&&n&&d(o,{sticky:n}),o},$=function(t){t in C||o(C,t,{configurable:!0,get:function(){return m[t]},set:function(e){m[t]=e}})},L=u(m),S=0;L.length>S;)$(L[S++]);b.constructor=C,C.prototype=b,h(r,"RegExp",C)}g("RegExp")},function(t,e,n){"use strict";var i=n(13),r=n(8),a=n(2),s=n(99),o=RegExp.prototype,u=o.toString,l=a((function(){return"/a/b"!=u.call({source:"a",flags:"b"})})),c="toString"!=u.name;(l||c)&&i(RegExp.prototype,"toString",(function(){var t=r(this),e=String(t.source),n=t.flags;return"/"+e+"/"+String(void 0===n&&t instanceof RegExp&&!("flags"in o)?s.call(t):n)}),{unsafe:!0})},function(t,e,n){"use strict";var i=n(149);n.n(i).a},function(t,e){t.exports=function(t){var e=null==t?0:t.length;return e?t[e-1]:void 0}},function(t,e,n){"use strict";var i=n(150);n.n(i).a},function(t,e,n){"use strict";var i=n(151);n.n(i).a},function(t,e,n){"use strict";var i=n(152);n.n(i).a},function(t,e,n){"use strict";var i=n(153);n.n(i).a},function(t,e,n){var i=n(189),r=n(194),a=n(195);t.exports=function(t){return"string"==typeof t||!r(t)&&a(t)&&"[object String]"==i(t)}},function(t,e,n){var i=n(163),r=n(192),a=n(193),s=i?i.toStringTag:void 0;t.exports=function(t){return null==t?void 0===t?"[object Undefined]":"[object Null]":s&&s in Object(t)?r(t):a(t)}},function(t,e,n){var i=n(191),r="object"==typeof self&&self&&self.Object===Object&&self,a=i||r||Function("return this")();t.exports=a},function(t,e){var n="object"==typeof global&&global&&global.Object===Object&&global;t.exports=n},function(t,e,n){var i=n(163),r=Object.prototype,a=r.hasOwnProperty,s=r.toString,o=i?i.toStringTag:void 0;t.exports=function(t){var e=a.call(t,o),n=t[o];try{t[o]=void 0;var i=!0}catch(t){}var r=s.call(t);return i&&(e?t[o]=n:delete t[o]),r}},function(t,e){var n=Object.prototype.toString;t.exports=function(t){return n.call(t)}},function(t,e){var n=Array.isArray;t.exports=n},function(t,e){t.exports=function(t){return null!=t&&"object"==typeof t}},function(t,e,n){"use strict";var i=n(154);n.n(i).a},function(t,e,n){"use strict";var i=n(155);n.n(i).a},function(t,e,n){"use strict";var i=n(156);n.n(i).a},function(t,e,n){"use strict";var i=n(0),r=n(19).find,a=n(65),s=n(11),o=!0,u=s("find");"find"in[]&&Array(1).find((function(){o=!1})),i({target:"Array",proto:!0,forced:o||!u},{find:function(t){return r(this,t,arguments.length>1?arguments[1]:void 0)}}),a("find")},function(t,e,n){"use strict";var i=n(157);n.n(i).a},function(t,e,n){"use strict";var i=n(158);n.n(i).a},,function(t,e,n){"use strict";n.r(e);n(97),n(61),n(166);var i=n(143),r={name:"NavLink",props:{item:{required:!0}},computed:{link:function(){return Object(i.b)(this.item.link)},exact:function(){var t=this;return this.$site.locales?Object.keys(this.$site.locales).some((function(e){return e===t.link})):"/"===this.link},isNonHttpURI:function(){return Object(i.g)(this.link)||Object(i.h)(this.link)},isBlankTarget:function(){return"_blank"===this.target},isInternal:function(){return!Object(i.f)(this.link)&&!this.isBlankTarget},target:function(){return this.isNonHttpURI?null:this.item.target?this.item.target:Object(i.f)(this.link)?"_blank":""},rel:function(){return this.isNonHttpURI?null:this.item.rel?this.item.rel:this.isBlankTarget?"noopener noreferrer":""}},methods:{focusoutAction:function(){this.$emit("focusout")}}},a=n(28),s=Object(a.a)(r,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return t.isInternal?n("RouterLink",{staticClass:"nav-link",attrs:{to:t.link,exact:t.exact},nativeOn:{focusout:function(e){return t.focusoutAction(e)}}},[t._v("\n "+t._s(t.item.text)+"\n")]):n("a",{staticClass:"nav-link external",attrs:{href:t.link,target:t.target,rel:t.rel},on:{focusout:t.focusoutAction}},[t._v("\n "+t._s(t.item.text)+"\n "),t.isBlankTarget?n("OutboundLink"):t._e()],1)}),[],!1,null,null,null).exports,o={name:"Home",components:{NavLink:s},computed:{data:function(){return this.$page.frontmatter},actionLink:function(){return{link:this.data.actionLink,text:this.data.actionText}}}},u=(n(172),Object(a.a)(o,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("main",{staticClass:"home",attrs:{"aria-labelledby":"main-title"}},[n("header",{staticClass:"hero"},[t.data.heroImage?n("img",{attrs:{src:t.$withBase(t.data.heroImage),alt:t.data.heroAlt||"hero"}}):t._e(),t._v(" "),null!==t.data.heroText?n("h1",{attrs:{id:"main-title"}},[t._v("\n "+t._s(t.data.heroText||t.$title||"Hello")+"\n ")]):t._e(),t._v(" "),null!==t.data.tagline?n("p",{staticClass:"description"},[t._v("\n "+t._s(t.data.tagline||t.$description||"Welcome to your VuePress site")+"\n ")]):t._e(),t._v(" "),t.data.actionText&&t.data.actionLink?n("p",{staticClass:"action"},[n("NavLink",{staticClass:"action-button",attrs:{item:t.actionLink}})],1):t._e()]),t._v(" "),t.data.features&&t.data.features.length?n("div",{staticClass:"features"},t._l(t.data.features,(function(e,i){return n("div",{key:i,staticClass:"feature"},[n("h2",[t._v(t._s(e.title))]),t._v(" "),n("p",[t._v(t._s(e.details))])])})),0):t._e(),t._v(" "),n("Content",{staticClass:"theme-default-content custom"}),t._v(" "),t.data.footer?n("div",{staticClass:"footer"},[t._v("\n "+t._s(t.data.footer)+"\n ")]):t._e()],1)}),[],!1,null,null,null).exports),l=(n(173),n(17),n(106),n(103),n(160),n(29),n(108),n(144),n(175),{name:"SearchBox",data:function(){return{query:"",focused:!1,focusIndex:0,placeholder:void 0}},computed:{showSuggestions:function(){return this.focused&&this.suggestions&&this.suggestions.length},suggestions:function(){var t=this.query.trim().toLowerCase();if(t){for(var e=this.$site.pages,n=this.$site.themeConfig.searchMaxSuggestions||5,i=this.$localePath,r=function(e){return e&&e.title&&e.title.toLowerCase().indexOf(t)>-1},a=[],s=0;s=n);s++){var o=e[s];if(this.getPageLocalePath(o)===i&&this.isSearchable(o))if(r(o))a.push(o);else if(o.headers)for(var u=0;u=n);u++){var l=o.headers[u];r(l)&&a.push(Object.assign({},o,{path:o.path+"#"+l.slug,header:l}))}}return a}},alignRight:function(){return(this.$site.themeConfig.nav||[]).length+(this.$site.repo?1:0)<=2}},mounted:function(){this.placeholder=this.$site.themeConfig.searchPlaceholder||"",document.addEventListener("keydown",this.onHotkey)},beforeDestroy:function(){document.removeEventListener("keydown",this.onHotkey)},methods:{getPageLocalePath:function(t){for(var e in this.$site.locales||{})if("/"!==e&&0===t.path.indexOf(e))return e;return"/"},isSearchable:function(t){var e=null;return null===e||(e=Array.isArray(e)?e:new Array(e)).filter((function(e){return t.path.match(e)})).length>0},onHotkey:function(t){t.srcElement===document.body&&["s","/"].includes(t.key)&&(this.$refs.input.focus(),t.preventDefault())},onUp:function(){this.showSuggestions&&(this.focusIndex>0?this.focusIndex--:this.focusIndex=this.suggestions.length-1)},onDown:function(){this.showSuggestions&&(this.focusIndex "+t._s(e.header.title))]):t._e()])])})),0):t._e()])}),[],!1,null,null,null).exports),f=(n(178),Object(a.a)({},(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"sidebar-button",on:{click:function(e){return t.$emit("toggle-sidebar")}}},[n("svg",{staticClass:"icon",attrs:{xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",role:"img",viewBox:"0 0 448 512"}},[n("path",{attrs:{fill:"currentColor",d:"M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"}})])])}),[],!1,null,null,null).exports),h=(n(179),n(40),n(180),n(181),n(41),n(38)),p=n(165),d=n(183),g=n.n(d),v={name:"DropdownLink",components:{NavLink:s,DropdownTransition:p.a},props:{item:{required:!0}},data:function(){return{open:!1}},computed:{dropdownAriaLabel:function(){return this.item.ariaLabel||this.item.text}},watch:{$route:function(){this.open=!1}},methods:{setOpen:function(t){this.open=t},isLastItemOfArray:function(t,e){return g()(e)===t}}},m=(n(184),{name:"NavLinks",components:{NavLink:s,DropdownLink:Object(a.a)(v,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"dropdown-wrapper",class:{open:t.open}},[n("button",{staticClass:"dropdown-title",attrs:{type:"button","aria-label":t.dropdownAriaLabel},on:{click:function(e){return t.setOpen(!t.open)}}},[n("span",{staticClass:"title"},[t._v(t._s(t.item.text))]),t._v(" "),n("span",{staticClass:"arrow",class:t.open?"down":"right"})]),t._v(" "),n("DropdownTransition",[n("ul",{directives:[{name:"show",rawName:"v-show",value:t.open,expression:"open"}],staticClass:"nav-dropdown"},t._l(t.item.items,(function(e,i){return n("li",{key:e.link||i,staticClass:"dropdown-item"},["links"===e.type?n("h4",[t._v("\n "+t._s(e.text)+"\n ")]):t._e(),t._v(" "),"links"===e.type?n("ul",{staticClass:"dropdown-subitem-wrapper"},t._l(e.items,(function(i){return n("li",{key:i.link,staticClass:"dropdown-subitem"},[n("NavLink",{attrs:{item:i},on:{focusout:function(n){t.isLastItemOfArray(i,e.items)&&t.isLastItemOfArray(e,t.item.items)&&t.setOpen(!1)}}})],1)})),0):n("NavLink",{attrs:{item:e},on:{focusout:function(n){t.isLastItemOfArray(e,t.item.items)&&t.setOpen(!1)}}})],1)})),0)])],1)}),[],!1,null,null,null).exports},computed:{userNav:function(){return this.$themeLocaleConfig.nav||this.$site.themeConfig.nav||[]},nav:function(){var t=this,e=this.$site.locales;if(e&&Object.keys(e).length>1){var n=this.$page.path,i=this.$router.options.routes,r=this.$site.themeConfig.locales||{},a={text:this.$themeLocaleConfig.selectText||"Languages",ariaLabel:this.$themeLocaleConfig.ariaLabel||"Select language",items:Object.keys(e).map((function(a){var s,o=e[a],u=r[a]&&r[a].label||o.lang;return o.lang===t.$lang?s=n:(s=n.replace(t.$localeConfig.path,a),i.some((function(t){return t.path===s}))||(s=a)),{text:u,link:s}}))};return[].concat(Object(h.a)(this.userNav),[a])}return this.userNav},userLinks:function(){return(this.nav||[]).map((function(t){return Object.assign(Object(i.j)(t),{items:(t.items||[]).map(i.j)})}))},repoLink:function(){var t=this.$site.themeConfig.repo;return t?/^https?:/.test(t)?t:"https://github.com/".concat(t):null},repoLabel:function(){if(this.repoLink){if(this.$site.themeConfig.repoLabel)return this.$site.themeConfig.repoLabel;for(var t=this.repoLink.match(/^https?:\/\/[^/]+/)[0],e=["GitHub","GitLab","Bitbucket"],n=0;nMath.abs(n)&&Math.abs(e)>40&&(e>0&&this.touchStart.x<=80?this.toggleSidebar(!0):this.toggleSidebar(!1))}}}),D=Object(a.a)(R,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"theme-container",class:t.pageClasses,on:{touchstart:t.onTouchStart,touchend:t.onTouchEnd}},[t.shouldShowNavbar?n("Navbar",{on:{"toggle-sidebar":t.toggleSidebar}}):t._e(),t._v(" "),n("div",{staticClass:"sidebar-mask",on:{click:function(e){return t.toggleSidebar(!1)}}}),t._v(" "),n("Sidebar",{attrs:{items:t.sidebarItems},on:{"toggle-sidebar":t.toggleSidebar},scopedSlots:t._u([{key:"top",fn:function(){return[t._t("sidebar-top")]},proxy:!0},{key:"bottom",fn:function(){return[t._t("sidebar-bottom")]},proxy:!0}],null,!0)}),t._v(" "),t.$page.frontmatter.home?n("Home"):n("Page",{attrs:{"sidebar-items":t.sidebarItems},scopedSlots:t._u([{key:"top",fn:function(){return[t._t("page-top")]},proxy:!0},{key:"bottom",fn:function(){return[t._t("page-bottom")]},proxy:!0}],null,!0)})],1)}),[],!1,null,null,null);e.default=D.exports}])]); \ No newline at end of file diff --git a/assets/js/2.fd7e9e0b.js b/assets/js/2.fd7e9e0b.js new file mode 100644 index 0000000..63a261d --- /dev/null +++ b/assets/js/2.fd7e9e0b.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[2],{307:function(t,e,n){"use strict";n.d(e,"d",(function(){return i})),n.d(e,"a",(function(){return a})),n.d(e,"i",(function(){return s})),n.d(e,"f",(function(){return u})),n.d(e,"g",(function(){return l})),n.d(e,"h",(function(){return c})),n.d(e,"b",(function(){return h})),n.d(e,"e",(function(){return p})),n.d(e,"k",(function(){return f})),n.d(e,"l",(function(){return d})),n.d(e,"c",(function(){return v})),n.d(e,"j",(function(){return m}));n(45),n(67),n(308),n(310),n(171),n(66),n(95),n(96),n(27),n(97),n(164);var i=/#.*$/,r=/\.(md|html)$/,a=/\/$/,s=/^[a-z]+:/i;function o(t){return decodeURI(t).replace(i,"").replace(r,"")}function u(t){return s.test(t)}function l(t){return/^mailto:/.test(t)}function c(t){return/^tel:/.test(t)}function h(t){if(u(t))return t;var e=t.match(i),n=e?e[0]:"",r=o(t);return a.test(r)?t:r+".html"+n}function p(t,e){var n=decodeURIComponent(t.hash),r=function(t){var e=t.match(i);if(e)return e[0]}(e);return(!r||n===r)&&o(t.path)===o(e)}function f(t,e,n){if(u(e))return{type:"external",path:e};n&&(e=function(t,e,n){var i=t.charAt(0);if("/"===i)return t;if("?"===i||"#"===i)return e+t;var r=e.split("/");n&&r[r.length-1]||r.pop();for(var a=t.replace(/^\//,"").split("/"),s=0;s3&&void 0!==arguments[3]?arguments[3]:1;if("string"==typeof e)return f(n,e,i);if(Array.isArray(e))return Object.assign(f(n,e[0],i),{title:e[1]});var a=e.children||[];return 0===a.length&&e.path?Object.assign(f(n,e.path,i),{title:e.title}):{type:"group",path:e.path,title:e.title,sidebarDepth:e.sidebarDepth,initialOpenGroupIndex:e.initialOpenGroupIndex,children:a.map((function(e){return t(e,n,i,r+1)})),collapsable:!1!==e.collapsable}}(t,r,l)})):[]}return[]}function g(t){var e=v(t.headers||[]);return[{type:"group",collapsable:!1,title:t.title,path:null,children:e.map((function(e){return{type:"auto",title:e.title,basePath:t.path,path:t.path+"#"+e.slug,children:e.children||[]}}))}]}function v(t){var e;return(t=t.map((function(t){return Object.assign({},t)}))).forEach((function(t){2===t.level?e=t:e&&(e.children||(e.children=[])).push(t)})),t.filter((function(t){return 2===t.level}))}function m(t){return Object.assign(t,{type:t.items&&t.items.length?"links":"link"})}},308:function(t,e,n){"use strict";var i=n(168),r=n(5),a=n(13),s=n(23),o=n(169),u=n(170);i("match",1,(function(t,e,n){return[function(e){var n=s(this),i=null==e?void 0:e[t];return void 0!==i?i.call(e,n):new RegExp(e)[t](String(n))},function(t){var i=n(e,t,this);if(i.done)return i.value;var s=r(t),l=String(this);if(!s.global)return u(s,l);var c=s.unicode;s.lastIndex=0;for(var h,p=[],f=0;null!==(h=u(s,l));){var d=String(h[0]);p[f]=d,""===d&&(s.lastIndex=o(l,a(s.lastIndex),c)),f++}return 0===f?null:p}]}))},309:function(t,e){t.exports="\t\n\v\f\r                 \u2028\u2029\ufeff"},310:function(t,e,n){"use strict";var i=n(168),r=n(165),a=n(5),s=n(23),o=n(100),u=n(169),l=n(13),c=n(170),h=n(70),p=n(167).UNSUPPORTED_Y,f=[].push,d=Math.min;i("split",2,(function(t,e,n){var i;return i="c"=="abbc".split(/(b)*/)[1]||4!="test".split(/(?:)/,-1).length||2!="ab".split(/(?:ab)*/).length||4!=".".split(/(.?)(.?)/).length||".".split(/()()/).length>1||"".split(/.?/).length?function(t,n){var i=String(s(this)),a=void 0===n?4294967295:n>>>0;if(0===a)return[];if(void 0===t)return[i];if(!r(t))return e.call(i,t,a);for(var o,u,l,c=[],p=(t.ignoreCase?"i":"")+(t.multiline?"m":"")+(t.unicode?"u":"")+(t.sticky?"y":""),d=0,g=new RegExp(t.source,p+"g");(o=h.call(g,i))&&!((u=g.lastIndex)>d&&(c.push(i.slice(d,o.index)),o.length>1&&o.index=a));)g.lastIndex===o.index&&g.lastIndex++;return d===i.length?!l&&g.test("")||c.push(""):c.push(i.slice(d)),c.length>a?c.slice(0,a):c}:"0".split(void 0,0).length?function(t,n){return void 0===t&&0===n?[]:e.call(this,t,n)}:e,[function(e,n){var r=s(this),a=null==e?void 0:e[t];return void 0!==a?a.call(e,r,n):i.call(String(r),e,n)},function(t,r){var s=n(i,t,this,r,i!==e);if(s.done)return s.value;var h=a(t),f=String(this),g=o(h,RegExp),v=h.unicode,m=(h.ignoreCase?"i":"")+(h.multiline?"m":"")+(h.unicode?"u":"")+(p?"g":"y"),b=new g(p?"^(?:"+h.source+")":h,m),k=void 0===r?4294967295:r>>>0;if(0===k)return[];if(0===f.length)return null===c(b,f)?[f]:[];for(var _=0,x=0,C=[];x-1)&&(e=e.replace(/y/g,""));var o=s(x?new m(t,e):m(t,e),i?this:b,$);C&&n&&(d(o).sticky=!0);return o},y=function(t){t in $||o($,t,{configurable:!0,get:function(){return m[t]},set:function(e){m[t]=e}})},L=u(m),w=0;L.length>w;)y(L[w++]);b.constructor=$,$.prototype=b,p(r,"RegExp",$)}g("RegExp")},315:function(t,e,n){"use strict";var i=n(18),r=n(5),a=n(2),s=n(166),o=RegExp.prototype,u=o.toString,l=a((function(){return"/a/b"!=u.call({source:"a",flags:"b"})})),c="toString"!=u.name;(l||c)&&i(RegExp.prototype,"toString",(function(){var t=r(this),e=String(t.source),n=t.flags;return"/"+e+"/"+String(void 0===n&&t instanceof RegExp&&!("flags"in o)?s.call(t):n)}),{unsafe:!0})},316:function(t,e,n){},317:function(t,e,n){},318:function(t,e,n){},319:function(t,e,n){},320:function(t,e,n){},321:function(t,e,n){},322:function(t,e){t.exports=function(t){return null==t}},323:function(t,e,n){},324:function(t,e,n){},325:function(t,e,n){},326:function(t,e,n){},327:function(t,e,n){},328:function(t,e,n){},332:function(t,e,n){"use strict";n.r(e);n(93);var i=n(307),r={name:"SidebarGroup",components:{DropdownTransition:n(333).a},props:["item","open","collapsable","depth"],beforeCreate:function(){this.$options.components.SidebarLinks=n(332).default},methods:{isActive:i.e}},a=(n(353),n(44)),s=Object(a.a)(r,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("section",{staticClass:"sidebar-group",class:[{collapsable:t.collapsable,"is-sub-group":0!==t.depth},"depth-"+t.depth]},[t.item.path?n("RouterLink",{staticClass:"sidebar-heading clickable",class:{open:t.open,active:t.isActive(t.$route,t.item.path)},attrs:{to:t.item.path},nativeOn:{click:function(e){return t.$emit("toggle")}}},[n("span",[t._v(t._s(t.item.title))]),t._v(" "),t.collapsable?n("span",{staticClass:"arrow",class:t.open?"down":"right"}):t._e()]):n("p",{staticClass:"sidebar-heading",class:{open:t.open},on:{click:function(e){return t.$emit("toggle")}}},[n("span",[t._v(t._s(t.item.title))]),t._v(" "),t.collapsable?n("span",{staticClass:"arrow",class:t.open?"down":"right"}):t._e()]),t._v(" "),n("DropdownTransition",[t.open||!t.collapsable?n("SidebarLinks",{staticClass:"sidebar-group-items",attrs:{items:t.item.children,"sidebar-depth":t.item.sidebarDepth,"initial-open-group-index":t.item.initialOpenGroupIndex,depth:t.depth+1}}):t._e()],1)],1)}),[],!1,null,null,null).exports;n(354),n(66);function o(t,e,n,i,r){var a={props:{to:e,activeClass:"",exactActiveClass:""},class:{active:i,"sidebar-link":!0}};return r>2&&(a.style={"padding-left":r+"rem"}),t("RouterLink",a,n)}function u(t,e,n,r,a){var s=arguments.length>5&&void 0!==arguments[5]?arguments[5]:1;return!e||s>a?null:t("ul",{class:"sidebar-sub-headers"},e.map((function(e){var l=Object(i.e)(r,n+"#"+e.slug);return t("li",{class:"sidebar-sub-header"},[o(t,n+"#"+e.slug,e.title,l,e.level-1),u(t,e.children,n,r,a,s+1)])})))}var l={functional:!0,props:["item","sidebarDepth"],render:function(t,e){var n=e.parent,r=n.$page,a=(n.$site,n.$route),s=n.$themeConfig,l=n.$themeLocaleConfig,c=e.props,h=c.item,p=c.sidebarDepth,f=Object(i.e)(a,h.path),d="auto"===h.type?f||h.children.some((function(t){return Object(i.e)(a,h.basePath+"#"+t.slug)})):f,g="external"===h.type?function(t,e,n){return t("a",{attrs:{href:e,target:"_blank",rel:"noopener noreferrer"},class:{"sidebar-link":!0}},[n,t("OutboundLink")])}(t,h.path,h.title||h.path):o(t,h.path,h.title||h.path,d),v=[r.frontmatter.sidebarDepth,p,l.sidebarDepth,s.sidebarDepth,1].find((function(t){return void 0!==t})),m=l.displayAllHeaders||s.displayAllHeaders;return"auto"===h.type?[g,u(t,h.children,h.basePath,a,v)]:(d||m)&&h.headers&&!i.d.test(h.path)?[g,u(t,Object(i.c)(h.headers),h.path,a,v)]:g}};n(355);function c(t,e){if("group"===e.type){var n=e.path&&Object(i.e)(t,e.path),r=e.children.some((function(e){return"group"===e.type?c(t,e):"page"===e.type&&Object(i.e)(t,e.path)}));return n||r}return!1}var h={name:"SidebarLinks",components:{SidebarGroup:s,SidebarLink:Object(a.a)(l,void 0,void 0,!1,null,null,null).exports},props:["items","depth","sidebarDepth","initialOpenGroupIndex"],data:function(){return{openGroupIndex:this.initialOpenGroupIndex||0}},watch:{$route:function(){this.refreshIndex()}},created:function(){this.refreshIndex()},methods:{refreshIndex:function(){var t=function(t,e){for(var n=0;n-1&&(this.openGroupIndex=t)},toggleGroup:function(t){this.openGroupIndex=t===this.openGroupIndex?-1:t},isActive:function(t){return Object(i.e)(this.$route,t.regularPath)}}},p=Object(a.a)(h,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return t.items.length?n("ul",{staticClass:"sidebar-links"},t._l(t.items,(function(e,i){return n("li",{key:i},["group"===e.type?n("SidebarGroup",{attrs:{item:e,open:i===t.openGroupIndex,collapsable:e.collapsable||e.collapsible,depth:t.depth},on:{toggle:function(e){return t.toggleGroup(i)}}}):n("SidebarLink",{attrs:{"sidebar-depth":t.sidebarDepth,item:e}})],1)})),0):t._e()}),[],!1,null,null,null);e.default=p.exports},333:function(t,e,n){"use strict";var i={name:"DropdownTransition",methods:{setHeight:function(t){t.style.height=t.scrollHeight+"px"},unsetHeight:function(t){t.style.height=""}}},r=(n(345),n(44)),a=Object(r.a)(i,(function(){var t=this.$createElement;return(this._self._c||t)("transition",{attrs:{name:"dropdown"},on:{enter:this.setHeight,"after-enter":this.unsetHeight,"before-leave":this.setHeight}},[this._t("default")],2)}),[],!1,null,null,null);e.a=a.exports},334:function(t,e,n){"use strict";var i=n(0),r=n(335);i({target:"String",proto:!0,forced:n(336)("link")},{link:function(t){return r(this,"a","href",t)}})},335:function(t,e,n){var i=n(23),r=/"/g;t.exports=function(t,e,n,a){var s=String(i(t)),o="<"+e;return""!==n&&(o+=" "+n+'="'+String(a).replace(r,""")+'"'),o+">"+s+""}},336:function(t,e,n){var i=n(2);t.exports=function(t){return i((function(){var e=""[t]('"');return e!==e.toLowerCase()||e.split('"').length>3}))}},337:function(t,e,n){"use strict";n(311)},338:function(t,e,n){var i=n(0),r=n(339);i({global:!0,forced:parseInt!=r},{parseInt:r})},339:function(t,e,n){var i=n(3),r=n(312).trim,a=n(309),s=i.parseInt,o=/^[+-]?0[Xx]/,u=8!==s(a+"08")||22!==s(a+"0x16");t.exports=u?function(t,e){var n=r(String(t));return s(n,e>>>0||(o.test(n)?16:10))}:s},340:function(t,e,n){var i=n(2),r=n(309);t.exports=function(t){return i((function(){return!!r[t]()||"​…᠎"!="​…᠎"[t]()||r[t].name!==t}))}},341:function(t,e,n){var i=n(4),r=n(69);t.exports=function(t,e,n){var a,s;return r&&"function"==typeof(a=e.constructor)&&a!==n&&i(s=a.prototype)&&s!==n.prototype&&r(t,s),t}},342:function(t,e,n){"use strict";var i,r=n(0),a=n(24).f,s=n(13),o=n(101),u=n(23),l=n(102),c=n(20),h="".endsWith,p=Math.min,f=l("endsWith");r({target:"String",proto:!0,forced:!!(c||f||(i=a(String.prototype,"endsWith"),!i||i.writable))&&!f},{endsWith:function(t){var e=String(u(this));o(t);var n=arguments.length>1?arguments[1]:void 0,i=s(e.length),r=void 0===n?i:p(s(n),i),a=String(t);return h?h.call(e,a,r):e.slice(r-a.length,r)===a}})},343:function(t,e,n){"use strict";n(316)},344:function(t,e,n){"use strict";n(317)},345:function(t,e,n){"use strict";n(318)},346:function(t,e,n){"use strict";n(319)},347:function(t,e,n){"use strict";n(320)},348:function(t,e,n){"use strict";n(321)},349:function(t,e,n){"use strict";n(323)},350:function(t,e,n){var i=n(30),r=n(14),a=n(25);t.exports=function(t){return"string"==typeof t||!r(t)&&a(t)&&"[object String]"==i(t)}},351:function(t,e,n){"use strict";n(324)},352:function(t,e,n){"use strict";n(325)},353:function(t,e,n){"use strict";n(326)},354:function(t,e,n){"use strict";var i=n(0),r=n(29).find,a=n(98),s=!0;"find"in[]&&Array(1).find((function(){s=!1})),i({target:"Array",proto:!0,forced:s},{find:function(t){return r(this,t,arguments.length>1?arguments[1]:void 0)}}),a("find")},355:function(t,e,n){"use strict";n(327)},356:function(t,e,n){"use strict";n(328)},360:function(t,e,n){"use strict";n.r(e);n(334),n(93),n(94);var i=n(307),r={name:"NavLink",props:{item:{required:!0}},computed:{link:function(){return Object(i.b)(this.item.link)},exact:function(){var t=this;return this.$site.locales?Object.keys(this.$site.locales).some((function(e){return e===t.link})):"/"===this.link},isNonHttpURI:function(){return Object(i.g)(this.link)||Object(i.h)(this.link)},isBlankTarget:function(){return"_blank"===this.target},isInternal:function(){return!Object(i.f)(this.link)&&!this.isBlankTarget},target:function(){return this.isNonHttpURI?null:this.item.target?this.item.target:Object(i.f)(this.link)?"_blank":""},rel:function(){return this.isNonHttpURI||!1===this.item.rel?null:this.item.rel?this.item.rel:this.isBlankTarget?"noopener noreferrer":null}},methods:{focusoutAction:function(){this.$emit("focusout")}}},a=n(44),s=Object(a.a)(r,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return t.isInternal?n("RouterLink",{staticClass:"nav-link",attrs:{to:t.link,exact:t.exact},nativeOn:{focusout:function(e){return t.focusoutAction(e)}}},[t._v("\n "+t._s(t.item.text)+"\n")]):n("a",{staticClass:"nav-link external",attrs:{href:t.link,target:t.target,rel:t.rel},on:{focusout:t.focusoutAction}},[t._v("\n "+t._s(t.item.text)+"\n "),t.isBlankTarget?n("OutboundLink"):t._e()],1)}),[],!1,null,null,null).exports,o={name:"Home",components:{NavLink:s},computed:{data:function(){return this.$page.frontmatter},actionLink:function(){return{link:this.data.actionLink,text:this.data.actionText}}}},u=(n(337),Object(a.a)(o,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("main",{staticClass:"home",attrs:{"aria-labelledby":null!==t.data.heroText?"main-title":null}},[n("header",{staticClass:"hero"},[t.data.heroImage?n("img",{attrs:{src:t.$withBase(t.data.heroImage),alt:t.data.heroAlt||"hero"}}):t._e(),t._v(" "),null!==t.data.heroText?n("h1",{attrs:{id:"main-title"}},[t._v("\n "+t._s(t.data.heroText||t.$title||"Hello")+"\n ")]):t._e(),t._v(" "),null!==t.data.tagline?n("p",{staticClass:"description"},[t._v("\n "+t._s(t.data.tagline||t.$description||"Welcome to your VuePress site")+"\n ")]):t._e(),t._v(" "),t.data.actionText&&t.data.actionLink?n("p",{staticClass:"action"},[n("NavLink",{staticClass:"action-button",attrs:{item:t.actionLink}})],1):t._e()]),t._v(" "),t.data.features&&t.data.features.length?n("div",{staticClass:"features"},t._l(t.data.features,(function(e,i){return n("div",{key:i,staticClass:"feature"},[n("h2",[t._v(t._s(e.title))]),t._v(" "),n("p",[t._v(t._s(e.details))])])})),0):t._e(),t._v(" "),n("Content",{staticClass:"theme-default-content custom"}),t._v(" "),t.data.footer?n("div",{staticClass:"footer"},[t._v("\n "+t._s(t.data.footer)+"\n ")]):t._e()],1)}),[],!1,null,null,null).exports),l=(n(338),n(313),n(164),n(97),n(27),n(45),n(308),n(173),n(174),n(171),n(67),n(314),n(315),n(66),n(310),n(342),n(176)),c=n.n(l),h=function(t,e){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null,i=c()(e,"title","");return c()(e,"frontmatter.tags")&&(i+=" ".concat(e.frontmatter.tags.join(" "))),n&&(i+=" ".concat(n)),p(t,i)},p=function(t,e){var n=function(t){return t.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&")},i=new RegExp("[^\0-]"),r=t.split(/\s+/g).map((function(t){return t.trim()})).filter((function(t){return!!t}));if(i.test(t))return r.some((function(t){return e.toLowerCase().indexOf(t)>-1}));var a=t.endsWith(" ");return new RegExp(r.map((function(t,e){return r.length!==e+1||a?"(?=.*\\b".concat(n(t),"\\b)"):"(?=.*\\b".concat(n(t),")")})).join("")+".+","gi").test(e)},f={name:"SearchBox",data:function(){return{query:"",focused:!1,focusIndex:0,placeholder:void 0}},computed:{showSuggestions:function(){return this.focused&&this.suggestions&&this.suggestions.length},suggestions:function(){var t=this.query.trim().toLowerCase();if(t){for(var e=this.$site.pages,n=this.$site.themeConfig.searchMaxSuggestions||5,i=this.$localePath,r=[],a=0;a=n);a++){var s=e[a];if(this.getPageLocalePath(s)===i&&this.isSearchable(s))if(h(t,s))r.push(s);else if(s.headers)for(var o=0;o=n);o++){var u=s.headers[o];u.title&&h(t,s,u.title)&&r.push(Object.assign({},s,{path:s.path+"#"+u.slug,header:u}))}}return r}},alignRight:function(){return(this.$site.themeConfig.nav||[]).length+(this.$site.repo?1:0)<=2}},mounted:function(){this.placeholder=this.$site.themeConfig.searchPlaceholder||"",document.addEventListener("keydown",this.onHotkey)},beforeDestroy:function(){document.removeEventListener("keydown",this.onHotkey)},methods:{getPageLocalePath:function(t){for(var e in this.$site.locales||{})if("/"!==e&&0===t.path.indexOf(e))return e;return"/"},isSearchable:function(t){var e=null;return null===e||(e=Array.isArray(e)?e:new Array(e)).filter((function(e){return t.path.match(e)})).length>0},onHotkey:function(t){t.srcElement===document.body&&["s","/"].includes(t.key)&&(this.$refs.input.focus(),t.preventDefault())},onUp:function(){this.showSuggestions&&(this.focusIndex>0?this.focusIndex--:this.focusIndex=this.suggestions.length-1)},onDown:function(){this.showSuggestions&&(this.focusIndex "+t._s(e.header.title))]):t._e()])])})),0):t._e()])}),[],!1,null,null,null).exports),g=(n(344),Object(a.a)({},(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"sidebar-button",on:{click:function(e){return t.$emit("toggle-sidebar")}}},[n("svg",{staticClass:"icon",attrs:{xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",role:"img",viewBox:"0 0 448 512"}},[n("path",{attrs:{fill:"currentColor",d:"M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"}})])])}),[],!1,null,null,null).exports),v=n(42),m=(n(175),n(333)),b=n(177),k=n.n(b),_={name:"DropdownLink",components:{NavLink:s,DropdownTransition:m.a},props:{item:{required:!0}},data:function(){return{open:!1}},computed:{dropdownAriaLabel:function(){return this.item.ariaLabel||this.item.text}},watch:{$route:function(){this.open=!1}},methods:{setOpen:function(t){this.open=t},isLastItemOfArray:function(t,e){return k()(e)===t},handleDropdown:function(){0===event.detail&&this.setOpen(!this.open)}}},x=(n(346),{name:"NavLinks",components:{NavLink:s,DropdownLink:Object(a.a)(_,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"dropdown-wrapper",class:{open:t.open}},[n("button",{staticClass:"dropdown-title",attrs:{type:"button","aria-label":t.dropdownAriaLabel},on:{click:t.handleDropdown}},[n("span",{staticClass:"title"},[t._v(t._s(t.item.text))]),t._v(" "),n("span",{staticClass:"arrow down"})]),t._v(" "),n("button",{staticClass:"mobile-dropdown-title",attrs:{type:"button","aria-label":t.dropdownAriaLabel},on:{click:function(e){return t.setOpen(!t.open)}}},[n("span",{staticClass:"title"},[t._v(t._s(t.item.text))]),t._v(" "),n("span",{staticClass:"arrow",class:t.open?"down":"right"})]),t._v(" "),n("DropdownTransition",[n("ul",{directives:[{name:"show",rawName:"v-show",value:t.open,expression:"open"}],staticClass:"nav-dropdown"},t._l(t.item.items,(function(e,i){return n("li",{key:e.link||i,staticClass:"dropdown-item"},["links"===e.type?n("h4",[t._v("\n "+t._s(e.text)+"\n ")]):t._e(),t._v(" "),"links"===e.type?n("ul",{staticClass:"dropdown-subitem-wrapper"},t._l(e.items,(function(i){return n("li",{key:i.link,staticClass:"dropdown-subitem"},[n("NavLink",{attrs:{item:i},on:{focusout:function(n){t.isLastItemOfArray(i,e.items)&&t.isLastItemOfArray(e,t.item.items)&&t.setOpen(!1)}}})],1)})),0):n("NavLink",{attrs:{item:e},on:{focusout:function(n){t.isLastItemOfArray(e,t.item.items)&&t.setOpen(!1)}}})],1)})),0)])],1)}),[],!1,null,null,null).exports},computed:{userNav:function(){return this.$themeLocaleConfig.nav||this.$site.themeConfig.nav||[]},nav:function(){var t=this,e=this.$site.locales;if(e&&Object.keys(e).length>1){var n=this.$page.path,i=this.$router.options.routes,r=this.$site.themeConfig.locales||{},a={text:this.$themeLocaleConfig.selectText||"Languages",ariaLabel:this.$themeLocaleConfig.ariaLabel||"Select language",items:Object.keys(e).map((function(a){var s,o=e[a],u=r[a]&&r[a].label||o.lang;return o.lang===t.$lang?s=n:(s=n.replace(t.$localeConfig.path,a),i.some((function(t){return t.path===s}))||(s=a)),{text:u,link:s}}))};return[].concat(Object(v.a)(this.userNav),[a])}return this.userNav},userLinks:function(){return(this.nav||[]).map((function(t){return Object.assign(Object(i.j)(t),{items:(t.items||[]).map(i.j)})}))},repoLink:function(){var t=this.$site.themeConfig.repo;return t?/^https?:/.test(t)?t:"https://github.com/".concat(t):null},repoLabel:function(){if(this.repoLink){if(this.$site.themeConfig.repoLabel)return this.$site.themeConfig.repoLabel;for(var t=this.repoLink.match(/^https?:\/\/[^/]+/)[0],e=["GitHub","GitLab","Bitbucket"],n=0;nMath.abs(n)&&Math.abs(e)>40&&(e>0&&this.touchStart.x<=80?this.toggleSidebar(!0):this.toggleSidebar(!1))}}}),G=Object(a.a)(W,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"theme-container",class:t.pageClasses,on:{touchstart:t.onTouchStart,touchend:t.onTouchEnd}},[t.shouldShowNavbar?n("Navbar",{on:{"toggle-sidebar":t.toggleSidebar}}):t._e(),t._v(" "),n("div",{staticClass:"sidebar-mask",on:{click:function(e){return t.toggleSidebar(!1)}}}),t._v(" "),n("Sidebar",{attrs:{items:t.sidebarItems},on:{"toggle-sidebar":t.toggleSidebar},scopedSlots:t._u([{key:"top",fn:function(){return[t._t("sidebar-top")]},proxy:!0},{key:"bottom",fn:function(){return[t._t("sidebar-bottom")]},proxy:!0}],null,!0)}),t._v(" "),t.$page.frontmatter.home?n("Home"):n("Page",{attrs:{"sidebar-items":t.sidebarItems},scopedSlots:t._u([{key:"top",fn:function(){return[t._t("page-top")]},proxy:!0},{key:"bottom",fn:function(){return[t._t("page-bottom")]},proxy:!0}],null,!0)})],1)}),[],!1,null,null,null);e.default=G.exports}}]); \ No newline at end of file diff --git a/assets/js/3.8d00273c.js b/assets/js/3.8d00273c.js deleted file mode 100644 index 68a026a..0000000 --- a/assets/js/3.8d00273c.js +++ /dev/null @@ -1 +0,0 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[3],{159:function(t,e,n){},202:function(t,e,n){"use strict";var i=n(159);n.n(i).a},210:function(t,e,n){"use strict";n.r(e);var i={functional:!0,props:{type:{type:String,default:"tip"},text:String,vertical:{type:String,default:"top"}},render:function(t,e){var n=e.props,i=e.slots;return t("span",{class:["badge",n.type],style:{verticalAlign:n.vertical}},n.text||i().default)}},r=(n(202),n(28)),a=Object(r.a)(i,void 0,void 0,!1,null,"15b7b770",null);e.default=a.exports}}]); \ No newline at end of file diff --git a/assets/js/3.c5869ccf.js b/assets/js/3.c5869ccf.js new file mode 100644 index 0000000..0cd03bc --- /dev/null +++ b/assets/js/3.c5869ccf.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[3],{329:function(t,e,n){},357:function(t,e,n){"use strict";n(329)},372:function(t,e,n){"use strict";n.r(e);var i={functional:!0,props:{type:{type:String,default:"tip"},text:String,vertical:{type:String,default:"top"}},render:function(t,e){var n=e.props,i=e.slots;return t("span",{class:["badge",n.type],style:{verticalAlign:n.vertical}},n.text||i().default)}},r=(n(357),n(44)),p=Object(r.a)(i,void 0,void 0,!1,null,"15b7b770",null);e.default=p.exports}}]); \ No newline at end of file diff --git a/assets/js/4.b9b777bd.js b/assets/js/4.b9b777bd.js new file mode 100644 index 0000000..a1433ec --- /dev/null +++ b/assets/js/4.b9b777bd.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[4],{330:function(t,e,a){},358:function(t,e,a){"use strict";a(330)},362:function(t,e,a){"use strict";a.r(e);var n={name:"CodeBlock",props:{title:{type:String,required:!0},active:{type:Boolean,default:!1}},mounted:function(){this.$parent&&this.$parent.loadTabs&&this.$parent.loadTabs()}},i=(a(358),a(44)),s=Object(i.a)(n,(function(){var t=this.$createElement;return(this._self._c||t)("div",{staticClass:"theme-code-block",class:{"theme-code-block__active":this.active}},[this._t("default")],2)}),[],!1,null,"759a7d02",null);e.default=s.exports}}]); \ No newline at end of file diff --git a/assets/js/5.073c37d9.js b/assets/js/5.073c37d9.js new file mode 100644 index 0000000..19a777f --- /dev/null +++ b/assets/js/5.073c37d9.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[5],{331:function(e,t,a){},359:function(e,t,a){"use strict";a(331)},363:function(e,t,a){"use strict";a.r(t);a(66),a(27),a(95),a(96);var o={name:"CodeGroup",data:function(){return{codeTabs:[],activeCodeTabIndex:-1}},watch:{activeCodeTabIndex:function(e){this.activateCodeTab(e)}},mounted:function(){this.loadTabs()},methods:{changeCodeTab:function(e){this.activeCodeTabIndex=e},loadTabs:function(){var e=this;this.codeTabs=(this.$slots.default||[]).filter((function(e){return Boolean(e.componentOptions)})).map((function(t,a){return""===t.componentOptions.propsData.active&&(e.activeCodeTabIndex=a),{title:t.componentOptions.propsData.title,elm:t.elm}})),-1===this.activeCodeTabIndex&&this.codeTabs.length>0&&(this.activeCodeTabIndex=0),this.activateCodeTab(0)},activateCodeTab:function(e){this.codeTabs.forEach((function(e){e.elm&&e.elm.classList.remove("theme-code-block__active")})),this.codeTabs[e].elm&&this.codeTabs[e].elm.classList.add("theme-code-block__active")}}},n=(a(359),a(44)),c=Object(n.a)(o,(function(){var e=this,t=e.$createElement,a=e._self._c||t;return a("ClientOnly",[a("div",{staticClass:"theme-code-group"},[a("div",{staticClass:"theme-code-group__nav"},[a("ul",{staticClass:"theme-code-group__ul"},e._l(e.codeTabs,(function(t,o){return a("li",{key:t.title,staticClass:"theme-code-group__li"},[a("button",{staticClass:"theme-code-group__nav-tab",class:{"theme-code-group__nav-tab-active":o===e.activeCodeTabIndex},on:{click:function(t){return e.changeCodeTab(o)}}},[e._v("\n "+e._s(t.title)+"\n ")])])})),0)]),e._v(" "),e._t("default"),e._v(" "),e.codeTabs.length<1?a("pre",{staticClass:"pre-blank"},[e._v("// Make sure to add code blocks to your code group")]):e._e()],2)])}),[],!1,null,"deefee04",null);t.default=c.exports}}]); \ No newline at end of file diff --git a/assets/js/4.27329ebd.js b/assets/js/6.7db49fe2.js similarity index 72% rename from assets/js/4.27329ebd.js rename to assets/js/6.7db49fe2.js index 0a34b2a..777d009 100644 --- a/assets/js/4.27329ebd.js +++ b/assets/js/6.7db49fe2.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[4],{204:function(t,e,s){"use strict";s.r(e);var n=["There's nothing here.","How did we get here?","That's a Four-Oh-Four.","Looks like we've got some broken links."],o={methods:{getMsg:function(){return n[Math.floor(Math.random()*n.length)]}}},i=s(28),h=Object(i.a)(o,(function(){var t=this.$createElement,e=this._self._c||t;return e("div",{staticClass:"theme-container"},[e("div",{staticClass:"theme-default-content"},[e("h1",[this._v("404")]),this._v(" "),e("blockquote",[this._v(this._s(this.getMsg()))]),this._v(" "),e("RouterLink",{attrs:{to:"/"}},[this._v("\n Take me home.\n ")])],1)])}),[],!1,null,null,null);e.default=h.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[6],{361:function(t,e,s){"use strict";s.r(e);var n=["There's nothing here.","How did we get here?","That's a Four-Oh-Four.","Looks like we've got some broken links."],o={methods:{getMsg:function(){return n[Math.floor(Math.random()*n.length)]}}},i=s(44),h=Object(i.a)(o,(function(){var t=this.$createElement,e=this._self._c||t;return e("div",{staticClass:"theme-container"},[e("div",{staticClass:"theme-default-content"},[e("h1",[this._v("404")]),this._v(" "),e("blockquote",[this._v(this._s(this.getMsg()))]),this._v(" "),e("RouterLink",{attrs:{to:"/"}},[this._v("\n Take me home.\n ")])],1)])}),[],!1,null,null,null);e.default=h.exports}}]); \ No newline at end of file diff --git a/assets/js/5.80ea750d.js b/assets/js/7.852d0869.js similarity index 96% rename from assets/js/5.80ea750d.js rename to assets/js/7.852d0869.js index e2019be..138381b 100644 --- a/assets/js/5.80ea750d.js +++ b/assets/js/7.852d0869.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[5],{206:function(t,e,a){"use strict";a.r(e);var r=a(28),s=Object(r.a)({},(function(){var t=this,e=t.$createElement,a=t._self._c||e;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"how-the-documentation-is-organized"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#how-the-documentation-is-organized"}},[t._v("#")]),t._v(" How the Documentation is organized")]),t._v(" "),a("p",[t._v("Documentation is organized into four categories: tutorials, overviews, API references and how-to guides.")]),t._v(" "),a("ul",[a("li",[t._v("Tutorials take you by the hand through a series of steps to put a library / module to use. Start here if you’re new to a library.")]),t._v(" "),a("li",[t._v("Overviews discuss key topics and concepts at a fairly high level and provide useful background information and explanation. Those are the things you usually see in READMEs of repos.")]),t._v(" "),a("li",[t._v("API references contain technical reference for APIs and other aspects of a module's machinery. They describe how it works and how to use it but assume that you have a basic understanding of key concepts. These are auto-generated from the code, and depend heavily on the programmer's verbosity and the technical writer's persistence.")]),t._v(" "),a("li",[t._v("How-to guides are recipes. They guide you through the steps involved in addressing key problems and use-cases. They are more advanced, shorter, and more specific than tutorials and assume some previous knowledge.")])]),t._v(" "),a("h2",{attrs:{id:"get-started"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#get-started"}},[t._v("#")]),t._v(" Get Started")]),t._v(" "),a("p",[t._v("Use the search field in the header, or find a desired library in the sections below. Each library has its own documentation with a full API reference and guides. If you'd like to contribute to these docs with your own work or some corrections, please file issues or PRs "),a("a",{attrs:{href:"https://github.com/status-im/nimbus-libs-site",target:"_blank",rel:"noopener noreferrer"}},[t._v("in the Github repo"),a("OutboundLink")],1),t._v(".")]),t._v(" "),a("div",{staticClass:"theorem"},[a("p",{staticClass:"title"},[a("a",{attrs:{href:"/lib/nim-libp2p/"}},[t._v("libp2p")]),a("Badge",{attrs:{text:"libp2p"}}),a("Badge",{attrs:{text:"networking"}}),a("Badge",{attrs:{text:"development",type:"warn"}})],1),a("p",[t._v("nim-libp2p is an implementation of the libp2p modular peer-to-peer networking stack based on Chronos")])]),a("div",{staticClass:"theorem"},[a("p",{staticClass:"title"},[a("a",{attrs:{href:"/lib/nim-chronicles/"}},[t._v("Chronicles")]),a("Badge",{attrs:{text:"logging"}}),a("Badge",{attrs:{text:"stable"}})],1),a("p",[t._v("Chronicles is a library for structured logging. It adheres to the philosophy that log files shouldn't be based on formatted text strings, but rather on well-defined event records with arbitrary properties that are easy to read for both humans and machines.")])]),a("div",{staticClass:"theorem"},[a("p",{staticClass:"title"},[a("a",{attrs:{href:"/lib/nimcrypto/"}},[t._v("Nimcrypto")]),a("Badge",{attrs:{text:"cryptography"}}),a("Badge",{attrs:{text:"development",type:"warn"}})],1),a("p",[t._v("Nimcrypto is Nim's cryptographic library. It implements several popular cryptographic algorithms and their tests with some "),a("a",{attrs:{href:"https://github.com/cheatfate/nimcrypto/tree/master/examples",target:"_blank",rel:"noopener noreferrer"}},[t._v("examples"),a("OutboundLink")],1),t._v(".")])]),a("div",{staticClass:"theorem"},[a("p",{staticClass:"title"},[a("a",{attrs:{href:"/lib/nim-chronos/"}},[t._v("Chronos")]),a("Badge",{attrs:{text:"async"}}),a("Badge",{attrs:{text:"stable"}}),a("Badge",{attrs:{text:"networking"}})],1),a("p",[t._v("Chronos is an efficient library for asynchronous programming and an alternative to Nim's asyncdispatch.")])]),a("div",{staticClass:"theorem"},[a("p",{staticClass:"title"},[a("a",{attrs:{href:"/lib/nim-eth/"}},[t._v("Eth")]),a("Badge",{attrs:{text:"eth"}}),a("Badge",{attrs:{text:"keys"}}),a("Badge",{attrs:{text:"bloom"}}),a("Badge",{attrs:{text:"rlp"}}),a("Badge",{attrs:{text:"encoding"}}),a("Badge",{attrs:{text:"formatting"}}),a("Badge",{attrs:{text:"cryptography"}}),a("Badge",{attrs:{text:"development",type:"warn"}})],1),a("p",[t._v("Ethereum-related utilities written in Nim. Includes things like Bloom filters, private/public key utilities, devp2p, RLP, and more.")])]),a("div",{staticClass:"theorem"},[a("p",{staticClass:"title"},[a("a",{attrs:{href:"/lib/nim-stew/"}},[t._v("Stew")]),a("Badge",{attrs:{text:"encoding"}}),a("Badge",{attrs:{text:"formatting"}}),a("Badge",{attrs:{text:"development",type:"warn"}}),a("Badge",{attrs:{text:"utilities"}})],1),a("p",[t._v("General-purpose utilities and standard library extensions")])])])}),[],!1,null,null,null);e.default=s.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[7],{364:function(t,e,a){"use strict";a.r(e);var r=a(44),s=Object(r.a)({},(function(){var t=this,e=t.$createElement,a=t._self._c||e;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"how-the-documentation-is-organized"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#how-the-documentation-is-organized"}},[t._v("#")]),t._v(" How the Documentation is organized")]),t._v(" "),a("p",[t._v("Documentation is organized into four categories: tutorials, overviews, API references and how-to guides.")]),t._v(" "),a("ul",[a("li",[t._v("Tutorials take you by the hand through a series of steps to put a library / module to use. Start here if you’re new to a library.")]),t._v(" "),a("li",[t._v("Overviews discuss key topics and concepts at a fairly high level and provide useful background information and explanation. Those are the things you usually see in READMEs of repos.")]),t._v(" "),a("li",[t._v("API references contain technical reference for APIs and other aspects of a module's machinery. They describe how it works and how to use it but assume that you have a basic understanding of key concepts. These are auto-generated from the code, and depend heavily on the programmer's verbosity and the technical writer's persistence.")]),t._v(" "),a("li",[t._v("How-to guides are recipes. They guide you through the steps involved in addressing key problems and use-cases. They are more advanced, shorter, and more specific than tutorials and assume some previous knowledge.")])]),t._v(" "),a("h2",{attrs:{id:"get-started"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#get-started"}},[t._v("#")]),t._v(" Get Started")]),t._v(" "),a("p",[t._v("Use the search field in the header, or find a desired library in the sections below. Each library has its own documentation with a full API reference and guides. If you'd like to contribute to these docs with your own work or some corrections, please file issues or PRs "),a("a",{attrs:{href:"https://github.com/status-im/nimbus-libs-site",target:"_blank",rel:"noopener noreferrer"}},[t._v("in the Github repo"),a("OutboundLink")],1),t._v(".")]),t._v(" "),a("div",{staticClass:"theorem"},[a("p",{staticClass:"title"},[a("a",{attrs:{href:"/lib/nim-libp2p/"}},[t._v("libp2p")]),a("Badge",{attrs:{text:"libp2p"}}),a("Badge",{attrs:{text:"networking"}}),a("Badge",{attrs:{text:"development",type:"warn"}})],1),a("p",[t._v("nim-libp2p is an implementation of the libp2p modular peer-to-peer networking stack based on Chronos")])]),a("div",{staticClass:"theorem"},[a("p",{staticClass:"title"},[a("a",{attrs:{href:"/lib/nim-chronicles/"}},[t._v("Chronicles")]),a("Badge",{attrs:{text:"logging"}}),a("Badge",{attrs:{text:"stable"}})],1),a("p",[t._v("Chronicles is a library for structured logging. It adheres to the philosophy that log files shouldn't be based on formatted text strings, but rather on well-defined event records with arbitrary properties that are easy to read for both humans and machines.")])]),a("div",{staticClass:"theorem"},[a("p",{staticClass:"title"},[a("a",{attrs:{href:"/lib/nimcrypto/"}},[t._v("Nimcrypto")]),a("Badge",{attrs:{text:"cryptography"}}),a("Badge",{attrs:{text:"development",type:"warn"}})],1),a("p",[t._v("Nimcrypto is Nim's cryptographic library. It implements several popular cryptographic algorithms and their tests with some "),a("a",{attrs:{href:"https://github.com/cheatfate/nimcrypto/tree/master/examples",target:"_blank",rel:"noopener noreferrer"}},[t._v("examples"),a("OutboundLink")],1),t._v(".")])]),a("div",{staticClass:"theorem"},[a("p",{staticClass:"title"},[a("a",{attrs:{href:"/lib/nim-chronos/"}},[t._v("Chronos")]),a("Badge",{attrs:{text:"async"}}),a("Badge",{attrs:{text:"stable"}}),a("Badge",{attrs:{text:"networking"}})],1),a("p",[t._v("Chronos is an efficient library for asynchronous programming and an alternative to Nim's asyncdispatch.")])]),a("div",{staticClass:"theorem"},[a("p",{staticClass:"title"},[a("a",{attrs:{href:"/lib/nim-eth/"}},[t._v("Eth")]),a("Badge",{attrs:{text:"eth"}}),a("Badge",{attrs:{text:"keys"}}),a("Badge",{attrs:{text:"bloom"}}),a("Badge",{attrs:{text:"rlp"}}),a("Badge",{attrs:{text:"encoding"}}),a("Badge",{attrs:{text:"formatting"}}),a("Badge",{attrs:{text:"cryptography"}}),a("Badge",{attrs:{text:"development",type:"warn"}})],1),a("p",[t._v("Ethereum-related utilities written in Nim. Includes things like Bloom filters, private/public key utilities, devp2p, RLP, and more.")])]),a("div",{staticClass:"theorem"},[a("p",{staticClass:"title"},[a("a",{attrs:{href:"/lib/nim-stew/"}},[t._v("Stew")]),a("Badge",{attrs:{text:"encoding"}}),a("Badge",{attrs:{text:"formatting"}}),a("Badge",{attrs:{text:"development",type:"warn"}}),a("Badge",{attrs:{text:"utilities"}})],1),a("p",[t._v("General-purpose utilities and standard library extensions")])])])}),[],!1,null,null,null);e.default=s.exports}}]); \ No newline at end of file diff --git a/assets/js/8.9a0afdb5.js b/assets/js/8.9a0afdb5.js deleted file mode 100644 index 50c5dcb..0000000 --- a/assets/js/8.9a0afdb5.js +++ /dev/null @@ -1 +0,0 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[8],{207:function(t,a,n){"use strict";n.r(a);var s=n(28),e=Object(s.a)({},(function(){var t=this,a=t.$createElement,n=t._self._c||a;return n("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[n("h1",{attrs:{id:"chronos"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#chronos"}},[t._v("#")]),t._v(" Chronos")]),t._v(" "),n("p",[t._v("Chronos is an efficient library for asynchronous programming and an alternative to Nim's asyncdispatch.")]),t._v(" "),n("h2",{attrs:{id:"documentation"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#documentation"}},[t._v("#")]),t._v(" Documentation")]),t._v(" "),n("p",[t._v("You can find more documentation, notes and examples in "),n("a",{attrs:{href:"https://github.com/status-im/nim-chronos/wiki",target:"_blank",rel:"noopener noreferrer"}},[t._v("Wiki"),n("OutboundLink")],1),t._v(".")]),t._v(" "),n("h2",{attrs:{id:"installation"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#installation"}},[t._v("#")]),t._v(" Installation")]),t._v(" "),n("p",[t._v("You can use Nim official package manager "),n("code",[t._v("nimble")]),t._v(" to install "),n("code",[t._v("chronos")]),t._v(". The most recent version of the library can be installed via:")]),t._v(" "),n("div",{staticClass:"language- line-numbers-mode"},[n("pre",{pre:!0,attrs:{class:"language-text"}},[n("code",[t._v("$ nimble install https://github.com/status-im/nim-chronos.git\n")])]),t._v(" "),n("div",{staticClass:"line-numbers-wrapper"},[n("span",{staticClass:"line-number"},[t._v("1")]),n("br")])]),n("h2",{attrs:{id:"todo"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#todo"}},[t._v("#")]),t._v(" TODO")]),t._v(" "),n("ul",[n("li",[t._v("Pipe/Subprocess Transports.")]),t._v(" "),n("li",[t._v("Multithreading Stream/Datagram servers")]),t._v(" "),n("li",[t._v("Future[T] cancelation")])])])}),[],!1,null,null,null);a.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/6.ccddad9d.js b/assets/js/8.b8ee59fd.js similarity index 93% rename from assets/js/6.ccddad9d.js rename to assets/js/8.b8ee59fd.js index 9102c99..09a6e97 100644 --- a/assets/js/6.ccddad9d.js +++ b/assets/js/8.b8ee59fd.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[6],{212:function(t,e,i){"use strict";i.r(e);var s=i(28),o=Object(s.a)({},(function(){var t=this,e=t.$createElement,i=t._self._c||e;return i("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[i("h1",{attrs:{id:"about"}},[i("a",{staticClass:"header-anchor",attrs:{href:"#about"}},[t._v("#")]),t._v(" About")]),t._v(" "),i("p",[t._v("This documentation suite was created as a comprehensive guide for using the Nim libraries produced by the Nimbus team at Status.im.")]),t._v(" "),i("h2",{attrs:{id:"what-is-nimbus"}},[i("a",{staticClass:"header-anchor",attrs:{href:"#what-is-nimbus"}},[t._v("#")]),t._v(" What is Nimbus?")]),t._v(" "),i("p",[i("a",{attrs:{href:"https://nimbus.status.im",target:"_blank",rel:"noopener noreferrer"}},[t._v("Nimbus"),i("OutboundLink")],1),t._v(" is an Ethereum 2.0 client, but these libraries are designed to be used outside of that context too. If your project needs good cryptography or verbose logging output, these libraries should fit the bill nicely.")]),t._v(" "),i("p",[t._v("You do not need to be a Nimbus user or developer to make use of these libraries.")]),t._v(" "),i("h2",{attrs:{id:"why-not-nimdoc"}},[i("a",{staticClass:"header-anchor",attrs:{href:"#why-not-nimdoc"}},[t._v("#")]),t._v(" Why not Nimdoc?")]),t._v(" "),i("p",[t._v("We actually do use Nimdoc for the API reference included in each library's documentation on this site. However, Nimdoc's template isn't the easiest to modify and it can produce some buggy results, so we use its JSON output to feed the API docs into this tome, and we use Vuepress for the rest of the functionality, like custom layouts, styling, SEO support, searchability, and of course - custom documentation support, like guides, tutorials, references, and more.")]),t._v(" "),i("h2",{attrs:{id:"contributing"}},[i("a",{staticClass:"header-anchor",attrs:{href:"#contributing"}},[t._v("#")]),t._v(" Contributing")]),t._v(" "),i("p",[t._v("You can contribute to these docs by submitting issues or pull requests in the official repository at "),i("a",{attrs:{href:"https://github.com/status-im/nimbus-libs-site",target:"_blank",rel:"noopener noreferrer"}},[t._v("status-im/nimbus-libs-site"),i("OutboundLink")],1),t._v(".")]),t._v(" "),i("p",[t._v("Keep in mind the following:")]),t._v(" "),i("ul",[i("li",[t._v("the API reference is generated from individual libraries. Thus, if you notice a mistake in the API reference, to submit a fix you should submit a PR to the library in question and fix its docblock.")]),t._v(" "),i("li",[t._v("the guides are curated and not everything that's written about the libraries will be included here.")])])])}),[],!1,null,null,null);e.default=o.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[8],{365:function(t,e,i){"use strict";i.r(e);var s=i(44),o=Object(s.a)({},(function(){var t=this,e=t.$createElement,i=t._self._c||e;return i("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[i("h1",{attrs:{id:"about"}},[i("a",{staticClass:"header-anchor",attrs:{href:"#about"}},[t._v("#")]),t._v(" About")]),t._v(" "),i("p",[t._v("This documentation suite was created as a comprehensive guide for using the Nim libraries produced by the Nimbus team at Status.im.")]),t._v(" "),i("h2",{attrs:{id:"what-is-nimbus"}},[i("a",{staticClass:"header-anchor",attrs:{href:"#what-is-nimbus"}},[t._v("#")]),t._v(" What is Nimbus?")]),t._v(" "),i("p",[i("a",{attrs:{href:"https://nimbus.status.im",target:"_blank",rel:"noopener noreferrer"}},[t._v("Nimbus"),i("OutboundLink")],1),t._v(" is an Ethereum 2.0 client, but these libraries are designed to be used outside of that context too. If your project needs good cryptography or verbose logging output, these libraries should fit the bill nicely.")]),t._v(" "),i("p",[t._v("You do not need to be a Nimbus user or developer to make use of these libraries.")]),t._v(" "),i("h2",{attrs:{id:"why-not-nimdoc"}},[i("a",{staticClass:"header-anchor",attrs:{href:"#why-not-nimdoc"}},[t._v("#")]),t._v(" Why not Nimdoc?")]),t._v(" "),i("p",[t._v("We actually do use Nimdoc for the API reference included in each library's documentation on this site. However, Nimdoc's template isn't the easiest to modify and it can produce some buggy results, so we use its JSON output to feed the API docs into this tome, and we use Vuepress for the rest of the functionality, like custom layouts, styling, SEO support, searchability, and of course - custom documentation support, like guides, tutorials, references, and more.")]),t._v(" "),i("h2",{attrs:{id:"contributing"}},[i("a",{staticClass:"header-anchor",attrs:{href:"#contributing"}},[t._v("#")]),t._v(" Contributing")]),t._v(" "),i("p",[t._v("You can contribute to these docs by submitting issues or pull requests in the official repository at "),i("a",{attrs:{href:"https://github.com/status-im/nimbus-libs-site",target:"_blank",rel:"noopener noreferrer"}},[t._v("status-im/nimbus-libs-site"),i("OutboundLink")],1),t._v(".")]),t._v(" "),i("p",[t._v("Keep in mind the following:")]),t._v(" "),i("ul",[i("li",[t._v("the API reference is generated from individual libraries. Thus, if you notice a mistake in the API reference, to submit a fix you should submit a PR to the library in question and fix its docblock.")]),t._v(" "),i("li",[t._v("the guides are curated and not everything that's written about the libraries will be included here.")])])])}),[],!1,null,null,null);e.default=o.exports}}]); \ No newline at end of file diff --git a/assets/js/7.11707fb6.js b/assets/js/9.249d32d4.js similarity index 91% rename from assets/js/7.11707fb6.js rename to assets/js/9.249d32d4.js index 4ea33e3..2f467bb 100644 --- a/assets/js/7.11707fb6.js +++ b/assets/js/9.249d32d4.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[7],{211:function(t,e,s){"use strict";s.r(e);var a=s(28),n=Object(a.a)({},(function(){var t=this,e=t.$createElement,s=t._self._c||e;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"chronicles"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#chronicles"}},[t._v("#")]),t._v(" Chronicles")]),t._v(" "),s("p",[t._v("Chronicles is a library for structured logging. It adheres to the philosophy\nthat log files shouldn't be based on formatted text strings, but rather on\nwell-defined event records with arbitrary properties that are easy to read\nfor both humans and machines. Let's illustrate this with an example:")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" net"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" chronicles\n\nsocket"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("accept")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("..")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".)")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("...")]),t._v("\ndebug "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Client PSK"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" psk "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" client"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("getPskIdentity\ninfo "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"New incoming connection"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" remoteAddr "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" ip"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" remotePort "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" port\n\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br")])]),s("p",[t._v("Here, "),s("code",[t._v("debug")]),t._v(" and "),s("code",[t._v("info")]),t._v(" are logging statements, corresponding to different\nseverity levels. You can think of their first argument as the name of a\nparticular event that happened during the execution of the program, while\nthe rest of the arguments are the properties of this event.")]),t._v(" "),s("p",[t._v("From these logging statements, Chronicles can be configured to produce log\noutput in various structured formats. The default format is called "),s("code",[t._v("textlines")]),t._v("\nand it looks like this:")]),t._v(" "),s("p",[s("img",{attrs:{src:"https://github.com/status-im/nim-chronicles/raw/master/media/textlines.svg?sanitize=true",alt:"textblocks format example"}})]),t._v(" "),s("p",[t._v("Alternatively, you can use a multi-line format called "),s("code",[t._v("textblocks")]),t._v(":")]),t._v(" "),s("p",[s("img",{attrs:{src:"https://github.com/status-im/nim-chronicles/raw/master/media/textblocks.svg?sanitize=true",alt:"textblocks format example"}})]),t._v(" "),s("p",[t._v("While these human-readable formats provide a more traditional and familiar\nexperience of using a logging library, the true power of Chronicles is\nunlocked only after switching to the "),s("code",[t._v("JSON")]),t._v(" format. Then, the same log output\nwill look like this:")]),t._v(" "),s("p",[s("img",{attrs:{src:"https://github.com/status-im/nim-chronicles/raw/master/media/json.svg?sanitize=true",alt:"json format example"}})]),t._v(" "),s("p",[t._v("At first, switching to JSON may look like a daunting proposition, but\nChronicles provides a customized log tailing program called "),s("code",[t._v("chronicles-tail")]),t._v("\nwhich is able to transform the JSON stream back into the familiar human-readable\nform, while also providing additional advanced features such as on on-the-fly\nfiltering, sound alerts and more.")]),t._v(" "),s("p",[t._v("The main advantage of using JSON logging is that this facilitates the storage\nof the log records in specialized databases which are usually able to provide\nsearch and filtering capabilities and allow you to compute various aggregated\nmetrics and time-series data from the accumulated logs.")]),t._v(" "),s("p",[t._v("Typical log storage choices for the above are open-source search engines such\nas "),s("a",{attrs:{href:"https://www.elastic.co/",target:"_blank",rel:"noopener noreferrer"}},[t._v("ElasticSearch"),s("OutboundLink")],1),t._v(" or specialized providers such as "),s("a",{attrs:{href:"https://www.loggly.com/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Loggly"),s("OutboundLink")],1),t._v(".")]),t._v(" "),s("h2",{attrs:{id:"logging-scopes"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#logging-scopes"}},[t._v("#")]),t._v(" Logging Scopes")]),t._v(" "),s("p",[t._v("In the introduction, we saw "),s("code",[t._v("debug")]),t._v(" and "),s("code",[t._v("info")]),t._v(" as examples for logging\nstatements. Other similar statements include "),s("code",[t._v("trace")]),t._v(", "),s("code",[t._v("notice")]),t._v(", "),s("code",[t._v("warn")]),t._v(", "),s("code",[t._v("error")]),t._v("\nand "),s("code",[t._v("fatal")]),t._v(". All of these statements accept arbitrary key-value pairs.\nAs a short-cut, you are also allowed to specify only the name of a particular\nvariable and Chronicles will create a key with the same name (i.e. passing\na local variable named "),s("code",[t._v("foo")]),t._v(" will be translated to the pair "),s("code",[t._v("foo = foo")]),t._v(").")]),t._v(" "),s("p",[t._v("A common practice enforced in other logging libraries is to associate\nthe logging records with the name of the component that produced them\nor with a particular run-time property such as "),s("code",[t._v("RequestID")]),t._v(". Chronicles\nprovides two general-purpose facilities for assigning such properties\nin an automated way:")]),t._v(" "),s("h3",{attrs:{id:"logscope"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#logscope"}},[t._v("#")]),t._v(" "),s("code",[t._v("logScope")])]),t._v(" "),s("p",[s("code",[t._v("logScope")]),t._v(" can be used to introduce additional properties that will be\nautomatically attached to all logging statements in the current lexical\nscope:")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[t._v("logScope"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Lexical properties are typically assigned to a constant:")]),t._v("\n topics "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"rendering opengl"')]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# But you can also assign an expression that will be")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# evaluated on every log statement:")]),t._v("\n memoryUsage "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("currentMemUsage")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("renderFrame")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("..")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".)")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n inc frameCounter\n\n logScope"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# You can add additional properties in any scope. Only logging")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# statements that are in the same lexical scope will be affected:")]),t._v("\n frame "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" frameCounter\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" t "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("startTimer")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n debug "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Frame started"')]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("...")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("glFinish")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n debug "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Frame finished"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" totalPrimitives"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" frameTime "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" t"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("elapsed\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br"),s("span",{staticClass:"line-number"},[t._v("9")]),s("br"),s("span",{staticClass:"line-number"},[t._v("10")]),s("br"),s("span",{staticClass:"line-number"},[t._v("11")]),s("br"),s("span",{staticClass:"line-number"},[t._v("12")]),s("br"),s("span",{staticClass:"line-number"},[t._v("13")]),s("br"),s("span",{staticClass:"line-number"},[t._v("14")]),s("br"),s("span",{staticClass:"line-number"},[t._v("15")]),s("br"),s("span",{staticClass:"line-number"},[t._v("16")]),s("br"),s("span",{staticClass:"line-number"},[t._v("17")]),s("br"),s("span",{staticClass:"line-number"},[t._v("18")]),s("br"),s("span",{staticClass:"line-number"},[t._v("19")]),s("br"),s("span",{staticClass:"line-number"},[t._v("20")]),s("br"),s("span",{staticClass:"line-number"},[t._v("21")]),s("br"),s("span",{staticClass:"line-number"},[t._v("22")]),s("br"),s("span",{staticClass:"line-number"},[t._v("23")]),s("br")])]),s("p",[t._v("A "),s("code",[t._v("logScope")]),t._v(" is usually put near the top of a Nim module and used to\nspecify statically assigned properties such as message origin, component\nname, etc. The special "),s("code",[t._v("topics")]),t._v(" property demonstrated here is important\nfor the log filtering mechanism, which will be explained in more details\nlater. If present, this property will always appear first in the formatted\nlog output.")]),t._v(" "),s("h3",{attrs:{id:"publiclogscope"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#publiclogscope"}},[t._v("#")]),t._v(" "),s("code",[t._v("publicLogScope")])]),t._v(" "),s("p",[t._v("While a "),s("code",[t._v("logScope")]),t._v(" affects only the current module, a "),s("code",[t._v("publicLogScope")]),t._v("\nallows you to specify a set of custom properties that may affect your\nentire program. For example, if you have an application running in a\nserver cluster, you may want to assign a property such as "),s("code",[t._v("serverId")]),t._v("\nto every record. To achieve this, create a proxy logging module\nimporting "),s("code",[t._v("chronicles")]),t._v(" and setting up a "),s("code",[t._v("publicLogScope")]),t._v(":")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# logging.nim")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" chronicles\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getServerId"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\npublicLogScope"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("\n serverId "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getServerId")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br"),s("span",{staticClass:"line-number"},[t._v("9")]),s("br")])]),s("p",[t._v("Every other module importing the proxy module will be able to use the\nentire Chronicles API and will be affected by the public scope.\nIn fact, you should not import "),s("code",[t._v("chronicles")]),t._v(" from such modules, because\nthis will lead to ambiguous symbols such as "),s("code",[t._v("activeChroniclesScope")]),t._v(" and\n"),s("code",[t._v("activeChroniclesStream")]),t._v(".")]),t._v(" "),s("p",[t._v("Using Nim's "),s("code",[t._v("--import:")]),t._v(" option may be a good way to enforce the use of\nthe proxy module in your entire program.")]),t._v(" "),s("h3",{attrs:{id:"dynamiclogscope"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#dynamiclogscope"}},[t._v("#")]),t._v(" "),s("code",[t._v("dynamicLogScope")])]),t._v(" "),s("p",[t._v("A "),s("code",[t._v("dynamicLogScope")]),t._v(" is a construct accepting a block of code that can be\nused to attach properties to all logging statements that will be executed\nanywhere within the tree of calls originating from the said block. The key\ndifference with the lexically bound properties is that this includes\nlogging statements from other modules, which are not within the lexical\nscope of the "),s("code",[t._v("dynamicLogScope")]),t._v(" statement.")]),t._v(" "),s("p",[t._v("If you still find the distinction between lexical and dynamic scopes confusing,\nreading the following explanation may help you:")]),t._v(" "),s("p",[t._v("http://wiki.c2.com/?DynamicScoping")]),t._v(" "),s("p",[t._v("A dynamic scope is usually used to track the reason why a particular\nlibrary function is being called (e.g. you are opening a file as a result\nof a particular network request):")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("onNewRequest")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("req"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Request"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n inc reqID\n info "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"request received"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" reqID"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" origin "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" req"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("remoteAddress\n "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("dynamicLogScope")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("reqID"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# All logging statements triggered before the current block returns")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# will feature the reqID property. This includes logging statements")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# from other modules.")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("handleRequest")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("req"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br")])]),s("p",[t._v("Just like regular log statements, "),s("code",[t._v("dynamicLogScope")]),t._v(" accepts a list of arbitrary\nkey-value pairs. The use of "),s("code",[t._v("reqID")]),t._v(" in the example above is a convenient short\nform for specifying the pair "),s("code",[t._v("reqID = reqID")]),t._v(".")]),t._v(" "),s("p",[t._v("While the properties associated with lexical scopes are lazily evaluated as\npreviously demonstrated, all expressions at the beginning of a dynamic scope\nwill be eagerly evaluated before the block is entered.")]),t._v(" "),s("h2",{attrs:{id:"compile-time-configuration"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#compile-time-configuration"}},[t._v("#")]),t._v(" Compile-Time Configuration")]),t._v(" "),s("p",[t._v("Almost everything about Chronicles in configured at compile-time, through the\nmechanism of Nim's "),s("code",[t._v("-d:")]),t._v(" flags. For example, you can completely remove all of\nthe code related to logging by simply setting "),s("code",[t._v("chronicles_enabled")]),t._v(" to "),s("code",[t._v("off")]),t._v(":")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("nim c -d:chronicles_enabled=off myprogram.nim\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("p",[t._v("Chronicles comes with a very reasonable default configuration, but let's look\nat some of the other supported options:")]),t._v(" "),s("h3",{attrs:{id:"chronicles-sinks"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#chronicles-sinks"}},[t._v("#")]),t._v(" chronicles_sinks")]),t._v(" "),s("p",[t._v("Chronicles supports producing log records in multiple formats and writing\nthose to various destinations such as the std streams, the system's syslog\ndaemon, or to one or more log files.")]),t._v(" "),s("p",[t._v("The combination of a log format and one or more associated log destinations\nis called a 'sink'. You can use the "),s("code",[t._v("chronicles_sinks")]),t._v(" option to provide the\nlist of sinks that will be used in your program.")]),t._v(" "),s("p",[t._v("The sinks are specified as a comma-separated list of valid Nim expressions\nthat will be better illustrated by the following examples:")]),t._v(" "),s("ul",[s("li",[s("p",[s("code",[t._v("json")])]),t._v(" "),s("p",[t._v("Write JSON-records to stdout")])]),t._v(" "),s("li",[s("p",[s("code",[t._v("json[file]")])]),t._v(" "),s("p",[t._v("Write JSON-records to a file in the current directory named after the\napplication itself.")])]),t._v(" "),s("li",[s("p",[s("code",[t._v("textblocks[stdout,file(/var/log/myapp.log)]")])]),t._v(" "),s("p",[t._v("Use the 'textblocks' format and send the output both to stdout and\nto a file with an absolute path /var/log/myapp.log")])]),t._v(" "),s("li",[s("p",[s("code",[t._v("textlines[notimestamps,file(myapp.txt),syslog]")])]),t._v(" "),s("p",[t._v("Use the 'textlines' format, but don't include timestamps and write\nboth to a file named 'myapp.txt' with a relative path to the current\nworking directory and also to syslog.")])]),t._v(" "),s("li",[s("p",[s("code",[t._v("textlines[nocolors],json[file(logs/myapp.json,truncate)]")])]),t._v(" "),s("p",[t._v("Send the output both in the 'textlines' format to stdout (but without\nusing colors) and to a JSON file named myapp.json in the relative\ndirectory 'logs'. The myapp.json file will be truncated on each\nprogram execution.")])])]),t._v(" "),s("p",[t._v("The built-in formats include "),s("code",[t._v("json")]),t._v(", "),s("code",[t._v("textlines")]),t._v(" and "),s("code",[t._v("textblocks")]),t._v(", which\nsupport options for specifying the use of colors and timestamps (for more\ninfo see "),s("code",[t._v("chronicles_colors")]),t._v(" and "),s("code",[t._v("chronicles_timestamps")]),t._v(").")]),t._v(" "),s("p",[t._v("The possible log destinations are "),s("code",[t._v("stdout")]),t._v(", "),s("code",[t._v("stderr")]),t._v(", "),s("code",[t._v("file")]),t._v(", "),s("code",[t._v("syslog")]),t._v("\nand "),s("code",[t._v("dynamic")]),t._v(".")]),t._v(" "),s("p",[t._v("Please note that Chronicles also allows you to implement custom logging\nformats through the use of the "),s("code",[t._v("customLogStream")]),t._v(" facility.")]),t._v(" "),s("h3",{attrs:{id:"chronicles-default-output-device"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#chronicles-default-output-device"}},[t._v("#")]),t._v(" chronicles_default_output_device")]),t._v(" "),s("p",[t._v('When a sink doesn\'t explicitly specify a particular log destination,\nChronicles will log to "stdout" by default. Use this define to specify\na different default choice.')]),t._v(" "),s("h3",{attrs:{id:"chronicles-streams"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#chronicles-streams"}},[t._v("#")]),t._v(" chronicles_streams")]),t._v(" "),s("p",[t._v("While having multiple log sinks enables you to record the same stream of\nevents in multiple formats and destinations, "),s("code",[t._v("chronicles_streams")]),t._v(" allows\nyou to define additional independent streams of events identified by their\nname. In the code, each logging statement is associated with exactly one\nlog stream, which in turn has an associated list of sinks.")]),t._v(" "),s("p",[t._v("The syntax for defining streams closely resembles the syntax for defining\nsinks:")]),t._v(" "),s("ul",[s("li",[s("code",[t._v("textlog[textlines],transactions[json[file(transactions.json)]]")])])]),t._v(" "),s("p",[t._v("This will create two streams, called "),s("code",[t._v("textlog")]),t._v(" and "),s("code",[t._v("transactions")]),t._v(".\nThe former will be considered the default stream associated with unqualified\nlogging statements, but each of the streams will exist as a separate symbol\nin the code, supporting the full set of logging operations:")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[t._v("textlog"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("debug "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"about to create a transaction"')]),t._v("\ntransactions"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("info "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"transaction created"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" buyer "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" alice"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" seller "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" bob\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br")])]),s("p",[t._v("The streams created through "),s("code",[t._v("chronicles_streams")]),t._v(" will be exported by the\n"),s("code",[t._v("chronicles")]),t._v(" module itself, but you can also introduce additional streams\nin your own modules by using the helpers "),s("code",[t._v("logStream")]),t._v(" and "),s("code",[t._v("customLogStream")]),t._v(".")]),t._v(" "),s("h3",{attrs:{id:"chronicles-enabled-topics"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#chronicles-enabled-topics"}},[t._v("#")]),t._v(" chronicles_enabled_topics")]),t._v(" "),s("p",[t._v("All logging statements may be associated with a statically known list of\ntopics. Usually, this is done by specifying the "),s("code",[t._v("topics")]),t._v(" property in a\nparticular "),s("code",[t._v("logScope")]),t._v(", but you can also specify it for individual log\nstatements.")]),t._v(" "),s("p",[t._v("You can use the "),s("code",[t._v("chronicles_enabled_topics")]),t._v(" option to specify the list of\ntopics for which the logging statements should produce output. All other\nlogging statements will be erased at compile-time from the final code.\nWhen the list includes multiple topics, any of them is considered a match.")]),t._v(" "),s("blockquote",[s("p",[t._v("In both contexts, the list of topics is written as a comma or space-separated\nstring of case-sensitive topic names.")])]),t._v(" "),s("p",[t._v("In the list of topics, you can also optionally provide a log level after the\ntopic, separated with a colon from the topic. If a log level is provided it will\noverrule the "),s("code",[t._v("chronicles_log_level")]),t._v(" setting. The log level can be defined as\n"),s("code",[t._v("LogLevel")]),t._v(" values or directly as the corresponding integer values.")]),t._v(" "),s("p",[t._v("e.g. "),s("code",[t._v("-d:chronicles_enabled_topics:MyTopic:DEBUG,AnotherTopic:5")])]),t._v(" "),s("h3",{attrs:{id:"chronicles-required-topics"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#chronicles-required-topics"}},[t._v("#")]),t._v(" chronicles_required_topics")]),t._v(" "),s("p",[t._v("Similar to "),s("code",[t._v("chronicles_enabled_topics")]),t._v(", but requires the logging statements\nto have all of the topics specified in this list.")]),t._v(" "),s("p",[t._v("You cannot specify "),s("code",[t._v("chronicles_enabled_topics")]),t._v(" and "),s("code",[t._v("chronicles_required_topics")]),t._v("\nat the same time.")]),t._v(" "),s("h3",{attrs:{id:"chronicles-disabled-topics"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#chronicles-disabled-topics"}},[t._v("#")]),t._v(" chronicles_disabled_topics")]),t._v(" "),s("p",[t._v("The dual of "),s("code",[t._v("chronicles_enabled_topics")]),t._v(". This option specifies a black-list\nof topics for which the associated logging statements should be erased from\nthe program.")]),t._v(" "),s("p",[t._v("Topics in "),s("code",[t._v("chronicles_disabled_topics")]),t._v(" have precedence over the ones in\n"),s("code",[t._v("chronicles_enabled_topics")]),t._v(" or "),s("code",[t._v("chronicles_required_topics")]),t._v(".")]),t._v(" "),s("h3",{attrs:{id:"chronicles-log-level"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#chronicles-log-level"}},[t._v("#")]),t._v(" chronicles_log_level")]),t._v(" "),s("p",[t._v("This option can be used to erase at compile-time all log statements, not\nmatching the specified minimum log level.")]),t._v(" "),s("p",[t._v("Possible values are "),s("code",[t._v("TRACE")]),t._v(", "),s("code",[t._v("DEBUG")]),t._v(", "),s("code",[t._v("INFO")]),t._v(", "),s("code",[t._v("NOTICE")]),t._v(", "),s("code",[t._v("WARN")]),t._v(", "),s("code",[t._v("ERROR")]),t._v(", "),s("code",[t._v("FATAL")]),t._v(",\nand "),s("code",[t._v("NONE")]),t._v(". The default value is "),s("code",[t._v("DEBUG")]),t._v(" in debug builds and "),s("code",[t._v("INFO")]),t._v(" in\nrelease mode.")]),t._v(" "),s("h3",{attrs:{id:"chronicles-runtime-filtering"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#chronicles-runtime-filtering"}},[t._v("#")]),t._v(" chronicles_runtime_filtering")]),t._v(" "),s("p",[t._v("This option enables the run-filtering capabilities of Chronicles.\nThe run-time filtering is controlled through the procs "),s("code",[t._v("setLogLevel")]),t._v("\nand "),s("code",[t._v("setTopicState")]),t._v(":")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("type")]),t._v(" LogLevel "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("enum")]),t._v("\n NONE"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" TRACE"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" DEBUG"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" INFO"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" NOTICE"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" WARN"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" ERROR"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" FATAL\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("setLogLevel"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("level"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" LogLevel"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("type")]),t._v(" TopicState "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("enum")]),t._v("\n Normal"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" Enabled"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" Required"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" Disabled\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("setTopicState"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("name"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" string"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n newState"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" TopicState"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n logLevel "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" LogLevel"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("NONE"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" bool\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br"),s("span",{staticClass:"line-number"},[t._v("9")]),s("br"),s("span",{staticClass:"line-number"},[t._v("10")]),s("br"),s("span",{staticClass:"line-number"},[t._v("11")]),s("br")])]),s("p",[t._v("The log levels available at runtime - and therefor to "),s("code",[t._v("setLogLevel()")]),t._v(" - are\nthose greater than or equal to the one set at compile time by\n"),s("code",[t._v("chronicles_log_level")]),t._v(".")]),t._v(" "),s("p",[t._v("It is also possible for a specific topic to overrule the global "),s("code",[t._v("LogLevel")]),t._v(", set\nby "),s("code",[t._v("setLogLevel")]),t._v(", by setting the optional "),s("code",[t._v("logLevel")]),t._v(" parameter in\n"),s("code",[t._v("setTopicState")]),t._v(" to a valid "),s("code",[t._v("LogLevel")]),t._v(".")]),t._v(" "),s("p",[t._v("The option is disabled by default because we recommend filtering the\nlog output in a tailing program. This allows you to still look at all\nlogged events in case this becomes necessary. Set the option to "),s("code",[t._v("on")]),t._v("\nto enable it.")]),t._v(" "),s("h3",{attrs:{id:"chronicles-timestamps"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#chronicles-timestamps"}},[t._v("#")]),t._v(" chronicles_timestamps")]),t._v(" "),s("p",[t._v("This option controls the use of timestamps in the log output.\nPossible values are:")]),t._v(" "),s("ul",[s("li",[s("p",[s("code",[t._v("RfcTime")]),t._v(" (used by default)")]),t._v(" "),s("p",[t._v("Chronicles will use the human-readable format specified in\nRFC 3339: Date and Time on the Internet: Timestamps")]),t._v(" "),s("p",[t._v("https://tools.ietf.org/html/rfc3339")])]),t._v(" "),s("li",[s("p",[s("code",[t._v("UnixTime")])]),t._v(" "),s("p",[t._v('Chronicles will write a single float value for the number\nof seconds since the "Unix epoch"')]),t._v(" "),s("p",[t._v("https://en.wikipedia.org/wiki/Unix_time")])]),t._v(" "),s("li",[s("p",[s("code",[t._v("None")]),t._v(" or "),s("code",[t._v("NoTimestamps")])]),t._v(" "),s("p",[t._v("Chronicles will not include timestamps in the log output.")])])]),t._v(" "),s("p",[t._v("Please note that the timestamp format can also be specified\nfor individual sinks (see "),s("code",[t._v("chronicles_sinks")]),t._v(").")]),t._v(" "),s("h3",{attrs:{id:"chronicles-line-numbers"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#chronicles-line-numbers"}},[t._v("#")]),t._v(" chronicles_line_numbers")]),t._v(" "),s("p",[t._v("This option, disabled by default, enables the display of filename and line number\nwhere each record was instantiated. It adds a property "),s("code",[t._v("file")]),t._v(" to the output, for example:")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("file: example.nim:15\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("p",[t._v("While "),s("code",[t._v("chronicles_line_numbers")]),t._v(" sets the default option for all records, it is\nalso possible to control the same property in a lexical scope or for a particular\nlog statement with "),s("code",[t._v("chroniclesLineNumbers")]),t._v(", which can be either "),s("code",[t._v("true")]),t._v(" or "),s("code",[t._v("false")]),t._v(".")]),t._v(" "),s("h3",{attrs:{id:"chronicles-colors"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#chronicles-colors"}},[t._v("#")]),t._v(" chronicles_colors")]),t._v(" "),s("p",[t._v("This option controls the default color scheme used by Chronicles for\nits human-readable text formats when sent to the standard output streams.")]),t._v(" "),s("p",[t._v("Possible values are:")]),t._v(" "),s("ul",[s("li",[s("p",[s("code",[t._v("NativeColors")]),t._v(" (used by default)")]),t._v(" "),s("p",[t._v("In this mode, Windows builds will produce output suitable for the console\napplication in older versions of Windows. On Unix-like systems, ANSI codes\nare still used.")])]),t._v(" "),s("li",[s("p",[s("code",[t._v("AnsiColors")])]),t._v(" "),s("p",[t._v("Output suitable for terminals supporting the standard ANSI escape codes:\nhttps://en.wikipedia.org/wiki/ANSI_escape_code")]),t._v(" "),s("p",[t._v("This includes most terminal emulators on modern Unix-like systems,\nWindows console replacements such as ConEmu, and the native Console\nand PowerShell applications on Windows 10.")])]),t._v(" "),s("li",[s("p",[s("code",[t._v("None")]),t._v(" or "),s("code",[t._v("NoColors")])]),t._v(" "),s("p",[t._v("Chronicles will produce color-less output. Please note that this is the\ndefault mode for sinks logging only to files or for sinks using the json\nformat.")])])]),t._v(" "),s("p",[t._v("Current known limitations:")]),t._v(" "),s("ul",[s("li",[t._v("Chronicles will not try to detect if the standard outputs\nof the program are being redirected to another program or a file.\nIt's typical for the colored output to be disabled in such circumstances.\n("),s("a",{attrs:{href:"https://github.com/status-im/nim-chronicles/issues/1",target:"_blank",rel:"noopener noreferrer"}},[t._v("issue"),s("OutboundLink")],1),t._v(")")])]),t._v(" "),s("h3",{attrs:{id:"chronicles-indent"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#chronicles-indent"}},[t._v("#")]),t._v(" chronicles_indent")]),t._v(" "),s("p",[t._v("This option sets the desired number of spaces that Chronicles should\nuse as indentation in the "),s("code",[t._v("textblocks")]),t._v(" format.")]),t._v(" "),s("hr"),t._v(" "),s("p",[t._v("All of the discussed options are case-insensitive and accept a number of\ntruthy and falsy values such as "),s("code",[t._v("on")]),t._v(", "),s("code",[t._v("off")]),t._v(", "),s("code",[t._v("true")]),t._v(", "),s("code",[t._v("false")]),t._v(", "),s("code",[t._v("0")]),t._v(", "),s("code",[t._v("1")]),t._v(",\n"),s("code",[t._v("yes")]),t._v(", "),s("code",[t._v("no")]),t._v(" or "),s("code",[t._v("none")]),t._v(".")]),t._v(" "),s("h2",{attrs:{id:"working-with-file-outputs"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#working-with-file-outputs"}},[t._v("#")]),t._v(" Working with "),s("code",[t._v("file")]),t._v(" outputs")]),t._v(" "),s("p",[t._v("When a stream has "),s("code",[t._v("file")]),t._v(" outputs, you may choose to provide the log file\nlocation at run-time. Chronicles will create each log file lazily when the\nfirst log record is written. This gives you a chance to modify the default\ncompile-time path associated with each file output by calling the "),s("code",[t._v("open")]),t._v("\nproc on an "),s("code",[t._v("output")]),t._v(" symbol associated with the stream:")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# my_program.nim")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" config "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("loadConfiguration")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" success "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" defaultChroniclesStream"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("output"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("open")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("config"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("logFile"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fmAppend"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\ninfo "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"APPLICATION STARTED"')]),t._v("\n\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br")])]),s("p",[t._v("Compiled with:")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("nim c -d:chronicles_sinks=textlines[file] my_program.nim\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("p",[t._v("As you can see above, the default stream in Chronicles is called\n"),s("code",[t._v("defaultChroniclesStream")]),t._v(". If the stream had multiple file outputs,\nthey would have been accessible separately as "),s("code",[t._v("outputs[0]")]),t._v(", "),s("code",[t._v("outputs[1]")]),t._v("\nand so on. "),s("code",[t._v("output")]),t._v(" is a simple short-cut referring to the first of them.")]),t._v(" "),s("p",[t._v("When the compile-time configuration doesn't specify a default file name for\na particular file output, Chronicles will use the following rules for picking\nthe default automatically:")]),t._v(" "),s("ol",[s("li",[s("p",[t._v("The log file is created in the current working directory and its name\nmatches the name of the stream (plus a "),s("code",[t._v(".log")]),t._v(" extension). The exception\nfor this rule is the default stream, for which the log file will be\nassigned the name of the application binary.")])]),t._v(" "),s("li",[s("p",[t._v("If more than one unnamed file outputs exist for a given stream,\nchronicles will add an index such as "),s("code",[t._v(".2.log")]),t._v(", "),s("code",[t._v(".3.log")]),t._v(" .. "),s("code",[t._v(".N.log")]),t._v("\nto the final file name.")])])]),t._v(" "),s("h2",{attrs:{id:"working-with-dynamic-outputs"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#working-with-dynamic-outputs"}},[t._v("#")]),t._v(" Working with "),s("code",[t._v("dynamic")]),t._v(" outputs")]),t._v(" "),s("p",[t._v("A "),s("code",[t._v("dynamic")]),t._v(" output redirects all logged messages to a closure supplied by\nthe host application. Similar to working with file ouputs "),s("a",{attrs:{href:"#working-with-file-outputs"}},[t._v("file outputs")]),t._v(",\nyou can use the "),s("code",[t._v("output")]),t._v(" and "),s("code",[t._v("outputs")]),t._v(" properties of a Chronicles stream\nto specify a gcsafe closure:")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[t._v("defaultChroniclesStream"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("output"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("writer "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("logLevel"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" LogLevel"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" msg"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" LogOutputStr"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{.")]),t._v("gcsafe"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n database"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("writeLogEntry")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("msg"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br")])]),s("h2",{attrs:{id:"using-chronicles-with-nosideeffect"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#using-chronicles-with-nosideeffect"}},[t._v("#")]),t._v(" Using Chronicles with "),s("code",[t._v("{.noSideEffect.}")])]),t._v(" "),s("p",[t._v("Usage of Chronicles from "),s("code",[t._v("noSideEffect")]),t._v(" procs (or "),s("code",[t._v("func")]),t._v(") is limited to the\n"),s("code",[t._v("trace")]),t._v(" statement. Normal logging can be considered a side effect, but "),s("code",[t._v("trace")]),t._v("\nis meant as a debugging aid. It's analogous to Nim's "),s("code",[t._v("debugEcho")]),t._v(", which also\nbypasses the effect system.")]),t._v(" "),s("h2",{attrs:{id:"teaching-chronicles-about-your-types"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#teaching-chronicles-about-your-types"}},[t._v("#")]),t._v(" Teaching Chronicles about your types")]),t._v(" "),s("p",[t._v("Chronicles can output log records in any of the formats supported by the Nim\n"),s("a",{attrs:{href:"https://github.com/status-im/nim-serialization",target:"_blank",rel:"noopener noreferrer"}},[s("code",[t._v("serialization")]),s("OutboundLink")],1),t._v(" package.\nWhen you specify a named format such as "),s("code",[t._v("json")]),t._v(", Chronicles will expect that\nyour project also depends on the respective serialization package (e.g.\n"),s("a",{attrs:{href:"https://github.com/status-im/nim-json-serialization",target:"_blank",rel:"noopener noreferrer"}},[s("code",[t._v("json_serialization")]),s("OutboundLink")],1),t._v(").")]),t._v(" "),s("p",[t._v("In the text formats ("),s("code",[t._v("textlines")]),t._v(" and "),s("code",[t._v("textblocks")]),t._v("), the Nim's standard "),s("code",[t._v("$")]),t._v("\noperator will be used to convert the logged properties to strings.")]),t._v(" "),s("h3",{attrs:{id:"formatit"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#formatit"}},[t._v("#")]),t._v(" "),s("code",[t._v("formatIt")])]),t._v(" "),s("p",[t._v("You can instruct Chronicles to alter this default behavior for a particular\ntype by providing a "),s("code",[t._v("chronicles.formatIt")]),t._v(" override:")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("type")]),t._v(" Dollar "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("distinct")]),t._v(" int\nchronicles"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("formatIt")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Dollar"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"$"')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("$")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("it"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("int"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br")])]),s("p",[t._v("The "),s("code",[t._v("formatIt")]),t._v(" block can evaluate to any expression that will be then\nsubjected to the standard serialization logic described above.")]),t._v(" "),s("h3",{attrs:{id:"expandit"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#expandit"}},[t._v("#")]),t._v(" "),s("code",[t._v("expandIt")])]),t._v(" "),s("p",[t._v("The "),s("code",[t._v("expandIt")]),t._v(" override can be used to turn any logged property of a\nparticular type into multiple properties:")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[t._v("chronicles"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("expandIt")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("EncryptedEnvelope"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("\n peer "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" it"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("fromAddress\n msg "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" it"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("decryptMsg\n\n"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("...")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" e "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("EncryptedEnvelope")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("..")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".)")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# The following two statements are equivalent:")]),t._v("\ninfo "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Received message"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" e\ninfo "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Received message"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" peer "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" e"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("fromAddress"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" msg "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" e"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("decryptMsg\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br"),s("span",{staticClass:"line-number"},[t._v("9")]),s("br"),s("span",{staticClass:"line-number"},[t._v("10")]),s("br"),s("span",{staticClass:"line-number"},[t._v("11")]),s("br")])]),s("p",[t._v("You can also derive the names of the expanded properties from the name of\nthe original logged property. This is achieved by using the Nim's backticks\nsyntax to construct the expanded property names:")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[t._v("chronicles"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("expandIt")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# You can use both identifiers and string literals:")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token ignore"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("`")]),t._v("it Name"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("`")])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" it"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("name\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("`")]),t._v("it "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"LastSeen"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("`")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" it"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("lastSeen\n\n"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("...")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" alice "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("User")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("name"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Alice"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("..")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".)")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# The following two statements are equivalent:")]),t._v("\ninfo "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Sending message"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" recipient "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" alice\ninfo "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Sending message"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" recipientName "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" alice"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("name"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" recipientLastSeen "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" alice"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("lastSeen\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br"),s("span",{staticClass:"line-number"},[t._v("9")]),s("br"),s("span",{staticClass:"line-number"},[t._v("10")]),s("br"),s("span",{staticClass:"line-number"},[t._v("11")]),s("br"),s("span",{staticClass:"line-number"},[t._v("12")]),s("br")])]),s("h2",{attrs:{id:"custom-log-streams"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#custom-log-streams"}},[t._v("#")]),t._v(" Custom Log Streams")]),t._v(" "),s("h3",{attrs:{id:"logstream"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#logstream"}},[t._v("#")]),t._v(" "),s("code",[t._v("logStream")])]),t._v(" "),s("p",[t._v("As an alternative to specifying multiple output streams with the\n"),s("code",[t._v("chronicles_streams")]),t._v(" option, you can also introduce additional\nstreams within the code of your program. A typical way to do this\nwould be to introduce a proxy module that imports and re-exports\n"),s("code",[t._v("chronicles")]),t._v(" while adding additional streams with "),s("code",[t._v("logStream")]),t._v(":")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" chronicles\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("export")]),t._v(" chronicles\n\nlogStream transactions"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("json"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("file")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("transactions"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("json"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br")])]),s("p",[t._v("The expression expected by "),s("code",[t._v("logStream")]),t._v(" has exactly the same format\nas the compile-time option and produces the same effect. In this particular\nexample, it will create a new stream called "),s("code",[t._v("transactions")]),t._v(" that will be sent\nto a JSON file named "),s("code",[t._v("transactions.json")]),t._v(".")]),t._v(" "),s("p",[t._v("After importing the proxy module, you'll be able to create records with any\nof the logging statements in the usual way:")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" transactions_log\n\n"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("...")]),t._v("\n\ntransactions"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("error "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"payment gateway time-out"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" orderId"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n networkStatus "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("obtainNetworkStatus")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br")])]),s("h3",{attrs:{id:"customlogstream"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#customlogstream"}},[t._v("#")]),t._v(" "),s("code",[t._v("customLogStream")])]),t._v(" "),s("p",[s("code",[t._v("customLogStream")]),t._v(" enables you to implement arbitrary log formats and\ndestinations.")]),t._v(" "),s("p",[t._v('Each logging statement is translated to a set of calls operating over\na structure called "Log Record" (with one instance created per logging\nstatement). New log formats can be implemented by defining a suitable\nlog record type. Let\'s demonstrate this by implementing a simple XML logger:')]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" xmltree"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" chronicles\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("type")]),t._v(" XmlRecord"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("Output"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("object")]),t._v("\n output"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Output\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("template")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("initLogRecord"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("r"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" XmlRecord"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" lvl"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" LogLevel"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n topics"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" string"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" name"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" string"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n r"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("output"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("append "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"\\n"')]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("template")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("setProperty"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("r"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" XmlRecord"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" key"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" string"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" val"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" auto"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n r"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("output"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("append textBlockIndent"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"<"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" key"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('">"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("escape")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("$")]),t._v("val"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"\\n"')]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("template")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("setFirstProperty"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("r"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" XmlRecord"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" key"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" string"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" val"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" auto"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n r"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("setProperty key"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" val\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("template")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("flushRecord"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("r"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" XmlRecord"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n r"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("output"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("append "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"\\n"')]),t._v("\n r"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("output"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("flushOutput\n\ncustomLogStream xmlout"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("XmlRecord"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("StdOutOutput"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n\npublicLogScope"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("\n stream "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" xmlout\n\ninfo "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"New Video"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" franchise "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Tom & Jerry"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" episode "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Smarty Cat"')]),t._v("\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br"),s("span",{staticClass:"line-number"},[t._v("9")]),s("br"),s("span",{staticClass:"line-number"},[t._v("10")]),s("br"),s("span",{staticClass:"line-number"},[t._v("11")]),s("br"),s("span",{staticClass:"line-number"},[t._v("12")]),s("br"),s("span",{staticClass:"line-number"},[t._v("13")]),s("br"),s("span",{staticClass:"line-number"},[t._v("14")]),s("br"),s("span",{staticClass:"line-number"},[t._v("15")]),s("br"),s("span",{staticClass:"line-number"},[t._v("16")]),s("br"),s("span",{staticClass:"line-number"},[t._v("17")]),s("br"),s("span",{staticClass:"line-number"},[t._v("18")]),s("br"),s("span",{staticClass:"line-number"},[t._v("19")]),s("br"),s("span",{staticClass:"line-number"},[t._v("20")]),s("br"),s("span",{staticClass:"line-number"},[t._v("21")]),s("br"),s("span",{staticClass:"line-number"},[t._v("22")]),s("br"),s("span",{staticClass:"line-number"},[t._v("23")]),s("br"),s("span",{staticClass:"line-number"},[t._v("24")]),s("br"),s("span",{staticClass:"line-number"},[t._v("25")]),s("br")])]),s("p",[t._v("The produced output from the example will be:")]),t._v(" "),s("div",{staticClass:"language-xml line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-xml"}},[s("code",[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("event")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("name")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')]),t._v("New Video"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("severity")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')]),t._v("INFO"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("tid")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("0"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("episode")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("Smarty Cat"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("franchise")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("Tom "),s("span",{pre:!0,attrs:{class:"token entity",title:"&"}},[t._v("&")]),t._v(" Jerry"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br")])]),s("p",[t._v("As you can see, "),s("code",[t._v("customLogStream")]),t._v(" looks similar to a regular "),s("code",[t._v("logStream")]),t._v(",\nbut it expects a log record type as its only argument.")]),t._v(" "),s("p",[t._v("The record type is implemented by providing suitable definitons for\n"),s("code",[t._v("initLogRecord")]),t._v(", "),s("code",[t._v("setFirstProperty")]),t._v(", "),s("code",[t._v("setProperty")]),t._v(" and "),s("code",[t._v("flushRecord")]),t._v(".\nWe recommend defining these operations as templates because this will\nfacilitate the aggressive constant-folding employed by Chronicles (discussed\nin more details in the next section). We also recommend making your log\nrecord types parametric on an "),s("code",[t._v("Output")]),t._v(" type, because this will allow the\nusers of the code to specify any of the output types defined in Chronicles\nitself (see the module "),s("code",[t._v("log_output")]),t._v(" for a list of those).")]),t._v(" "),s("p",[t._v("As demonstrated in the example above, you can set the "),s("code",[t._v("stream")]),t._v(" property in\na Chronicles lexical scope to redirect all unqualified log statements to a\nparticular default stream.")]),t._v(" "),s("h2",{attrs:{id:"cost-of-abstractions-and-implementation-details"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#cost-of-abstractions-and-implementation-details"}},[t._v("#")]),t._v(" Cost of Abstractions and Implementation Details")]),t._v(" "),s("p",[t._v("Chronicles makes use of advanced compile-time programming techniques to\nproduce very efficient run-time code with minimal footprint.")]),t._v(" "),s("p",[t._v("The properties from lexical scopes are merged at compile-time with the\nlog statement arguments and if any constant variables are about to be\nsent to the log output, they will be first concatenated by the compiler\nin order to issue the minimum number of "),s("code",[t._v("write")]),t._v(" operations possible.")]),t._v(" "),s("p",[t._v("The dynamic scopes store their run-time bindings on the stack, in special\nframe structures forming a linked list. This list is traversed on each log\nstatement and each active property leads to one dynamically dispatched call.")]),t._v(" "),s("p",[t._v("To support constant-time topic filtering and property overriding in dynamic\nscopes, Chronicles consumes a large amount of thread-local memory, roughly\nproportional to the number of unique topic names and property names used\nin the program.")]),t._v(" "),s("h2",{attrs:{id:"future-directions"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#future-directions"}},[t._v("#")]),t._v(" Future Directions")]),t._v(" "),s("p",[t._v("At the moment, Chronicles intentionally omits certain features expected\nfrom a logging library such as log rotation and archival. We recommend\nfollowing the guidelines set in the "),s("a",{attrs:{href:"https://12factor.net/logs",target:"_blank",rel:"noopener noreferrer"}},[t._v("12-factor app methodology"),s("OutboundLink")],1),t._v("\nand sending your log output to "),s("code",[t._v("stdout")]),t._v(". It should be the responsibility\nof the supervising daemon of the app to implement log rotation and archival.")]),t._v(" "),s("p",[t._v("We understand that certain users would want to take advantage of the\nfile sinks provided by Chronicles and these users may benefit from the\naforementioned features. If the Nim community provides a package for\na low-level abstraction of an automatically rotated and archived log\nfile, Chronicles will provide options for using it.")])])}),[],!1,null,null,null);e.default=n.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[9],{367:function(t,e,s){"use strict";s.r(e);var a=s(44),n=Object(a.a)({},(function(){var t=this,e=t.$createElement,s=t._self._c||e;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"chronicles"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#chronicles"}},[t._v("#")]),t._v(" Chronicles")]),t._v(" "),s("p",[t._v("Chronicles is a library for structured logging. It adheres to the philosophy\nthat log files shouldn't be based on formatted text strings, but rather on\nwell-defined event records with arbitrary properties that are easy to read\nfor both humans and machines. Let's illustrate this with an example:")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" net"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" chronicles\n\nsocket"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("accept")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("..")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".)")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("...")]),t._v("\ndebug "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Client PSK"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" psk "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" client"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("getPskIdentity\ninfo "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"New incoming connection"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" remoteAddr "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" ip"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" remotePort "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" port\n\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br")])]),s("p",[t._v("Here, "),s("code",[t._v("debug")]),t._v(" and "),s("code",[t._v("info")]),t._v(" are logging statements, corresponding to different\nseverity levels. You can think of their first argument as the name of a\nparticular event that happened during the execution of the program, while\nthe rest of the arguments are the properties of this event.")]),t._v(" "),s("p",[t._v("From these logging statements, Chronicles can be configured to produce log\noutput in various structured formats. The default format is called "),s("code",[t._v("textlines")]),t._v("\nand it looks like this:")]),t._v(" "),s("p",[s("img",{attrs:{src:"https://github.com/status-im/nim-chronicles/raw/master/media/textlines.svg?sanitize=true",alt:"textblocks format example"}})]),t._v(" "),s("p",[t._v("Alternatively, you can use a multi-line format called "),s("code",[t._v("textblocks")]),t._v(":")]),t._v(" "),s("p",[s("img",{attrs:{src:"https://github.com/status-im/nim-chronicles/raw/master/media/textblocks.svg?sanitize=true",alt:"textblocks format example"}})]),t._v(" "),s("p",[t._v("While these human-readable formats provide a more traditional and familiar\nexperience of using a logging library, the true power of Chronicles is\nunlocked only after switching to the "),s("code",[t._v("JSON")]),t._v(" format. Then, the same log output\nwill look like this:")]),t._v(" "),s("p",[s("img",{attrs:{src:"https://github.com/status-im/nim-chronicles/raw/master/media/json.svg?sanitize=true",alt:"json format example"}})]),t._v(" "),s("p",[t._v("At first, switching to JSON may look like a daunting proposition, but\nChronicles provides a customized log tailing program called "),s("code",[t._v("chronicles-tail")]),t._v("\nwhich is able to transform the JSON stream back into the familiar human-readable\nform, while also providing additional advanced features such as on on-the-fly\nfiltering, sound alerts and more.")]),t._v(" "),s("p",[t._v("The main advantage of using JSON logging is that this facilitates the storage\nof the log records in specialized databases which are usually able to provide\nsearch and filtering capabilities and allow you to compute various aggregated\nmetrics and time-series data from the accumulated logs.")]),t._v(" "),s("p",[t._v("Typical log storage choices for the above are open-source search engines such\nas "),s("a",{attrs:{href:"https://www.elastic.co/",target:"_blank",rel:"noopener noreferrer"}},[t._v("ElasticSearch"),s("OutboundLink")],1),t._v(" or specialized providers such as "),s("a",{attrs:{href:"https://www.loggly.com/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Loggly"),s("OutboundLink")],1),t._v(".")]),t._v(" "),s("h2",{attrs:{id:"logging-scopes"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#logging-scopes"}},[t._v("#")]),t._v(" Logging Scopes")]),t._v(" "),s("p",[t._v("In the introduction, we saw "),s("code",[t._v("debug")]),t._v(" and "),s("code",[t._v("info")]),t._v(" as examples for logging\nstatements. Other similar statements include "),s("code",[t._v("trace")]),t._v(", "),s("code",[t._v("notice")]),t._v(", "),s("code",[t._v("warn")]),t._v(", "),s("code",[t._v("error")]),t._v("\nand "),s("code",[t._v("fatal")]),t._v(". All of these statements accept arbitrary key-value pairs.\nAs a short-cut, you are also allowed to specify only the name of a particular\nvariable and Chronicles will create a key with the same name (i.e. passing\na local variable named "),s("code",[t._v("foo")]),t._v(" will be translated to the pair "),s("code",[t._v("foo = foo")]),t._v(").")]),t._v(" "),s("p",[t._v("A common practice enforced in other logging libraries is to associate\nthe logging records with the name of the component that produced them\nor with a particular run-time property such as "),s("code",[t._v("RequestID")]),t._v(". Chronicles\nprovides two general-purpose facilities for assigning such properties\nin an automated way:")]),t._v(" "),s("h3",{attrs:{id:"logscope"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#logscope"}},[t._v("#")]),t._v(" "),s("code",[t._v("logScope")])]),t._v(" "),s("p",[s("code",[t._v("logScope")]),t._v(" can be used to introduce additional properties that will be\nautomatically attached to all logging statements in the current lexical\nscope:")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[t._v("logScope"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Lexical properties are typically assigned to a constant:")]),t._v("\n topics "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"rendering opengl"')]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# But you can also assign an expression that will be")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# evaluated on every log statement:")]),t._v("\n memoryUsage "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("currentMemUsage")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("renderFrame")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("..")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".)")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n inc frameCounter\n\n logScope"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# You can add additional properties in any scope. Only logging")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# statements that are in the same lexical scope will be affected:")]),t._v("\n frame "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" frameCounter\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" t "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("startTimer")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n debug "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Frame started"')]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("...")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("glFinish")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n debug "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Frame finished"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" totalPrimitives"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" frameTime "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" t"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("elapsed\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br"),s("span",{staticClass:"line-number"},[t._v("9")]),s("br"),s("span",{staticClass:"line-number"},[t._v("10")]),s("br"),s("span",{staticClass:"line-number"},[t._v("11")]),s("br"),s("span",{staticClass:"line-number"},[t._v("12")]),s("br"),s("span",{staticClass:"line-number"},[t._v("13")]),s("br"),s("span",{staticClass:"line-number"},[t._v("14")]),s("br"),s("span",{staticClass:"line-number"},[t._v("15")]),s("br"),s("span",{staticClass:"line-number"},[t._v("16")]),s("br"),s("span",{staticClass:"line-number"},[t._v("17")]),s("br"),s("span",{staticClass:"line-number"},[t._v("18")]),s("br"),s("span",{staticClass:"line-number"},[t._v("19")]),s("br"),s("span",{staticClass:"line-number"},[t._v("20")]),s("br"),s("span",{staticClass:"line-number"},[t._v("21")]),s("br"),s("span",{staticClass:"line-number"},[t._v("22")]),s("br"),s("span",{staticClass:"line-number"},[t._v("23")]),s("br")])]),s("p",[t._v("A "),s("code",[t._v("logScope")]),t._v(" is usually put near the top of a Nim module and used to\nspecify statically assigned properties such as message origin, component\nname, etc. The special "),s("code",[t._v("topics")]),t._v(" property demonstrated here is important\nfor the log filtering mechanism, which will be explained in more details\nlater. If present, this property will always appear first in the formatted\nlog output.")]),t._v(" "),s("h3",{attrs:{id:"publiclogscope"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#publiclogscope"}},[t._v("#")]),t._v(" "),s("code",[t._v("publicLogScope")])]),t._v(" "),s("p",[t._v("While a "),s("code",[t._v("logScope")]),t._v(" affects only the current module, a "),s("code",[t._v("publicLogScope")]),t._v("\nallows you to specify a set of custom properties that may affect your\nentire program. For example, if you have an application running in a\nserver cluster, you may want to assign a property such as "),s("code",[t._v("serverId")]),t._v("\nto every record. To achieve this, create a proxy logging module\nimporting "),s("code",[t._v("chronicles")]),t._v(" and setting up a "),s("code",[t._v("publicLogScope")]),t._v(":")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# logging.nim")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" chronicles\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getServerId"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\npublicLogScope"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("\n serverId "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getServerId")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br"),s("span",{staticClass:"line-number"},[t._v("9")]),s("br")])]),s("p",[t._v("Every other module importing the proxy module will be able to use the\nentire Chronicles API and will be affected by the public scope.\nIn fact, you should not import "),s("code",[t._v("chronicles")]),t._v(" from such modules, because\nthis will lead to ambiguous symbols such as "),s("code",[t._v("activeChroniclesScope")]),t._v(" and\n"),s("code",[t._v("activeChroniclesStream")]),t._v(".")]),t._v(" "),s("p",[t._v("Using Nim's "),s("code",[t._v("--import:")]),t._v(" option may be a good way to enforce the use of\nthe proxy module in your entire program.")]),t._v(" "),s("h3",{attrs:{id:"dynamiclogscope"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#dynamiclogscope"}},[t._v("#")]),t._v(" "),s("code",[t._v("dynamicLogScope")])]),t._v(" "),s("p",[t._v("A "),s("code",[t._v("dynamicLogScope")]),t._v(" is a construct accepting a block of code that can be\nused to attach properties to all logging statements that will be executed\nanywhere within the tree of calls originating from the said block. The key\ndifference with the lexically bound properties is that this includes\nlogging statements from other modules, which are not within the lexical\nscope of the "),s("code",[t._v("dynamicLogScope")]),t._v(" statement.")]),t._v(" "),s("p",[t._v("If you still find the distinction between lexical and dynamic scopes confusing,\nreading the following explanation may help you:")]),t._v(" "),s("p",[t._v("http://wiki.c2.com/?DynamicScoping")]),t._v(" "),s("p",[t._v("A dynamic scope is usually used to track the reason why a particular\nlibrary function is being called (e.g. you are opening a file as a result\nof a particular network request):")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("onNewRequest")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("req"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Request"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n inc reqID\n info "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"request received"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" reqID"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" origin "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" req"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("remoteAddress\n "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("dynamicLogScope")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("reqID"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# All logging statements triggered before the current block returns")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# will feature the reqID property. This includes logging statements")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# from other modules.")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("handleRequest")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("req"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br")])]),s("p",[t._v("Just like regular log statements, "),s("code",[t._v("dynamicLogScope")]),t._v(" accepts a list of arbitrary\nkey-value pairs. The use of "),s("code",[t._v("reqID")]),t._v(" in the example above is a convenient short\nform for specifying the pair "),s("code",[t._v("reqID = reqID")]),t._v(".")]),t._v(" "),s("p",[t._v("While the properties associated with lexical scopes are lazily evaluated as\npreviously demonstrated, all expressions at the beginning of a dynamic scope\nwill be eagerly evaluated before the block is entered.")]),t._v(" "),s("h2",{attrs:{id:"compile-time-configuration"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#compile-time-configuration"}},[t._v("#")]),t._v(" Compile-Time Configuration")]),t._v(" "),s("p",[t._v("Almost everything about Chronicles in configured at compile-time, through the\nmechanism of Nim's "),s("code",[t._v("-d:")]),t._v(" flags. For example, you can completely remove all of\nthe code related to logging by simply setting "),s("code",[t._v("chronicles_enabled")]),t._v(" to "),s("code",[t._v("off")]),t._v(":")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("nim c -d:chronicles_enabled=off myprogram.nim\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("p",[t._v("Chronicles comes with a very reasonable default configuration, but let's look\nat some of the other supported options:")]),t._v(" "),s("h3",{attrs:{id:"chronicles-sinks"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#chronicles-sinks"}},[t._v("#")]),t._v(" chronicles_sinks")]),t._v(" "),s("p",[t._v("Chronicles supports producing log records in multiple formats and writing\nthose to various destinations such as the std streams, the system's syslog\ndaemon, or to one or more log files.")]),t._v(" "),s("p",[t._v("The combination of a log format and one or more associated log destinations\nis called a 'sink'. You can use the "),s("code",[t._v("chronicles_sinks")]),t._v(" option to provide the\nlist of sinks that will be used in your program.")]),t._v(" "),s("p",[t._v("The sinks are specified as a comma-separated list of valid Nim expressions\nthat will be better illustrated by the following examples:")]),t._v(" "),s("ul",[s("li",[s("p",[s("code",[t._v("json")])]),t._v(" "),s("p",[t._v("Write JSON-records to stdout")])]),t._v(" "),s("li",[s("p",[s("code",[t._v("json[file]")])]),t._v(" "),s("p",[t._v("Write JSON-records to a file in the current directory named after the\napplication itself.")])]),t._v(" "),s("li",[s("p",[s("code",[t._v("textblocks[stdout,file(/var/log/myapp.log)]")])]),t._v(" "),s("p",[t._v("Use the 'textblocks' format and send the output both to stdout and\nto a file with an absolute path /var/log/myapp.log")])]),t._v(" "),s("li",[s("p",[s("code",[t._v("textlines[notimestamps,file(myapp.txt),syslog]")])]),t._v(" "),s("p",[t._v("Use the 'textlines' format, but don't include timestamps and write\nboth to a file named 'myapp.txt' with a relative path to the current\nworking directory and also to syslog.")])]),t._v(" "),s("li",[s("p",[s("code",[t._v("textlines[nocolors],json[file(logs/myapp.json,truncate)]")])]),t._v(" "),s("p",[t._v("Send the output both in the 'textlines' format to stdout (but without\nusing colors) and to a JSON file named myapp.json in the relative\ndirectory 'logs'. The myapp.json file will be truncated on each\nprogram execution.")])])]),t._v(" "),s("p",[t._v("The built-in formats include "),s("code",[t._v("json")]),t._v(", "),s("code",[t._v("textlines")]),t._v(" and "),s("code",[t._v("textblocks")]),t._v(", which\nsupport options for specifying the use of colors and timestamps (for more\ninfo see "),s("code",[t._v("chronicles_colors")]),t._v(" and "),s("code",[t._v("chronicles_timestamps")]),t._v(").")]),t._v(" "),s("p",[t._v("The possible log destinations are "),s("code",[t._v("stdout")]),t._v(", "),s("code",[t._v("stderr")]),t._v(", "),s("code",[t._v("file")]),t._v(", "),s("code",[t._v("syslog")]),t._v("\nand "),s("code",[t._v("dynamic")]),t._v(".")]),t._v(" "),s("p",[t._v("Please note that Chronicles also allows you to implement custom logging\nformats through the use of the "),s("code",[t._v("customLogStream")]),t._v(" facility.")]),t._v(" "),s("h3",{attrs:{id:"chronicles-default-output-device"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#chronicles-default-output-device"}},[t._v("#")]),t._v(" chronicles_default_output_device")]),t._v(" "),s("p",[t._v('When a sink doesn\'t explicitly specify a particular log destination,\nChronicles will log to "stdout" by default. Use this define to specify\na different default choice.')]),t._v(" "),s("h3",{attrs:{id:"chronicles-streams"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#chronicles-streams"}},[t._v("#")]),t._v(" chronicles_streams")]),t._v(" "),s("p",[t._v("While having multiple log sinks enables you to record the same stream of\nevents in multiple formats and destinations, "),s("code",[t._v("chronicles_streams")]),t._v(" allows\nyou to define additional independent streams of events identified by their\nname. In the code, each logging statement is associated with exactly one\nlog stream, which in turn has an associated list of sinks.")]),t._v(" "),s("p",[t._v("The syntax for defining streams closely resembles the syntax for defining\nsinks:")]),t._v(" "),s("ul",[s("li",[s("code",[t._v("textlog[textlines],transactions[json[file(transactions.json)]]")])])]),t._v(" "),s("p",[t._v("This will create two streams, called "),s("code",[t._v("textlog")]),t._v(" and "),s("code",[t._v("transactions")]),t._v(".\nThe former will be considered the default stream associated with unqualified\nlogging statements, but each of the streams will exist as a separate symbol\nin the code, supporting the full set of logging operations:")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[t._v("textlog"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("debug "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"about to create a transaction"')]),t._v("\ntransactions"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("info "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"transaction created"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" buyer "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" alice"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" seller "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" bob\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br")])]),s("p",[t._v("The streams created through "),s("code",[t._v("chronicles_streams")]),t._v(" will be exported by the\n"),s("code",[t._v("chronicles")]),t._v(" module itself, but you can also introduce additional streams\nin your own modules by using the helpers "),s("code",[t._v("logStream")]),t._v(" and "),s("code",[t._v("customLogStream")]),t._v(".")]),t._v(" "),s("h3",{attrs:{id:"chronicles-enabled-topics"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#chronicles-enabled-topics"}},[t._v("#")]),t._v(" chronicles_enabled_topics")]),t._v(" "),s("p",[t._v("All logging statements may be associated with a statically known list of\ntopics. Usually, this is done by specifying the "),s("code",[t._v("topics")]),t._v(" property in a\nparticular "),s("code",[t._v("logScope")]),t._v(", but you can also specify it for individual log\nstatements.")]),t._v(" "),s("p",[t._v("You can use the "),s("code",[t._v("chronicles_enabled_topics")]),t._v(" option to specify the list of\ntopics for which the logging statements should produce output. All other\nlogging statements will be erased at compile-time from the final code.\nWhen the list includes multiple topics, any of them is considered a match.")]),t._v(" "),s("blockquote",[s("p",[t._v("In both contexts, the list of topics is written as a comma or space-separated\nstring of case-sensitive topic names.")])]),t._v(" "),s("p",[t._v("In the list of topics, you can also optionally provide a log level after the\ntopic, separated with a colon from the topic. If a log level is provided it will\noverrule the "),s("code",[t._v("chronicles_log_level")]),t._v(" setting. The log level can be defined as\n"),s("code",[t._v("LogLevel")]),t._v(" values or directly as the corresponding integer values.")]),t._v(" "),s("p",[t._v("e.g. "),s("code",[t._v("-d:chronicles_enabled_topics:MyTopic:DEBUG,AnotherTopic:5")])]),t._v(" "),s("h3",{attrs:{id:"chronicles-required-topics"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#chronicles-required-topics"}},[t._v("#")]),t._v(" chronicles_required_topics")]),t._v(" "),s("p",[t._v("Similar to "),s("code",[t._v("chronicles_enabled_topics")]),t._v(", but requires the logging statements\nto have all of the topics specified in this list.")]),t._v(" "),s("p",[t._v("You cannot specify "),s("code",[t._v("chronicles_enabled_topics")]),t._v(" and "),s("code",[t._v("chronicles_required_topics")]),t._v("\nat the same time.")]),t._v(" "),s("h3",{attrs:{id:"chronicles-disabled-topics"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#chronicles-disabled-topics"}},[t._v("#")]),t._v(" chronicles_disabled_topics")]),t._v(" "),s("p",[t._v("The dual of "),s("code",[t._v("chronicles_enabled_topics")]),t._v(". This option specifies a black-list\nof topics for which the associated logging statements should be erased from\nthe program.")]),t._v(" "),s("p",[t._v("Topics in "),s("code",[t._v("chronicles_disabled_topics")]),t._v(" have precedence over the ones in\n"),s("code",[t._v("chronicles_enabled_topics")]),t._v(" or "),s("code",[t._v("chronicles_required_topics")]),t._v(".")]),t._v(" "),s("h3",{attrs:{id:"chronicles-log-level"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#chronicles-log-level"}},[t._v("#")]),t._v(" chronicles_log_level")]),t._v(" "),s("p",[t._v("This option can be used to erase at compile-time all log statements, not\nmatching the specified minimum log level.")]),t._v(" "),s("p",[t._v("Possible values are "),s("code",[t._v("TRACE")]),t._v(", "),s("code",[t._v("DEBUG")]),t._v(", "),s("code",[t._v("INFO")]),t._v(", "),s("code",[t._v("NOTICE")]),t._v(", "),s("code",[t._v("WARN")]),t._v(", "),s("code",[t._v("ERROR")]),t._v(", "),s("code",[t._v("FATAL")]),t._v(",\nand "),s("code",[t._v("NONE")]),t._v(". The default value is "),s("code",[t._v("DEBUG")]),t._v(" in debug builds and "),s("code",[t._v("INFO")]),t._v(" in\nrelease mode.")]),t._v(" "),s("h3",{attrs:{id:"chronicles-runtime-filtering"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#chronicles-runtime-filtering"}},[t._v("#")]),t._v(" chronicles_runtime_filtering")]),t._v(" "),s("p",[t._v("This option enables the run-filtering capabilities of Chronicles.\nThe run-time filtering is controlled through the procs "),s("code",[t._v("setLogLevel")]),t._v("\nand "),s("code",[t._v("setTopicState")]),t._v(":")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("type")]),t._v(" LogLevel "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("enum")]),t._v("\n NONE"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" TRACE"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" DEBUG"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" INFO"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" NOTICE"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" WARN"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" ERROR"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" FATAL\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("setLogLevel"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("level"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" LogLevel"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("type")]),t._v(" TopicState "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("enum")]),t._v("\n Normal"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" Enabled"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" Required"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" Disabled\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("setTopicState"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("name"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" string"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n newState"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" TopicState"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n logLevel "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" LogLevel"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("NONE"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" bool\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br"),s("span",{staticClass:"line-number"},[t._v("9")]),s("br"),s("span",{staticClass:"line-number"},[t._v("10")]),s("br"),s("span",{staticClass:"line-number"},[t._v("11")]),s("br")])]),s("p",[t._v("The log levels available at runtime - and therefor to "),s("code",[t._v("setLogLevel()")]),t._v(" - are\nthose greater than or equal to the one set at compile time by\n"),s("code",[t._v("chronicles_log_level")]),t._v(".")]),t._v(" "),s("p",[t._v("It is also possible for a specific topic to overrule the global "),s("code",[t._v("LogLevel")]),t._v(", set\nby "),s("code",[t._v("setLogLevel")]),t._v(", by setting the optional "),s("code",[t._v("logLevel")]),t._v(" parameter in\n"),s("code",[t._v("setTopicState")]),t._v(" to a valid "),s("code",[t._v("LogLevel")]),t._v(".")]),t._v(" "),s("p",[t._v("The option is disabled by default because we recommend filtering the\nlog output in a tailing program. This allows you to still look at all\nlogged events in case this becomes necessary. Set the option to "),s("code",[t._v("on")]),t._v("\nto enable it.")]),t._v(" "),s("h3",{attrs:{id:"chronicles-timestamps"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#chronicles-timestamps"}},[t._v("#")]),t._v(" chronicles_timestamps")]),t._v(" "),s("p",[t._v("This option controls the use of timestamps in the log output.\nPossible values are:")]),t._v(" "),s("ul",[s("li",[s("p",[s("code",[t._v("RfcTime")]),t._v(" (used by default)")]),t._v(" "),s("p",[t._v("Chronicles will use the human-readable format specified in\nRFC 3339: Date and Time on the Internet: Timestamps")]),t._v(" "),s("p",[t._v("https://tools.ietf.org/html/rfc3339")])]),t._v(" "),s("li",[s("p",[s("code",[t._v("UnixTime")])]),t._v(" "),s("p",[t._v('Chronicles will write a single float value for the number\nof seconds since the "Unix epoch"')]),t._v(" "),s("p",[t._v("https://en.wikipedia.org/wiki/Unix_time")])]),t._v(" "),s("li",[s("p",[s("code",[t._v("None")]),t._v(" or "),s("code",[t._v("NoTimestamps")])]),t._v(" "),s("p",[t._v("Chronicles will not include timestamps in the log output.")])])]),t._v(" "),s("p",[t._v("Please note that the timestamp format can also be specified\nfor individual sinks (see "),s("code",[t._v("chronicles_sinks")]),t._v(").")]),t._v(" "),s("h3",{attrs:{id:"chronicles-line-numbers"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#chronicles-line-numbers"}},[t._v("#")]),t._v(" chronicles_line_numbers")]),t._v(" "),s("p",[t._v("This option, disabled by default, enables the display of filename and line number\nwhere each record was instantiated. It adds a property "),s("code",[t._v("file")]),t._v(" to the output, for example:")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("file: example.nim:15\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("p",[t._v("While "),s("code",[t._v("chronicles_line_numbers")]),t._v(" sets the default option for all records, it is\nalso possible to control the same property in a lexical scope or for a particular\nlog statement with "),s("code",[t._v("chroniclesLineNumbers")]),t._v(", which can be either "),s("code",[t._v("true")]),t._v(" or "),s("code",[t._v("false")]),t._v(".")]),t._v(" "),s("h3",{attrs:{id:"chronicles-colors"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#chronicles-colors"}},[t._v("#")]),t._v(" chronicles_colors")]),t._v(" "),s("p",[t._v("This option controls the default color scheme used by Chronicles for\nits human-readable text formats when sent to the standard output streams.")]),t._v(" "),s("p",[t._v("Possible values are:")]),t._v(" "),s("ul",[s("li",[s("p",[s("code",[t._v("NativeColors")]),t._v(" (used by default)")]),t._v(" "),s("p",[t._v("In this mode, Windows builds will produce output suitable for the console\napplication in older versions of Windows. On Unix-like systems, ANSI codes\nare still used.")])]),t._v(" "),s("li",[s("p",[s("code",[t._v("AnsiColors")])]),t._v(" "),s("p",[t._v("Output suitable for terminals supporting the standard ANSI escape codes:\nhttps://en.wikipedia.org/wiki/ANSI_escape_code")]),t._v(" "),s("p",[t._v("This includes most terminal emulators on modern Unix-like systems,\nWindows console replacements such as ConEmu, and the native Console\nand PowerShell applications on Windows 10.")])]),t._v(" "),s("li",[s("p",[s("code",[t._v("None")]),t._v(" or "),s("code",[t._v("NoColors")])]),t._v(" "),s("p",[t._v("Chronicles will produce color-less output. Please note that this is the\ndefault mode for sinks logging only to files or for sinks using the json\nformat.")])])]),t._v(" "),s("p",[t._v("Current known limitations:")]),t._v(" "),s("ul",[s("li",[t._v("Chronicles will not try to detect if the standard outputs\nof the program are being redirected to another program or a file.\nIt's typical for the colored output to be disabled in such circumstances.\n("),s("a",{attrs:{href:"https://github.com/status-im/nim-chronicles/issues/1",target:"_blank",rel:"noopener noreferrer"}},[t._v("issue"),s("OutboundLink")],1),t._v(")")])]),t._v(" "),s("h3",{attrs:{id:"chronicles-indent"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#chronicles-indent"}},[t._v("#")]),t._v(" chronicles_indent")]),t._v(" "),s("p",[t._v("This option sets the desired number of spaces that Chronicles should\nuse as indentation in the "),s("code",[t._v("textblocks")]),t._v(" format.")]),t._v(" "),s("hr"),t._v(" "),s("p",[t._v("All of the discussed options are case-insensitive and accept a number of\ntruthy and falsy values such as "),s("code",[t._v("on")]),t._v(", "),s("code",[t._v("off")]),t._v(", "),s("code",[t._v("true")]),t._v(", "),s("code",[t._v("false")]),t._v(", "),s("code",[t._v("0")]),t._v(", "),s("code",[t._v("1")]),t._v(",\n"),s("code",[t._v("yes")]),t._v(", "),s("code",[t._v("no")]),t._v(" or "),s("code",[t._v("none")]),t._v(".")]),t._v(" "),s("h2",{attrs:{id:"working-with-file-outputs"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#working-with-file-outputs"}},[t._v("#")]),t._v(" Working with "),s("code",[t._v("file")]),t._v(" outputs")]),t._v(" "),s("p",[t._v("When a stream has "),s("code",[t._v("file")]),t._v(" outputs, you may choose to provide the log file\nlocation at run-time. Chronicles will create each log file lazily when the\nfirst log record is written. This gives you a chance to modify the default\ncompile-time path associated with each file output by calling the "),s("code",[t._v("open")]),t._v("\nproc on an "),s("code",[t._v("output")]),t._v(" symbol associated with the stream:")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# my_program.nim")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" config "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("loadConfiguration")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" success "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" defaultChroniclesStream"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("output"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("open")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("config"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("logFile"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fmAppend"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\ninfo "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"APPLICATION STARTED"')]),t._v("\n\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br")])]),s("p",[t._v("Compiled with:")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("nim c -d:chronicles_sinks=textlines[file] my_program.nim\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("p",[t._v("As you can see above, the default stream in Chronicles is called\n"),s("code",[t._v("defaultChroniclesStream")]),t._v(". If the stream had multiple file outputs,\nthey would have been accessible separately as "),s("code",[t._v("outputs[0]")]),t._v(", "),s("code",[t._v("outputs[1]")]),t._v("\nand so on. "),s("code",[t._v("output")]),t._v(" is a simple short-cut referring to the first of them.")]),t._v(" "),s("p",[t._v("When the compile-time configuration doesn't specify a default file name for\na particular file output, Chronicles will use the following rules for picking\nthe default automatically:")]),t._v(" "),s("ol",[s("li",[s("p",[t._v("The log file is created in the current working directory and its name\nmatches the name of the stream (plus a "),s("code",[t._v(".log")]),t._v(" extension). The exception\nfor this rule is the default stream, for which the log file will be\nassigned the name of the application binary.")])]),t._v(" "),s("li",[s("p",[t._v("If more than one unnamed file outputs exist for a given stream,\nchronicles will add an index such as "),s("code",[t._v(".2.log")]),t._v(", "),s("code",[t._v(".3.log")]),t._v(" .. "),s("code",[t._v(".N.log")]),t._v("\nto the final file name.")])])]),t._v(" "),s("h2",{attrs:{id:"working-with-dynamic-outputs"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#working-with-dynamic-outputs"}},[t._v("#")]),t._v(" Working with "),s("code",[t._v("dynamic")]),t._v(" outputs")]),t._v(" "),s("p",[t._v("A "),s("code",[t._v("dynamic")]),t._v(" output redirects all logged messages to a closure supplied by\nthe host application. Similar to working with file ouputs "),s("a",{attrs:{href:"#working-with-file-outputs"}},[t._v("file outputs")]),t._v(",\nyou can use the "),s("code",[t._v("output")]),t._v(" and "),s("code",[t._v("outputs")]),t._v(" properties of a Chronicles stream\nto specify a gcsafe closure:")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[t._v("defaultChroniclesStream"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("output"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("writer "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("logLevel"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" LogLevel"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" msg"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" LogOutputStr"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{.")]),t._v("gcsafe"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n database"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("writeLogEntry")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("msg"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br")])]),s("h2",{attrs:{id:"using-chronicles-with-nosideeffect"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#using-chronicles-with-nosideeffect"}},[t._v("#")]),t._v(" Using Chronicles with "),s("code",[t._v("{.noSideEffect.}")])]),t._v(" "),s("p",[t._v("Usage of Chronicles from "),s("code",[t._v("noSideEffect")]),t._v(" procs (or "),s("code",[t._v("func")]),t._v(") is limited to the\n"),s("code",[t._v("trace")]),t._v(" statement. Normal logging can be considered a side effect, but "),s("code",[t._v("trace")]),t._v("\nis meant as a debugging aid. It's analogous to Nim's "),s("code",[t._v("debugEcho")]),t._v(", which also\nbypasses the effect system.")]),t._v(" "),s("h2",{attrs:{id:"teaching-chronicles-about-your-types"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#teaching-chronicles-about-your-types"}},[t._v("#")]),t._v(" Teaching Chronicles about your types")]),t._v(" "),s("p",[t._v("Chronicles can output log records in any of the formats supported by the Nim\n"),s("a",{attrs:{href:"https://github.com/status-im/nim-serialization",target:"_blank",rel:"noopener noreferrer"}},[s("code",[t._v("serialization")]),s("OutboundLink")],1),t._v(" package.\nWhen you specify a named format such as "),s("code",[t._v("json")]),t._v(", Chronicles will expect that\nyour project also depends on the respective serialization package (e.g.\n"),s("a",{attrs:{href:"https://github.com/status-im/nim-json-serialization",target:"_blank",rel:"noopener noreferrer"}},[s("code",[t._v("json_serialization")]),s("OutboundLink")],1),t._v(").")]),t._v(" "),s("p",[t._v("In the text formats ("),s("code",[t._v("textlines")]),t._v(" and "),s("code",[t._v("textblocks")]),t._v("), the Nim's standard "),s("code",[t._v("$")]),t._v("\noperator will be used to convert the logged properties to strings.")]),t._v(" "),s("h3",{attrs:{id:"formatit"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#formatit"}},[t._v("#")]),t._v(" "),s("code",[t._v("formatIt")])]),t._v(" "),s("p",[t._v("You can instruct Chronicles to alter this default behavior for a particular\ntype by providing a "),s("code",[t._v("chronicles.formatIt")]),t._v(" override:")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("type")]),t._v(" Dollar "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("distinct")]),t._v(" int\nchronicles"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("formatIt")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Dollar"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"$"')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("$")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("it"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("int"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br")])]),s("p",[t._v("The "),s("code",[t._v("formatIt")]),t._v(" block can evaluate to any expression that will be then\nsubjected to the standard serialization logic described above.")]),t._v(" "),s("h3",{attrs:{id:"expandit"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#expandit"}},[t._v("#")]),t._v(" "),s("code",[t._v("expandIt")])]),t._v(" "),s("p",[t._v("The "),s("code",[t._v("expandIt")]),t._v(" override can be used to turn any logged property of a\nparticular type into multiple properties:")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[t._v("chronicles"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("expandIt")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("EncryptedEnvelope"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("\n peer "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" it"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("fromAddress\n msg "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" it"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("decryptMsg\n\n"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("...")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" e "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("EncryptedEnvelope")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("..")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".)")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# The following two statements are equivalent:")]),t._v("\ninfo "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Received message"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" e\ninfo "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Received message"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" peer "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" e"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("fromAddress"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" msg "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" e"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("decryptMsg\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br"),s("span",{staticClass:"line-number"},[t._v("9")]),s("br"),s("span",{staticClass:"line-number"},[t._v("10")]),s("br"),s("span",{staticClass:"line-number"},[t._v("11")]),s("br")])]),s("p",[t._v("You can also derive the names of the expanded properties from the name of\nthe original logged property. This is achieved by using the Nim's backticks\nsyntax to construct the expanded property names:")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[t._v("chronicles"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("expandIt")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# You can use both identifiers and string literals:")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token ignore"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("`")]),t._v("it Name"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("`")])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" it"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("name\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("`")]),t._v("it "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"LastSeen"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("`")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" it"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("lastSeen\n\n"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("...")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" alice "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("User")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("name"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Alice"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("..")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".)")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# The following two statements are equivalent:")]),t._v("\ninfo "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Sending message"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" recipient "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" alice\ninfo "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Sending message"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" recipientName "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" alice"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("name"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" recipientLastSeen "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" alice"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("lastSeen\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br"),s("span",{staticClass:"line-number"},[t._v("9")]),s("br"),s("span",{staticClass:"line-number"},[t._v("10")]),s("br"),s("span",{staticClass:"line-number"},[t._v("11")]),s("br"),s("span",{staticClass:"line-number"},[t._v("12")]),s("br")])]),s("h2",{attrs:{id:"custom-log-streams"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#custom-log-streams"}},[t._v("#")]),t._v(" Custom Log Streams")]),t._v(" "),s("h3",{attrs:{id:"logstream"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#logstream"}},[t._v("#")]),t._v(" "),s("code",[t._v("logStream")])]),t._v(" "),s("p",[t._v("As an alternative to specifying multiple output streams with the\n"),s("code",[t._v("chronicles_streams")]),t._v(" option, you can also introduce additional\nstreams within the code of your program. A typical way to do this\nwould be to introduce a proxy module that imports and re-exports\n"),s("code",[t._v("chronicles")]),t._v(" while adding additional streams with "),s("code",[t._v("logStream")]),t._v(":")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" chronicles\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("export")]),t._v(" chronicles\n\nlogStream transactions"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("json"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("file")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("transactions"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("json"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br")])]),s("p",[t._v("The expression expected by "),s("code",[t._v("logStream")]),t._v(" has exactly the same format\nas the compile-time option and produces the same effect. In this particular\nexample, it will create a new stream called "),s("code",[t._v("transactions")]),t._v(" that will be sent\nto a JSON file named "),s("code",[t._v("transactions.json")]),t._v(".")]),t._v(" "),s("p",[t._v("After importing the proxy module, you'll be able to create records with any\nof the logging statements in the usual way:")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" transactions_log\n\n"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("...")]),t._v("\n\ntransactions"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("error "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"payment gateway time-out"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" orderId"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n networkStatus "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("obtainNetworkStatus")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br")])]),s("h3",{attrs:{id:"customlogstream"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#customlogstream"}},[t._v("#")]),t._v(" "),s("code",[t._v("customLogStream")])]),t._v(" "),s("p",[s("code",[t._v("customLogStream")]),t._v(" enables you to implement arbitrary log formats and\ndestinations.")]),t._v(" "),s("p",[t._v('Each logging statement is translated to a set of calls operating over\na structure called "Log Record" (with one instance created per logging\nstatement). New log formats can be implemented by defining a suitable\nlog record type. Let\'s demonstrate this by implementing a simple XML logger:')]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" xmltree"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" chronicles\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("type")]),t._v(" XmlRecord"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("Output"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("object")]),t._v("\n output"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Output\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("template")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("initLogRecord"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("r"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" XmlRecord"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" lvl"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" LogLevel"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n topics"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" string"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" name"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" string"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n r"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("output"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("append "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"\\n"')]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("template")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("setProperty"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("r"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" XmlRecord"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" key"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" string"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" val"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" auto"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n r"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("output"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("append textBlockIndent"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"<"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" key"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('">"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("escape")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("$")]),t._v("val"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"\\n"')]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("template")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("setFirstProperty"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("r"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" XmlRecord"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" key"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" string"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" val"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" auto"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n r"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("setProperty key"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" val\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("template")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("flushRecord"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("r"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" XmlRecord"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n r"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("output"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("append "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"\\n"')]),t._v("\n r"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("output"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("flushOutput\n\ncustomLogStream xmlout"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("XmlRecord"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("StdOutOutput"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n\npublicLogScope"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("\n stream "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" xmlout\n\ninfo "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"New Video"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" franchise "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Tom & Jerry"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" episode "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Smarty Cat"')]),t._v("\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br"),s("span",{staticClass:"line-number"},[t._v("9")]),s("br"),s("span",{staticClass:"line-number"},[t._v("10")]),s("br"),s("span",{staticClass:"line-number"},[t._v("11")]),s("br"),s("span",{staticClass:"line-number"},[t._v("12")]),s("br"),s("span",{staticClass:"line-number"},[t._v("13")]),s("br"),s("span",{staticClass:"line-number"},[t._v("14")]),s("br"),s("span",{staticClass:"line-number"},[t._v("15")]),s("br"),s("span",{staticClass:"line-number"},[t._v("16")]),s("br"),s("span",{staticClass:"line-number"},[t._v("17")]),s("br"),s("span",{staticClass:"line-number"},[t._v("18")]),s("br"),s("span",{staticClass:"line-number"},[t._v("19")]),s("br"),s("span",{staticClass:"line-number"},[t._v("20")]),s("br"),s("span",{staticClass:"line-number"},[t._v("21")]),s("br"),s("span",{staticClass:"line-number"},[t._v("22")]),s("br"),s("span",{staticClass:"line-number"},[t._v("23")]),s("br"),s("span",{staticClass:"line-number"},[t._v("24")]),s("br"),s("span",{staticClass:"line-number"},[t._v("25")]),s("br")])]),s("p",[t._v("The produced output from the example will be:")]),t._v(" "),s("div",{staticClass:"language-xml line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-xml"}},[s("code",[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("event")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("name")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[s("span",{pre:!0,attrs:{class:"token punctuation attr-equals"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')]),t._v("New Video"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("severity")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[s("span",{pre:!0,attrs:{class:"token punctuation attr-equals"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')]),t._v("INFO"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("tid")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("0"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("episode")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("Smarty Cat"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("franchise")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("Tom "),s("span",{pre:!0,attrs:{class:"token entity named-entity",title:"&"}},[t._v("&")]),t._v(" Jerry"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br")])]),s("p",[t._v("As you can see, "),s("code",[t._v("customLogStream")]),t._v(" looks similar to a regular "),s("code",[t._v("logStream")]),t._v(",\nbut it expects a log record type as its only argument.")]),t._v(" "),s("p",[t._v("The record type is implemented by providing suitable definitons for\n"),s("code",[t._v("initLogRecord")]),t._v(", "),s("code",[t._v("setFirstProperty")]),t._v(", "),s("code",[t._v("setProperty")]),t._v(" and "),s("code",[t._v("flushRecord")]),t._v(".\nWe recommend defining these operations as templates because this will\nfacilitate the aggressive constant-folding employed by Chronicles (discussed\nin more details in the next section). We also recommend making your log\nrecord types parametric on an "),s("code",[t._v("Output")]),t._v(" type, because this will allow the\nusers of the code to specify any of the output types defined in Chronicles\nitself (see the module "),s("code",[t._v("log_output")]),t._v(" for a list of those).")]),t._v(" "),s("p",[t._v("As demonstrated in the example above, you can set the "),s("code",[t._v("stream")]),t._v(" property in\na Chronicles lexical scope to redirect all unqualified log statements to a\nparticular default stream.")]),t._v(" "),s("h2",{attrs:{id:"cost-of-abstractions-and-implementation-details"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#cost-of-abstractions-and-implementation-details"}},[t._v("#")]),t._v(" Cost of Abstractions and Implementation Details")]),t._v(" "),s("p",[t._v("Chronicles makes use of advanced compile-time programming techniques to\nproduce very efficient run-time code with minimal footprint.")]),t._v(" "),s("p",[t._v("The properties from lexical scopes are merged at compile-time with the\nlog statement arguments and if any constant variables are about to be\nsent to the log output, they will be first concatenated by the compiler\nin order to issue the minimum number of "),s("code",[t._v("write")]),t._v(" operations possible.")]),t._v(" "),s("p",[t._v("The dynamic scopes store their run-time bindings on the stack, in special\nframe structures forming a linked list. This list is traversed on each log\nstatement and each active property leads to one dynamically dispatched call.")]),t._v(" "),s("p",[t._v("To support constant-time topic filtering and property overriding in dynamic\nscopes, Chronicles consumes a large amount of thread-local memory, roughly\nproportional to the number of unique topic names and property names used\nin the program.")]),t._v(" "),s("h2",{attrs:{id:"future-directions"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#future-directions"}},[t._v("#")]),t._v(" Future Directions")]),t._v(" "),s("p",[t._v("At the moment, Chronicles intentionally omits certain features expected\nfrom a logging library such as log rotation and archival. We recommend\nfollowing the guidelines set in the "),s("a",{attrs:{href:"https://12factor.net/logs",target:"_blank",rel:"noopener noreferrer"}},[t._v("12-factor app methodology"),s("OutboundLink")],1),t._v("\nand sending your log output to "),s("code",[t._v("stdout")]),t._v(". It should be the responsibility\nof the supervising daemon of the app to implement log rotation and archival.")]),t._v(" "),s("p",[t._v("We understand that certain users would want to take advantage of the\nfile sinks provided by Chronicles and these users may benefit from the\naforementioned features. If the Nim community provides a package for\na low-level abstraction of an automatically rotated and archived log\nfile, Chronicles will provide options for using it.")])])}),[],!1,null,null,null);e.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/9.40f78cab.js b/assets/js/9.40f78cab.js deleted file mode 100644 index 500ee7d..0000000 --- a/assets/js/9.40f78cab.js +++ /dev/null @@ -1 +0,0 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[9],{209:function(t,e,s){"use strict";s.r(e);var a=s(28),n=Object(a.a)({},(function(){var t=this,e=t.$createElement,s=t._self._c||e;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"eth"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#eth"}},[t._v("#")]),t._v(" Eth")]),t._v(" "),s("p",[t._v("Ethereum-related utilities written in Nim. Includes things like Bloom filters, private/public key utilities, RLP, devp2p, and more.")]),t._v(" "),s("h2",{attrs:{id:"rlp"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#rlp"}},[t._v("#")]),t._v(" rlp")]),t._v(" "),s("h3",{attrs:{id:"introduction"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#introduction"}},[t._v("#")]),t._v(" Introduction")]),t._v(" "),s("p",[t._v("A Nim implementation of the Recursive Length Prefix encoding (RLP) as specified\nin the Ethereum's "),s("a",{attrs:{href:"https://ethereum.github.io/yellowpaper/paper.pdf",target:"_blank",rel:"noopener noreferrer"}},[t._v("Yellow Papper"),s("OutboundLink")],1),t._v("\nand "),s("a",{attrs:{href:"https://github.com/ethereum/wiki/wiki/RLP",target:"_blank",rel:"noopener noreferrer"}},[t._v("Wiki"),s("OutboundLink")],1),t._v(".")]),t._v(" "),s("h3",{attrs:{id:"reading-rlp-data"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#reading-rlp-data"}},[t._v("#")]),t._v(" Reading RLP data")]),t._v(" "),s("p",[t._v("The "),s("code",[t._v("Rlp")]),t._v(" type provided by this library represents a cursor over a RLP-encoded\nbyte stream. Before instantiating such a cursor, you must convert your\ninput data a "),s("code",[t._v("BytesRange")]),t._v(" value provided by the "),s("a",{attrs:{href:"https://github.com/status-im/nim-ranges",target:"_blank",rel:"noopener noreferrer"}},[t._v("nim-ranges"),s("OutboundLink")],1),t._v(" library,\nwhich represents an immutable and thus cheap-to-copy sub-range view over an\nunderlying "),s("code",[t._v("seq[byte]")]),t._v(" instance:")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("rlpFromBytes"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("data"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" BytesRange"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Rlp\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("h3",{attrs:{id:"streaming-api"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#streaming-api"}},[t._v("#")]),t._v(" Streaming API")]),t._v(" "),s("p",[t._v("Once created, the "),s("code",[t._v("Rlp")]),t._v(" object will offer procs such as "),s("code",[t._v("isList")]),t._v(", "),s("code",[t._v("isBlob")]),t._v(",\n"),s("code",[t._v("getType")]),t._v(", "),s("code",[t._v("listLen")]),t._v(", "),s("code",[t._v("blobLen")]),t._v(" to determine the type of the value under\nthe cursor. The contents of blobs can be extracted with procs such as\n"),s("code",[t._v("toString")]),t._v(", "),s("code",[t._v("toBytes")]),t._v(" and "),s("code",[t._v("toInt")]),t._v(" without advancing the cursor.")]),t._v(" "),s("p",[t._v("Lists can be traversed with the standard "),s("code",[t._v("items")]),t._v(" iterator, which will advance\nthe cursor to each sub-item position and yield the "),s("code",[t._v("Rlp")]),t._v(" object at that point.\nAs an alternative, "),s("code",[t._v("listElem")]),t._v(" can return a new "),s("code",[t._v("Rlp")]),t._v(" object adjusted to a\nparticular sub-item position without advancing the original cursor.\nKeep in mind that copying "),s("code",[t._v("Rlp")]),t._v(" objects is cheap and you can create as many\ncursors pointing to different positions in the RLP stream as necessary.")]),t._v(" "),s("p",[s("code",[t._v("skipElem")]),t._v(" will advance the cursor to the next position in the current list.\n"),s("code",[t._v("hasData")]),t._v(" will indicate that there are no more bytes in the stream that can\nbe consumed.")]),t._v(" "),s("p",[t._v("Another way to extract data from the stream is through the universal "),s("code",[t._v("read")]),t._v("\nproc that accepts a type as a parameter. You can pass any supported type\nsuch as "),s("code",[t._v("string")]),t._v(", "),s("code",[t._v("int")]),t._v(", "),s("code",[t._v("seq[T]")]),t._v(", etc, including composite user-defined\ntypes (see "),s("a",{attrs:{href:"#object-serialization"}},[t._v("Object Serialization")]),t._v("). The cursor\nwill be advanced just past the end of the consumed object.")]),t._v(" "),s("p",[t._v("The "),s("code",[t._v("toXX")]),t._v(" and "),s("code",[t._v("read")]),t._v(" family of procs may raise a "),s("code",[t._v("RlpTypeMismatch")]),t._v(" in case\nof type mismatch with the stream contents under the cursor. A corrupted\nRLP stream or an attemp to read past the stream end will be signaled\nwith the "),s("code",[t._v("MalformedRlpError")]),t._v(" exception. If the RLP stream includes data\nthat cannot be processed on the current platform (e.g. an integer value\nthat is too large), the library will raise an "),s("code",[t._v("UnsupportedRlpError")]),t._v(" exception.")]),t._v(" "),s("h3",{attrs:{id:"dom-api"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#dom-api"}},[t._v("#")]),t._v(" DOM API")]),t._v(" "),s("p",[t._v("Calling "),s("code",[t._v("Rlp.toNodes")]),t._v(" at any position within the stream will return a tree\nof "),s("code",[t._v("RlpNode")]),t._v(" objects representing the collection of values begging at that\nposition:")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("type")]),t._v("\n RlpNodeType"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("enum")]),t._v("\n rlpBlob\n rlpList\n\n RlpNode"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("object")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" kind"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*:")]),t._v(" RlpNodeType\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("of")]),t._v(" rlpBlob"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("\n bytes"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*:")]),t._v(" BytesRange\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("of")]),t._v(" rlpList"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("\n elems"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*:")]),t._v(" seq"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("RlpNode"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br"),s("span",{staticClass:"line-number"},[t._v("9")]),s("br"),s("span",{staticClass:"line-number"},[t._v("10")]),s("br"),s("span",{staticClass:"line-number"},[t._v("11")]),s("br")])]),s("p",[t._v("As a short-cut, you can also call "),s("code",[t._v("decode")]),t._v(" directly on a byte sequence to\navoid creating a "),s("code",[t._v("Rlp")]),t._v(" object when obtaining the nodes.\nFor debugging purposes, you can also create a human readable representation\nof the Rlp nodes by calling the "),s("code",[t._v("inspect")]),t._v(" proc:")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("inspect"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("self"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Rlp"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" indent "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" string\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("h3",{attrs:{id:"creating-rlp-data"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#creating-rlp-data"}},[t._v("#")]),t._v(" Creating RLP data")]),t._v(" "),s("p",[t._v("The "),s("code",[t._v("RlpWriter")]),t._v(" type can be used to encode RLP data. Instances are created\nwith the "),s("code",[t._v("initRlpWriter")]),t._v(" proc. This should be followed by one or more calls\nto "),s("code",[t._v("append")]),t._v(" which is overloaded to accept arbitrary values. Finally, you can\ncall "),s("code",[t._v("finish")]),t._v(" to obtain the final "),s("code",[t._v("BytesRange")]),t._v(".")]),t._v(" "),s("p",[t._v("If the end result should be a RLP list of particular length, you can replace\nthe initial call to "),s("code",[t._v("initRlpWriter")]),t._v(" with "),s("code",[t._v("initRlpList(n)")]),t._v(". Calling "),s("code",[t._v("finish")]),t._v("\nbefore writing the sufficient number of elements will then result in an assertion failure.")]),t._v(" "),s("p",[t._v("As an alternative short-cut, you can also call "),s("code",[t._v("encode")]),t._v(" on an arbitrary value\n(including sequences and user-defined types) to execute all of the steps at\nonce and directly obtain the final RLP bytes. "),s("code",[t._v("encodeList(varargs)")]),t._v(" is another\nshort-cut for creating RLP lists.")]),t._v(" "),s("h3",{attrs:{id:"object-serialization"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#object-serialization"}},[t._v("#")]),t._v(" Object serialization")]),t._v(" "),s("p",[t._v("As previously explained, generic procs such as "),s("code",[t._v("read")]),t._v(", "),s("code",[t._v("append")]),t._v(", "),s("code",[t._v("encode")]),t._v(" and\n"),s("code",[t._v("decode")]),t._v(" can be used with arbitrary used-defined object types. By default, the\nlibrary will serialize all of the fields of the object using the "),s("code",[t._v("fields")]),t._v("\niterator, but you can also include only a subset of the fields or modify the\norder of serialization or by employing the "),s("code",[t._v("rlpIgnore")]),t._v(" pragma or by using the\n"),s("code",[t._v("rlpFields")]),t._v(" macro:")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("macro")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("rlpFields"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("T"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" typedesc"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fields"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" varargs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("untyped"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("## example usage:")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("type")]),t._v("\n Transaction "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("object")]),t._v("\n amount"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" int\n time"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" DateTime\n sender"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" string\n receiver"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" string\n\nrlpFields Transaction"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n sender"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" receiver"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" amount\n\n"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("...")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" t1 "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" rlp"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("read")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Transaction"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" bytes "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("encode")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("t1"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" t2 "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" bytes"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("decode")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Transaction"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br"),s("span",{staticClass:"line-number"},[t._v("9")]),s("br"),s("span",{staticClass:"line-number"},[t._v("10")]),s("br"),s("span",{staticClass:"line-number"},[t._v("11")]),s("br"),s("span",{staticClass:"line-number"},[t._v("12")]),s("br"),s("span",{staticClass:"line-number"},[t._v("13")]),s("br"),s("span",{staticClass:"line-number"},[t._v("14")]),s("br"),s("span",{staticClass:"line-number"},[t._v("15")]),s("br"),s("span",{staticClass:"line-number"},[t._v("16")]),s("br"),s("span",{staticClass:"line-number"},[t._v("17")]),s("br"),s("span",{staticClass:"line-number"},[t._v("18")]),s("br"),s("span",{staticClass:"line-number"},[t._v("19")]),s("br")])]),s("p",[t._v("By default, sub-fields within objects are wrapped in RLP lists. You can avoid this\nbehavior by adding the custom pragma "),s("code",[t._v("rlpInline")]),t._v(" on a particular field. In rare\ncircumstances, you may need to serialize the same field type differently depending\non the enclosing object type. You can use the "),s("code",[t._v("rlpCustomSerialization")]),t._v(" pragma to\nachieve this.")]),t._v(" "),s("h3",{attrs:{id:"contributing-testing"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#contributing-testing"}},[t._v("#")]),t._v(" Contributing / Testing")]),t._v(" "),s("p",[t._v("To test the correctness of any modifications to the library, please execute\n"),s("code",[t._v("nimble test")]),t._v(" at the root of the repo.")]),t._v(" "),s("h2",{attrs:{id:"p2p"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#p2p"}},[t._v("#")]),t._v(" p2p")]),t._v(" "),s("h3",{attrs:{id:"introduction-2"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#introduction-2"}},[t._v("#")]),t._v(" Introduction")]),t._v(" "),s("p",[t._v("This library implements the DevP2P family of networking protocols used\nin the Ethereum world.")]),t._v(" "),s("h3",{attrs:{id:"connecting-to-the-ethereum-network"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#connecting-to-the-ethereum-network"}},[t._v("#")]),t._v(" Connecting to the Ethereum network")]),t._v(" "),s("p",[t._v("A connection to the Ethereum network can be created by instantiating\nthe "),s("code",[t._v("EthereumNode")]),t._v(" type:")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("newEthereumNode"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("keys"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" KeyPair"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n listeningAddress"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Address"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n networkId"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" uint"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n chain"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" AbstractChainDB"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n clientId "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"nim-eth-p2p"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n addAllCapabilities "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" true"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" EthereumNode "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br")])]),s("h4",{attrs:{id:"parameters"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#parameters"}},[t._v("#")]),t._v(" Parameters:")]),t._v(" "),s("p",[s("code",[t._v("keys")]),t._v(":\nA pair of public and private keys used to authenticate the node\non the network and to determine its node ID.\nSee the "),s("a",{attrs:{href:"https://github.com/status-im/nim-eth-keys",target:"_blank",rel:"noopener noreferrer"}},[t._v("eth_keys"),s("OutboundLink")],1),t._v("\nlibrary for utilities that will help you generate and manage\nsuch keys.")]),t._v(" "),s("p",[s("code",[t._v("listeningAddress")]),t._v(":\nThe network interface and port where your client will be\naccepting incoming connections.")]),t._v(" "),s("p",[s("code",[t._v("networkId")]),t._v(":\nThe Ethereum network ID. The client will disconnect immediately\nfrom any peers who don't use the same network.")]),t._v(" "),s("p",[s("code",[t._v("chain")]),t._v(":\nAn abstract instance of the Ethereum blockchain associated\nwith the node. This library allows you to plug any instance\nconforming to the abstract interface defined in the\n"),s("a",{attrs:{href:"https://github.com/status-im/nim-eth-common",target:"_blank",rel:"noopener noreferrer"}},[t._v("eth_common"),s("OutboundLink")],1),t._v("\npackage.")]),t._v(" "),s("p",[s("code",[t._v("clientId")]),t._v(":\nA name used to identify the software package connecting\nto the network (i.e. similar to the "),s("code",[t._v("User-Agent")]),t._v(" string\nin a browser).")]),t._v(" "),s("p",[s("code",[t._v("addAllCapabilities")]),t._v(":\nBy default, the node will support all RPLx protocols imported in\nyour project. You can specify "),s("code",[t._v("false")]),t._v(" if you prefer to create a\nnode with a more limited set of protocols. Use one or more calls\nto "),s("code",[t._v("node.addCapability")]),t._v(" to specify the desired set:")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[t._v("node"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("addCapability")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("eth"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nnode"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("addCapability")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("shh"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br")])]),s("p",[t._v("Each supplied protocol identifier is a name of a protocol introduced\nby the "),s("code",[t._v("p2pProtocol")]),t._v(" macro discussed later in this document.")]),t._v(" "),s("p",[t._v("Instantiating an "),s("code",[t._v("EthereumNode")]),t._v(" does not immediately connect you to\nthe network. To start the connection process, call "),s("code",[t._v("node.connectToNetwork")]),t._v(":")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("connectToNetwork"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("node"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" EthereumNode"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n bootstrapNodes"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" openarray"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("ENode"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n startListening "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" true"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n enableDiscovery "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" true"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br")])]),s("p",[t._v("The "),s("code",[t._v("EthereumNode")]),t._v(" will automatically find and maintain a pool of peers\nusing the Ethereum node discovery protocol. You can access the pool as\n"),s("code",[t._v("node.peers")]),t._v(".")]),t._v(" "),s("h3",{attrs:{id:"communicating-with-peers-using-rlpx"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#communicating-with-peers-using-rlpx"}},[t._v("#")]),t._v(" Communicating with Peers using RLPx")]),t._v(" "),s("p",[s("a",{attrs:{href:"https://github.com/ethereum/devp2p/blob/master/rlpx.md",target:"_blank",rel:"noopener noreferrer"}},[t._v("RLPx"),s("OutboundLink")],1),t._v(" is the\nhigh-level protocol for exchanging messages between peers in the Ethereum\nnetwork. Most of the client code of this library should not be concerned\nwith the implementation details of the underlying protocols and should use\nthe high-level APIs described in this section.")]),t._v(" "),s("p",[t._v("The RLPx protocols are defined as a collection of strongly-typed messages,\nwhich are grouped into sub-protocols multiplexed over the same TCP connection.")]),t._v(" "),s("p",[t._v("This library represents each such message as a regular Nim function call\nover the "),s("code",[t._v("Peer")]),t._v(" object. Certain messages act only as notifications, while\nothers fit the request/response pattern.")]),t._v(" "),s("p",[t._v("To understand more about how messages are defined and used, let's look at\nthe definition of a RLPx protocol:")]),t._v(" "),s("h4",{attrs:{id:"rlpx-sub-protocols"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#rlpx-sub-protocols"}},[t._v("#")]),t._v(" RLPx sub-protocols")]),t._v(" "),s("p",[t._v("The sub-protocols are defined with the "),s("code",[t._v("p2pProtocol")]),t._v(" macro. It will accept\na short identifier for the protocol and the current protocol version:")]),t._v(" "),s("p",[t._v("Here is how the "),s("a",{attrs:{href:"https://github.com/ethereum/devp2p/blob/master/rlpx.md#p2p-capability",target:"_blank",rel:"noopener noreferrer"}},[t._v("DevP2P wire protocol"),s("OutboundLink")],1),t._v(" might look like:")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[t._v("p2pProtocol "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("DevP2P")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("version "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" rlpxName "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"p2p"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("hello")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("peer"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Peer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n version"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" uint"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n clientId"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" string"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n capabilities"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" openarray"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("Capability"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n listenPort"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" uint"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n nodeId"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" P2PNodeId"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n peer"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("id "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" nodeId\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("disconnect")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("peer"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Peer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" reason"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" DisconnectionReason"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ping")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("peer"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Peer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n await peer"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("pong")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("pong")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("peer"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Peer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n echo "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"received pong from "')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" peer"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("id\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br"),s("span",{staticClass:"line-number"},[t._v("9")]),s("br"),s("span",{staticClass:"line-number"},[t._v("10")]),s("br"),s("span",{staticClass:"line-number"},[t._v("11")]),s("br"),s("span",{staticClass:"line-number"},[t._v("12")]),s("br"),s("span",{staticClass:"line-number"},[t._v("13")]),s("br"),s("span",{staticClass:"line-number"},[t._v("14")]),s("br"),s("span",{staticClass:"line-number"},[t._v("15")]),s("br"),s("span",{staticClass:"line-number"},[t._v("16")]),s("br")])]),s("p",[t._v("As seen in the example above, a protocol definition determines both the\navailable messages that can be sent to another peer (e.g. as in "),s("code",[t._v("peer.pong()")]),t._v(")\nand the asynchronous code responsible for handling the incoming messages.")]),t._v(" "),s("h4",{attrs:{id:"protocol-state"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#protocol-state"}},[t._v("#")]),t._v(" Protocol state")]),t._v(" "),s("p",[t._v("The protocol implementations are expected to maintain a state and to act\nlike a state machine handling the incoming messages. You are allowed to\ndefine an arbitrary state type that can be specified in the "),s("code",[t._v("peerState")]),t._v("\nprotocol option. Later, instances of the state object can be obtained\nthough the "),s("code",[t._v("state")]),t._v(" pseudo-field of the "),s("code",[t._v("Peer")]),t._v(" object:")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("type")]),t._v(" AbcPeerState "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("object")]),t._v("\n receivedMsgsCount"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" int\n\np2pProtocol "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("abc")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("version "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n peerState "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" AbcPeerState"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("incomingMessage")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("p"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Peer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n p"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("state"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("receivedMsgsCount "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),t._v("\n\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br"),s("span",{staticClass:"line-number"},[t._v("9")]),s("br")])]),s("p",[t._v("Besides the per-peer state demonstrated above, there is also support\nfor maintaining a network-wide state. It's enabled by specifying the\n"),s("code",[t._v("networkState")]),t._v(" option of the protocol and the state object can be obtained\nthrough accessor of the same name.")]),t._v(" "),s("p",[t._v("The state objects are initialized to zero by default, but you can modify\nthis behaviour by overriding the following procs for your state types:")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("initProtocolState"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("state"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" MyPeerState"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" p"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Peer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("initProtocolState"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("state"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" MyNetworkState"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" n"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" EthereumNode"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br")])]),s("p",[t._v("Sometimes, you'll need to access the state of another protocol.\nTo do this, specify the protocol identifier to the "),s("code",[t._v("state")]),t._v(" accessors:")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[t._v(" echo "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"ABC protocol messages: "')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" peer"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("state")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("abc"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("receivedMsgCount\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("p",[t._v("While the state machine approach may be a particularly robust way of\nimplementing sub-protocols (it is more amenable to proving the correctness\nof the implementation through formal verification methods), sometimes it may\nbe more convenient to use more imperative style of communication where the\ncode is able to wait for a particular response after sending a particular\nrequest. The library provides two mechanisms for achieving this:")]),t._v(" "),s("h4",{attrs:{id:"waiting-particular-messages-with-nextmsg"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#waiting-particular-messages-with-nextmsg"}},[t._v("#")]),t._v(" Waiting particular messages with "),s("code",[t._v("nextMsg")])]),t._v(" "),s("p",[t._v("The "),s("code",[t._v("nextMsg")]),t._v(" helper proc can be used to pause the execution of an async\nproc until a particular incoming message from a peer arrives:")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("helloExample")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("peer"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Peer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("...")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# send a hello message")]),t._v("\n await peer"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("hello")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("..")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".)")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# wait for a matching hello response, might want to add a timeout here")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" response "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" await peer"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("nextMsg")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("p2p"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("hello"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n echo response"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("clientId "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# print the name of the Ethereum client")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# used by the other peer (Geth, Parity, Nimbus, etc)")]),t._v("\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br"),s("span",{staticClass:"line-number"},[t._v("9")]),s("br")])]),s("p",[t._v("There are few things to note in the above example:")]),t._v(" "),s("ol",[s("li",[s("p",[t._v("The "),s("code",[t._v("p2pProtocol")]),t._v(" definition created a pseudo-variable named after the\nprotocol holding various properties of the protocol.")])]),t._v(" "),s("li",[s("p",[t._v("Each message defined in the protocol received a corresponding type name,\nmatching the message name (e.g. "),s("code",[t._v("p2p.hello")]),t._v("). This type will have fields\nmatching the parameter names of the message. If the messages has "),s("code",[t._v("openarray")]),t._v("\nparams, these will be remapped to "),s("code",[t._v("seq")]),t._v(" types.")])])]),t._v(" "),s("p",[t._v("If the designated messages also has an attached handler, the future returned\nby "),s("code",[t._v("nextMsg")]),t._v(" will be resolved only after the handler has been fully executed\n(so you can count on any side effects produced by the handler to have taken\nplace). If there are multiple outstanding calls to "),s("code",[t._v("nextMsg")]),t._v(", they will\ncomplete together. Any other messages received in the meantime will still\nbe dispatched to their respective handlers.")]),t._v(" "),s("p",[t._v("Please also note that the "),s("code",[t._v("p2pProtocol")]),t._v(" macro will make this "),s("code",[t._v("helloExample")]),t._v(" proc\n"),s("code",[t._v("async")]),t._v(". Practically see it as "),s("code",[t._v("proc helloExample(peer: Peer) {.async.}")]),t._v(", and\nthus never use "),s("code",[t._v("waitFor")]),t._v(", but rather "),s("code",[t._v("await")]),t._v(" inside this proc.")]),t._v(" "),s("p",[t._v("For implementing protocol handshakes with "),s("code",[t._v("nextMsg")]),t._v(" there are specific helpers\nwhich are explained "),s("a",{attrs:{href:"https://github.com/status-im/nim-eth/blob/master/doc/p2p.md#implementing-handshakes-and-reacting-to-other-events",target:"_blank",rel:"noopener noreferrer"}},[t._v("below"),s("OutboundLink")],1),t._v(".")]),t._v(" "),s("h4",{attrs:{id:"requestresponse-pairs"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#requestresponse-pairs"}},[t._v("#")]),t._v(" "),s("code",[t._v("requestResponse")]),t._v(" pairs")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[t._v("p2pProtocol "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("les")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("version "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("...")]),t._v("\n\n requestResponse"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getProofs")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("p"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Peer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" proofs"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" openarray"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("ProofRequest"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("proofs")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("p"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Peer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" BV"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" uint"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" proofs"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" openarray"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("Blob"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("...")]),t._v("\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br")])]),s("p",[t._v("Two or more messages within the protocol may be grouped into a\n"),s("code",[t._v("requestResponse")]),t._v(" block. The last message in the group is assumed\nto be the response while all other messages are considered requests.")]),t._v(" "),s("p",[t._v("When a request message is sent, the return type will be a "),s("code",[t._v("Future")]),t._v("\nthat will be completed once the response is received. Please note\nthat there is a mandatory timeout parameter, so the actual return\ntype is "),s("code",[t._v("Future[Option[MessageType]]")]),t._v(". The "),s("code",[t._v("timeout")]),t._v(" parameter can\nbe specified for each individual call and the default value can be\noverridden on the level of individual message, or the entire protocol:")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[t._v("p2pProtocol "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("abc")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("version "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n useRequestIds "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" false"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n timeout "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("5000")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# value in milliseconds")]),t._v("\n requestResponse"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("myReq")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("dataId"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" int"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" timeout "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("3000")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("myRes")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("data"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" string"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br")])]),s("p",[t._v("By default, the library will take care of inserting a hidden "),s("code",[t._v("reqId")]),t._v("\nparameter as used in the "),s("a",{attrs:{href:"https://github.com/zsfelfoldi/go-ethereum/wiki/Light-Ethereum-Subprotocol-%28LES%29",target:"_blank",rel:"noopener noreferrer"}},[t._v("LES protocol"),s("OutboundLink")],1),t._v(",\nbut you can disable this behavior by overriding the protocol setting\n"),s("code",[t._v("useRequestIds")]),t._v(".")]),t._v(" "),s("h4",{attrs:{id:"implementing-handshakes-and-reacting-to-other-events"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#implementing-handshakes-and-reacting-to-other-events"}},[t._v("#")]),t._v(" Implementing handshakes and reacting to other events")]),t._v(" "),s("p",[t._v("Besides message definitions and implementations, a protocol specification may\nalso include handlers for certain important events such as newly connected\npeers or misbehaving or disconnecting peers:")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[t._v("p2pProtocol "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("foo")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("version "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" fooVersion"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("\n onPeerConnected "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("do")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("peer"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Peer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" m "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" await peer"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("status")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("fooVersion"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n timeout "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" chronos"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("milliseconds")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("5000")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" m"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("protocolVersion "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" fooVersion"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("\n debug "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Foo peer"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" peer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fooVersion\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("else")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("raise")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("newException")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("UselessPeerError"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Incompatible Foo version"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n onPeerDisconnected "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("do")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("peer"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Peer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" reason"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" DisconnectionReason"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("\n debug "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"peer disconnected"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" peer\n\n handshake"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proc")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("status")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("peer"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Peer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n protocolVersion"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" uint"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br"),s("span",{staticClass:"line-number"},[t._v("9")]),s("br"),s("span",{staticClass:"line-number"},[t._v("10")]),s("br"),s("span",{staticClass:"line-number"},[t._v("11")]),s("br"),s("span",{staticClass:"line-number"},[t._v("12")]),s("br"),s("span",{staticClass:"line-number"},[t._v("13")]),s("br"),s("span",{staticClass:"line-number"},[t._v("14")]),s("br"),s("span",{staticClass:"line-number"},[t._v("15")]),s("br"),s("span",{staticClass:"line-number"},[t._v("16")]),s("br")])]),s("p",[t._v("For handshake messages, where the same type of message needs to be send to and\nreceived from the peer, a "),s("code",[t._v("handshake")]),t._v(" helper is introduced, as you can see in\nthe code example above.")]),t._v(" "),s("p",[t._v("Thanks to the "),s("code",[t._v("handshake")]),t._v(" helper the "),s("code",[t._v("status")]),t._v(" message will both be send, and be\nawaited for receival from the peer, with the defined timeout. In case no "),s("code",[t._v("status")]),t._v("\nmessage is received within the defined timeout, an error will be raised which\nwill result in a disconnect from the peer.")]),t._v(" "),s("p",[s("strong",[t._v("Note:")]),t._v(" Be aware that if currently one of the subprotocol "),s("code",[t._v("onPeerConnected")]),t._v("\ncalls fails, the client will be disconnected as "),s("code",[t._v("UselessPeer")]),t._v(" but no\n"),s("code",[t._v("onPeerDisconnect")]),t._v(" calls are run.")]),t._v(" "),s("h4",{attrs:{id:"checking-the-other-peer-s-supported-sub-protocols"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#checking-the-other-peer-s-supported-sub-protocols"}},[t._v("#")]),t._v(" Checking the other peer's supported sub-protocols")]),t._v(" "),s("p",[t._v("Upon establishing a connection, RLPx will automatically negotiate the list of\nmutually supported protocols by the peers. To check whether a particular peer\nsupports a particular sub-protocol, use the following code:")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" peer"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("supports")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("les"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# `les` is the identifier of the light clients sub-protocol")]),t._v("\n peer"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getReceipts")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("nextReqId")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("neededReceipts")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br")])]),s("h2",{attrs:{id:"keys"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#keys"}},[t._v("#")]),t._v(" keys")]),t._v(" "),s("p",[t._v("This library is a Nim re-implementation of "),s("a",{attrs:{href:"https://github.com/ethereum/eth-keys",target:"_blank",rel:"noopener noreferrer"}},[t._v("eth-keys"),s("OutboundLink")],1),t._v(": the common API for working with Ethereum's public and private keys, signatures, and addresses.")]),t._v(" "),s("p",[t._v("By default, Nim eth-keys uses Bitcoin's "),s("a",{attrs:{href:"https://github.com/bitcoin-core/secp256k1",target:"_blank",rel:"noopener noreferrer"}},[t._v("libsecp256k1"),s("OutboundLink")],1),t._v(" as a backend. Make sure libsecp256k1 is available on your system.")]),t._v(" "),s("p",[t._v("An experimental pure Nim backend (Warning ⚠: do not use in production) is available with the compilation switch "),s("code",[t._v("-d:backend_native")])]),t._v(" "),s("h2",{attrs:{id:"keyfile"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#keyfile"}},[t._v("#")]),t._v(" keyfile")]),t._v(" "),s("h3",{attrs:{id:"introduction-3"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#introduction-3"}},[t._v("#")]),t._v(" Introduction")]),t._v(" "),s("p",[t._v("This library is a Nim reimplementation of "),s("a",{attrs:{href:"https://github.com/ethereum/eth-keyfile",target:"_blank",rel:"noopener noreferrer"}},[t._v("ethereum/eth-keyfile"),s("OutboundLink")],1),t._v(", which is used to create and load Ethereum "),s("code",[t._v("keyfile")]),t._v(" format and the tools for handling the format and for storing private keys. Currently, the library supports only the PBKDF2 method and does not support the Scrypt method.")]),t._v(" "),s("h2",{attrs:{id:"trie"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#trie"}},[t._v("#")]),t._v(" trie")]),t._v(" "),s("h2",{attrs:{id:"nim-implementation-of-the-ethereum-trie-structure"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#nim-implementation-of-the-ethereum-trie-structure"}},[t._v("#")]),t._v(" Nim Implementation of the Ethereum Trie structure")]),t._v(" "),s("h3",{attrs:{id:"hexary-trie"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#hexary-trie"}},[t._v("#")]),t._v(" Hexary Trie")]),t._v(" "),s("h3",{attrs:{id:"binary-trie"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#binary-trie"}},[t._v("#")]),t._v(" Binary Trie")]),t._v(" "),s("p",[t._v("Binary-trie is a dictionary-like data structure to store key-value pair.\nMuch like it's sibling Hexary-trie, the key-value pair will be stored into key-value flat-db.\nThe primary difference with Hexary-trie is, each node of Binary-trie only consist of one or two child,\nwhile Hexary-trie node can contains up to 16 or 17 child-nodes.")]),t._v(" "),s("p",[t._v("Unlike Hexary-trie, Binary-trie store it's data into flat-db without using rlp encoding.\nBinary-trie store its value using simple "),s("strong",[t._v("Node-Types")]),t._v(" encoding.\nThe encoded-node will be hashed by keccak_256 and the hash value will be the key to flat-db.\nEach entry in the flat-db will looks like:")]),t._v(" "),s("table",[s("thead",[s("tr",[s("th",[t._v("key")]),t._v(" "),s("th",[t._v("value")])])]),t._v(" "),s("tbody",[s("tr",[s("td",[t._v("32-bytes-keccak-hash")]),t._v(" "),s("td",[t._v("encoded-node(KV or BRANCH or LEAF encoded)")])])])]),t._v(" "),s("h4",{attrs:{id:"node-types"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#node-types"}},[t._v("#")]),t._v(" Node-Types")]),t._v(" "),s("ul",[s("li",[t._v("KV = [0, encoded-key-path, 32 bytes hash of child]")]),t._v(" "),s("li",[t._v("BRANCH = [1, 32 bytes hash of left child, 32 bytes hash of right child]")]),t._v(" "),s("li",[t._v("LEAF = [2, value]")])]),t._v(" "),s("p",[t._v("The KV node can have BRANCH node or LEAF node as it's child, but cannot a KV node.\nThe internal algorithm will merge a KV(parent)->KV(child) into one KV node.\nEvery KV node contains encoded keypath to reduce the number of blank nodes.")]),t._v(" "),s("p",[t._v("The BRANCH node can have KV, BRANCH, or LEAF node as it's children.")]),t._v(" "),s("p",[t._v("The LEAF node is the terminal node, it contains the value of a key.")]),t._v(" "),s("h4",{attrs:{id:"encoded-key-path"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#encoded-key-path"}},[t._v("#")]),t._v(" encoded-key-path")]),t._v(" "),s("p",[t._v("While Hexary-trie encode the path using Hex-Prefix encoding, Binary-trie\nencode the path using binary encoding, the scheme looks like this table below.")]),t._v(" "),s("div",{staticClass:"language-text line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v(" |--------- odd --------|\n 00mm yyyy xxxx xxxx xxxx xxxx\n |------ even -----|\n 1000 00mm yyyy xxxx xxxx xxxx\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br")])]),s("table",[s("thead",[s("tr",[s("th",[t._v("symbol")]),t._v(" "),s("th",[t._v("explanation")])])]),t._v(" "),s("tbody",[s("tr",[s("td",[t._v("xxxx")]),t._v(" "),s("td",[t._v("nibble of binary keypath in bits, 0 = left, 1 = right")])]),t._v(" "),s("tr",[s("td",[t._v("yyyy")]),t._v(" "),s("td",[t._v("nibble contains 0-3 bits padding + binary keypath")])]),t._v(" "),s("tr",[s("td",[t._v("mm")]),t._v(" "),s("td",[t._v("number of binary keypath bits modulo 4 (0-3)")])]),t._v(" "),s("tr",[s("td",[t._v("00")]),t._v(" "),s("td",[t._v("zero zero prefix")])]),t._v(" "),s("tr",[s("td",[t._v("1000")]),t._v(" "),s("td",[t._v("even numbered nibbles prefix")])])])]),t._v(" "),s("p",[t._v("if there is no padding, then yyyy bit sequence is absent, mm also zero.\nyyyy = mm bits + padding bits must be 4 bits length.")]),t._v(" "),s("h4",{attrs:{id:"the-api"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#the-api"}},[t._v("#")]),t._v(" The API")]),t._v(" "),s("p",[t._v("The primary API for Binary-trie is "),s("code",[t._v("set")]),t._v(" and "),s("code",[t._v("get")]),t._v(".")]),t._v(" "),s("ul",[s("li",[t._v("set(key, value) --- "),s("em",[t._v("store a value associated with a key")])]),t._v(" "),s("li",[t._v("get(key): value --- "),s("em",[t._v("get a value using a key")])])]),t._v(" "),s("p",[t._v("Both "),s("code",[t._v("key")]),t._v(" and "),s("code",[t._v("value")]),t._v(" are of "),s("code",[t._v("BytesRange")]),t._v(" type. And they cannot have zero length.\nYou can also use convenience API "),s("code",[t._v("get")]),t._v(" and "),s("code",[t._v("set")]),t._v(" which accepts\n"),s("code",[t._v("Bytes")]),t._v(" or "),s("code",[t._v("string")]),t._v(" (a "),s("code",[t._v("string")]),t._v(" is conceptually wrong in this context\nand may costlier than a "),s("code",[t._v("BytesRange")]),t._v(", but it is good for testing purpose).")]),t._v(" "),s("p",[t._v("Getting a non-existent key will return zero length BytesRange.")]),t._v(" "),s("p",[t._v("Binary-trie also provide dictionary syntax API for "),s("code",[t._v("set")]),t._v(" and "),s("code",[t._v("get")]),t._v(".")]),t._v(" "),s("ul",[s("li",[t._v("trie[key] = value -- same as "),s("code",[t._v("set")])]),t._v(" "),s("li",[t._v("value = trie[key] -- same as "),s("code",[t._v("get")])]),t._v(" "),s("li",[t._v("contains(key) a.k.a. "),s("code",[t._v("in")]),t._v(" operator")])]),t._v(" "),s("p",[t._v("Additional APIs are:")]),t._v(" "),s("ul",[s("li",[t._v("exists(key) -- returns "),s("code",[t._v("bool")]),t._v(", to check key-value existence -- same as contains")]),t._v(" "),s("li",[t._v("delete(key) -- remove a key-value from the trie")]),t._v(" "),s("li",[t._v("deleteSubtrie(key) -- remove a key-value from the trie plus all of it's subtrie\nthat starts with the same key prefix")]),t._v(" "),s("li",[t._v("rootNode() -- get root node")]),t._v(" "),s("li",[t._v("rootNode(node) -- replace the root node")]),t._v(" "),s("li",[t._v("getRootHash(): "),s("code",[t._v("KeccakHash")]),t._v(" with "),s("code",[t._v("BytesRange")]),t._v(" type")]),t._v(" "),s("li",[t._v("getDB(): "),s("code",[t._v("DB")]),t._v(" -- get flat-db pointer")])]),t._v(" "),s("p",[t._v("Constructor API:")]),t._v(" "),s("ul",[s("li",[t._v("initBinaryTrie(DB, rootHash[optional]) -- rootHash has "),s("code",[t._v("BytesRange")]),t._v(" or KeccakHash type")]),t._v(" "),s("li",[t._v("init(BinaryTrie, DB, rootHash[optional])")])]),t._v(" "),s("p",[t._v("Normally you would not set the rootHash when constructing an empty Binary-trie.\nSetting the rootHash occured in a scenario where you have a populated DB\nwith existing trie structure and you know the rootHash,\nand then you want to continue/resume the trie operations.")]),t._v(" "),s("h3",{attrs:{id:"examples"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#examples"}},[t._v("#")]),t._v(" Examples")]),t._v(" "),s("div",{staticClass:"language-Nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v("\n eth"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),t._v("trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("db"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" binary"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" utils"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" db "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("newMemoryDB")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" trie "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("initBinaryTrie")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("db"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\ntrie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("set")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"key1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\ntrie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("set")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"key2"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value2"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\ndoAssert trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("get")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"key1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value1"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("toRange\ndoAssert trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("get")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"key2"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value2"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("toRange\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v('## delete all subtrie with key prefixes "key"')]),t._v("\ntrie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("deleteSubtrie")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"key"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\ndoAssert trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("get")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"key1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" zeroBytesRange\ndoAssert trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("get")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"key2"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" zeroBytesRange\n\ntrie"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"moon"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"sun"')]),t._v("\ndoAssert "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"moon"')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("in")]),t._v(" trie\ndoAssert trie"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"moon"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"sun"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("toRange\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br"),s("span",{staticClass:"line-number"},[t._v("9")]),s("br"),s("span",{staticClass:"line-number"},[t._v("10")]),s("br"),s("span",{staticClass:"line-number"},[t._v("11")]),s("br"),s("span",{staticClass:"line-number"},[t._v("12")]),s("br"),s("span",{staticClass:"line-number"},[t._v("13")]),s("br"),s("span",{staticClass:"line-number"},[t._v("14")]),s("br"),s("span",{staticClass:"line-number"},[t._v("15")]),s("br"),s("span",{staticClass:"line-number"},[t._v("16")]),s("br"),s("span",{staticClass:"line-number"},[t._v("17")]),s("br"),s("span",{staticClass:"line-number"},[t._v("18")]),s("br")])]),s("p",[t._v("Remember, "),s("code",[t._v("set")]),t._v(" and "),s("code",[t._v("get")]),t._v(" are trie operations. A single "),s("code",[t._v("set")]),t._v(" operation may invoke\nmore than one store/lookup operation into the underlying DB. The same is also happened to "),s("code",[t._v("get")]),t._v(" operation,\nit could do more than one flat-db lookup before it return the requested value.")]),t._v(" "),s("h3",{attrs:{id:"the-truth-behind-a-lie"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#the-truth-behind-a-lie"}},[t._v("#")]),t._v(" The truth behind a lie")]),t._v(" "),s("p",[t._v("What kind of lie? actually, "),s("code",[t._v("delete")]),t._v(" and "),s("code",[t._v("deleteSubtrie")]),t._v(" doesn't remove the\n'deleted' node from the underlying DB. It only make the node inaccessible\nfrom the user of the trie. The same also happened if you update the value of a key,\nthe old value node is not removed from the underlying DB.\nA more subtle lie also happened when you add new entrie into the trie using "),s("code",[t._v("set")]),t._v(" operation.\nThe previous hash of affected branch become obsolete and replaced by new hash,\nthe old hash become inaccessible to the user.\nYou may think that is a waste of storage space.\nLuckily, we also provide some utilities to deal with this situation, the branch utils.")]),t._v(" "),s("h3",{attrs:{id:"the-branch-utils"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#the-branch-utils"}},[t._v("#")]),t._v(" The branch utils")]),t._v(" "),s("p",[t._v("The branch utils consist of these API:")]),t._v(" "),s("ul",[s("li",[t._v("checkIfBranchExist(DB; rootHash; keyPrefix): bool")]),t._v(" "),s("li",[t._v("getBranch(DB; rootHash; key): branch")]),t._v(" "),s("li",[t._v("isValidBranch(branch, rootHash, key, value): bool")]),t._v(" "),s("li",[t._v("getWitness(DB; nodeHash; key): branch")]),t._v(" "),s("li",[t._v("getTrieNodes(DB; nodeHash): branch")])]),t._v(" "),s("p",[s("code",[t._v("keyPrefix")]),t._v(", "),s("code",[t._v("key")]),t._v(", and "),s("code",[t._v("value")]),t._v(" are bytes container with length greater than zero.\nThey can be BytesRange, Bytes, and string(again, for convenience and testing purpose).")]),t._v(" "),s("p",[s("code",[t._v("rootHash")]),t._v(" and "),s("code",[t._v("nodeHash")]),t._v(" also bytes container,\nbut they have constraint: must be 32 bytes in length, and it must be a keccak_256 hash value.")]),t._v(" "),s("p",[s("code",[t._v("branch")]),t._v(" is a list of nodes, or in this case a seq[BytesRange].\nA list? yes, the structure is stored along with the encoded node.\nTherefore a list is enough to reconstruct the entire trie/branch.")]),t._v(" "),s("div",{staticClass:"language-Nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v("\n eth"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),t._v("trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("db"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" binary"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" utils"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" db "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("newMemoryDB")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" trie "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("initBinaryTrie")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("db"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\ntrie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("set")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"key1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\ntrie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("set")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"key2"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value2"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\ndoAssert "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("checkIfBranchExist")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("db"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getRootHash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"key"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" true\ndoAssert "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("checkIfBranchExist")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("db"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getRootHash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"key1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" true\ndoAssert "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("checkIfBranchExist")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("db"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getRootHash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"ken"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" false\ndoAssert "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("checkIfBranchExist")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("db"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getRootHash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"key123"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" false\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br"),s("span",{staticClass:"line-number"},[t._v("9")]),s("br"),s("span",{staticClass:"line-number"},[t._v("10")]),s("br"),s("span",{staticClass:"line-number"},[t._v("11")]),s("br"),s("span",{staticClass:"line-number"},[t._v("12")]),s("br")])]),s("p",[t._v("The tree will looks like:")]),t._v(" "),s("div",{staticClass:"language-text line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v(" root ---\x3e A(kvnode, *common key prefix*)\n |\n |\n |\n B(branchnode)\n / \\\n / \\\n / \\\nC1(kvnode, *remain kepath*) C2(kvnode, *remain kepath*)\n | |\n | |\n | |\n D1(leafnode, b'value1') D2(leafnode, b'value2')\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br"),s("span",{staticClass:"line-number"},[t._v("9")]),s("br"),s("span",{staticClass:"line-number"},[t._v("10")]),s("br"),s("span",{staticClass:"line-number"},[t._v("11")]),s("br"),s("span",{staticClass:"line-number"},[t._v("12")]),s("br"),s("span",{staticClass:"line-number"},[t._v("13")]),s("br")])]),s("div",{staticClass:"language-Nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" branchA "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getBranch")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("db"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getRootHash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"key1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("## ==> [A, B, C1, D1]")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" branchB "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getBranch")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("db"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getRootHash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"key2"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("## ==> [A, B, C2, D2]")]),t._v("\n\ndoAssert "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("isValidBranch")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("branchA"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getRootHash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"key1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" true\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("## wrong key, return zero bytes")]),t._v("\ndoAssert "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("isValidBranch")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("branchA"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getRootHash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"key5"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('""')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" true\n\ndoAssert "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("isValidBranch")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("branchB"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getRootHash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"key1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# InvalidNode")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" x "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getBranch")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("db"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getRootHash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"key"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("## ==> [A]")]),t._v("\n\nx "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getBranch")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("db"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getRootHash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"key123"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# InvalidKeyError")]),t._v("\nx "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getBranch")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("db"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getRootHash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"key5"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# there is still branch for non-exist key")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("## ==> [A]")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" branch "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getWitness")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("db"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getRootHash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"key1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v('## equivalent to `getBranch(db, trie.getRootHash(), "key1")`')]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("## ==> [A, B, C1, D1]")]),t._v("\n\nbranch "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getWitness")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("db"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getRootHash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"key"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v('## this will include additional nodes of "key2"')]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("## ==> [A, B, C1, D1, C2, D2]")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" wholeTrie "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getWitness")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("db"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getRootHash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('""')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("## this will return the whole trie")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("## ==> [A, B, C1, D1, C2, D2]")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" node "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" branch"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# B")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" nodeHash "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" keccak256"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("digest")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("node"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("baseAddr"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("uint")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("node"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("len"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" nodes "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getTrieNodes")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("db"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" nodeHash"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\ndoAssert nodes"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("len "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" wholeTrie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("len "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("## ==> [B, C1, D1, C2, D2]")]),t._v("\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br"),s("span",{staticClass:"line-number"},[t._v("9")]),s("br"),s("span",{staticClass:"line-number"},[t._v("10")]),s("br"),s("span",{staticClass:"line-number"},[t._v("11")]),s("br"),s("span",{staticClass:"line-number"},[t._v("12")]),s("br"),s("span",{staticClass:"line-number"},[t._v("13")]),s("br"),s("span",{staticClass:"line-number"},[t._v("14")]),s("br"),s("span",{staticClass:"line-number"},[t._v("15")]),s("br"),s("span",{staticClass:"line-number"},[t._v("16")]),s("br"),s("span",{staticClass:"line-number"},[t._v("17")]),s("br"),s("span",{staticClass:"line-number"},[t._v("18")]),s("br"),s("span",{staticClass:"line-number"},[t._v("19")]),s("br"),s("span",{staticClass:"line-number"},[t._v("20")]),s("br"),s("span",{staticClass:"line-number"},[t._v("21")]),s("br"),s("span",{staticClass:"line-number"},[t._v("22")]),s("br"),s("span",{staticClass:"line-number"},[t._v("23")]),s("br"),s("span",{staticClass:"line-number"},[t._v("24")]),s("br"),s("span",{staticClass:"line-number"},[t._v("25")]),s("br"),s("span",{staticClass:"line-number"},[t._v("26")]),s("br"),s("span",{staticClass:"line-number"},[t._v("27")]),s("br"),s("span",{staticClass:"line-number"},[t._v("28")]),s("br"),s("span",{staticClass:"line-number"},[t._v("29")]),s("br"),s("span",{staticClass:"line-number"},[t._v("30")]),s("br"),s("span",{staticClass:"line-number"},[t._v("31")]),s("br"),s("span",{staticClass:"line-number"},[t._v("32")]),s("br"),s("span",{staticClass:"line-number"},[t._v("33")]),s("br"),s("span",{staticClass:"line-number"},[t._v("34")]),s("br"),s("span",{staticClass:"line-number"},[t._v("35")]),s("br"),s("span",{staticClass:"line-number"},[t._v("36")]),s("br")])]),s("h3",{attrs:{id:"remember-the-lie"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#remember-the-lie"}},[t._v("#")]),t._v(" Remember the lie?")]),t._v(" "),s("p",[t._v("Because trie "),s("code",[t._v("delete")]),t._v(", "),s("code",[t._v("deleteSubtrie")]),t._v(" and "),s("code",[t._v("set")]),t._v(" operation create inaccessible nodes in the underlying DB,\nwe need to remove them if necessary. We already see that "),s("code",[t._v('wholeTrie = getWitness(db, trie.getRootHash(), "")')]),t._v("\nwill return the whole trie, a list of accessible nodes.\nThen we can write the clean tree into a new DB instance to replace the old one.")]),t._v(" "),s("h3",{attrs:{id:"sparse-merkle-trie"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#sparse-merkle-trie"}},[t._v("#")]),t._v(" Sparse Merkle Trie")]),t._v(" "),s("p",[t._v("Sparse Merkle Trie(SMT) is a variant of Binary Trie which uses binary encoding to\nrepresent path during trie travelsal. When Binary Trie uses three types of node,\nSMT only use one type of node without any additional special encoding to store it's key-path.")]),t._v(" "),s("p",[t._v("Actually, it doesn't even store it's key-path anywhere like Binary Trie,\nthe key-path is stored implicitly in the trie structure during key-value insertion.")]),t._v(" "),s("p",[t._v("Because the key-path is not encoded in any special ways, the bits can be extracted directly from\nthe key without any conversion.")]),t._v(" "),s("p",[t._v("However, the key restricted to a fixed length because the algorithm demand a fixed height trie\nto works properly. In this case, the trie height is limited to 160 level,\nor the key is of fixed length 20 bytes (8 bits x 20 = 160).")]),t._v(" "),s("p",[t._v("To be able to use variable length key, the algorithm can be adapted slightly using hashed key before\nconstructing the binary key-path. For example, if using keccak256 as the hashing function,\nthen the height of the tree will be 256, but the key itself can be any length.")]),t._v(" "),s("h4",{attrs:{id:"the-api-2"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#the-api-2"}},[t._v("#")]),t._v(" The API")]),t._v(" "),s("p",[t._v("The primary API for Binary-trie is "),s("code",[t._v("set")]),t._v(" and "),s("code",[t._v("get")]),t._v(".")]),t._v(" "),s("ul",[s("li",[t._v("set(key, value, rootHash[optional]) --- "),s("em",[t._v("store a value associated with a key")])]),t._v(" "),s("li",[t._v("get(key, rootHash[optional]): value --- "),s("em",[t._v("get a value using a key")])])]),t._v(" "),s("p",[t._v("Both "),s("code",[t._v("key")]),t._v(" and "),s("code",[t._v("value")]),t._v(" are of "),s("code",[t._v("BytesRange")]),t._v(" type. And they cannot have zero length.\nYou can also use convenience API "),s("code",[t._v("get")]),t._v(" and "),s("code",[t._v("set")]),t._v(" which accepts\n"),s("code",[t._v("Bytes")]),t._v(" or "),s("code",[t._v("string")]),t._v(" (a "),s("code",[t._v("string")]),t._v(" is conceptually wrong in this context\nand may costlier than a "),s("code",[t._v("BytesRange")]),t._v(", but it is good for testing purpose).")]),t._v(" "),s("p",[t._v("rootHash is an optional parameter. When used, "),s("code",[t._v("get")]),t._v(" will get a key from specific root,\nand "),s("code",[t._v("set")]),t._v(" will also set a key at specific root.")]),t._v(" "),s("p",[t._v("Getting a non-existent key will return zero length BytesRange or a zeroBytesRange.")]),t._v(" "),s("p",[t._v("Sparse Merkle Trie also provide dictionary syntax API for "),s("code",[t._v("set")]),t._v(" and "),s("code",[t._v("get")]),t._v(".")]),t._v(" "),s("ul",[s("li",[t._v("trie[key] = value -- same as "),s("code",[t._v("set")])]),t._v(" "),s("li",[t._v("value = trie[key] -- same as "),s("code",[t._v("get")])]),t._v(" "),s("li",[t._v("contains(key) a.k.a. "),s("code",[t._v("in")]),t._v(" operator")])]),t._v(" "),s("p",[t._v("Additional APIs are:")]),t._v(" "),s("ul",[s("li",[t._v("exists(key) -- returns "),s("code",[t._v("bool")]),t._v(", to check key-value existence -- same as contains")]),t._v(" "),s("li",[t._v("delete(key) -- remove a key-value from the trie")]),t._v(" "),s("li",[t._v("getRootHash(): "),s("code",[t._v("KeccakHash")]),t._v(" with "),s("code",[t._v("BytesRange")]),t._v(" type")]),t._v(" "),s("li",[t._v("getDB(): "),s("code",[t._v("DB")]),t._v(" -- get flat-db pointer")]),t._v(" "),s("li",[t._v("prove(key, rootHash[optional]): proof -- useful for merkling")])]),t._v(" "),s("p",[t._v("Constructor API:")]),t._v(" "),s("ul",[s("li",[t._v("initSparseBinaryTrie(DB, rootHash[optional])")]),t._v(" "),s("li",[t._v("init(SparseBinaryTrie, DB, rootHash[optional])")])]),t._v(" "),s("p",[t._v("Normally you would not set the rootHash when constructing an empty Sparse Merkle Trie.\nSetting the rootHash occured in a scenario where you have a populated DB\nwith existing trie structure and you know the rootHash,\nand then you want to continue/resume the trie operations.")]),t._v(" "),s("h3",{attrs:{id:"examples-2"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#examples-2"}},[t._v("#")]),t._v(" Examples")]),t._v(" "),s("div",{staticClass:"language-Nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v("\n eth"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),t._v("trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("db"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" sparse_binary"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" utils"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v("\n db "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("newMemoryDB")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n trie "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("initSparseMerkleTrie")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("db"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v("\n key1 "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"01234567890123456789"')]),t._v("\n key2 "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"abcdefghijklmnopqrst"')]),t._v("\n\ntrie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("set")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("key1"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\ntrie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("set")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("key2"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value2"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\ndoAssert trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("get")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("key1"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value1"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("toRange\ndoAssert trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("get")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("key2"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value2"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("toRange\n\ntrie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("delete")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("key1"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\ndoAssert trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("get")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("key1"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" zeroBytesRange\n\ntrie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("delete")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("key2"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\ndoAssert trie"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("key2"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" zeroBytesRange\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br"),s("span",{staticClass:"line-number"},[t._v("9")]),s("br"),s("span",{staticClass:"line-number"},[t._v("10")]),s("br"),s("span",{staticClass:"line-number"},[t._v("11")]),s("br"),s("span",{staticClass:"line-number"},[t._v("12")]),s("br"),s("span",{staticClass:"line-number"},[t._v("13")]),s("br"),s("span",{staticClass:"line-number"},[t._v("14")]),s("br"),s("span",{staticClass:"line-number"},[t._v("15")]),s("br"),s("span",{staticClass:"line-number"},[t._v("16")]),s("br"),s("span",{staticClass:"line-number"},[t._v("17")]),s("br"),s("span",{staticClass:"line-number"},[t._v("18")]),s("br"),s("span",{staticClass:"line-number"},[t._v("19")]),s("br"),s("span",{staticClass:"line-number"},[t._v("20")]),s("br"),s("span",{staticClass:"line-number"},[t._v("21")]),s("br")])]),s("p",[t._v("Remember, "),s("code",[t._v("set")]),t._v(" and "),s("code",[t._v("get")]),t._v(" are trie operations. A single "),s("code",[t._v("set")]),t._v(" operation may invoke\nmore than one store/lookup operation into the underlying DB. The same is also happened to "),s("code",[t._v("get")]),t._v(" operation,\nit could do more than one flat-db lookup before it return the requested value.\nWhile Binary Trie perform a variable numbers of lookup and store operations, Sparse Merkle Trie\nwill do constant numbers of lookup and store operations each "),s("code",[t._v("get")]),t._v(" and "),s("code",[t._v("set")]),t._v(" operation.")]),t._v(" "),s("h3",{attrs:{id:"merkle-proofing"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#merkle-proofing"}},[t._v("#")]),t._v(" Merkle Proofing")]),t._v(" "),s("p",[t._v("Using "),s("code",[t._v("prove")]),t._v(" dan "),s("code",[t._v("verifyProof")]),t._v(" API, we can do some merkling with SMT.")]),t._v(" "),s("div",{staticClass:"language-Nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v("\n value1 "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"hello world"')]),t._v("\n badValue "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"bad value"')]),t._v("\n\n trie"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("key1"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" value1\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" proof "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("prove")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("key1"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n doAssert "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("verifyProof")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("proof"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getRootHash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" key1"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" value1"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" true\n doAssert "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("verifyProof")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("proof"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getRootHash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" key1"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" badValue"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" false\n doAssert "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("verifyProof")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("proof"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" trie"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getRootHash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" key2"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" value1"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" false\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br"),s("span",{staticClass:"line-number"},[t._v("9")]),s("br"),s("span",{staticClass:"line-number"},[t._v("10")]),s("br")])]),s("h2",{attrs:{id:"bloom-an-ethereum-bloom-filter"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#bloom-an-ethereum-bloom-filter"}},[t._v("#")]),t._v(" bloom: an Ethereum Bloom Filter")]),t._v(" "),s("h2",{attrs:{id:"introduction-4"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#introduction-4"}},[t._v("#")]),t._v(" Introduction")]),t._v(" "),s("p",[t._v("A Nim implementation of the bloom filter used by Ethereum.")]),t._v(" "),s("h2",{attrs:{id:"description"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#description"}},[t._v("#")]),t._v(" Description")]),t._v(" "),s("p",[s("a",{attrs:{href:"https://en.wikipedia.org/wiki/Bloom_filter",target:"_blank",rel:"noopener noreferrer"}},[t._v("Bloom filters"),s("OutboundLink")],1),t._v(" are data structures that use hash functions to test whether an element is a member of a set. They work like other data structures but are probabilistic in nature: that is, they allow false positive matches but not false negative. Bloom filters use less storage space than other data structures.")]),t._v(" "),s("p",[t._v("Ethereum bloom filters are implemented with the Keccak-256 cryptographic hash function.")]),t._v(" "),s("p",[t._v("To see the bloom filter used in the context of Ethereum, please refer to the "),s("a",{attrs:{href:"https://ethereum.github.io/yellowpaper/paper.pdf",target:"_blank",rel:"noopener noreferrer"}},[t._v("Ethereum Yellow Paper"),s("OutboundLink")],1),t._v(".")]),t._v(" "),s("h2",{attrs:{id:"usage"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#usage"}},[t._v("#")]),t._v(" Usage")]),t._v(" "),s("div",{staticClass:"language-nim line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-nim"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" eth"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),t._v("bloom"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stint\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" f"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" BloomFilter\nf"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("incl")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"test1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("doAssert")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"test1"')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("in")]),t._v(" f"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("doAssert")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"test2"')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("notin")]),t._v(" f"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nf"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("incl")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"test2"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("doAssert")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"test2"')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("in")]),t._v(" f"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("doAssert")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("f"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("value"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),t._v("toHex "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000200000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br")])]),s("h2",{attrs:{id:"building-testing"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#building-testing"}},[t._v("#")]),t._v(" Building & Testing")]),t._v(" "),s("h3",{attrs:{id:"prerequisites"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#prerequisites"}},[t._v("#")]),t._v(" Prerequisites")]),t._v(" "),s("p",[t._v("Nimble is installed.")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("nimble install\nnimble test\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br")])])])}),[],!1,null,null,null);e.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/app.0bbcba5f.js b/assets/js/app.0bbcba5f.js deleted file mode 100644 index 01acc58..0000000 --- a/assets/js/app.0bbcba5f.js +++ /dev/null @@ -1,13 +0,0 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[0],[]]);!function(t){function e(e){for(var r,a,s=e[0],c=e[1],u=e[2],f=0,p=[];f0?o(r(t),9007199254740991):0}},function(t,e,n){var r=n(3),o=n(9),i=n(5),a=n(47),s=n(71),c=n(18),u=c.get,l=c.enforce,f=String(String).split("String");(t.exports=function(t,e,n,s){var c=!!s&&!!s.unsafe,u=!!s&&!!s.enumerable,p=!!s&&!!s.noTargetGet;"function"==typeof n&&("string"!=typeof e||i(n,"name")||o(n,"name",e),l(n).source=f.join("string"==typeof e?e:"")),t!==r?(c?!p&&t[e]&&(u=!0):delete t[e],u?t[e]=n:o(t,e,n)):u?t[e]=n:a(e,n)})(Function.prototype,"toString",(function(){return"function"==typeof this&&u(this).source||s(this)}))},function(t,e,n){var r=n(16);t.exports=function(t){return Object(r(t))}},function(t,e,n){var r=n(53),o=n(13),i=n(114);r||o(Object.prototype,"toString",i,{unsafe:!0})},function(t,e){t.exports=function(t){if(null==t)throw TypeError("Can't call method on "+t);return t}},function(t,e,n){"use strict";var r=n(0),o=n(19).filter,i=n(45),a=n(11),s=i("filter"),c=a("filter");r({target:"Array",proto:!0,forced:!s||!c},{filter:function(t){return o(this,t,arguments.length>1?arguments[1]:void 0)}})},function(t,e,n){var r,o,i,a=n(112),s=n(3),c=n(4),u=n(9),l=n(5),f=n(32),p=n(24),h=s.WeakMap;if(a){var d=new h,v=d.get,m=d.has,y=d.set;r=function(t,e){return y.call(d,t,e),e},o=function(t){return v.call(d,t)||{}},i=function(t){return m.call(d,t)}}else{var g=f("state");p[g]=!0,r=function(t,e){return u(t,g,e),e},o=function(t){return l(t,g)?t[g]:{}},i=function(t){return l(t,g)}}t.exports={set:r,get:o,has:i,enforce:function(t){return i(t)?o(t):r(t,{})},getterFor:function(t){return function(e){var n;if(!c(e)||(n=o(e)).type!==t)throw TypeError("Incompatible receiver, "+t+" required");return n}}}},function(t,e,n){var r=n(51),o=n(43),i=n(14),a=n(12),s=n(104),c=[].push,u=function(t){var e=1==t,n=2==t,u=3==t,l=4==t,f=6==t,p=5==t||f;return function(h,d,v,m){for(var y,g,b=i(h),_=o(b),w=r(d,v,3),x=a(_.length),S=0,O=m||s,k=e?O(h,x):n?O(h,0):void 0;x>S;S++)if((p||S in _)&&(g=w(y=_[S],S,b),t))if(e)k[S]=g;else if(g)switch(t){case 3:return!0;case 5:return y;case 6:return S;case 2:c.call(k,y)}else if(l)return!1;return f?-1:u||l?l:k}};t.exports={forEach:u(0),map:u(1),filter:u(2),some:u(3),every:u(4),find:u(5),findIndex:u(6)}},function(t,e,n){var r=n(6),o=n(68),i=n(21),a=n(10),s=n(31),c=n(5),u=n(69),l=Object.getOwnPropertyDescriptor;e.f=r?l:function(t,e){if(t=a(t),e=s(e,!0),u)try{return l(t,e)}catch(t){}if(c(t,e))return i(!o.f.call(t,e),t[e])}},function(t,e){t.exports=function(t,e){return{enumerable:!(1&t),configurable:!(2&t),writable:!(4&t),value:e}}},function(t,e){var n={}.toString;t.exports=function(t){return n.call(t).slice(8,-1)}},function(t,e){t.exports=!1},function(t,e){t.exports={}},function(t,e,n){var r=n(75),o=n(3),i=function(t){return"function"==typeof t?t:void 0};t.exports=function(t,e){return arguments.length<2?i(r[t])||i(o[t]):r[t]&&r[t][e]||o[t]&&o[t][e]}},function(t,e,n){var r,o=n(8),i=n(116),a=n(50),s=n(24),c=n(117),u=n(70),l=n(32),f=l("IE_PROTO"),p=function(){},h=function(t){return" + diff --git a/lib/nim-chronicles/index.html b/lib/nim-chronicles/index.html index 64e8ef6..e97b837 100644 --- a/lib/nim-chronicles/index.html +++ b/lib/nim-chronicles/index.html @@ -4,17 +4,17 @@ Chronicles | Nimbus Libraries - - + + - - + +
- + diff --git a/lib/nim-chronos/index.html b/lib/nim-chronos/index.html index dea9180..d84fbc7 100644 --- a/lib/nim-chronos/index.html +++ b/lib/nim-chronos/index.html @@ -4,12 +4,12 @@ Chronos | Nimbus Libraries - - + + - - + +
- +

# Chronos

Chronos is an efficient async/await (opens new window) framework for Nim. Features include:

  • Efficient dispatch pipeline for asynchronous execution
  • HTTP server with SSL/TLS support out of the box (no OpenSSL needed)
  • Cancellation support
  • Synchronization primitivies like queues, events and locks
  • FIFO processing order of dispatch queue
  • Minimal exception effect support (see exception effects)

# Installation

You can use Nim's official package manager Nimble to install Chronos:

nimble install https://github.com/status-im/nim-chronos.git
+
1

or add a dependency to your .nimble file:

requires "chronos"
+
1

# Projects using chronos

chronos is available in the Nim Playground (opens new window)

Submit a PR to add yours!

# Documentation

# Concepts

Chronos implements the async/await paradigm in a self-contained library, using +macros, with no specific helpers from the compiler.

Our event loop is called a "dispatcher" and a single instance per thread is +created, as soon as one is needed.

To trigger a dispatcher's processing step, we need to call poll() - either +directly or through a wrapper like runForever() or waitFor(). This step +handles any file descriptors, timers and callbacks that are ready to be +processed.

Future objects encapsulate the result of an async procedure, upon successful +completion, and a list of callbacks to be scheduled after any type of +completion - be that success, failure or cancellation.

(These explicit callbacks are rarely used outside Chronos, being replaced by +implicit ones generated by async procedure execution and await chaining.)

Async procedures (those using the {.async.} pragma) return Future objects.

Inside an async procedure, you can await the future returned by another async +procedure. At this point, control will be handled to the event loop until that +future is completed.

Future completion is tested with Future.finished() and is defined as success, +failure or cancellation. This means that a future is either pending or completed.

To differentiate between completion states, we have Future.failed() and +Future.cancelled().

# Dispatcher

You can run the "dispatcher" event loop forever, with runForever() which is defined as:

proc runForever*() =
+  while true:
+    poll()
+
1
2
3

You can also run it until a certain future is completed, with waitFor() which +will also call Future.read() on it:

proc p(): Future[int] {.async.} =
+  await sleepAsync(100.milliseconds)
+  return 1
+
+echo waitFor p() # prints "1"
+
1
2
3
4
5

waitFor() is defined like this:

proc waitFor*[T](fut: Future[T]): T =
+  while not(fut.finished()):
+    poll()
+  return fut.read()
+
1
2
3
4

# Async procedures and methods

The {.async.} pragma will transform a procedure (or a method) returning a +specialised Future type into a closure iterator. If there is no return type +specified, a Future[void] is returned.

proc p() {.async.} =
+  await sleepAsync(100.milliseconds)
+
+echo p().type # prints "Future[system.void]"
+
1
2
3
4

Whenever await is encountered inside an async procedure, control is passed +back to the dispatcher for as many steps as it's necessary for the awaited +future to complete successfully, fail or be cancelled. await calls the +equivalent of Future.read() on the completed future and returns the +encapsulated value.

proc p1() {.async.} =
+  await sleepAsync(1.seconds)
+
+proc p2() {.async.} =
+  await sleepAsync(1.seconds)
+
+proc p3() {.async.} =
+  let
+    fut1 = p1()
+    fut2 = p2()
+  # Just by executing the async procs, both resulting futures entered the
+  # dispatcher's queue and their "clocks" started ticking.
+  await fut1
+  await fut2
+  # Only one second passed while awaiting them both, not two.
+
+waitFor p3()
+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

Don't let await's behaviour of giving back control to the dispatcher surprise +you. If an async procedure modifies global state, and you can't predict when it +will start executing, the only way to avoid that state changing underneath your +feet, in a certain section, is to not use await in it.

# Error handling

Exceptions inheriting from CatchableError are caught by hidden try blocks +and placed in the Future.error field, changing the future's status to +Failed.

When a future is awaited, that exception is re-raised, only to be caught again +by a hidden try block in the calling async procedure. That's how these +exceptions move up the async chain.

A failed future's callbacks will still be scheduled, but it's not possible to +resume execution from the point an exception was raised.

proc p1() {.async.} =
+  await sleepAsync(1.seconds)
+  raise newException(ValueError, "ValueError inherits from CatchableError")
+
+proc p2() {.async.} =
+  await sleepAsync(1.seconds)
+
+proc p3() {.async.} =
+  let
+    fut1 = p1()
+    fut2 = p2()
+  await fut1
+  echo "unreachable code here"
+  await fut2
+
+# `waitFor()` would call `Future.read()` unconditionally, which would raise the
+# exception in `Future.error`.
+let fut3 = p3()
+while not(fut3.finished()):
+  poll()
+
+echo "fut3.state = ", fut3.state # "Failed"
+if fut3.failed():
+  echo "p3() failed: ", fut3.error.name, ": ", fut3.error.msg
+  # prints "p3() failed: ValueError: ValueError inherits from CatchableError"
+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

You can put the await in a try block, to deal with that exception sooner:

proc p3() {.async.} =
+  let
+    fut1 = p1()
+    fut2 = p2()
+  try:
+    await fut1
+  except CachableError:
+    echo "p1() failed: ", fut1.error.name, ": ", fut1.error.msg
+  echo "reachable code here"
+  await fut2
+
1
2
3
4
5
6
7
8
9
10

Chronos does not allow that future continuations and other callbacks raise +CatchableError - as such, calls to poll will never raise exceptions caused +originating from tasks on the dispatcher queue. It is however possible that +Defect that happen in tasks bubble up through poll as these are not caught +by the transformation.

# Platform independence

Several functions in chronos are backed by the operating system, such as +waiting for network events, creating files and sockets etc. The specific +exceptions that are raised by the OS is platform-dependent, thus such functions +are declared as raising CatchableError but will in general raise something +more specific. In particular, it's possible that some functions that are +annotated as raising CatchableError only raise on some platforms - in order +to work on all platforms, calling code must assume that they will raise even +when they don't seem to do so on one platform.

# Exception effects

chronos currently offers minimal support for exception effects and raises +annotations. In general, during the async transformation, a generic +except CatchableError handler is added around the entire function being +transformed, in order to catch any exceptions and transfer them to the Future. +Because of this, the effect system thinks no exceptions are "leaking" because in +fact, exception handling is deferred to when the future is being read.

Effectively, this means that while code can be compiled with +{.push raises: [Defect]}, the intended effect propagation and checking is +disabled for async functions.

To enable checking exception effects in async code, enable strict mode with +-d:chronosStrictException.

In the strict mode, async functions are checked such that they only raise +CatchableError and thus must make sure to explicitly specify exception +effects on forward declarations, callbacks and methods using +{.raises: [CatchableError].} (or more strict) annotations.

# TODO

  • Pipe/Subprocess Transports.
  • Multithreading Stream/Datagram servers
+ diff --git a/lib/nim-eth/index.html b/lib/nim-eth/index.html index 4b37f5a..67c8e62 100644 --- a/lib/nim-eth/index.html +++ b/lib/nim-eth/index.html @@ -4,12 +4,12 @@ Eth | Nimbus Libraries - - + + - - + +
- +
1
2
3
4

You can also run specific parts of the test suite, e.g.:

# Test p2p functionality
+nimble test_p2p
+# Test rlp functionality
+nimble test_rlp
+
1
2
3
4

# Fuzzing

Next to the test suite, there are also several fuzzing test cases available. +How these can be run is explained in the fuzzing readme (opens new window).

+ diff --git a/lib/nim-libp2p/index.html b/lib/nim-libp2p/index.html index 060c53a..914083d 100644 --- a/lib/nim-libp2p/index.html +++ b/lib/nim-libp2p/index.html @@ -4,15 +4,15 @@ libp2p | Nimbus Libraries - - + + - - + + -

# libp2p

# Running against the Go daemon

An implementation of libp2p in Nim, as a wrapper of the Libp2p Go daemon.

Note that you need Go 1.12+ for the below instructions to work!

Install dependencies and run tests with:

git clone https://github.com/status-im/nim-libp2p && cd nim-libp2p
+

# libp2p

An implementation of libp2p (opens new window) in Nim. Also provides a Nim wrapper of the Libp2p Go daemon (opens new window).

# Project Status

The current native Nim libp2p implementation support is experimental and shouldn't be relied on for production use. It is under active development and contributions are highly welcomed. 😃

Check our examples folder to get started!

# Table of Contents

# Background

libp2p is a networking stack and library modularized out of The IPFS Project (opens new window), and bundled separately for other tools to use.

libp2p is the product of a long and arduous quest of understanding; a deep dive into the internet's network stack and the peer-to-peer protocols from the past. Building large scale peer-to-peer systems has been complex and difficult in the last 15 years and libp2p is a way to fix that. It is a "network stack", a suite of networking protocols that cleanly separates concerns and enables sophisticated applications to only use the protocols they absolutely need, without giving up interoperability and upgradeability.

libp2p grew out of IPFS, but it is built so that lots of people can use it, for lots of different projects.

# Install

nimble install libp2p
+
1

# Prerequisite

# Usage

# API

The specification is available in the docs/api folder.

# Getting Started

Please read the GETTING_STARTED.md guide.

# Tutorials and Examples

Example code can be found in the examples folder.

# Direct Chat Tutorial

# Using the Go Daemon

Please find the installation and usage intructions in daemonapi.md.

Examples can be found in the examples/go-daemon folder (opens new window);

# Development

Clone and Install dependencies:

git clone https://github.com/status-im/nim-libp2p
+cd nim-libp2p
 nimble install
+
1
2
3

# Tests

# Prerequisite

# Run unit tests

# run all the unit tests
 nimble test
-git submodule update --init --recursive
-go version
-git clone https://github.com/libp2p/go-libp2p-daemon
-cd go-libp2p-daemon
-git checkout v0.0.1
-go install ./...
-cd ..
-
1
2
3
4
5
6
7
8
9
10

Try out the chat example:

nim c -r --threads:on examples\chat.nim
-
1

This will output a peer ID such as QmbmHfVvouKammmQDJck4hz33WvVktNEe7pasxz2HgseRu which you can use in another instance to connect to it.

./example/chat
-/connect QmbmHfVvouKammmQDJck4hz33WvVktNEe7pasxz2HgseRu
-
1
2

You can now chat between the instances!

Chat example

# API

Coming soon...

# Experimental native implementation

The native Nim libp2p implementation has finally arrived. Currently, it's support is experimental and shouldn't be relied on for production use. It is however under active development and we hope to achieve a reasonable level of stability in the upcoming months, as we will be integrating it across our own set of products, such as the Nim Beacon Chain.

# What to expect?

This implementation has a bare minimum set of components in order to provide a functional and interoperable libp2p stack. These are:

  • A TCP transport
  • multistream-select
  • Secio
  • Mplex
  • Identify
  • FloodSub
  • GossipSub

This stack reflects the minimal requirements for the upcoming Eth2 implementation.

# How to try it out?

To run it, add nim-libp2p to your project's nimble file and spawn a node as follows:

import tables
-import chronos
-import ../libp2p/[switch,
-                  multistream,
-                  protocols/identify,
-                  connection,
-                  transports/transport,
-                  transports/tcptransport,
-                  multiaddress,
-                  peerinfo,
-                  crypto/crypto,
-                  peer,
-                  protocols/protocol,
-                  muxers/muxer,
-                  muxers/mplex/mplex,
-                  muxers/mplex/types,
-                  protocols/secure/secio,
-                  protocols/secure/secure]
-
-const TestCodec = "/test/proto/1.0.0" # custom protocol string
-
-type
-  TestProto = ref object of LPProtocol # declare a custom protocol
-
-method init(p: TestProto) {.gcsafe.} =
-  # handle incoming connections in closure
-  proc handle(conn: Connection, proto: string) {.async, gcsafe.} =
-    echo "Got from remote - ", cast[string](await conn.readLp())
-    await conn.writeLp("Hello!")
-    await conn.close()
-
-  p.codec = TestCodec # init proto with the correct string id
-  p.handler = handle # set proto handler
-
-proc createSwitch(ma: MultiAddress): (Switch, PeerInfo) =
-  ## Helper to create a swith
-
-  let seckey = PrivateKey.random(RSA) # use a random key for peer id
-  var peerInfo = PeerInfo.init(seckey) # create a peer id and assign
-  peerInfo.addrs.add(ma) # set this peer's multiaddresses (can be any number)
-
-  let identify = newIdentify(peerInfo) # create the identify proto
-
-  proc createMplex(conn: Connection): Muxer =
-    # helper proc to create multiplexers,
-    # use this to perform any custom setup up,
-    # such as adjusting timeout or anything else
-    # that the muxer requires
-    result = newMplex(conn)
-
-  let mplexProvider = newMuxerProvider(createMplex, MplexCodec) # create multiplexer
-  let transports = @[Transport(newTransport(TcpTransport))] # add all transports (tcp only for now, but can be anything in the future)
-  let muxers = {MplexCodec: mplexProvider}.toTable() # add all muxers
-  let secureManagers = {SecioCodec: Secure(newSecio(seckey))}.toTable() # setup the secio and any other secure provider
-
-  # create the switch
-  let switch = newSwitch(peerInfo,
-                         transports,
-                         identify,
-                         muxers,
-                         secureManagers)
-  result = (switch, peerInfo)
-
-proc main() {.async, gcsafe.} =
-  let ma1: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0")
-  let ma2: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0")
-
-  var peerInfo1, peerInfo2: PeerInfo
-  var switch1, switch2: Switch
-  (switch1, peerInfo1) = createSwitch(ma1) # create node 1
-
-  # setup the custom proto
-  let testProto = new TestProto
-  testProto.init() # run it's init method to perform any required initialization
-  switch1.mount(testProto) # mount the proto
-  var switch1Fut = await switch1.start() # start the node
-
-  (switch2, peerInfo2) = createSwitch(ma2) # create node 2
-  var switch2Fut = await switch2.start() # start second node
-  let conn = await switch2.dial(switch1.peerInfo, TestCodec) # dial the first node
-
-  await conn.writeLp("Hello!") # writeLp send a length prefixed buffer over the wire
-  # readLp reads length prefixed bytes and returns a buffer without the prefix
-  echo "Remote responded with - ", cast[string](await conn.readLp())
-
-  await allFutures(switch1.stop(), switch2.stop()) # close connections and shutdown all transports
-  await allFutures(switch1Fut & switch2Fut) # wait for all transports to shutdown
-
-waitFor(main())
-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89

For a more complete example, checkout the directchat.nim example in the examples directory.

- +
1
2

# Packages

List of packages currently in existence for nim-libp2p:

# Libp2p

# Transports

# Secure Channels

# Stream Multiplexers

# Utilities

# Data Types

# Pubsub

Packages that exist in the original libp2p specs and are under active development:

  • libp2p-daemon
  • libp2p-webrtc-direct
  • libp2p-webrtc-star
  • libp2p-websockets
  • libp2p-spdy
  • libp2p-bootstrap
  • libp2p-kad-dht
  • libp2p-mdns
  • libp2p-webrtc-star
  • libp2p-delegated-content-routing
  • libp2p-delegated-peer-routing
  • libp2p-nat-mgnr
  • libp2p-utils

** Note that the current stack reflects the minimal requirements for the upcoming Eth2 implementation.

# Tips and tricks

# enable expensive metrics:

nim c -d:libp2p_expensive_metrics some_file.nim
+
1

# use identify metrics

nim c -d:libp2p_agents_metrics -d:KnownLibP2PAgents=nimbus,lighthouse,prysm,teku some_file.nim
+
1

# specify gossipsub specific topics to measure

nim c -d:KnownLibP2PTopics=topic1,topic2,topic3 some_file.nim
+
1

# Contribute

The libp2p implementation in Nim is a work in progress. We welcome contributors to help out! Specifically, you can:

  • Go through the modules and check out existing issues. This would be especially useful for modules in active development. Some knowledge of IPFS/libp2p may be required, as well as the infrastructure behind it.
  • Perform code reviews. Feel free to let us know if you found anything that can a) speed up the project development b) ensure better quality and c) reduce possible future bugs.
  • Add tests. Help nim-libp2p to be more robust by adding more tests to the tests folder (opens new window).

# Core Developers

@cheatfate (opens new window), Dmitriy Ryajov (opens new window), Giovanni Petrantoni (opens new window), Zahary Karadjov (opens new window)

+ diff --git a/lib/nim-stew/index.html b/lib/nim-stew/index.html index b18ea42..2e85882 100644 --- a/lib/nim-stew/index.html +++ b/lib/nim-stew/index.html @@ -4,12 +4,12 @@ Stew | Nimbus Libraries - - + + - - + +

# Stew

# stew - status e-something w-something

Build Status (Travis) Windows build status (Appveyor) License: Apache License: MIT Stability: experimental

stew is collection of utilities, std library extensions and budding libraries +

# Stew

# stew - status e-something w-something

Build Status (Travis) (opens new window) Windows build status (Appveyor) (opens new window) License: Apache (opens new window) License: MIT (opens new window) Stability: experimental Github action

stew is collection of utilities, std library extensions and budding libraries that are frequently used at Status, but are too small to deserve their own git repository.

We also use stew as a staging ground for code that has yet to be battle-tested.

Some of these libraries may eventually be proposed for inclusion in Nim or broken out into separate repositories.

# Notable libraries

Libraries are documented either in-module or on a separate README in their -respective folders

  • bitops2 - an updated version of bitops.nim, filling in gaps in original code
  • byteutils - utilities that make working with the Nim byte type convenient
  • endians2 - utilities for converting to and from little / big endian integers
  • ptrops - pointer arithmetic utilities
  • ranges - utility functions for working with parts and blobs of memory
  • shims - backports of nim devel code to the stable version that Status is using

# Layout

stew modules are made to be fairly independent of each other, but generally +respective folders

  • arrayops - small helpers and operations on array/openArray
  • assign2 - fast assignments (unlike the = operator in nim which is very slow)
  • bitops2 - an updated version of bitops.nim, filling in gaps in original code
  • byteutils - utilities that make working with the Nim byte type convenient
  • endians2 - utilities for converting to and from little / big endian integers
  • objects - get an object's base type at runtime, as a string
  • ptrops - pointer arithmetic utilities
  • result - friendly, exception-free value-or-error returns, similar to Option[T], from nim-result (opens new window)
  • shims - backports of nim devel code to the stable version that Status is using
  • sequtils2 - extensions to the sequtils module for working conveniently with seq
  • varints - helpers for working with variable length integers

# Layout

stew modules are made to be fairly independent of each other, but generally follow the following layout - if you've used C++'s boost, you'll feel right at home:

# Single-module libraries
 stew/small.nim # small libraries that fits in one module
@@ -75,6 +75,6 @@ submodule) or copy the file to your project instead.

Typically, you will submodules:

import stew/bitops2
 import stew/ranges/bitranges
 
1
2

⚠️ No API/ABI stability - pick a commit and stick with it ⚠️

- + diff --git a/lib/nimcrypto/index.html b/lib/nimcrypto/index.html index d1a5eb9..e244ce4 100644 --- a/lib/nimcrypto/index.html +++ b/lib/nimcrypto/index.html @@ -4,19 +4,19 @@ Nimcrypto | Nimbus Libraries - - + + - - + +

# Documentation

For usage examples of the below algorithm implementations see each module's individual page. In depth documentation also available at Nimbus Libs (opens new window).

# nimcrypto/hash

This module provides helper procedures for calculating secure digests supported by nimcrypto library.

# nimcrypto/sha2

This module implements SHA2 (Secure Hash Algorithm 2) set of cryptographic hash functions designed by National Security Agency, version FIPS-180-4. http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf (opens new window)

# nimcrypto/ripemd

This module implements RIPEMD set of cryptographic hash functions, designed by Hans Dobbertin, Antoon Bosselaers and Bart Preneel. http://www.esat.kuleuven.be/~bosselae/ripemd160/pdf/AB-9601/AB-9601.pdf (opens new window)

This module is Nim adoptation of original C source code by Antoon Bosselaers. https://homes.esat.kuleuven.be/~bosselae/ripemd160/ps/AB-9601/rmd160.c (opens new window)

This module includes support of RIPEMD-128/160/256/320.

# nimcrypto/keccak

This module implements SHA3 (Secure Hash Algorithm 3) set of cryptographic hash functions designed by Guido Bertoni, Joan Daemen, Michaël Peeters and Gilles Van Assche.

This module supports SHA3-224/256/384/512 and SHAKE-128/256.

# nimcrypto/blake2

This module implements BLAKE2 set of cryptographic hash functions designed by Jean-Philippe Aumasson, Luca Henzen, Willi Meier, Raphael C.W. Phan.

This module supports BLAKE2s-224/256 and BLAKE2b-384/512.

# nimcrypto/hmac

This module implements HMAC (Keyed-Hashing for Message Authentication) http://www.ietf.org/rfc/rfc2104.txt (opens new window).

# nimcrypto/rijndael

This module implements Rijndael(AES) crypto algorithm by Vincent Rijmen, Antoon Bosselaers and Paulo Barreto.

Code based on version 3.0 (December 2000) of Optimised ANSI C code for the Rijndael cipher http://www.fastcrypto.org/front/misc/rijndael-alg-fst.c (opens new window).

# nimcrypto/blowfish

This module implements Blowfish crypto algorithm by Bruce Schneier

Code based on C implementation of the Blowfish algorithm created by Paul Kocher https://www.schneier.com/code/bfsh-koc.zip (opens new window).

# nimcrypto/twofish

This module implements Twofish crypto algorithm by Bruce Schneier.

Code based on Optimized C created by Drew Csillag https://www.schneier.com/code/twofish-cpy.zip (opens new window).

# nimcrypto/bcmode

This module implements various Block Cipher Modes.

The five modes currently supported:

  • ECB (Electronic Code Book)
  • CBC (Cipher Block Chaining)
  • CFB (Cipher FeedBack)
  • OFB (Output FeedBack)
  • CTR (Counter)
  • GCM (Galois/Counter Mode)

You can use any of this modes with all the block ciphers of nimcrypto library

GHASH implementation is Nim version of ghash_ctmul64.c which is part of decent BearSSL project https://bearssl.org (opens new window). Copyright (c) 2016 Thomas Pornin

# nimcrypto/utils

Utility functions common to all submodules.

# nimcrypto/sysrand

This module implements interface to operation system's random number generator.

Windows using BCryptGenRandom (if available), CryptGenRandom(PROV_INTEL_SEC) (if available), RtlGenRandom.

RtlGenRandom (available from Windows XP) BCryptGenRandom (available from Windows Vista SP1) CryptGenRandom(PROV_INTEL_SEC) (only when Intel SandyBridge CPU is available).

Linux using genrandom (if available), /dev/urandom.

OpenBSD using getentropy.

NetBSD, FreeBSD, MacOS, Solaris using /dev/urandom.

+